From 338b02d02ee78904ec726fa43f0c093331c2234f Mon Sep 17 00:00:00 2001
From: Karina Litskevich <litskevichkarina@gmail.com>
Date: Tue, 28 Nov 2023 13:21:15 +0300
Subject: [PATCH v2] Fix TransactionIdInRecentPast()

---
 src/backend/utils/adt/xid8funcs.c | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/src/backend/utils/adt/xid8funcs.c b/src/backend/utils/adt/xid8funcs.c
index 06ae940df6..f2a37b2708 100644
--- a/src/backend/utils/adt/xid8funcs.c
+++ b/src/backend/utils/adt/xid8funcs.c
@@ -98,11 +98,12 @@ StaticAssertDecl(MAX_BACKENDS * 2 <= PG_SNAPSHOT_MAX_NXIP,
 static bool
 TransactionIdInRecentPast(FullTransactionId fxid, TransactionId *extracted_xid)
 {
-	uint32		xid_epoch = EpochFromFullTransactionId(fxid);
 	TransactionId xid = XidFromFullTransactionId(fxid);
 	uint32		now_epoch;
 	TransactionId now_epoch_next_xid;
 	FullTransactionId now_fullxid;
+	TransactionId oldest_xid;
+	FullTransactionId oldest_fxid;
 
 	now_fullxid = ReadNextFullTransactionId();
 	now_epoch_next_xid = XidFromFullTransactionId(now_fullxid);
@@ -135,17 +136,22 @@ TransactionIdInRecentPast(FullTransactionId fxid, TransactionId *extracted_xid)
 	Assert(LWLockHeldByMe(XactTruncationLock));
 
 	/*
-	 * If the transaction ID has wrapped around, it's definitely too old to
-	 * determine the commit status.  Otherwise, we can compare it to
-	 * ShmemVariableCache->oldestClogXid to determine whether the relevant
-	 * CLOG entry is guaranteed to still exist.
+	 * If fxid is not older than ShmemVariableCache->oldestClogXid, the relevant
+	 * CLOG entry is guaranteed to still exist. Convert oldestClogXid into a
+	 * full XID to compare it with fxid. Determine the right epoch knowing that
+	 * the oldest and the newest XIDs are guaranteed to be within the XID
+	 * wraparound distance.
 	 */
-	if (xid_epoch + 1 < now_epoch
-		|| (xid_epoch + 1 == now_epoch && xid < now_epoch_next_xid)
-		|| TransactionIdPrecedes(xid, ShmemVariableCache->oldestClogXid))
-		return false;
-
-	return true;
+	oldest_xid = ShmemVariableCache->oldestClogXid;
+	Assert(TransactionIdPrecedesOrEquals(oldest_xid, now_epoch_next_xid));
+	if (oldest_xid <= now_epoch_next_xid)
+		oldest_fxid = FullTransactionIdFromEpochAndXid(now_epoch, oldest_xid);
+	else
+	{
+		Assert(now_epoch > 0);
+		oldest_fxid = FullTransactionIdFromEpochAndXid(now_epoch - 1, oldest_xid);
+	}
+	return !FullTransactionIdPrecedes(fxid, oldest_fxid);
 }
 
 /*
-- 
2.34.1

