From f0643957eb29d57dab401ec20e746875d5000e0e Mon Sep 17 00:00:00 2001
From: Vadim Ponomarev <vbponomarev@gmail.com>
Date: Sat, 15 Aug 2026 12:14:40 +0300
Subject: [PATCH v1 4/4] Let a committer whose acknowledgement already arrived
 skip the queue lock

SyncRepWaitForLSN() runs on every commit that wrote WAL, and it takes
SyncRepLock exclusively before it can find out whether there is anything to
wait for.  On a busy primary a large share of those commits find their LSN
already acknowledged and queue for nothing, so the answer costs them a
period of the lock every other committer is lining up on.

Mirror lsn[] into an atomic watermark, written under SyncRepLock right
after lsn[] itself, and read it before taking the lock.  A watermark that
already covers the commit's LSN says a valid quorum acknowledged it, which
is exactly the answer the check under the lock gives.  Both are only ever
moved forward, so a read gone stale can send a committer to the slow path
that would have exited, but never past a wait it owes.

On platforms where pg_atomic_read_u64() is not a plain load the read is
itself a compare-and-exchange, or a spinlock acquisition where 64-bit
atomics are emulated.  Whether the exit still pays for itself there is
untested.
---
 src/backend/replication/syncrep.c           | 17 +++++++++++++++++
 src/backend/replication/walsender.c         |  3 +++
 src/include/replication/walsender_private.h | 11 +++++++++++
 3 files changed, 31 insertions(+)

diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 6406168721b..b23e029661c 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -193,6 +193,17 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
 	Assert(dlist_node_is_detached(&MyProc->syncRepLinks));
 	Assert(WalSndCtl != NULL);
 
+	/*
+	 * A published watermark that already covers this LSN says a valid quorum
+	 * acknowledged it, which is the same answer the check below the lock
+	 * would give.  The watermark only ever moves forward, so a stale read can
+	 * only send us to take the lock for nothing, never past a wait we owe.
+	 * How often this exit fires depends on the wait mode: it needs the
+	 * acknowledgement to have arrived before the committer got here.
+	 */
+	if (lsn <= (XLogRecPtr) pg_atomic_read_u64(&WalSndCtl->lsn_published[mode]))
+		return;
+
 	LWLockAcquire(SyncRepLock, LW_EXCLUSIVE);
 	Assert(MyProc->syncRepState == SYNC_REP_NOT_WAITING);
 
@@ -565,18 +576,24 @@ SyncRepReleaseWaiters(void)
 	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
 		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		pg_atomic_write_u64(&WalSndCtl->lsn_published[SYNC_REP_WAIT_WRITE],
+							(uint64) writePtr);
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE,
 									wakelist, &nwake);
 	}
 	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
 		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		pg_atomic_write_u64(&WalSndCtl->lsn_published[SYNC_REP_WAIT_FLUSH],
+							(uint64) flushPtr);
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH,
 									wakelist, &nwake);
 	}
 	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
 		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		pg_atomic_write_u64(&WalSndCtl->lsn_published[SYNC_REP_WAIT_APPLY],
+							(uint64) applyPtr);
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY,
 									wakelist, &nwake);
 	}
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 0db72ac85b3..17f49aa9f8f 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -4074,7 +4074,10 @@ static void
 WalSndShmemInit(void *arg)
 {
 	for (int i = 0; i < NUM_SYNC_REP_WAIT_MODE; i++)
+	{
 		dlist_init(&(WalSndCtl->SyncRepQueue[i]));
+		pg_atomic_init_u64(&(WalSndCtl->lsn_published[i]), 0);
+	}
 
 	for (int i = 0; i < max_wal_senders; i++)
 	{
diff --git a/src/include/replication/walsender_private.h b/src/include/replication/walsender_private.h
index b0c80deeb24..4354bce759a 100644
--- a/src/include/replication/walsender_private.h
+++ b/src/include/replication/walsender_private.h
@@ -16,6 +16,7 @@
 #include "lib/ilist.h"
 #include "nodes/nodes.h"
 #include "nodes/replnodes.h"
+#include "port/atomics.h"
 #include "replication/syncrep.h"
 #include "storage/condition_variable.h"
 #include "storage/shmem.h"
@@ -95,6 +96,16 @@ typedef struct
 	 */
 	XLogRecPtr	lsn[NUM_SYNC_REP_WAIT_MODE];
 
+	/*
+	 * An atomic mirror of lsn[], written right after it under SyncRepLock and
+	 * only ever forward.  A committer whose LSN this mirror already covers
+	 * was acknowledged by a valid quorum and has nothing to wait for, so it
+	 * reads this before taking SyncRepLock at all.  On platforms where a
+	 * 64-bit atomic read is not a plain load, this read is itself a
+	 * compare-and-exchange or a spinlock acquisition.
+	 */
+	pg_atomic_uint64 lsn_published[NUM_SYNC_REP_WAIT_MODE];
+
 	/*
 	 * Status of data related to the synchronous standbys.  Waiting backends
 	 * can't reload the config file safely, so checkpointer updates this value
-- 
2.34.1

