diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c index c976f947a0..1c7466c815 100644 --- a/contrib/amcheck/verify_nbtree.c +++ b/contrib/amcheck/verify_nbtree.c @@ -36,7 +36,6 @@ #include "storage/lmgr.h" #include "utils/memutils.h" #include "utils/snapmgr.h" -#include "utils/tqual.h" PG_MODULE_MAGIC; diff --git a/contrib/sepgsql/database.c b/contrib/sepgsql/database.c index b2419f0d81..0cffb69c76 100644 --- a/contrib/sepgsql/database.c +++ b/contrib/sepgsql/database.c @@ -21,7 +21,7 @@ #include "commands/seclabel.h" #include "utils/builtins.h" #include "utils/fmgroids.h" -#include "utils/tqual.h" +#include "utils/snapmgr.h" #include "sepgsql.h" /* diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c index a4038dfd1b..aa12dbe236 100644 --- a/contrib/sepgsql/proc.c +++ b/contrib/sepgsql/proc.c @@ -24,8 +24,8 @@ #include "utils/builtins.h" #include "utils/fmgroids.h" #include "utils/lsyscache.h" +#include "utils/snapmgr.h" #include "utils/syscache.h" -#include "utils/tqual.h" #include "sepgsql.h" diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c index 6842d2a42b..061527559c 100644 --- a/contrib/sepgsql/relation.c +++ b/contrib/sepgsql/relation.c @@ -26,8 +26,8 @@ #include "utils/catcache.h" #include "utils/lsyscache.h" #include "utils/rel.h" +#include "utils/snapmgr.h" #include "utils/syscache.h" -#include "utils/tqual.h" #include "sepgsql.h" diff --git a/contrib/sepgsql/schema.c b/contrib/sepgsql/schema.c index 668d65e70f..4c4a90f978 100644 --- a/contrib/sepgsql/schema.c +++ b/contrib/sepgsql/schema.c @@ -24,7 +24,7 @@ #include "utils/builtins.h" #include "utils/fmgroids.h" #include "utils/lsyscache.h" -#include "utils/tqual.h" +#include "utils/snapmgr.h" #include "sepgsql.h" diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index a3e22dd51c..dc398e1186 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -72,7 +72,6 @@ #include "utils/rel.h" #include "utils/sortsupport.h" #include "utils/tuplesort.h" -#include "utils/tqual.h" /* Magic numbers for parallel state sharing */ diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index a9d2621a7e..c39da41d2e 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -47,8 +47,8 @@ #include "utils/fmgroids.h" #include "utils/fmgrprotos.h" #include "utils/rel.h" +#include "utils/snapmgr.h" #include "utils/syscache.h" -#include "utils/tqual.h" /* diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c index 45ebe0ad63..0099b88137 100644 --- a/src/backend/commands/async.c +++ b/src/backend/commands/async.c @@ -139,7 +139,6 @@ #include "utils/ps_status.h" #include "utils/snapmgr.h" #include "utils/timestamp.h" -#include "utils/tqual.h" /* diff --git a/src/backend/commands/constraint.c b/src/backend/commands/constraint.c index 66914007ec..f9ada29af8 100644 --- a/src/backend/commands/constraint.c +++ b/src/backend/commands/constraint.c @@ -20,7 +20,7 @@ #include "executor/executor.h" #include "utils/builtins.h" #include "utils/rel.h" -#include "utils/tqual.h" +#include "utils/snapmgr.h" /* diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c index 92ca129858..fd0520105d 100644 --- a/src/backend/executor/execIndexing.c +++ b/src/backend/executor/execIndexing.c @@ -113,7 +113,7 @@ #include "executor/executor.h" #include "nodes/nodeFuncs.h" #include "storage/lmgr.h" -#include "utils/tqual.h" +#include "utils/snapmgr.h" /* waitMode argument to check_exclusion_or_unique_constraint() */ typedef enum diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c index 7a102a7ad3..dad2b3d065 100644 --- a/src/backend/replication/logical/origin.c +++ b/src/backend/replication/logical/origin.c @@ -95,7 +95,7 @@ #include "utils/pg_lsn.h" #include "utils/rel.h" #include "utils/syscache.h" -#include "utils/tqual.h" +#include "utils/snapmgr.h" /* * Replay progress of a single remote node. diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index 3e48beaa22..2310e9fafe 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -136,7 +136,6 @@ #include "utils/memutils.h" #include "utils/snapshot.h" #include "utils/snapmgr.h" -#include "utils/tqual.h" #include "storage/block.h" /* debugging output */ #include "storage/fd.h" diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index bdb7d70827..dcb35d8975 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -146,7 +146,6 @@ #include "utils/spccache.h" #include "utils/syscache.h" #include "utils/timestamp.h" -#include "utils/tqual.h" #include "utils/typcache.h" #include "utils/varlena.h" diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c index d47d2b3ef7..6e02585e10 100644 --- a/src/backend/utils/time/snapmgr.c +++ b/src/backend/utils/time/snapmgr.c @@ -48,6 +48,7 @@ #include #include +#include "access/subtrans.h" #include "access/transam.h" #include "access/xact.h" #include "access/xlog.h" @@ -66,7 +67,6 @@ #include "utils/resowner_private.h" #include "utils/snapmgr.h" #include "utils/syscache.h" -#include "utils/tqual.h" /* @@ -144,6 +144,8 @@ static volatile OldSnapshotControlData *oldSnapshotControl; static SnapshotData CurrentSnapshotData = {SNAPSHOT_MVCC}; static SnapshotData SecondarySnapshotData = {SNAPSHOT_MVCC}; SnapshotData CatalogSnapshotData = {SNAPSHOT_MVCC}; +SnapshotData SnapshotSelfData = {SNAPSHOT_SELF}; +SnapshotData SnapshotAnyData = {SNAPSHOT_ANY}; /* Pointers to valid snapshots */ static Snapshot CurrentSnapshot = NULL; @@ -2192,3 +2194,125 @@ RestoreTransactionSnapshot(Snapshot snapshot, void *master_pgproc) { SetTransactionSnapshot(snapshot, NULL, InvalidPid, master_pgproc); } + +/* + * XidInMVCCSnapshot + * Is the given XID still-in-progress according to the snapshot? + * + * Note: GetSnapshotData never stores either top xid or subxids of our own + * backend into a snapshot, so these xids will not be reported as "running" + * by this function. This is OK for current uses, because we always check + * TransactionIdIsCurrentTransactionId first, except when it's known the + * XID could not be ours anyway. + */ +bool +XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot) +{ + uint32 i; + + /* + * Make a quick range check to eliminate most XIDs without looking at the + * xip arrays. Note that this is OK even if we convert a subxact XID to + * its parent below, because a subxact with XID < xmin has surely also got + * a parent with XID < xmin, while one with XID >= xmax must belong to a + * parent that was not yet committed at the time of this snapshot. + */ + + /* Any xid < xmin is not in-progress */ + if (TransactionIdPrecedes(xid, snapshot->xmin)) + return false; + /* Any xid >= xmax is in-progress */ + if (TransactionIdFollowsOrEquals(xid, snapshot->xmax)) + return true; + + /* + * Snapshot information is stored slightly differently in snapshots taken + * during recovery. + */ + if (!snapshot->takenDuringRecovery) + { + /* + * If the snapshot contains full subxact data, the fastest way to + * check things is just to compare the given XID against both subxact + * XIDs and top-level XIDs. If the snapshot overflowed, we have to + * use pg_subtrans to convert a subxact XID to its parent XID, but + * then we need only look at top-level XIDs not subxacts. + */ + if (!snapshot->suboverflowed) + { + /* we have full data, so search subxip */ + int32 j; + + for (j = 0; j < snapshot->subxcnt; j++) + { + if (TransactionIdEquals(xid, snapshot->subxip[j])) + return true; + } + + /* not there, fall through to search xip[] */ + } + else + { + /* + * Snapshot overflowed, so convert xid to top-level. This is safe + * because we eliminated too-old XIDs above. + */ + xid = SubTransGetTopmostTransaction(xid); + + /* + * If xid was indeed a subxact, we might now have an xid < xmin, + * so recheck to avoid an array scan. No point in rechecking + * xmax. + */ + if (TransactionIdPrecedes(xid, snapshot->xmin)) + return false; + } + + for (i = 0; i < snapshot->xcnt; i++) + { + if (TransactionIdEquals(xid, snapshot->xip[i])) + return true; + } + } + else + { + int32 j; + + /* + * In recovery we store all xids in the subxact array because it is by + * far the bigger array, and we mostly don't know which xids are + * top-level and which are subxacts. The xip array is empty. + * + * We start by searching subtrans, if we overflowed. + */ + if (snapshot->suboverflowed) + { + /* + * Snapshot overflowed, so convert xid to top-level. This is safe + * because we eliminated too-old XIDs above. + */ + xid = SubTransGetTopmostTransaction(xid); + + /* + * If xid was indeed a subxact, we might now have an xid < xmin, + * so recheck to avoid an array scan. No point in rechecking + * xmax. + */ + if (TransactionIdPrecedes(xid, snapshot->xmin)) + return false; + } + + /* + * We now have either a top-level xid higher than xmin or an + * indeterminate xid. We don't know whether it's top level or subxact + * but it doesn't matter. If it's present, the xid is visible. + */ + for (j = 0; j < snapshot->subxcnt; j++) + { + if (TransactionIdEquals(xid, snapshot->subxip[j])) + return true; + } + } + + return false; +} diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c index 3a44ccae3c..71d7e25777 100644 --- a/src/backend/utils/time/tqual.c +++ b/src/backend/utils/time/tqual.c @@ -77,11 +77,6 @@ #include "utils/tqual.h" -/* Static variables representing various special snapshot semantics */ -SnapshotData SnapshotSelfData = {SNAPSHOT_SELF}; -SnapshotData SnapshotAnyData = {SNAPSHOT_ANY}; - - /* * SetHintBits() * @@ -1452,128 +1447,6 @@ HeapTupleIsSurelyDead(HeapTuple htup, TransactionId OldestXmin) return TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin); } -/* - * XidInMVCCSnapshot - * Is the given XID still-in-progress according to the snapshot? - * - * Note: GetSnapshotData never stores either top xid or subxids of our own - * backend into a snapshot, so these xids will not be reported as "running" - * by this function. This is OK for current uses, because we always check - * TransactionIdIsCurrentTransactionId first, except when it's known the - * XID could not be ours anyway. - */ -bool -XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot) -{ - uint32 i; - - /* - * Make a quick range check to eliminate most XIDs without looking at the - * xip arrays. Note that this is OK even if we convert a subxact XID to - * its parent below, because a subxact with XID < xmin has surely also got - * a parent with XID < xmin, while one with XID >= xmax must belong to a - * parent that was not yet committed at the time of this snapshot. - */ - - /* Any xid < xmin is not in-progress */ - if (TransactionIdPrecedes(xid, snapshot->xmin)) - return false; - /* Any xid >= xmax is in-progress */ - if (TransactionIdFollowsOrEquals(xid, snapshot->xmax)) - return true; - - /* - * Snapshot information is stored slightly differently in snapshots taken - * during recovery. - */ - if (!snapshot->takenDuringRecovery) - { - /* - * If the snapshot contains full subxact data, the fastest way to - * check things is just to compare the given XID against both subxact - * XIDs and top-level XIDs. If the snapshot overflowed, we have to - * use pg_subtrans to convert a subxact XID to its parent XID, but - * then we need only look at top-level XIDs not subxacts. - */ - if (!snapshot->suboverflowed) - { - /* we have full data, so search subxip */ - int32 j; - - for (j = 0; j < snapshot->subxcnt; j++) - { - if (TransactionIdEquals(xid, snapshot->subxip[j])) - return true; - } - - /* not there, fall through to search xip[] */ - } - else - { - /* - * Snapshot overflowed, so convert xid to top-level. This is safe - * because we eliminated too-old XIDs above. - */ - xid = SubTransGetTopmostTransaction(xid); - - /* - * If xid was indeed a subxact, we might now have an xid < xmin, - * so recheck to avoid an array scan. No point in rechecking - * xmax. - */ - if (TransactionIdPrecedes(xid, snapshot->xmin)) - return false; - } - - for (i = 0; i < snapshot->xcnt; i++) - { - if (TransactionIdEquals(xid, snapshot->xip[i])) - return true; - } - } - else - { - int32 j; - - /* - * In recovery we store all xids in the subxact array because it is by - * far the bigger array, and we mostly don't know which xids are - * top-level and which are subxacts. The xip array is empty. - * - * We start by searching subtrans, if we overflowed. - */ - if (snapshot->suboverflowed) - { - /* - * Snapshot overflowed, so convert xid to top-level. This is safe - * because we eliminated too-old XIDs above. - */ - xid = SubTransGetTopmostTransaction(xid); - - /* - * If xid was indeed a subxact, we might now have an xid < xmin, - * so recheck to avoid an array scan. No point in rechecking - * xmax. - */ - if (TransactionIdPrecedes(xid, snapshot->xmin)) - return false; - } - - /* - * We now have either a top-level xid higher than xmin or an - * indeterminate xid. We don't know whether it's top level or subxact - * but it doesn't matter. If it's present, the xid is visible. - */ - for (j = 0; j < snapshot->subxcnt; j++) - { - if (TransactionIdEquals(xid, snapshot->subxip[j])) - return true; - } - } - - return false; -} - /* * Is the tuple really only locked? That is, is it not updated? * diff --git a/src/include/utils/snapmgr.h b/src/include/utils/snapmgr.h index f8308e6925..c49aceadfb 100644 --- a/src/include/utils/snapmgr.h +++ b/src/include/utils/snapmgr.h @@ -61,6 +61,45 @@ extern PGDLLIMPORT TransactionId RecentXmin; extern PGDLLIMPORT TransactionId RecentGlobalXmin; extern PGDLLIMPORT TransactionId RecentGlobalDataXmin; +/* Variables representing various special snapshot semantics */ +extern PGDLLIMPORT SnapshotData SnapshotSelfData; +extern PGDLLIMPORT SnapshotData SnapshotAnyData; +extern PGDLLIMPORT SnapshotData CatalogSnapshotData; + +#define SnapshotSelf (&SnapshotSelfData) +#define SnapshotAny (&SnapshotAnyData) + +/* + * We don't provide a static SnapshotDirty variable because it would be + * non-reentrant. Instead, users of that snapshot type should declare a + * local variable of type SnapshotData, and initialize it with this macro. + */ +#define InitDirtySnapshot(snapshotdata) \ + ((snapshotdata).snapshot_type = SNAPSHOT_DIRTY) + +/* + * Similarly, some initialization is required for a NonVacuumable snapshot. + * The caller must supply the xmin horizon to use (e.g., RecentGlobalXmin). + */ +#define InitNonVacuumableSnapshot(snapshotdata, xmin_horizon) \ + ((snapshotdata).snapshot_type = SNAPSHOT_NON_VACUUMABLE, \ + (snapshotdata).xmin = (xmin_horizon)) + +/* + * Similarly, some initialization is required for SnapshotToast. We need + * to set lsn and whenTaken correctly to support snapshot_too_old. + */ +#define InitToastSnapshot(snapshotdata, l, w) \ + ((snapshotdata).snapshot_type = SNAPSHOT_TOAST, \ + (snapshotdata).lsn = (l), \ + (snapshotdata).whenTaken = (w)) + +/* This macro encodes the knowledge of which snapshots are MVCC-safe */ +#define IsMVCCSnapshot(snapshot) \ + ((snapshot)->snapshot_type == SNAPSHOT_MVCC || \ + (snapshot)->snapshot_type == SNAPSHOT_HISTORIC_MVCC) + + extern Snapshot GetTransactionSnapshot(void); extern Snapshot GetLatestSnapshot(void); extern void SnapshotSetCommandId(CommandId curcid); @@ -98,6 +137,11 @@ extern void MaintainOldSnapshotTimeMapping(TimestampTz whenTaken, extern char *ExportSnapshot(Snapshot snapshot); +/* + * Utility functions for implementing visibility routines in table AMs. + */ +extern bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot); + /* Support for catalog timetravel for logical decoding */ struct HTAB; extern struct HTAB *HistoricSnapshotGetTupleCids(void); diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h index 049a723a69..de8c799ea5 100644 --- a/src/include/utils/tqual.h +++ b/src/include/utils/tqual.h @@ -17,20 +17,6 @@ #include "utils/snapshot.h" - -/* Static variables representing various special snapshot semantics */ -extern PGDLLIMPORT SnapshotData SnapshotSelfData; -extern PGDLLIMPORT SnapshotData SnapshotAnyData; -extern PGDLLIMPORT SnapshotData CatalogSnapshotData; - -#define SnapshotSelf (&SnapshotSelfData) -#define SnapshotAny (&SnapshotAnyData) - -/* This macro encodes the knowledge of which snapshots are MVCC-safe */ -#define IsMVCCSnapshot(snapshot) \ - ((snapshot)->snapshot_type == SNAPSHOT_MVCC || \ - (snapshot)->snapshot_type == SNAPSHOT_HISTORIC_MVCC) - extern bool HeapTupleSatisfiesVisibility(HeapTuple stup, Snapshot snapshot, Buffer buffer); @@ -51,7 +37,6 @@ extern HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer); extern bool HeapTupleIsSurelyDead(HeapTuple htup, TransactionId OldestXmin); -extern bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot); extern void HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid); @@ -68,29 +53,4 @@ extern bool ResolveCminCmaxDuringDecoding(struct HTAB *tuplecid_data, Buffer buffer, CommandId *cmin, CommandId *cmax); -/* - * We don't provide a static SnapshotDirty variable because it would be - * non-reentrant. Instead, users of that snapshot type should declare a - * local variable of type SnapshotData, and initialize it with this macro. - */ -#define InitDirtySnapshot(snapshotdata) \ - ((snapshotdata).snapshot_type = SNAPSHOT_DIRTY) - -/* - * Similarly, some initialization is required for a NonVacuumable snapshot. - * The caller must supply the xmin horizon to use (e.g., RecentGlobalXmin). - */ -#define InitNonVacuumableSnapshot(snapshotdata, xmin_horizon) \ - ((snapshotdata).snapshot_type = SNAPSHOT_NON_VACUUMABLE, \ - (snapshotdata).xmin = (xmin_horizon)) - -/* - * Similarly, some initialization is required for SnapshotToast. We need - * to set lsn and whenTaken correctly to support snapshot_too_old. - */ -#define InitToastSnapshot(snapshotdata, l, w) \ - ((snapshotdata).snapshot_type = SNAPSHOT_TOAST, \ - (snapshotdata).lsn = (l), \ - (snapshotdata).whenTaken = (w)) - #endif /* TQUAL_H */