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 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 */ -- 2.40.0