1/*-------------------------------------------------------------------------
4 * postgres transaction (commit) log interface routines
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/access/transam/transam.c
14 * This file contains the high level access-method interface to the
17 *-------------------------------------------------------------------------
28 * Single-item cache for results of TransactionLogFetch. It's worth having
29 * such a cache because we frequently find ourselves repeatedly checking the
30 * same XID, for example when scanning a table just after a bulk insert,
41/* ----------------------------------------------------------------
42 * Postgres log access method interface
45 * ----------------------------------------------------------------
49 * TransactionLogFetch --- fetch commit status of specified transaction id
58 * Before going to the commit log manager, check our single item cache to
59 * see if we didn't just check the transaction status a moment ago.
65 * Also, check to see if the transaction ID is a permanent one.
77 * Get the transaction status.
82 * Cache it, but DO NOT cache status for unfinished or sub-committed
83 * transactions! We only cache status that is guaranteed not to change.
96/* ----------------------------------------------------------------
99 * TransactionIdDidCommit
100 * TransactionIdDidAbort
102 * these functions test the transaction status of
103 * a specified transaction id.
105 * TransactionIdCommitTree
106 * TransactionIdAsyncCommitTree
107 * TransactionIdAbortTree
109 * these functions set the transaction status of the specified
112 * See also TransactionIdIsInProgress, which once was in this module
113 * but now lives in procarray.c, as well as comments at the top of
114 * heapam_visibility.c that explain how everything fits together.
115 * ----------------------------------------------------------------
119 * TransactionIdDidCommit
120 * True iff transaction associated with the identifier did commit.
123 * Assumes transaction identifier is valid and exists in clog.
125bool /* true if given transaction committed */
133 * If it's marked committed, it's committed.
139 * If it's marked subcommitted, we have to check the parent recursively.
140 * However, if it's older than TransactionXmin, we can't look at
141 * pg_subtrans; instead assume that the parent crashed without cleaning up
144 * Originally we Assert'ed that the result of SubTransGetParent was not
145 * zero. However with the introduction of prepared transactions, there can
146 * be a window just after database startup where we do not have complete
147 * knowledge in pg_subtrans of the transactions after TransactionXmin.
148 * StartupSUBTRANS() has ensured that any missing information will be
149 * zeroed. Since this case should not happen under normal conditions, it
150 * seems reasonable to emit a WARNING for it.
161 elog(
WARNING,
"no pg_subtrans entry for subcommitted XID %u",
169 * It's not committed.
175 * TransactionIdDidAbort
176 * True iff transaction associated with the identifier did abort.
179 * Assumes transaction identifier is valid and exists in clog.
181 * Returns true only for explicitly aborted transactions, as transactions
182 * implicitly aborted due to a crash will commonly still appear to be
183 * in-progress in the clog. Most of the time TransactionIdDidCommit(),
184 * with a preceding TransactionIdIsInProgress() check, should be used
185 * instead of TransactionIdDidAbort().
187bool /* true if given transaction aborted */
195 * If it's marked aborted, it's aborted.
201 * If it's marked subcommitted, we have to check the parent recursively.
202 * However, if it's older than TransactionXmin, we can't look at
203 * pg_subtrans; instead assume that the parent crashed without cleaning up
215 /* see notes in TransactionIdDidCommit */
216 elog(
WARNING,
"no pg_subtrans entry for subcommitted XID %u",
230 * TransactionIdCommitTree
231 * Marks the given transaction and children as committed
233 * "xid" is a toplevel transaction commit, and the xids array contains its
234 * committed subtransactions.
236 * This commit operation is not guaranteed to be atomic, but if not, subxids
237 * are correctly marked subcommit first.
248 * TransactionIdAsyncCommitTree
249 * Same as above, but for async commits. The commit record LSN is needed.
260 * TransactionIdAbortTree
261 * Marks the given transaction and children as aborted.
263 * "xid" is a toplevel transaction commit, and the xids array contains its
264 * committed subtransactions.
266 * We don't need to worry about the non-atomic behavior, since any onlookers
267 * will consider all the xacts as not-yet-committed anyway.
277 * TransactionIdPrecedes --- is id1 logically < id2?
283 * If either ID is a permanent XID then we can just do unsigned
284 * comparison. If both are normal, do a modulo-2^32 comparison.
291 diff = (
int32) (id1 - id2);
296 * TransactionIdPrecedesOrEquals --- is id1 logically <= id2?
306 diff = (
int32) (id1 - id2);
311 * TransactionIdFollows --- is id1 logically > id2?
321 diff = (
int32) (id1 - id2);
326 * TransactionIdFollowsOrEquals --- is id1 logically >= id2?
336 diff = (
int32) (id1 - id2);
342 * TransactionIdLatest --- get latest XID among a main xact and its children
351 * In practice it is highly likely that the xids[] array is sorted, and so
352 * we could save some cycles by just taking the last child XID, but this
353 * probably isn't so performance-critical that it's worth depending on
354 * that assumption. But just to show we're not totally stupid, scan the
355 * array back-to-front to avoid useless assignments.
361 result = xids[nxids];
368 * TransactionIdGetCommitLSN
370 * This function returns an LSN that is late enough to be able
371 * to guarantee that if we flush up to the LSN returned then we
372 * will have flushed the transaction's commit record to disk.
374 * The result is not necessarily the exact LSN of the transaction's
375 * commit record! For example, for long-past transactions (those whose
376 * clog pages already migrated to disk), we'll return InvalidXLogRecPtr.
377 * Also, because we group transactions on the same clog page to conserve
378 * storage, we might return the LSN of a later transaction that falls into
387 * Currently, all uses of this function are for xids that were just
388 * reported to be committed by TransactionLogFetch, so we expect that
389 * checking TransactionLogFetch's cache will usually succeed and avoid an
390 * extra trip to shared memory.
395 /* Special XIDs are always known committed */
400 * Get the transaction status.
XidStatus TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
void TransactionIdSetTreeStatus(TransactionId xid, int nsubxids, TransactionId *subxids, XidStatus status, XLogRecPtr lsn)
#define TRANSACTION_STATUS_IN_PROGRESS
#define TRANSACTION_STATUS_ABORTED
#define TRANSACTION_STATUS_SUB_COMMITTED
#define TRANSACTION_STATUS_COMMITTED
TransactionId TransactionXmin
TransactionId SubTransGetParent(TransactionId xid)
void TransactionIdAsyncCommitTree(TransactionId xid, int nxids, TransactionId *xids, XLogRecPtr lsn)
static TransactionId cachedFetchXid
static XidStatus TransactionLogFetch(TransactionId transactionId)
TransactionId TransactionIdLatest(TransactionId mainxid, int nxids, const TransactionId *xids)
bool TransactionIdDidCommit(TransactionId transactionId)
void TransactionIdCommitTree(TransactionId xid, int nxids, TransactionId *xids)
void TransactionIdAbortTree(TransactionId xid, int nxids, TransactionId *xids)
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
bool TransactionIdDidAbort(TransactionId transactionId)
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid)
static XLogRecPtr cachedCommitLSN
static XidStatus cachedFetchXidStatus
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
#define FrozenTransactionId
#define InvalidTransactionId
#define TransactionIdEquals(id1, id2)
#define BootstrapTransactionId
#define TransactionIdIsValid(xid)
#define TransactionIdIsNormal(xid)
#define InvalidXLogRecPtr