From 6af193a42531f5876d1144e4f471e86d80264190 Mon Sep 17 00:00:00 2001
From: EC2 Default User <ec2-user@ip-172-31-44-253.ec2.internal>
Date: Thu, 5 Oct 2023 23:15:40 +0000
Subject: [PATCH 1/1] Fix false "apparent wraparound" detected in pg_serial

It is possible that a pg_serial tailXid is ahead of the
HeadXid. Currently, this appears as "wraparound" to
SimpleLruTruncate, which called during Checkpoint.

This patch fixes this scenario by adding a condition in
CheckPointPredicate which considers the SLRU no longer
needed if the tailXID has advanced beyond the headXid.

Discussion: https://www.postgresql.org/message-id/flat/755E19CA-D02C-4A4C-80D3-74F775410C48%40amazon.com
---
 src/backend/storage/lmgr/predicate.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 1af41213b4..92c8be8bca 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -1005,6 +1005,7 @@ void
 CheckPointPredicate(void)
 {
 	int			tailPage;
+	int			truncateCutoff;
 
 	LWLockAcquire(SerialSLRULock, LW_EXCLUSIVE);
 
@@ -1015,10 +1016,17 @@ CheckPointPredicate(void)
 		return;
 	}
 
-	if (TransactionIdIsValid(serialControl->tailXid))
+	tailPage = SerialPage(serialControl->tailXid);
+
+	/*
+	 * Check if the tailXid is valid and that the tailPage is not ahead of
+	 * the headPage, otherwise the SLRU is no longer needed.
+	 */
+	if (TransactionIdIsValid(serialControl->tailXid) &&
+		SerialPagePrecedesLogically(tailPage, serialControl->headPage))
 	{
 		/* We can truncate the SLRU up to the page containing tailXid */
-		tailPage = SerialPage(serialControl->tailXid);
+		truncateCutoff = tailPage;
 	}
 	else
 	{
@@ -1051,14 +1059,14 @@ CheckPointPredicate(void)
 		 *   transaction instigating the summarize fails in
 		 *   SimpleLruReadPage().
 		 */
-		tailPage = serialControl->headPage;
+		truncateCutoff = serialControl->headPage;
 		serialControl->headPage = -1;
 	}
 
 	LWLockRelease(SerialSLRULock);
 
 	/* Truncate away pages that are no longer required */
-	SimpleLruTruncate(SerialSlruCtl, tailPage);
+	SimpleLruTruncate(SerialSlruCtl, truncateCutoff);
 
 	/*
 	 * Write dirty SLRU pages to disk
-- 
2.40.1

