From d91d4aafcc4cac4344a0674e3119c6c504884810 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Wed, 23 Nov 2022 11:22:56 +0000
Subject: [PATCH v1] Decouple last important WAL record LSN from WAL insert
 locks

---
 src/backend/access/transam/xlog.c | 57 +++++++++++++------------------
 1 file changed, 23 insertions(+), 34 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index a31fbbff78..882e968c8f 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -363,21 +363,11 @@ typedef struct XLogwrtResult
  * the WAL record is just copied to the page and the lock is released. But
  * to avoid the deadlock-scenario explained above, the indicator is always
  * updated before sleeping while holding an insertion lock.
- *
- * lastImportantAt contains the LSN of the last important WAL record inserted
- * using a given lock. This value is used to detect if there has been
- * important WAL activity since the last time some action, like a checkpoint,
- * was performed - allowing to not repeat the action if not. The LSN is
- * updated for all insertions, unless the XLOG_MARK_UNIMPORTANT flag was
- * set. lastImportantAt is never cleared, only overwritten by the LSN of newer
- * records.  Tracking the WAL activity directly in WALInsertLock has the
- * advantage of not needing any additional locks to update the value.
  */
 typedef struct
 {
 	LWLock		lock;
 	XLogRecPtr	insertingAt;
-	XLogRecPtr	lastImportantAt;
 } WALInsertLock;
 
 /*
@@ -447,6 +437,19 @@ typedef struct XLogCtlInsert
 	int			runningBackups;
 	XLogRecPtr	lastBackupStart;
 
+	slock_t		lastimportantpos_lck;	/* protects lastImportantPos */
+
+	/*
+	 * lastImportantPos contains the LSN of the last important WAL record
+	 * inserted in the server. This value is used to detect if there has been
+	 * important WAL activity since the last time some action, like a
+	 * checkpoint, was performed - allowing to not repeat the action if not.
+	 * The LSN is updated for all insertions, unless the XLOG_MARK_UNIMPORTANT
+	 * flag was set. lastImportantPos is never cleared, only overwritten by the
+	 * LSN of newer records.
+	 */
+	XLogRecPtr	lastImportantPos;
+
 	/*
 	 * WAL insertion locks.
 	 */
@@ -871,9 +874,9 @@ XLogInsertRecord(XLogRecData *rdata,
 		 */
 		if ((flags & XLOG_MARK_UNIMPORTANT) == 0)
 		{
-			int			lockno = holdingAllLocks ? 0 : MyLockNo;
-
-			WALInsertLocks[lockno].l.lastImportantAt = StartPos;
+			SpinLockAcquire(&Insert->lastimportantpos_lck);
+			Insert->lastImportantPos = StartPos;
+			SpinLockRelease(&Insert->lastimportantpos_lck);
 		}
 	}
 	else
@@ -4603,9 +4606,10 @@ XLOGShmemInit(void)
 	{
 		LWLockInitialize(&WALInsertLocks[i].l.lock, LWTRANCHE_WAL_INSERT);
 		WALInsertLocks[i].l.insertingAt = InvalidXLogRecPtr;
-		WALInsertLocks[i].l.lastImportantAt = InvalidXLogRecPtr;
 	}
 
+	XLogCtl->Insert.lastImportantPos = InvalidXLogRecPtr;
+
 	/*
 	 * Align the start of the page buffers to a full xlog block size boundary.
 	 * This simplifies some calculations in XLOG insertion. It is also
@@ -4625,6 +4629,7 @@ XLOGShmemInit(void)
 	XLogCtl->WalWriterSleeping = false;
 
 	SpinLockInit(&XLogCtl->Insert.insertpos_lck);
+	SpinLockInit(&XLogCtl->Insert.lastimportantpos_lck);
 	SpinLockInit(&XLogCtl->info_lck);
 	SpinLockInit(&XLogCtl->ulsn_lck);
 }
@@ -6109,32 +6114,16 @@ GetWALInsertionTimeLine(void)
  * GetLastImportantRecPtr -- Returns the LSN of the last important record
  * inserted. All records not explicitly marked as unimportant are considered
  * important.
- *
- * The LSN is determined by computing the maximum of
- * WALInsertLocks[i].lastImportantAt.
  */
 XLogRecPtr
 GetLastImportantRecPtr(void)
 {
+	XLogCtlInsert *Insert = &XLogCtl->Insert;
 	XLogRecPtr	res = InvalidXLogRecPtr;
-	int			i;
 
-	for (i = 0; i < NUM_XLOGINSERT_LOCKS; i++)
-	{
-		XLogRecPtr	last_important;
-
-		/*
-		 * Need to take a lock to prevent torn reads of the LSN, which are
-		 * possible on some of the supported platforms. WAL insert locks only
-		 * support exclusive mode, so we have to use that.
-		 */
-		LWLockAcquire(&WALInsertLocks[i].l.lock, LW_EXCLUSIVE);
-		last_important = WALInsertLocks[i].l.lastImportantAt;
-		LWLockRelease(&WALInsertLocks[i].l.lock);
-
-		if (res < last_important)
-			res = last_important;
-	}
+	SpinLockAcquire(&Insert->lastimportantpos_lck);
+	res = Insert->lastImportantPos;
+	SpinLockRelease(&Insert->lastimportantpos_lck);
 
 	return res;
 }
-- 
2.34.1

