From 25f42429e2ff2acca35c9154fc2e36b75c79227a Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Sun, 7 Apr 2024 00:31:43 +0300 Subject: [PATCH] Use an LWLock instead of a spinlock in waitlsn.c This should prevent busy-waiting when number of waiting processes is high. Discussion: https://postgr.es/m/202404030658.hhj3vfxeyhft%40alvherre.pgsql Author: Alvaro Herrera --- src/backend/commands/waitlsn.c | 15 +++++++-------- src/backend/utils/activity/wait_event_names.txt | 1 + src/include/commands/waitlsn.h | 5 +---- src/include/storage/lwlocklist.h | 1 + 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/backend/commands/waitlsn.c b/src/backend/commands/waitlsn.c index 51a34d422e2..a57b818a2d4 100644 --- a/src/backend/commands/waitlsn.c +++ b/src/backend/commands/waitlsn.c @@ -58,7 +58,6 @@ WaitLSNShmemInit(void) &found); if (!found) { - SpinLockInit(&waitLSN->waitersHeapMutex); pg_atomic_init_u64(&waitLSN->minWaitedLSN, PG_UINT64_MAX); pairingheap_initialize(&waitLSN->waitersHeap, lsn_cmp, NULL); memset(&waitLSN->procInfos, 0, MaxBackends * sizeof(WaitLSNProcInfo)); @@ -115,13 +114,13 @@ addLSNWaiter(XLogRecPtr lsn) procInfo->procnum = MyProcNumber; procInfo->waitLSN = lsn; - SpinLockAcquire(&waitLSN->waitersHeapMutex); + LWLockAcquire(WaitLSNLock, LW_EXCLUSIVE); pairingheap_add(&waitLSN->waitersHeap, &procInfo->phNode); procInfo->inHeap = true; updateMinWaitedLSN(); - SpinLockRelease(&waitLSN->waitersHeapMutex); + LWLockRelease(WaitLSNLock); } /* @@ -132,11 +131,11 @@ deleteLSNWaiter(void) { WaitLSNProcInfo *procInfo = &waitLSN->procInfos[MyProcNumber]; - SpinLockAcquire(&waitLSN->waitersHeapMutex); + LWLockAcquire(WaitLSNLock, LW_EXCLUSIVE); if (!procInfo->inHeap) { - SpinLockRelease(&waitLSN->waitersHeapMutex); + LWLockRelease(WaitLSNLock); return; } @@ -144,7 +143,7 @@ deleteLSNWaiter(void) procInfo->inHeap = false; updateMinWaitedLSN(); - SpinLockRelease(&waitLSN->waitersHeapMutex); + LWLockRelease(WaitLSNLock); } /* @@ -160,7 +159,7 @@ WaitLSNSetLatches(XLogRecPtr currentLSN) wakeUpProcNums = palloc(sizeof(int) * MaxBackends); - SpinLockAcquire(&waitLSN->waitersHeapMutex); + LWLockAcquire(WaitLSNLock, LW_EXCLUSIVE); /* * Iterate the pairing heap of waiting processes till we find LSN not yet @@ -182,7 +181,7 @@ WaitLSNSetLatches(XLogRecPtr currentLSN) updateMinWaitedLSN(); - SpinLockRelease(&waitLSN->waitersHeapMutex); + LWLockRelease(WaitLSNLock); /* * Set latches for processes, whose waited LSNs are already replayed. This diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt index 39a1c40d76c..5f2fa814c8e 100644 --- a/src/backend/utils/activity/wait_event_names.txt +++ b/src/backend/utils/activity/wait_event_names.txt @@ -345,6 +345,7 @@ WALSummarizer "Waiting to read or update WAL summarization state." DSMRegistry "Waiting to read or update the dynamic shared memory registry." InjectionPoint "Waiting to read or update information related to injection points." SerialControl "Waiting to read or update shared pg_serial state." +WaitLSN "Waiting to read or update shared Wait-for-LSN state." # # END OF PREDEFINED LWLOCKS (DO NOT CHANGE THIS LINE) diff --git a/src/include/commands/waitlsn.h b/src/include/commands/waitlsn.h index 0d80248682c..b3d9eed64d8 100644 --- a/src/include/commands/waitlsn.h +++ b/src/include/commands/waitlsn.h @@ -55,13 +55,10 @@ typedef struct WaitLSNState /* * A pairing heap of waiting processes order by LSN values (least LSN is - * on top). + * on top). Protected by WaitLSNLock. */ pairingheap waitersHeap; - /* A mutex protecting the pairing heap above */ - slock_t waitersHeapMutex; - /* An array with per-process information, indexed by the process number */ WaitLSNProcInfo procInfos[FLEXIBLE_ARRAY_MEMBER]; } WaitLSNState; diff --git a/src/include/storage/lwlocklist.h b/src/include/storage/lwlocklist.h index 85f6568b9e4..c2bab5a794e 100644 --- a/src/include/storage/lwlocklist.h +++ b/src/include/storage/lwlocklist.h @@ -83,3 +83,4 @@ PG_LWLOCK(49, WALSummarizer) PG_LWLOCK(50, DSMRegistry) PG_LWLOCK(51, InjectionPoint) PG_LWLOCK(52, SerialControl) +PG_LWLOCK(53, WaitLSN)