From 6ed8533ace2aff0eb5bf0a3eeefe96af23839ba5 Mon Sep 17 00:00:00 2001
From: alterego655 <824662526@qq.com>
Date: Fri, 24 Jul 2026 16:34:29 +0800
Subject: [PATCH v6 3/5] Avoid locking when an LSN waiter is already removed

WaitLSNWakeup() removes each selected waiter from its heap and clears
its inHeap flag before setting its latch.  When such a waiter later
calls deleteLSNWaiter(), it acquires WaitLSNLock exclusively only to
discover that there is nothing left to remove.  Waking many waiters can
therefore make them serialize on the lock for no useful work.

Check inHeap before acquiring WaitLSNLock.  A lockless false value is
conclusive because only the owning backend can change inHeap from false
to true.  A concurrent waker can only clear it.  A stale true value
falls through to the existing recheck under the lock.
---
 src/backend/access/transam/xlogwait.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/backend/access/transam/xlogwait.c b/src/backend/access/transam/xlogwait.c
index 85de3f5cdae..6b501fef7ba 100644
--- a/src/backend/access/transam/xlogwait.c
+++ b/src/backend/access/transam/xlogwait.c
@@ -252,6 +252,15 @@ deleteLSNWaiter(WaitLSNType lsnType)
 
 	Assert(i >= 0 && i < WAIT_LSN_TYPE_COUNT);
 
+	/*
+	 * Avoid taking WaitLSNLock if a waker has already removed us.  Only this
+	 * backend can set inHeap; other processes can only clear it.  Therefore
+	 * false is conclusive, while a stale true is harmless because it is
+	 * rechecked under WaitLSNLock below.
+	 */
+	if (!procInfo->inHeap)
+		return;
+
 	LWLockAcquire(WaitLSNLock, LW_EXCLUSIVE);
 
 	Assert(procInfo->lsnType == lsnType);
-- 
2.51.0

