diff options
author | Alexander Korotkov <akorotkov@postgresql.org> | 2024-02-08 12:45:26 +0200 |
---|---|---|
committer | Alexander Korotkov <akorotkov@postgresql.org> | 2024-02-09 12:37:21 +0200 |
commit | e3e05addee42c643867557a3065debb085f1d169 (patch) | |
tree | 7aa59c503fca7c295b4ce42f89eda2a3085319cc /src | |
parent | 86d2b434c9a3520a10db4feae236b74452d3d157 (diff) | |
download | postgresql-e3e05addee42c643867557a3065debb085f1d169.tar.gz postgresql-e3e05addee42c643867557a3065debb085f1d169.zip |
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 06ae940df6f..6fbfb3a1cc2 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 - * 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 + * ShmemVariableCache->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, 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); } /* |