diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c new file mode 100644 index b13ebc6..fe0938a *** a/src/backend/storage/lmgr/lwlock.c --- b/src/backend/storage/lmgr/lwlock.c *************** LWLockAttemptLock(LWLock *lock, LWLockMo *** 584,642 **** { uint32 old_state; ! AssertArg(mode == LW_EXCLUSIVE || mode == LW_SHARED); ! ! /* ! * Read once outside the loop, later iterations will get the newer value ! * via compare & exchange. ! */ ! old_state = pg_atomic_read_u32(&lock->state); ! ! /* loop until we've determined whether we could acquire the lock or not */ ! while (true) { ! uint32 desired_state; ! bool lock_free; ! ! desired_state = old_state; ! if (mode == LW_EXCLUSIVE) { ! lock_free = (old_state & LW_LOCK_MASK) == 0; ! if (lock_free) ! desired_state += LW_VAL_EXCLUSIVE; } else { ! lock_free = (old_state & LW_VAL_EXCLUSIVE) == 0; ! if (lock_free) ! desired_state += LW_VAL_SHARED; } ! /* ! * Attempt to swap in the state we are expecting. If we didn't see ! * lock to be free, that's just the old value. If we saw it as free, ! * we'll attempt to mark it acquired. The reason that we always swap ! * in the value is that this doubles as a memory barrier. We could try ! * to be smarter and only swap in values if we saw the lock as free, ! * but benchmark haven't shown it as beneficial so far. ! * ! * Retry if the value changed since we last looked at it. ! */ ! if (pg_atomic_compare_exchange_u32(&lock->state, ! &old_state, desired_state)) { ! if (lock_free) { /* Great! Got the lock. */ #ifdef LOCK_DEBUG ! if (mode == LW_EXCLUSIVE) ! lock->owner = MyProc; #endif return false; } ! else ! return true; /* someobdy else has the lock */ } } pg_unreachable(); --- 584,629 ---- { uint32 old_state; ! if (mode == LW_SHARED) { ! /* Optimistically try to get the shared lock */ ! old_state = pg_atomic_fetch_add_u32(&lock->state, LW_VAL_SHARED); ! if (old_state & LW_VAL_EXCLUSIVE) { ! /* Failed: exclusive lock is already held. Return the state back. */ ! old_state = pg_atomic_sub_fetch_u32(&lock->state, LW_VAL_SHARED); ! return true; } else { ! /* Succeed: exclusive lock isn't held.*/ ! return false; } + } + else if (mode == LW_EXCLUSIVE) + { + /* Optimistically try to get the exclusive lock */ + old_state = pg_atomic_read_u32(&lock->state); ! if ((old_state & LW_LOCK_MASK) == 0) { ! uint32 desired_state = old_state | LW_VAL_EXCLUSIVE; ! ! if (pg_atomic_compare_exchange_u32(&lock->state, ! &old_state, desired_state)) { /* Great! Got the lock. */ #ifdef LOCK_DEBUG ! lock->owner = MyProc; #endif return false; } ! return true; ! } ! else ! { ! return true; } } pg_unreachable(); *************** LWLockRelease(LWLock *lock) *** 1563,1573 **** /* * We're still waiting for backends to get scheduled, don't wake them up ! * again. */ if ((oldstate & (LW_FLAG_HAS_WAITERS | LW_FLAG_RELEASE_OK)) == (LW_FLAG_HAS_WAITERS | LW_FLAG_RELEASE_OK) && ! (oldstate & LW_LOCK_MASK) == 0) check_waiters = true; else check_waiters = false; --- 1550,1562 ---- /* * We're still waiting for backends to get scheduled, don't wake them up ! * again. Since shared locks are taken optimistically we can observe them ! * during release an exclusive lock. We should still check waiters in this ! * case because those shared locks aren't actullay taked. */ if ((oldstate & (LW_FLAG_HAS_WAITERS | LW_FLAG_RELEASE_OK)) == (LW_FLAG_HAS_WAITERS | LW_FLAG_RELEASE_OK) && ! ((oldstate & LW_LOCK_MASK) == 0 || mode == LW_EXCLUSIVE)) check_waiters = true; else check_waiters = false;