Change snapshot type to be determined by enum rather than callback.
authorAndres Freund <[email protected]>
Tue, 22 Jan 2019 01:03:15 +0000 (17:03 -0800)
committerAndres Freund <[email protected]>
Tue, 22 Jan 2019 01:03:15 +0000 (17:03 -0800)
This is in preparation for allowing the same snapshot be used for
different table AMs. With the current callback based approach we would
need one callback for each supported AM, which clearly would not be
extensible.  Thus add a new Snapshot->snapshot_type field, and move
the dispatch into HeapTupleSatisfiesVisibility() (which is now a
function). Later work will then dispatch calls to
HeapTupleSatisfiesVisibility() and other AMs visibility functions
depending on the type of the table.  The central SnapshotType enum
also seems like a good location to centralize documentation about the
intended behaviour of various types of snapshots.

As tqual.h isn't included by bufmgr.h any more (as HeapTupleSatisfies*
isn't referenced by TestForOldSnapshot() anymore) a few files now need
to include it directly.

Author: Andres Freund, loosely based on earlier work by Haribabu Kommi
Discussion:
    https://postgr.es/m/20180703070645[email protected]
    https://postgr.es/m/20160812231527[email protected]

contrib/amcheck/verify_nbtree.c
contrib/pg_visibility/pg_visibility.c
src/backend/access/nbtree/nbtsort.c
src/backend/replication/logical/snapbuild.c
src/backend/utils/time/snapmgr.c
src/backend/utils/time/tqual.c
src/include/storage/bufmgr.h
src/include/utils/snapshot.h
src/include/utils/tqual.h
src/tools/pgindent/typedefs.list

index 1c7466c81583317a72112d38330bcc23a7280054..c976f947a02edb19b9a2ba2caa00c83fc05f4269 100644 (file)
@@ -36,6 +36,7 @@
 #include "storage/lmgr.h"
 #include "utils/memutils.h"
 #include "utils/snapmgr.h"
+#include "utils/tqual.h"
 
 
 PG_MODULE_MAGIC;
index 22adca18e64473f9ee386f08b8a62be7d8436715..d8125f1ba2f51d64024435c65e36eaf2653d8a86 100644 (file)
@@ -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;
 
index dc398e11867d172d3fcc6ec4cff175f1c34885be..a3e22dd51c321d585117a9350866ba407a82d363 100644 (file)
@@ -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 */
index 405348242005732fe8b96bcb3e83d49145218307..3e48beaa22f4bc97fc498e9e3bf07c7e5e431fa4 100644 (file)
@@ -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
index f93b37b9c9363782e4d784b9b1f3b4ddfc924e70..d47d2b3ef7a1d46592700edfba6d446f754400ee 100644 (file)
@@ -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;
index edd4f7e36c673ec69960f5d6cc077af1144b2932..3a44ccae3c98bbf0cea44d91a468fe31bfb9e33a 100644 (file)
@@ -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 */
+}
index f61794c016a422a29d252cab36dee1df83b7ed0c..c5826f691de272c347aa4c8de1c2bb4bbd6d2079 100644 (file)
@@ -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);
index 17c57b9edb7b893cb44b4515fc0214690e2537c1..952307103fc78a3d9dd28998948ffb3835369a00 100644 (file)
 #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
index e3c66fe113cb2db372d970933529dc0f6f91c9c1..049a723a69ac8e1a44bc196e0f2349144e014bcc 100644 (file)
@@ -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))
 
index 9fe950b29dbb81e4bda9f2529f0b2849149ba43c..84640c47a7da004bdffdea10f71dfbd64d4248f7 100644 (file)
@@ -2167,7 +2167,7 @@ SnapBuildOnDisk
 SnapBuildState
 Snapshot
 SnapshotData
-SnapshotSatisfiesFunc
+SnapshotType
 SockAddr
 Sort
 SortBy