From b7eda3e0e33402a7727253e6f307ca96b92eb23d Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Mon, 21 Jan 2019 17:03:15 -0800 Subject: [PATCH] Move generic snapshot related code from tqual.h to snapmgr.h. The code in tqual.c is largely heap specific. Due to the upcoming pluggable storage work, it therefore makes sense to move it into access/heap/ (as the file's header notes, the tqual name isn't very good). But the various statically allocated snapshot and snapshot initialization functions are now (see previous commit) generic and do not depend on functions declared in tqual.h anymore. Therefore move. Also move XidInMVCCSnapshot as that's useful for future AMs, and already used outside of tqual.c. Author: Andres Freund Discussion: https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de --- contrib/amcheck/verify_nbtree.c | 1 - contrib/sepgsql/database.c | 2 +- contrib/sepgsql/proc.c | 2 +- contrib/sepgsql/relation.c | 2 +- contrib/sepgsql/schema.c | 2 +- src/backend/access/nbtree/nbtsort.c | 1 - src/backend/catalog/catalog.c | 2 +- src/backend/commands/async.c | 1 - src/backend/commands/constraint.c | 2 +- src/backend/executor/execIndexing.c | 2 +- src/backend/replication/logical/origin.c | 2 +- src/backend/replication/logical/snapbuild.c | 1 - src/backend/utils/adt/selfuncs.c | 1 - src/backend/utils/time/snapmgr.c | 126 ++++++++++++++++++- src/backend/utils/time/tqual.c | 127 -------------------- src/include/utils/snapmgr.h | 44 +++++++ src/include/utils/tqual.h | 40 ------ 17 files changed, 177 insertions(+), 181 deletions(-) diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c index c976f947a02..1c7466c8158 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 b2419f0d811..0cffb69c76b 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 a4038dfd1b8..aa12dbe2367 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 6842d2a42b7..061527559c1 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 668d65e70f5..4c4a90f9781 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 a3e22dd51c3..dc398e11867 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 a9d2621a7ee..c39da41d2ec 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 45ebe0ad63c..0099b881378 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 66914007ecf..f9ada29af84 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 92ca129858c..fd0520105dc 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 7a102a7ad38..dad2b3d065a 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 3e48beaa22f..2310e9fafe0 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 bdb7d708279..dcb35d89752 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 d47d2b3ef7a..6e02585e10e 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 3a44ccae3c9..71d7e257773 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 f8308e69259..c49aceadfb1 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 049a723a69a..de8c799ea5e 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 */ -- 2.30.2