From 479bfdc34f6dc79cf31cdaac355465117b7a1992 Mon Sep 17 00:00:00 2001 From: John Morris Date: Wed, 1 Nov 2023 13:16:38 -0700 Subject: [PATCH] Use atomic increment instead of a lock when advancing the unlogged LSN --- src/backend/access/transam/xlog.c | 48 +++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index b541be8eec..d903f7280f 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -469,9 +469,8 @@ typedef struct XLogCtlData XLogSegNo lastRemovedSegNo; /* latest removed/recycled XLOG segment */ - /* Fake LSN counter, for unlogged relations. Protected by ulsn_lck. */ - XLogRecPtr unloggedLSN; - slock_t ulsn_lck; + /* Fake LSN counter for unlogged relations. Updated atomically. */ + pg_atomic_uint64 unloggedLSN; /* Time and LSN of last xlog segment switch. Protected by WALWriteLock. */ pg_time_t lastSegSwitchTime; @@ -4287,21 +4286,16 @@ DataChecksumsEnabled(void) * * Each call generates an LSN that is greater than any previous value * returned. The current counter value is saved and restored across clean - * shutdowns, but like unlogged relations, does not survive a crash. This can - * be used in lieu of real LSN values returned by XLogInsert, if you need an - * LSN-like increasing sequence of numbers without writing any WAL. + * shutdowns, but it is reset after a crash. Consequently, it should + * only be used for unlogged relations or for data which does not survive + * a crash. An unlogged LSN may be used in lieu of real LSN values + * returned by XLogInsert, if you need an LSN-like increasing sequence + * of numbers without writing any WAL. */ XLogRecPtr GetFakeLSNForUnloggedRel(void) { - XLogRecPtr nextUnloggedLSN; - - /* increment the unloggedLSN counter, need SpinLock */ - SpinLockAcquire(&XLogCtl->ulsn_lck); - nextUnloggedLSN = XLogCtl->unloggedLSN++; - SpinLockRelease(&XLogCtl->ulsn_lck); - - return nextUnloggedLSN; + return pg_atomic_fetch_add_u64(&XLogCtl->unloggedLSN, 1); } /* @@ -4714,7 +4708,6 @@ XLOGShmemInit(void) SpinLockInit(&XLogCtl->Insert.insertpos_lck); SpinLockInit(&XLogCtl->info_lck); - SpinLockInit(&XLogCtl->ulsn_lck); } /* @@ -5319,9 +5312,9 @@ StartupXLOG(void) * the unlogged LSN counter can be reset too. */ if (ControlFile->state == DB_SHUTDOWNED) - XLogCtl->unloggedLSN = ControlFile->unloggedLSN; + pg_atomic_init_u64(&XLogCtl->unloggedLSN, ControlFile->unloggedLSN); else - XLogCtl->unloggedLSN = FirstNormalUnloggedLSN; + pg_atomic_init_u64(&XLogCtl->unloggedLSN, FirstNormalUnloggedLSN); /* * Copy any missing timeline history files between 'now' and the recovery @@ -6899,13 +6892,20 @@ CreateCheckPoint(int flags) ControlFile->minRecoveryPointTLI = 0; /* - * Persist unloggedLSN value. It's reset on crash recovery, so this goes - * unused on non-shutdown checkpoints, but seems useful to store it always - * for debugging purposes. - */ - SpinLockAcquire(&XLogCtl->ulsn_lck); - ControlFile->unloggedLSN = XLogCtl->unloggedLSN; - SpinLockRelease(&XLogCtl->ulsn_lck); + * Persist the unloggedLSN. + * We have two cases to consider: + * 1) We are shutting down. All other backends have finished, and + * the unloggedLSN isn't being updated any more. There are no race + * conditions. We just save the current value and restore it + * when we are restarting. + * 2) We are actively running, say during a checkpoint. + * The unloggedLSN is being updated by other backends, + * but the value we write out doesn't matter. + * The unloggedLSN will be reset on crash recovery. + * We could simply write a zero, but the current value + * might be useful for debugging. + */ + ControlFile->unloggedLSN = pg_atomic_read_u64(&XLogCtl->unloggedLSN); UpdateControlFile(); LWLockRelease(ControlFileLock); -- 2.33.0