From 9b8830fe35ac9a2c2efabc1e91244e8abcd12345 Mon Sep 17 00:00:00 2001
From: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Date: Mon, 16 Mar 2026 12:00:00 +0000
Subject: [Draft Patch v1] Prevent SLRU divergence by checking wraparound before WAL
 flush

In TruncateMultiXact(), if SimpleLruTruncate() encounters an apparent
wraparound, it aborts the truncation safely. However, the TRUNCATE_ID
WAL record has already been emitted. Standbys blindly replay this record
and delete their SLRU segments.
This patch outlines a structural reordering so we only emit the
TRUNCATE WAL record if we are guaranteed to follow through.

---
 src/backend/access/transam/multixact.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index a1b2c3d4e..f5g6h7i8j 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -2980,10 +2980,20 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
 	Assert((MyProc->delayChkptFlags & DELAY_CHKPT_START) == 0);
 	MyProc->delayChkptFlags |= DELAY_CHKPT_START;
 
-	/* WAL log truncation */
-	WriteMTruncateXlogRec(newOldestMultiDB, newOldestMulti, newOldestOffset);
+	/* 
+	 * TODO/DRAFT: 
+	 * We should check if SimpleLruTruncate() will abort due to 
+	 * apparent wraparound *before* flushing the WAL.
+	 * 
+	 * if (SimpleLruCheckWraparound(MultiXactOffsetCtl, MultiXactIdToOffsetPage(newOldestMulti)) &&
+	 *     SimpleLruCheckWraparound(MultiXactMemberCtl, MultiXactIdToMemberPage(newOldestOffset)))
+	 * {
+	 *     // WAL log truncation
+	 *     WriteMTruncateXlogRec(newOldestMultiDB, newOldestMulti, newOldestOffset);
+	 *     // update in array limits, etc.
+	 *     // perform physical truncation
+	 * }
+	 */
 
 	/*
 	 * Update in-memory limits before performing the truncation, while inside
-- 
2.34.1
