From 6cf9d273b3b2c2845e94ace6e8332b5fd1b4e308 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Sat, 22 Oct 2022 22:54:31 +0300 Subject: [PATCH] Extra spin waits for the lock to be freed by concurrent callers --- src/backend/storage/lmgr/lwlock.c | 50 ++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index f5a149b4f42..0917b5874db 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -840,6 +840,19 @@ LWLockAttemptLock(LWLock *lock, LWLockMode mode, LWLockMode waitMode, bool queue_ok, bool wakeup) { uint64 old_state; + uint64 mask; + uint64 increment; + + if (mode == LW_EXCLUSIVE) + { + mask = LW_LOCK_MASK; + increment = LW_VAL_EXCLUSIVE; + } + else + { + mask = LW_VAL_EXCLUSIVE; + increment = LW_VAL_SHARED; + } /* * Read once outside the loop, later iterations will get the newer value @@ -853,21 +866,36 @@ LWLockAttemptLock(LWLock *lock, LWLockMode mode, LWLockMode waitMode, uint64 desired_state; bool lock_free; - desired_state = old_state; + lock_free = (old_state & mask) == 0; - if (mode == LW_EXCLUSIVE) - { - lock_free = (old_state & LW_LOCK_MASK) == 0; - if (lock_free) - desired_state += LW_VAL_EXCLUSIVE; - } - else + /* + * The retries on spin-wait helps to avoid going to relatively expensive + * OS semaphore when lock is freed fast enough by a concurrent process. + * XXX The initial delay and number of repeats are optimized based on + * heavy lock concurrency tests and the values are to be discussed. + */ + if (!lock_free && queue_ok) { - lock_free = (old_state & LW_VAL_EXCLUSIVE) == 0; - if (lock_free) - desired_state += LW_VAL_SHARED; + int i = 0; + SpinDelayStatus delayStatus; + + init_local_spin_delay(&delayStatus); + delayStatus.cur_delay = 500L; + + while (!lock_free && i < 2) + { + perform_spin_delay(&delayStatus); + old_state = pg_atomic_read_u64(&lock->state); + lock_free = (old_state & mask) == 0; + i++; + } } + desired_state = old_state; + + if (lock_free) + desired_state += increment; + if (wakeup) desired_state |= LW_FLAG_RELEASE_OK; -- 2.24.3 (Apple Git-128)