| /*------------------------------------------------------------------------- |
| * |
| * transam.h |
| * postgres transaction access method support code |
| * |
| * |
| * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group |
| * Portions Copyright (c) 1994, Regents of the University of California |
| * |
| * src/include/access/transam.h |
| * |
| *------------------------------------------------------------------------- |
| */ |
| #ifndef TRANSAM_H |
| #define TRANSAM_H |
| |
| #include "access/xlogdefs.h" |
| |
| |
| /* ---------------- |
| * Special transaction ID values |
| * |
| * BootstrapTransactionId is the XID for "bootstrap" operations, and |
| * FrozenTransactionId is used for very old tuples. Both should |
| * always be considered valid. |
| * |
| * FirstNormalTransactionId is the first "normal" transaction id. |
| * Note: if you need to change it, you must change pg_class.h as well. |
| * ---------------- |
| */ |
| #define InvalidTransactionId ((TransactionId) 0) |
| #define BootstrapTransactionId ((TransactionId) 1) |
| #define FrozenTransactionId ((TransactionId) 2) |
| #define FirstNormalTransactionId ((TransactionId) 3) |
| #define MaxTransactionId ((TransactionId) 0xFFFFFFFF) |
| |
| /* ---------------- |
| * transaction ID manipulation macros |
| * ---------------- |
| */ |
| #define TransactionIdIsValid(xid) ((xid) != InvalidTransactionId) |
| #define TransactionIdIsNormal(xid) ((xid) >= FirstNormalTransactionId) |
| #define TransactionIdEquals(id1, id2) ((id1) == (id2)) |
| #define TransactionIdStore(xid, dest) (*(dest) = (xid)) |
| #define StoreInvalidTransactionId(dest) (*(dest) = InvalidTransactionId) |
| |
| #define EpochFromFullTransactionId(x) ((uint32) ((x).value >> 32)) |
| #define XidFromFullTransactionId(x) ((uint32) (x).value) |
| #define U64FromFullTransactionId(x) ((x).value) |
| #define FullTransactionIdEquals(a, b) ((a).value == (b).value) |
| #define FullTransactionIdPrecedes(a, b) ((a).value < (b).value) |
| #define FullTransactionIdPrecedesOrEquals(a, b) ((a).value <= (b).value) |
| #define FullTransactionIdFollows(a, b) ((a).value > (b).value) |
| #define FullTransactionIdFollowsOrEquals(a, b) ((a).value >= (b).value) |
| #define FullTransactionIdIsValid(x) TransactionIdIsValid(XidFromFullTransactionId(x)) |
| #define InvalidFullTransactionId FullTransactionIdFromEpochAndXid(0, InvalidTransactionId) |
| #define FirstNormalFullTransactionId FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId) |
| #define FullTransactionIdIsNormal(x) FullTransactionIdFollowsOrEquals(x, FirstNormalFullTransactionId) |
| |
| /* |
| * A 64 bit value that contains an epoch and a TransactionId. This is |
| * wrapped in a struct to prevent implicit conversion to/from TransactionId. |
| * Not all values represent valid normal XIDs. |
| */ |
| typedef struct FullTransactionId |
| { |
| uint64 value; |
| } FullTransactionId; |
| |
| static inline FullTransactionId |
| FullTransactionIdFromEpochAndXid(uint32 epoch, TransactionId xid) |
| { |
| FullTransactionId result; |
| |
| result.value = ((uint64) epoch) << 32 | xid; |
| |
| return result; |
| } |
| |
| static inline FullTransactionId |
| FullTransactionIdFromU64(uint64 value) |
| { |
| FullTransactionId result; |
| |
| result.value = value; |
| |
| return result; |
| } |
| |
| /* advance a transaction ID variable, handling wraparound correctly */ |
| #define TransactionIdAdvance(dest) \ |
| do { \ |
| (dest)++; \ |
| if ((dest) < FirstNormalTransactionId) \ |
| (dest) = FirstNormalTransactionId; \ |
| } while(0) |
| |
| /* |
| * Retreat a FullTransactionId variable, stepping over xids that would appear |
| * to be special only when viewed as 32bit XIDs. |
| */ |
| static inline void |
| FullTransactionIdRetreat(FullTransactionId *dest) |
| { |
| dest->value--; |
| |
| /* |
| * In contrast to 32bit XIDs don't step over the "actual" special xids. |
| * For 64bit xids these can't be reached as part of a wraparound as they |
| * can in the 32bit case. |
| */ |
| if (FullTransactionIdPrecedes(*dest, FirstNormalFullTransactionId)) |
| return; |
| |
| /* |
| * But we do need to step over XIDs that'd appear special only for 32bit |
| * XIDs. |
| */ |
| while (XidFromFullTransactionId(*dest) < FirstNormalTransactionId) |
| dest->value--; |
| } |
| |
| /* |
| * Advance a FullTransactionId variable, stepping over xids that would appear |
| * to be special only when viewed as 32bit XIDs. |
| */ |
| static inline void |
| FullTransactionIdAdvance(FullTransactionId *dest) |
| { |
| dest->value++; |
| |
| /* see FullTransactionIdAdvance() */ |
| if (FullTransactionIdPrecedes(*dest, FirstNormalFullTransactionId)) |
| return; |
| |
| while (XidFromFullTransactionId(*dest) < FirstNormalTransactionId) |
| dest->value++; |
| } |
| |
| /* back up a transaction ID variable, handling wraparound correctly */ |
| #define TransactionIdRetreat(dest) \ |
| do { \ |
| (dest)--; \ |
| } while ((dest) < FirstNormalTransactionId) |
| |
| /* compare two XIDs already known to be normal; this is a macro for speed */ |
| #define NormalTransactionIdPrecedes(id1, id2) \ |
| (AssertMacro(TransactionIdIsNormal(id1) && TransactionIdIsNormal(id2)), \ |
| (int32) ((id1) - (id2)) < 0) |
| |
| /* compare two XIDs already known to be normal; this is a macro for speed */ |
| #define NormalTransactionIdFollows(id1, id2) \ |
| (AssertMacro(TransactionIdIsNormal(id1) && TransactionIdIsNormal(id2)), \ |
| (int32) ((id1) - (id2)) > 0) |
| |
| /* ---------- |
| * Object ID (OID) zero is InvalidOid. |
| * |
| * OIDs 1-9999 are reserved for manual assignment (see .dat files in |
| * src/include/catalog/). Of these, 8000-9999 are reserved for |
| * development purposes (such as in-progress patches and forks); |
| * they should not appear in released versions. |
| * |
| * OIDs 10000-11999 are reserved for assignment by genbki.pl, for use |
| * when the .dat files in src/include/catalog/ do not specify an OID |
| * for a catalog entry that requires one. Note that genbki.pl assigns |
| * these OIDs independently in each catalog, so they're not guaranteed |
| * to be globally unique. |
| * |
| * OIDS 12000-16383 are reserved for assignment during initdb |
| * using the OID generator. (We start the generator at 12000.) |
| * |
| * OIDs beginning at 16384 are assigned from the OID generator |
| * during normal multiuser operation. (We force the generator up to |
| * 16384 as soon as we are in normal operation.) |
| * |
| * The choices of 8000, 10000 and 12000 are completely arbitrary, and can be |
| * moved if we run low on OIDs in any category. Changing the macros below, |
| * and updating relevant documentation (see bki.sgml and RELEASE_CHANGES), |
| * should be sufficient to do this. Moving the 16384 boundary between |
| * initdb-assigned OIDs and user-defined objects would be substantially |
| * more painful, however, since some user-defined OIDs will appear in |
| * on-disk data; such a change would probably break pg_upgrade. |
| * |
| * NOTE: if the OID generator wraps around, we skip over OIDs 0-16383 |
| * and resume with 16384. This minimizes the odds of OID conflict, by not |
| * reassigning OIDs that might have been assigned during initdb. |
| * ---------- |
| */ |
| #define FirstGenbkiObjectId 10000 |
| #define FirstBootstrapObjectId 12000 |
| #define FirstNormalObjectId 16384 |
| |
| /* |
| * For the time being, we split the OID range so that newly added objects |
| * won't conflict between GPDB and GPSQL. If two merge into one in some day, |
| * this boundary will disappear. |
| */ |
| #define LowestGPSQLBootstrapObjectId 7500 |
| |
| /* |
| * Reserve a block of OIDs for use during binary upgrade. We create functions |
| * needed during the upgrade here, but they are dropped after the ugprade, so |
| * should not be present in other contexts. They need a reserved block of OIDs |
| * to avoid colliding with user objects that are created later in the upgrade |
| * process. |
| */ |
| #define FirstBinaryUpgradeReservedObjectId 9000 |
| #define LastBinaryUpgradeReservedObjectId 9100 |
| |
| /* |
| * VariableCache is a data structure in shared memory that is used to track |
| * OID and XID assignment state. For largely historical reasons, there is |
| * just one struct with different fields that are protected by different |
| * LWLocks. |
| * |
| * Note: xidWrapLimit and oldestXidDB are not "active" values, but are |
| * used just to generate useful messages when xidWarnLimit or xidStopLimit |
| * are exceeded. |
| */ |
| typedef struct VariableCacheData |
| { |
| /* |
| * These fields are protected by OidGenLock. |
| */ |
| Oid nextOid; /* next OID to assign */ |
| uint32 oidCount; /* OIDs available before must do XLOG work */ |
| |
| /* |
| * These fields are protected by RelfilenodeGenLock. |
| */ |
| Oid nextRelfilenode; /* next relfilenode to assign */ |
| uint32 relfilenodeCount; /* relfilenodes available before we must do XLOG work */ |
| |
| /* |
| * These fields are protected by XidGenLock. |
| */ |
| FullTransactionId nextXid; /* next XID to assign */ |
| |
| TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */ |
| TransactionId xidVacLimit; /* start forcing autovacuums here */ |
| TransactionId xidWarnLimit; /* start complaining here */ |
| TransactionId xidStopLimit; /* refuse to advance nextXid beyond here */ |
| TransactionId xidWrapLimit; /* where the world ends */ |
| Oid oldestXidDB; /* database with minimum datfrozenxid */ |
| |
| /* |
| * These fields are protected by CommitTsLock |
| */ |
| TransactionId oldestCommitTsXid; |
| TransactionId newestCommitTsXid; |
| |
| /* |
| * These fields are protected by ProcArrayLock. |
| */ |
| FullTransactionId latestCompletedXid; /* newest full XID that has |
| * committed or aborted */ |
| DistributedTransactionId latestCompletedGxid; /* newest distributed XID that has |
| committed or aborted */ |
| |
| /* |
| * The two variables are protected by shmGxidGenLock. Note nextGxid won't |
| * be accurate after crash recovery. When crash recovery happens, we bump |
| * them to the next batch on the coordinator, while on the primary, it is |
| * not accurate until the next query with an assigned gxid is dispatched. |
| */ |
| DistributedTransactionId nextGxid; /* next full XID to assign */ |
| uint32 GxidCount; /* Gxids available before must do XLOG work */ |
| |
| /* |
| * Number of top-level transactions with xids (i.e. which may have |
| * modified the database) that completed in some form since the start of |
| * the server. This currently is solely used to check whether |
| * GetSnapshotData() needs to recompute the contents of the snapshot, or |
| * not. There are likely other users of this. Always above 1. |
| */ |
| uint64 xactCompletionCount; |
| |
| /* |
| * These fields are protected by XactTruncationLock |
| */ |
| TransactionId oldestClogXid; /* oldest it's safe to look up in clog */ |
| |
| } VariableCacheData; |
| |
| typedef VariableCacheData *VariableCache; |
| |
| |
| /* ---------------- |
| * extern declarations |
| * ---------------- |
| */ |
| |
| /* in transam/xact.c */ |
| extern bool TransactionStartedDuringRecovery(void); |
| |
| /* in transam/varsup.c */ |
| extern PGDLLIMPORT VariableCache ShmemVariableCache; |
| |
| extern int xid_stop_limit; |
| extern int xid_warn_limit; |
| |
| /* GPDB-specific */ |
| extern char *gp_pause_on_restore_point_replay; |
| |
| /* hook for plugins to assign new relfilenode */ |
| typedef Oid (*NewSegRelfilenode_assign_hook_type)(void); |
| extern PGDLLIMPORT NewSegRelfilenode_assign_hook_type NewSegRelfilenode_assign_hook; |
| |
| /* |
| * prototypes for functions in transam/transam.c |
| */ |
| extern bool TransactionIdDidCommit(TransactionId transactionId); |
| extern bool TransactionIdDidAbort(TransactionId transactionId); |
| extern bool TransactionIdDidAbortForReader(TransactionId transactionId); |
| extern bool TransactionIdIsKnownCompleted(TransactionId transactionId); |
| extern void TransactionIdCommitTree(TransactionId xid, int nxids, TransactionId *xids); |
| extern void TransactionIdAsyncCommitTree(TransactionId xid, int nxids, TransactionId *xids, XLogRecPtr lsn); |
| extern void TransactionIdAbortTree(TransactionId xid, int nxids, TransactionId *xids); |
| extern bool TransactionIdPrecedes(TransactionId id1, TransactionId id2); |
| extern bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2); |
| extern bool TransactionIdFollows(TransactionId id1, TransactionId id2); |
| extern bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2); |
| extern TransactionId TransactionIdLatest(TransactionId mainxid, |
| int nxids, const TransactionId *xids); |
| extern XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid); |
| |
| /* in transam/varsup.c */ |
| extern FullTransactionId GetNewTransactionId(bool isSubXact); |
| extern void AdvanceNextFullTransactionIdPastXid(TransactionId xid); |
| extern FullTransactionId ReadNextFullTransactionId(void); |
| extern void SetTransactionIdLimit(TransactionId oldest_datfrozenxid, |
| Oid oldest_datoid); |
| extern void AdvanceOldestClogXid(TransactionId oldest_datfrozenxid); |
| extern bool ForceTransactionIdLimitUpdate(void); |
| extern Oid GetNewObjectId(void); |
| extern void AdvanceObjectId(Oid newOid); |
| extern Oid GetNewSegRelfilenode(void); |
| extern bool OidFollowsNextOid(Oid id); |
| |
| #ifdef USE_ASSERT_CHECKING |
| extern void AssertTransactionIdInAllowableRange(TransactionId xid); |
| #else |
| #define AssertTransactionIdInAllowableRange(xid) ((void)true) |
| #endif |
| |
| /* |
| * Some frontend programs include this header. For compilers that emit static |
| * inline functions even when they're unused, that leads to unsatisfied |
| * external references; hence hide them with #ifndef FRONTEND. |
| */ |
| #ifndef FRONTEND |
| |
| /* |
| * For callers that just need the XID part of the next transaction ID. |
| */ |
| static inline TransactionId |
| ReadNextTransactionId(void) |
| { |
| return XidFromFullTransactionId(ReadNextFullTransactionId()); |
| } |
| |
| /* return transaction ID backed up by amount, handling wraparound correctly */ |
| static inline TransactionId |
| TransactionIdRetreatedBy(TransactionId xid, uint32 amount) |
| { |
| xid -= amount; |
| |
| while (xid < FirstNormalTransactionId) |
| xid--; |
| |
| return xid; |
| } |
| |
| /* return the older of the two IDs */ |
| static inline TransactionId |
| TransactionIdOlder(TransactionId a, TransactionId b) |
| { |
| if (!TransactionIdIsValid(a)) |
| return b; |
| |
| if (!TransactionIdIsValid(b)) |
| return a; |
| |
| if (TransactionIdPrecedes(a, b)) |
| return a; |
| return b; |
| } |
| |
| /* return the older of the two IDs, assuming they're both normal */ |
| static inline TransactionId |
| NormalTransactionIdOlder(TransactionId a, TransactionId b) |
| { |
| Assert(TransactionIdIsNormal(a)); |
| Assert(TransactionIdIsNormal(b)); |
| if (NormalTransactionIdPrecedes(a, b)) |
| return a; |
| return b; |
| } |
| |
| /* return the newer of the two IDs */ |
| static inline FullTransactionId |
| FullTransactionIdNewer(FullTransactionId a, FullTransactionId b) |
| { |
| if (!FullTransactionIdIsValid(a)) |
| return b; |
| |
| if (!FullTransactionIdIsValid(b)) |
| return a; |
| |
| if (FullTransactionIdFollows(a, b)) |
| return a; |
| return b; |
| } |
| |
| #endif /* FRONTEND */ |
| |
| #endif /* TRANSAM_H */ |