diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c index 1c7466c815..c976f947a0 100644 --- a/contrib/amcheck/verify_nbtree.c +++ b/contrib/amcheck/verify_nbtree.c @@ -36,6 +36,7 @@ #include "storage/lmgr.h" #include "utils/memutils.h" #include "utils/snapmgr.h" +#include "utils/tqual.h" PG_MODULE_MAGIC; diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c index 22adca18e6..d8125f1ba2 100644 --- a/contrib/pg_visibility/pg_visibility.c +++ b/contrib/pg_visibility/pg_visibility.c @@ -21,6 +21,8 @@ #include "storage/procarray.h" #include "storage/smgr.h" #include "utils/rel.h" +#include "utils/snapmgr.h" +#include "utils/tqual.h" PG_MODULE_MAGIC; diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index dc398e1186..a3e22dd51c 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -72,6 +72,7 @@ #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/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index 4053482420..3e48beaa22 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -376,7 +376,7 @@ static void SnapBuildFreeSnapshot(Snapshot snap) { /* make sure we don't get passed an external snapshot */ - Assert(snap->satisfies == HeapTupleSatisfiesHistoricMVCC); + Assert(snap->snapshot_type == SNAPSHOT_HISTORIC_MVCC); /* make sure nobody modified our snapshot */ Assert(snap->curcid == FirstCommandId); @@ -434,7 +434,7 @@ void SnapBuildSnapDecRefcount(Snapshot snap) { /* make sure we don't get passed an external snapshot */ - Assert(snap->satisfies == HeapTupleSatisfiesHistoricMVCC); + Assert(snap->snapshot_type == SNAPSHOT_HISTORIC_MVCC); /* make sure nobody modified our snapshot */ Assert(snap->curcid == FirstCommandId); @@ -476,7 +476,7 @@ SnapBuildBuildSnapshot(SnapBuild *builder) snapshot = MemoryContextAllocZero(builder->context, ssize); - snapshot->satisfies = HeapTupleSatisfiesHistoricMVCC; + snapshot->snapshot_type = SNAPSHOT_HISTORIC_MVCC; /* * We misuse the original meaning of SnapshotData's xip and subxip fields diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c index f93b37b9c9..d47d2b3ef7 100644 --- a/src/backend/utils/time/snapmgr.c +++ b/src/backend/utils/time/snapmgr.c @@ -141,9 +141,9 @@ static volatile OldSnapshotControlData *oldSnapshotControl; * These SnapshotData structs are static to simplify memory allocation * (see the hack in GetSnapshotData to avoid repeated malloc/free). */ -static SnapshotData CurrentSnapshotData = {HeapTupleSatisfiesMVCC}; -static SnapshotData SecondarySnapshotData = {HeapTupleSatisfiesMVCC}; -SnapshotData CatalogSnapshotData = {HeapTupleSatisfiesMVCC}; +static SnapshotData CurrentSnapshotData = {SNAPSHOT_MVCC}; +static SnapshotData SecondarySnapshotData = {SNAPSHOT_MVCC}; +SnapshotData CatalogSnapshotData = {SNAPSHOT_MVCC}; /* Pointers to valid snapshots */ static Snapshot CurrentSnapshot = NULL; @@ -2046,7 +2046,7 @@ EstimateSnapshotSpace(Snapshot snap) Size size; Assert(snap != InvalidSnapshot); - Assert(snap->satisfies == HeapTupleSatisfiesMVCC); + Assert(snap->snapshot_type == SNAPSHOT_MVCC); /* We allocate any XID arrays needed in the same palloc block. */ size = add_size(sizeof(SerializedSnapshotData), @@ -2143,7 +2143,7 @@ RestoreSnapshot(char *start_address) /* Copy all required fields */ snapshot = (Snapshot) MemoryContextAlloc(TopTransactionContext, size); - snapshot->satisfies = HeapTupleSatisfiesMVCC; + snapshot->snapshot_type = SNAPSHOT_MVCC; snapshot->xmin = serialized_snapshot.xmin; snapshot->xmax = serialized_snapshot.xmax; snapshot->xip = NULL; diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c index edd4f7e36c..3a44ccae3c 100644 --- a/src/backend/utils/time/tqual.c +++ b/src/backend/utils/time/tqual.c @@ -78,8 +78,8 @@ /* Static variables representing various special snapshot semantics */ -SnapshotData SnapshotSelfData = {HeapTupleSatisfiesSelf}; -SnapshotData SnapshotAnyData = {HeapTupleSatisfiesAny}; +SnapshotData SnapshotSelfData = {SNAPSHOT_SELF}; +SnapshotData SnapshotAnyData = {SNAPSHOT_ANY}; /* @@ -152,10 +152,7 @@ HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer, * HeapTupleSatisfiesSelf * True iff heap tuple is valid "for itself". * - * Here, we consider the effects of: - * all committed transactions (as of the current instant) - * previous commands of this transaction - * changes made by the current command + * See SNAPSHOT_MVCC's definition for the intended behaviour. * * Note: * Assumes heap tuple is valid. @@ -172,7 +169,7 @@ HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer, * (Xmax != my-transaction && the row was deleted by another transaction * Xmax is not committed))) that has not been committed */ -bool +static bool HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer) { HeapTupleHeader tuple = htup->t_data; @@ -342,7 +339,7 @@ HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer) * HeapTupleSatisfiesAny * Dummy "satisfies" routine: any tuple satisfies SnapshotAny. */ -bool +static bool HeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer) { return true; @@ -352,6 +349,8 @@ HeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer) * HeapTupleSatisfiesToast * True iff heap tuple is valid as a TOAST row. * + * See SNAPSHOT_TOAST's definition for the intended behaviour. + * * This is a simplified version that only checks for VACUUM moving conditions. * It's appropriate for TOAST usage because TOAST really doesn't want to do * its own time qual checks; if you can see the main table row that contains @@ -362,7 +361,7 @@ HeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer) * Among other things, this means you can't do UPDATEs of rows in a TOAST * table. */ -bool +static bool HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot, Buffer buffer) { @@ -716,10 +715,7 @@ HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid, * HeapTupleSatisfiesDirty * True iff heap tuple is valid including effects of open transactions. * - * Here, we consider the effects of: - * all committed and in-progress transactions (as of the current instant) - * previous commands of this transaction - * changes made by the current command + * See SNAPSHOT_DIRTY's definition for the intended behaviour. * * This is essentially like HeapTupleSatisfiesSelf as far as effects of * the current transaction and committed/aborted xacts are concerned. @@ -735,7 +731,7 @@ HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid, * on the insertion without aborting the whole transaction, the associated * token is also returned in snapshot->speculativeToken. */ -bool +static bool HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot, Buffer buffer) { @@ -934,14 +930,7 @@ HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot, * HeapTupleSatisfiesMVCC * True iff heap tuple is valid for the given MVCC snapshot. * - * Here, we consider the effects of: - * all transactions committed as of the time of the given snapshot - * previous commands of this transaction - * - * Does _not_ include: - * transactions shown as in-progress by the snapshot - * transactions started after the snapshot was taken - * changes made by the current command + * See SNAPSHOT_MVCC's definition for the intended behaviour. * * Notice that here, we will not update the tuple status hint bits if the * inserting/deleting transaction is still running according to our snapshot, @@ -959,7 +948,7 @@ HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot, * inserting/deleting transaction was still running --- which was more cycles * and more contention on the PGXACT array. */ -bool +static bool HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer) { @@ -1390,11 +1379,13 @@ HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, * True if tuple might be visible to some transaction; false if it's * surely dead to everyone, ie, vacuumable. * - * This is an interface to HeapTupleSatisfiesVacuum that meets the - * SnapshotSatisfiesFunc API, so it can be used through a Snapshot. + * See SNAPSHOT_TOAST's definition for the intended behaviour. + * + * This is an interface to HeapTupleSatisfiesVacuum that's callable via + * HeapTupleSatisfiesSnapshot, so it can be used through a Snapshot. * snapshot->xmin must have been set up with the xmin horizon to use. */ -bool +static bool HeapTupleSatisfiesNonVacuumable(HeapTuple htup, Snapshot snapshot, Buffer buffer) { @@ -1659,7 +1650,7 @@ TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num) * dangerous to do so as the semantics of doing so during timetravel are more * complicated than when dealing "only" with the present. */ -bool +static bool HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer) { @@ -1796,3 +1787,44 @@ HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot, else return true; } + +/* + * HeapTupleSatisfiesVisibility + * True iff heap tuple satisfies a time qual. + * + * Notes: + * Assumes heap tuple is valid, and buffer at least share locked. + * + * Hint bits in the HeapTuple's t_infomask may be updated as a side effect; + * if so, the indicated buffer is marked dirty. + */ +bool +HeapTupleSatisfiesVisibility(HeapTuple tup, Snapshot snapshot, Buffer buffer) +{ + switch (snapshot->snapshot_type) + { + case SNAPSHOT_MVCC: + return HeapTupleSatisfiesMVCC(tup, snapshot, buffer); + break; + case SNAPSHOT_SELF: + return HeapTupleSatisfiesSelf(tup, snapshot, buffer); + break; + case SNAPSHOT_ANY: + return HeapTupleSatisfiesAny(tup, snapshot, buffer); + break; + case SNAPSHOT_TOAST: + return HeapTupleSatisfiesToast(tup, snapshot, buffer); + break; + case SNAPSHOT_DIRTY: + return HeapTupleSatisfiesDirty(tup, snapshot, buffer); + break; + case SNAPSHOT_HISTORIC_MVCC: + return HeapTupleSatisfiesHistoricMVCC(tup, snapshot, buffer); + break; + case SNAPSHOT_NON_VACUUMABLE: + return HeapTupleSatisfiesNonVacuumable(tup, snapshot, buffer); + break; + } + + return false; /* keep compiler quiet */ +} diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index f61794c016..c5826f691d 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -20,7 +20,6 @@ #include "storage/relfilenode.h" #include "utils/relcache.h" #include "utils/snapmgr.h" -#include "utils/tqual.h" typedef void *Block; @@ -268,8 +267,8 @@ TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page) if (old_snapshot_threshold >= 0 && (snapshot) != NULL - && ((snapshot)->satisfies == HeapTupleSatisfiesMVCC - || (snapshot)->satisfies == HeapTupleSatisfiesToast) + && ((snapshot)->snapshot_type == SNAPSHOT_MVCC + || (snapshot)->snapshot_type == SNAPSHOT_TOAST) && !XLogRecPtrIsInvalid((snapshot)->lsn) && PageGetLSN(page) > (snapshot)->lsn) TestForOldSnapshot_impl(snapshot, relation); diff --git a/src/include/utils/snapshot.h b/src/include/utils/snapshot.h index 17c57b9edb..952307103f 100644 --- a/src/include/utils/snapshot.h +++ b/src/include/utils/snapshot.h @@ -20,19 +20,89 @@ #include "storage/buf.h" +/* + * The different snapshot types. We use SnapshotData structures to represent + * both "regular" (MVCC) snapshots and "special" snapshots that have non-MVCC + * semantics. The specific semantics of a snapshot are encoded by its type. + * + * The behaviour of each type of snapshot should be documented alongside its + * enum value, best in terms that are not specific to an individual table AM. + * + * The reason the snapshot type rather than a callback as it used to be is + * that that allows to use the same snapshot for different table AMs without + * having one callback per AM. + */ +typedef enum SnapshotType +{ + /*------------------------------------------------------------------------- + * A tuple is visible iff the tuple is valid for the given MVCC snapshot. + * + * Here, we consider the effects of: + * - all transactions committed as of the time of the given snapshot + * - previous commands of this transaction + * + * Does _not_ include: + * - transactions shown as in-progress by the snapshot + * - transactions started after the snapshot was taken + * - changes made by the current command + * ------------------------------------------------------------------------- + */ + SNAPSHOT_MVCC = 0, + + /*------------------------------------------------------------------------- + * A tuple is visible iff the tuple is valid including effects of open + * transactions. + * + * Here, we consider the effects of: + * - all committed and in-progress transactions (as of the current instant) + * - previous commands of this transaction + * - changes made by the current command + * ------------------------------------------------------------------------- + */ + SNAPSHOT_SELF, + + /* + * Any tuple is visible. + */ + SNAPSHOT_ANY, + + /* + * A tuple is visible iff the tuple tuple is valid as a TOAST row. + */ + SNAPSHOT_TOAST, + + /*------------------------------------------------------------------------- + * A tuple is visible iff the tuple is valid including effects of open + * transactions. + * + * Here, we consider the effects of: + * - all committed and in-progress transactions (as of the current instant) + * - previous commands of this transaction + * - changes made by the current command + * ------------------------------------------------------------------------- + */ + SNAPSHOT_DIRTY, + + /* + * A tuple is visible iff it follows the rules of SNAPSHOT_MVCC, but + * supports being called in timetravel context (for decoding catalog + * contents in the context of logical decoding). + */ + SNAPSHOT_HISTORIC_MVCC, + + /* + * A tuple is visible iff the tuple might be visible to some transaction; + * false if it's surely dead to everyone, ie, vacuumable. + * + * Snapshot.xmin must have been set up with the xmin horizon to use. + */ + SNAPSHOT_NON_VACUUMABLE +} SnapshotType; + typedef struct SnapshotData *Snapshot; #define InvalidSnapshot ((Snapshot) NULL) -/* - * We use SnapshotData structures to represent both "regular" (MVCC) - * snapshots and "special" snapshots that have non-MVCC semantics. - * The specific semantics of a snapshot are encoded by the "satisfies" - * function. - */ -typedef bool (*SnapshotSatisfiesFunc) (HeapTuple htup, - Snapshot snapshot, Buffer buffer); - /* * Struct representing all kind of possible snapshots. * @@ -52,7 +122,7 @@ typedef bool (*SnapshotSatisfiesFunc) (HeapTuple htup, */ typedef struct SnapshotData { - SnapshotSatisfiesFunc satisfies; /* tuple test function */ + SnapshotType snapshot_type; /* type of snapshot */ /* * The remaining fields are used only for MVCC snapshots, and are normally diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h index e3c66fe113..049a723a69 100644 --- a/src/include/utils/tqual.h +++ b/src/include/utils/tqual.h @@ -28,21 +28,11 @@ extern PGDLLIMPORT SnapshotData CatalogSnapshotData; /* This macro encodes the knowledge of which snapshots are MVCC-safe */ #define IsMVCCSnapshot(snapshot) \ - ((snapshot)->satisfies == HeapTupleSatisfiesMVCC || \ - (snapshot)->satisfies == HeapTupleSatisfiesHistoricMVCC) + ((snapshot)->snapshot_type == SNAPSHOT_MVCC || \ + (snapshot)->snapshot_type == SNAPSHOT_HISTORIC_MVCC) -/* - * HeapTupleSatisfiesVisibility - * True iff heap tuple satisfies a time qual. - * - * Notes: - * Assumes heap tuple is valid. - * Beware of multiple evaluations of snapshot argument. - * Hint bits in the HeapTuple's t_infomask may be updated as a side effect; - * if so, the indicated buffer is marked dirty. - */ -#define HeapTupleSatisfiesVisibility(tuple, snapshot, buffer) \ - ((*(snapshot)->satisfies) (tuple, snapshot, buffer)) +extern bool HeapTupleSatisfiesVisibility(HeapTuple stup, Snapshot snapshot, + Buffer buffer); /* Result codes for HeapTupleSatisfiesVacuum */ typedef enum @@ -54,22 +44,6 @@ typedef enum HEAPTUPLE_DELETE_IN_PROGRESS /* deleting xact is still in progress */ } HTSV_Result; -/* These are the "satisfies" test routines for the various snapshot types */ -extern bool HeapTupleSatisfiesMVCC(HeapTuple htup, - Snapshot snapshot, Buffer buffer); -extern bool HeapTupleSatisfiesSelf(HeapTuple htup, - Snapshot snapshot, Buffer buffer); -extern bool HeapTupleSatisfiesAny(HeapTuple htup, - Snapshot snapshot, Buffer buffer); -extern bool HeapTupleSatisfiesToast(HeapTuple htup, - Snapshot snapshot, Buffer buffer); -extern bool HeapTupleSatisfiesDirty(HeapTuple htup, - Snapshot snapshot, Buffer buffer); -extern bool HeapTupleSatisfiesNonVacuumable(HeapTuple htup, - Snapshot snapshot, Buffer buffer); -extern bool HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, - Snapshot snapshot, Buffer buffer); - /* Special "satisfies" routines with different APIs */ extern HTSU_Result HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid, Buffer buffer); @@ -100,14 +74,14 @@ extern bool ResolveCminCmaxDuringDecoding(struct HTAB *tuplecid_data, * local variable of type SnapshotData, and initialize it with this macro. */ #define InitDirtySnapshot(snapshotdata) \ - ((snapshotdata).satisfies = HeapTupleSatisfiesDirty) + ((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).satisfies = HeapTupleSatisfiesNonVacuumable, \ + ((snapshotdata).snapshot_type = SNAPSHOT_NON_VACUUMABLE, \ (snapshotdata).xmin = (xmin_horizon)) /* @@ -115,7 +89,7 @@ extern bool ResolveCminCmaxDuringDecoding(struct HTAB *tuplecid_data, * to set lsn and whenTaken correctly to support snapshot_too_old. */ #define InitToastSnapshot(snapshotdata, l, w) \ - ((snapshotdata).satisfies = HeapTupleSatisfiesToast, \ + ((snapshotdata).snapshot_type = SNAPSHOT_TOAST, \ (snapshotdata).lsn = (l), \ (snapshotdata).whenTaken = (w)) diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 9fe950b29d..84640c47a7 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2167,7 +2167,7 @@ SnapBuildOnDisk SnapBuildState Snapshot SnapshotData -SnapshotSatisfiesFunc +SnapshotType SockAddr Sort SortBy