From 638359aa9d6868dc0c7f5919e0596490311e8ee8 Mon Sep 17 00:00:00 2001
From: alterego655 <824662526@qq.com>
Date: Thu, 9 Jul 2026 20:13:24 +0800
Subject: [PATCH v1] Add wait-for-lsn process-exit cleanup callback

Register an on_shmem_exit callback lazily before a process enters a
wait-for-lsn heap, so stale wait state is removed if the process exits while
waiting.  This keeps cleanup local to xlogwait.c and covers non-backend
callers as well.
---
 src/backend/access/transam/xlogwait.c | 33 +++++++++++++++++++++++++++
 src/backend/storage/lmgr/proc.c       |  6 -----
 2 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/src/backend/access/transam/xlogwait.c b/src/backend/access/transam/xlogwait.c
index 582dde3b061..aa6e549ea63 100644
--- a/src/backend/access/transam/xlogwait.c
+++ b/src/backend/access/transam/xlogwait.c
@@ -54,6 +54,7 @@
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "replication/walreceiver.h"
+#include "storage/ipc.h"
 #include "storage/latch.h"
 #include "storage/proc.h"
 #include "storage/shmem.h"
@@ -69,8 +70,12 @@ static int	waitlsn_cmp(const pairingheap_node *a, const pairingheap_node *b,
 
 struct WaitLSNState *waitLSNState = NULL;
 
+static bool waitLSNShmemExitRegistered = false;
+
 static void WaitLSNShmemRequest(void *arg);
 static void WaitLSNShmemInit(void *arg);
+static void WaitLSNShmemExit(int code, Datum arg);
+static void RegisterWaitLSNShmemExit(void);
 
 const ShmemCallbacks WaitLSNShmemCallbacks = {
 	.request_fn = WaitLSNShmemRequest,
@@ -378,6 +383,32 @@ WaitLSNCleanup(void)
 	}
 }
 
+/*
+ * Exit callback to clean up any LSN wait state left behind if this process
+ * exits while waiting.  Transaction abort paths call WaitLSNCleanup()
+ * directly.
+ */
+static void
+WaitLSNShmemExit(int code, Datum arg)
+{
+	WaitLSNCleanup();
+}
+
+/*
+ * Register the process-exit cleanup callback before this process can enter a
+ * wait-LSN heap.  One backend can execute WAIT FOR LSN more than once, so
+ * remember whether the callback is already registered.
+ */
+static void
+RegisterWaitLSNShmemExit(void)
+{
+	if (!waitLSNShmemExitRegistered)
+	{
+		on_shmem_exit(WaitLSNShmemExit, 0);
+		waitLSNShmemExitRegistered = true;
+	}
+}
+
 /*
  * Check if the given LSN type requires recovery to be in progress.
  * Standby wait types (replay, write, flush) require recovery;
@@ -412,6 +443,8 @@ WaitForLSN(WaitLSNType lsnType, XLogRecPtr targetLSN, int64 timeout)
 	/* Should have a valid proc number */
 	Assert(MyProcNumber >= 0 && MyProcNumber < MaxBackends + NUM_AUXILIARY_PROCS);
 
+	RegisterWaitLSNShmemExit();
+
 	if (timeout > 0)
 	{
 		endtime = TimestampTzPlusMilliseconds(GetCurrentTimestamp(), timeout);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 59640bb4f97..2588b14826e 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -37,7 +37,6 @@
 #include "access/transam.h"
 #include "access/twophase.h"
 #include "access/xlogutils.h"
-#include "access/xlogwait.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "postmaster/autovacuum.h"
@@ -963,11 +962,6 @@ ProcKill(int code, Datum arg)
 	 */
 	LWLockReleaseAll();
 
-	/*
-	 * Cleanup waiting for LSN if any.
-	 */
-	WaitLSNCleanup();
-
 	/* Cancel any pending condition variable sleep, too */
 	ConditionVariableCancelSleep();
 
-- 
2.51.0

