From 557ecbbead1ed01c0d11763fe65f02b7db6184c1 Mon Sep 17 00:00:00 2001
From: Shveta Malik <shveta.malik@gmail.com>
Date: Wed, 23 Sep 2026 15:46:51 +0530
Subject: [PATCH] helper function

---
 src/backend/replication/logical/slotsync.c | 63 ++++++++++++++--------
 1 file changed, 42 insertions(+), 21 deletions(-)

diff --git a/src/backend/replication/logical/slotsync.c b/src/backend/replication/logical/slotsync.c
index 9121a80ec36..b4731687865 100644
--- a/src/backend/replication/logical/slotsync.c
+++ b/src/backend/replication/logical/slotsync.c
@@ -671,6 +671,47 @@ reserve_wal_for_local_slot(XLogRecPtr restart_lsn)
 	LWLockRelease(ReplicationSlotAllocationLock);
 }
 
+/*
+ * Persist the invalidated state of a synchronized slot to disk.
+ *
+ * This encapsulates the required I/O lock management and error handling.
+ * If the disk write fails, we must explicitly release the I/O lock
+ * before re-throwing the error to avoid deadlock with concurrent
+ * Checkpointer processes waiting for the I/O lock while holding
+ * ReplicationSlotAllocationLock.
+ */
+static void
+persist_slot_invalidation(ReplicationSlot *slot, ReplicationSlotInvalidationCause cause)
+{
+	Assert(slot != NULL);
+
+	LWLockAcquire(&slot->io_in_progress_lock, LW_EXCLUSIVE);
+
+	PG_TRY();
+	{
+		/*
+		 * It persists the invalidated state to disk before publishing it in
+		 * shared memory to ensure state durability on crash.
+		 */
+		ReplicationSlotPersistInvalidation(cause,
+										   false);
+	}
+	PG_CATCH();
+	{
+		/*
+		 * Release ownership before making the I/O lock available to
+		 * concurrent invalidators.
+		 */
+		HOLD_INTERRUPTS();		/* match the upcoming RESUME_INTERRUPTS */
+		ReplicationSlotRelease();
+		LWLockRelease(&slot->io_in_progress_lock);
+		PG_RE_THROW();
+	}
+	PG_END_TRY();
+
+	LWLockRelease(&slot->io_in_progress_lock);
+}
+
 /*
  * If the remote restart_lsn and catalog_xmin have caught up with the
  * local ones, then update the LSNs and persist the local synced slot for
@@ -829,27 +870,7 @@ synchronize_one_slot(RemoteSlot *remote_slot, Oid remote_dbid,
 		if (slot->data.invalidated == RS_INVAL_NONE &&
 			remote_slot->invalidated != RS_INVAL_NONE)
 		{
-			LWLockAcquire(&slot->io_in_progress_lock, LW_EXCLUSIVE);
-
-			PG_TRY();
-			{
-				ReplicationSlotPersistInvalidation(remote_slot->invalidated,
-												   false);
-			}
-			PG_CATCH();
-			{
-				/*
-				 * Release ownership before making the I/O lock available to
-				 * concurrent invalidators.
-				 */
-				HOLD_INTERRUPTS();	/* match the upcoming RESUME_INTERRUPTS */
-				ReplicationSlotRelease();
-				LWLockRelease(&slot->io_in_progress_lock);
-				PG_RE_THROW();
-			}
-			PG_END_TRY();
-
-			LWLockRelease(&slot->io_in_progress_lock);
+			persist_slot_invalidation(slot, remote_slot->invalidated);
 			ReplicationSlotsComputeRequiredXmin(false);
 			ReplicationSlotsComputeRequiredLSN();
 
-- 
2.34.1

