From 4239e9524d9c82f1f0c4f11b4078206b193a065a Mon Sep 17 00:00:00 2001
From: Karina Litskevich <litskevichkarina@gmail.com>
Date: Tue, 21 Nov 2023 15:22:52 +0300
Subject: [PATCH v1] 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..6ce560a721 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. To compare them correctly make
+	 * FullTransactionId from ShmemVariableCache->oldestClogXid. Determine the
+	 * right epoch knowing that oldest_fxid should be not much older than
+	 * now_fullxid.
 	 */
-	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(TransactionIdPrecedes(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

