diff options
author | Alexander Korotkov | 2024-02-08 10:45:26 +0000 |
---|---|---|
committer | Alexander Korotkov | 2024-02-08 10:45:26 +0000 |
commit | 165d921c9a883814a35e8161fc692793e9c945a4 (patch) | |
tree | 1187aaa43f68c0c2600dbfea728d0cc422945a78 /src | |
parent | 5869aef9a15d5dc0b4de3d63d1ae360a6f34afb4 (diff) |
Fix wrong logic in TransactionIdInRecentPast()
The TransactionIdInRecentPast() should return false for all the transactions
older than TransamVariables->oldestClogXid. However, the function contains
a bug in comparison FullTransactionId to TransactionID allowing full
transactions between nextXid - 2^32 and oldestClogXid - 2^31.
This commit fixes TransactionIdInRecentPast() by turning the oldestClogXid into
FullTransactionId first, then performing the comparison.
Backpatch to all supported versions.
Reported-by: Egor Chindyaskin
Bug: 18212
Discussion: https://postgr.es/m/18212-547307f8adf57262%40postgresql.org
Author: Karina Litskevich
Reviewed-by: Kyotaro Horiguchi
Backpatch-through: 12
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/utils/adt/xid8funcs.c | 30 |
1 files changed, 19 insertions, 11 deletions
diff --git a/src/backend/utils/adt/xid8funcs.c b/src/backend/utils/adt/xid8funcs.c index be5e28c93ab..aa64a7c8b3f 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,24 @@ 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 - * TransamVariables->oldestClogXid to determine whether the relevant CLOG - * entry is guaranteed to still exist. + * If fxid is not older than TransamVariables->oldestClogXid, the relevant + * CLOG entry is guaranteed to still exist. Convert + * TransamVariables->oldestClogXid into a FullTransactionId to compare it + * with fxid. Determine the right epoch knowing that oldest_fxid + * shouldn't be more than 2^31 older than now_fullxid. */ - if (xid_epoch + 1 < now_epoch - || (xid_epoch + 1 == now_epoch && xid < now_epoch_next_xid) - || TransactionIdPrecedes(xid, TransamVariables->oldestClogXid)) - return false; - - return true; + oldest_xid = TransamVariables->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); } /* |