Get rid of globalXmin tracking.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 22 Aug 2016 13:05:56 +0000 (16:05 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 22 Aug 2016 18:21:58 +0000 (21:21 +0300)
src/backend/access/heap/heapam.c
src/backend/access/heap/pruneheap.c
src/backend/access/nbtree/nbtpage.c
src/backend/access/spgist/spgvacuum.c
src/backend/access/transam/xlog.c
src/backend/storage/ipc/procarray.c
src/backend/utils/time/snapmgr.c
src/include/access/mvccvars.h
src/include/storage/procarray.h
src/include/utils/snapmgr.h

index a01edd75d9d1c64ed25c849d905e7164e49a6fc4..2bd1e37be8fb71c68777036ddb6615f08485b0f4 100644 (file)
@@ -1995,8 +1995,6 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
        if (all_dead)
                *all_dead = first_call;
 
-       Assert(TransactionIdIsValid(RecentGlobalXmin));
-
        Assert(ItemPointerGetBlockNumber(tid) == BufferGetBlockNumber(buffer));
        offnum = ItemPointerGetOffsetNumber(tid);
        at_chain_start = first_call;
@@ -2092,7 +2090,7 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
                 * transactions.
                 */
                if (all_dead && *all_dead &&
-                       !HeapTupleIsSurelyDead(heapTuple, RecentGlobalXmin))
+                       !HeapTupleIsSurelyDead(heapTuple, GetRecentGlobalXmin()))
                        *all_dead = false;
 
                /*
@@ -6117,8 +6115,8 @@ heap_abort_speculative(Relation relation, HeapTuple tuple)
         * RecentGlobalXmin.  That's not pretty, but it doesn't seem worth
         * inventing a nicer API for this.
         */
-       Assert(TransactionIdIsValid(RecentGlobalXmin));
-       PageSetPrunable(page, RecentGlobalXmin);
+       Assert(TransactionIdIsValid(GetRecentGlobalXmin()));
+       PageSetPrunable(page, GetRecentGlobalXmin());
 
        /* store transaction information of xact deleting the tuple */
        tp.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);
index 6ff92516eda9e44f82f0be3ff08a90a2e5df6867..e4c18a6a0db3cbc192a95e21e39efe31647b1d5e 100644 (file)
@@ -23,6 +23,7 @@
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "storage/bufmgr.h"
+#include "storage/procarray.h"
 #include "utils/snapmgr.h"
 #include "utils/rel.h"
 #include "utils/tqual.h"
@@ -102,10 +103,10 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
         */
        if (IsCatalogRelation(relation) ||
                RelationIsAccessibleInLogicalDecoding(relation))
-               OldestXmin = RecentGlobalXmin;
+               OldestXmin = GetRecentGlobalXmin();
        else
                OldestXmin =
-                       TransactionIdLimitedForOldSnapshots(RecentGlobalDataXmin,
+                       TransactionIdLimitedForOldSnapshots(GetRecentGlobalDataXmin(),
                                                                                                relation);
 
        Assert(TransactionIdIsValid(OldestXmin));
index 2001dc14fba049f4f15ebe4622ca8786d2bafec9..88e5fdd4eaa295bd8414d2f56c0b6ad3ad22c141 100644 (file)
@@ -30,6 +30,7 @@
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
 #include "storage/predicate.h"
+#include "storage/procarray.h"
 #include "utils/snapmgr.h"
 
 static bool _bt_mark_page_halfdead(Relation rel, Buffer buf, BTStack stack);
@@ -759,7 +760,7 @@ _bt_page_recyclable(Page page)
         */
        opaque = (BTPageOpaque) PageGetSpecialPointer(page);
        if (P_ISDELETED(opaque) &&
-               TransactionIdPrecedes(opaque->btpo.xact, RecentGlobalXmin))
+               TransactionIdPrecedes(opaque->btpo.xact, GetRecentGlobalXmin()))
                return true;
        return false;
 }
index 15b867f24cbd3a19b948883c3c5fa52321435c98..067251e0f26c19f1ee57dfde51e621b1a46fd8b3 100644 (file)
@@ -25,6 +25,7 @@
 #include "storage/bufmgr.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
+#include "storage/procarray.h"
 #include "utils/snapmgr.h"
 
 
@@ -520,7 +521,7 @@ vacuumRedirectAndPlaceholder(Relation index, Buffer buffer)
                dt = (SpGistDeadTuple) PageGetItem(page, PageGetItemId(page, i));
 
                if (dt->tupstate == SPGIST_REDIRECT &&
-                       TransactionIdPrecedes(dt->xid, RecentGlobalXmin))
+                       TransactionIdPrecedes(dt->xid, GetRecentGlobalXmin()))
                {
                        dt->tupstate = SPGIST_PLACEHOLDER;
                        Assert(opaque->nRedirection > 0);
index 308398154c7fa44f1d8db19e3cd8e5c22982df40..3b7272c52288afaa23e55f72259280a765f65921 100644 (file)
@@ -4827,7 +4827,6 @@ BootStrapXLOG(void)
        TransactionIdRetreat(latestCompletedXid);
        pg_atomic_write_u32(&ShmemVariableCache->latestCompletedXid, latestCompletedXid);
        pg_atomic_write_u32(&ShmemVariableCache->oldestActiveXid, checkPoint.nextXid);
-       pg_atomic_write_u32(&ShmemVariableCache->globalXmin, checkPoint.nextXid);
 
        MultiXactSetNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset);
        SetTransactionIdLimit(checkPoint.oldestXid, checkPoint.oldestXidDB);
@@ -6361,7 +6360,6 @@ StartupXLOG(void)
        TransactionIdRetreat(latestCompletedXid);
        pg_atomic_write_u32(&ShmemVariableCache->latestCompletedXid, latestCompletedXid);
        pg_atomic_write_u32(&ShmemVariableCache->oldestActiveXid, checkPoint.nextXid);
-       pg_atomic_write_u32(&ShmemVariableCache->globalXmin, checkPoint.nextXid);
 
        /*
         * Initialize replication slots, before there's a chance to remove
index 570d2729113e7a596eaf98e660c489af1a244b97..1744e0b65b530763ae0496145399613bc2747ccc 100644 (file)
@@ -72,6 +72,17 @@ static ProcArrayStruct *procArray;
 static PGPROC *allProcs;
 static PGXACT *allPgXact;
 
+/*
+ * Cached values for GetRecentGlobalXmin().
+ *
+ * RecentGlobalXmin and RecentGlobalDataXmin are initialized to
+ * InvalidTransactionId, to ensure that no one tries to use a stale
+ * value. Readers should ensure that it has been set to something else
+ * before using it.
+ */
+static TransactionId RecentGlobalXmin = InvalidTransactionId;
+static TransactionId RecentGlobalDataXmin = InvalidTransactionId;
+
 /*
  * Bookkeeping for tracking transactions in recovery
  */
@@ -81,7 +92,6 @@ static TransactionId latestObservedXid = InvalidTransactionId;
 static LWLockTranche ProcLWLockTranche;
 
 static void AdvanceOldestActiveXid(TransactionId myXid);
-static void AdvanceGlobalXmin(TransactionId myXmin);
 
 /*
  * Report shared-memory space needed by CreateSharedProcArray.
@@ -233,10 +243,8 @@ ProcArrayEndTransaction(PGPROC *proc)
 {
        PGXACT     *pgxact = &allPgXact[proc->pgprocno];
        TransactionId myXid;
-       TransactionId myXmin;
 
        myXid = pgxact->xid;
-       myXmin = pgxact->xmin;
 
        /* A shared lock is enough to modify our own fields */
        LWLockAcquire(ProcArrayLock, LW_SHARED);
@@ -254,14 +262,20 @@ ProcArrayEndTransaction(PGPROC *proc)
        /* If we were the oldest active XID, advance oldestXid */
        if (TransactionIdIsValid(myXid))
                AdvanceOldestActiveXid(myXid);
+}
+
+void
+ProcArrayResetXmin(PGPROC *proc)
+{
+       PGXACT     *pgxact = &allPgXact[proc->pgprocno];
 
        /*
-        * Likewise, if we had the oldest xmin, advance GlobalXmin. (There
-        * can be multiple transactions with the same xmin, so this
-        * might be futile.)
+        * Note we can do this without locking because we assume that storing an Xid
+        * is atomic.
         */
-       if (TransactionIdIsValid(myXmin))
-               AdvanceGlobalXmin(myXmin);
+       pgxact->xmin = InvalidTransactionId;
+
+       RecentGlobalXmin = InvalidTransactionId;
 }
 
 /*
@@ -296,9 +310,6 @@ ProcArrayClearTransaction(PGPROC *proc)
        /*
         * We don't need to update oldestActiveXid, because the gxact entry in
         * the procarray is still running with the same XID.
-        *
-        * FIXME: Do we need advance GlobalXmin, though? Does a gxact have a
-        * valid xmin?
         */
 }
 
@@ -495,8 +506,6 @@ AdvanceOldestActiveXid(TransactionId myXid)
                           TransactionIdGetStatus(xid) != XID_INPROGRESS)
                        TransactionIdAdvance(xid);
 
-               Assert(xid >= pg_atomic_read_u32(&ShmemVariableCache->globalXmin));
-
                if (xid == oldValue)
                {
                        /* nothing more to do */
@@ -531,22 +540,22 @@ AdvanceOldestActiveXid(TransactionId myXid)
        }
 }
 
+
+
 /*
- * AdvanceGlobalXmin --
  *
- * Advance GlobalXmin.
  */
-static void
-AdvanceGlobalXmin(TransactionId myXmin)
+TransactionId
+GetRecentGlobalXmin(void)
 {
-       TransactionId newGlobalXmin;
-       TransactionId currentGlobalXmin;
+       TransactionId globalXmin;
        ProcArrayStruct *arrayP = procArray;
        int                     index;
+       volatile TransactionId replication_slot_xmin = InvalidTransactionId;
+       volatile TransactionId replication_slot_catalog_xmin = InvalidTransactionId;
 
-       /* Quick exit if we were not the oldest xmin */
-       if (myXmin != pg_atomic_read_u32(&ShmemVariableCache->globalXmin))
-               return;
+       if (TransactionIdIsValid(RecentGlobalXmin))
+               return RecentGlobalXmin;
 
        LWLockAcquire(ProcArrayLock, LW_SHARED);
 
@@ -556,8 +565,8 @@ AdvanceGlobalXmin(TransactionId myXmin)
         * and so protects us against overestimating the result due to future
         * additions.
         */
-       newGlobalXmin = pg_atomic_read_u32(&ShmemVariableCache->oldestActiveXid);
-       Assert(TransactionIdIsNormal(newGlobalXmin));
+       globalXmin = pg_atomic_read_u32(&ShmemVariableCache->oldestActiveXid);
+       Assert(TransactionIdIsNormal(globalXmin));
 
        for (index = 0; index < arrayP->numProcs; index++)
        {
@@ -579,8 +588,8 @@ AdvanceGlobalXmin(TransactionId myXmin)
 
                /* First consider the transaction's own Xid, if any */
                if (TransactionIdIsNormal(xid) &&
-                       TransactionIdPrecedes(xid, newGlobalXmin))
-                       newGlobalXmin = xid;
+                       TransactionIdPrecedes(xid, globalXmin))
+                       globalXmin = xid;
 
                /*
                 * Also consider the transaction's Xmin, if set.
@@ -591,22 +600,50 @@ AdvanceGlobalXmin(TransactionId myXmin)
                 */
                xid = pgxact->xmin; /* Fetch just once */
                if (TransactionIdIsNormal(xid) &&
-                       TransactionIdPrecedes(xid, newGlobalXmin))
-                       newGlobalXmin = xid;
+                       TransactionIdPrecedes(xid, globalXmin))
+                       globalXmin = xid;
        }
 
-       for (;;)
-       {
-               currentGlobalXmin = pg_atomic_read_u32(&ShmemVariableCache->globalXmin);
-               if (!TransactionIdFollows(newGlobalXmin, currentGlobalXmin))
-                       break;  /* someone else computed a higher value */
-
-               if (pg_atomic_compare_exchange_u32(&ShmemVariableCache->globalXmin,
-                                                                                  &currentGlobalXmin, newGlobalXmin))
-                       break;  /* we updated the value successfully. */
-       }
+       /* fetch into volatile var while ProcArrayLock is held */
+       replication_slot_xmin = procArray->replication_slot_xmin;
+       replication_slot_catalog_xmin = procArray->replication_slot_catalog_xmin;
 
        LWLockRelease(ProcArrayLock);
+
+       /* Update cached variables */
+       RecentGlobalXmin = globalXmin - vacuum_defer_cleanup_age;
+       if (!TransactionIdIsNormal(RecentGlobalXmin))
+               RecentGlobalXmin = FirstNormalTransactionId;
+
+       /* Check whether there's a replication slot requiring an older xmin. */
+       if (TransactionIdIsValid(replication_slot_xmin) &&
+               NormalTransactionIdPrecedes(replication_slot_xmin, RecentGlobalXmin))
+               RecentGlobalXmin = replication_slot_xmin;
+
+       /* Non-catalog tables can be vacuumed if older than this xid */
+       RecentGlobalDataXmin = RecentGlobalXmin;
+
+       /*
+        * Check whether there's a replication slot requiring an older catalog
+        * xmin.
+        */
+       if (TransactionIdIsNormal(replication_slot_catalog_xmin) &&
+               NormalTransactionIdPrecedes(replication_slot_catalog_xmin, RecentGlobalXmin))
+               RecentGlobalXmin = replication_slot_catalog_xmin;
+
+       return RecentGlobalXmin;
+}
+
+TransactionId
+GetRecentGlobalDataXmin(void)
+{
+       if (TransactionIdIsValid(RecentGlobalDataXmin))
+               return RecentGlobalDataXmin;
+
+       (void) GetRecentGlobalXmin();
+       Assert(TransactionIdIsValid(RecentGlobalDataXmin));
+
+       return RecentGlobalDataXmin;
 }
 
 /*
@@ -869,11 +906,8 @@ GetSnapshotData(Snapshot snapshot)
 {
        TransactionId xmin;
        TransactionId xmax;
-       TransactionId globalxmin;
        CommitSeqNo snapshotcsn;
        bool            takenDuringRecovery;
-       volatile TransactionId replication_slot_xmin = InvalidTransactionId;
-       volatile TransactionId replication_slot_catalog_xmin = InvalidTransactionId;
 
        Assert(snapshot != NULL);
 
@@ -940,36 +974,8 @@ GetSnapshotData(Snapshot snapshot)
        Assert(TransactionIdIsNormal(xmax));
        TransactionIdAdvance(xmax);
 
-       /* Also read GlobalXmin. */
-       globalxmin = pg_atomic_read_u32(&ShmemVariableCache->globalXmin);
-
-       /* fetch into volatile var while ProcArrayLock is held */
-       replication_slot_xmin = procArray->replication_slot_xmin;
-       replication_slot_catalog_xmin = procArray->replication_slot_catalog_xmin;
-
        LWLockRelease(ProcArrayLock);
 
-       /* Update global variables too */
-       RecentGlobalXmin = globalxmin - vacuum_defer_cleanup_age;
-       if (!TransactionIdIsNormal(RecentGlobalXmin))
-               RecentGlobalXmin = FirstNormalTransactionId;
-
-       /* Check whether there's a replication slot requiring an older xmin. */
-       if (TransactionIdIsValid(replication_slot_xmin) &&
-               NormalTransactionIdPrecedes(replication_slot_xmin, RecentGlobalXmin))
-               RecentGlobalXmin = replication_slot_xmin;
-
-       /* Non-catalog tables can be vacuumed if older than this xid */
-       RecentGlobalDataXmin = RecentGlobalXmin;
-
-       /*
-        * Check whether there's a replication slot requiring an older catalog
-        * xmin.
-        */
-       if (TransactionIdIsNormal(replication_slot_catalog_xmin) &&
-               NormalTransactionIdPrecedes(replication_slot_catalog_xmin, RecentGlobalXmin))
-               RecentGlobalXmin = replication_slot_catalog_xmin;
-
        snapshot->xmin = xmin;
        snapshot->xmax = xmax;
        snapshot->snapshotcsn = snapshotcsn;
index efe9a6b2e1fab37c2816a4737ca1243b344be503..b4df1067eaf816f80c8c81e717b9904ade078560 100644 (file)
@@ -156,15 +156,8 @@ static bool CatalogSnapshotStale = true;
  * These are updated by GetSnapshotData.  We initialize them this way,
  * because even in bootstrap mode, we don't want it to say that
  * BootstrapTransactionId is in progress.
- *
- * RecentGlobalXmin and RecentGlobalDataXmin are initialized to
- * InvalidTransactionId, to ensure that no one tries to use a stale
- * value. Readers should ensure that it has been set to something else
- * before using it.
  */
 TransactionId TransactionXmin = FirstNormalTransactionId;
-TransactionId RecentGlobalXmin = InvalidTransactionId;
-TransactionId RecentGlobalDataXmin = InvalidTransactionId;
 
 /* (table, ctid) => (cmin, cmax) mapping during timetravel */
 static HTAB *tuplecid_data = NULL;
@@ -534,6 +527,8 @@ SetTransactionSnapshot(Snapshot sourcesnap, TransactionId sourcexid,
         * RecentGlobalXmin.  (We could alternatively include those
         * two variables in exported snapshot files, but it seems better to have
         * snapshot importers compute reasonably up-to-date values for them.)
+        *
+        * FIXME: neither of those reasons hold anymore. Can we drop this?
         */
        CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
 
@@ -884,7 +879,7 @@ SnapshotResetXmin(void)
 
        if (pairingheap_is_empty(&RegisteredSnapshots))
        {
-               MyPgXact->xmin = InvalidTransactionId;
+               ProcArrayResetXmin(MyProc);
                return;
        }
 
@@ -892,7 +887,7 @@ SnapshotResetXmin(void)
                                                                        pairingheap_first(&RegisteredSnapshots));
 
        if (TransactionIdPrecedes(MyPgXact->xmin, minSnapshot->xmin))
-               MyPgXact->xmin = minSnapshot->xmin;
+               ProcArrayResetXmin(MyProc);
 }
 
 /*
index bfb0800ac79c063f5265806f50d026d7f25f9d0c..66d36aca5e3eec177007785c1059ca7b27f5719d 100644 (file)
@@ -61,16 +61,10 @@ typedef struct VariableCacheData
         * in-progress. (Or rather, the oldest XID among all still in-progress
         * transactions; it's not necessarily the one that started first).
         * Must hold ProcArrayLock in shared mode, and use atomic ops, to update.
-        *
-        * globalXmin is the oldest XMIN among all still in-progress transactions.
-        * Anything older than this is visible to everyone, and can be
-        * frozen/vacuumed. This does not include lazy VACUUM transactions. Must
-        * hold ProcArrayLock in shared mode, and use atomic ops to update.
         */
        pg_atomic_uint64 nextCommitSeqNo;
        pg_atomic_uint32 latestCompletedXid;
        pg_atomic_uint32 oldestActiveXid;
-       pg_atomic_uint32 globalXmin;
 
        /*
         * These fields are protected by CommitTsLock
index d57a2ba9eeaa02514cc67c7b1656987e3afc5adf..98ef8b0cdaf1980402a1feb93066b198baa4dcff 100644 (file)
@@ -27,6 +27,7 @@ extern void ProcArrayRemove(PGPROC *proc);
 
 extern void ProcArrayEndTransaction(PGPROC *proc);
 extern void ProcArrayClearTransaction(PGPROC *proc);
+extern void ProcArrayResetXmin(PGPROC *proc);
 
 extern void ProcArrayInitRecovery(TransactionId oldestActiveXID, TransactionId initializedUptoXID);
 extern void ProcArrayApplyRecoveryInfo(RunningTransactions running);
@@ -44,6 +45,8 @@ extern bool ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc);
 extern RunningTransactions GetRunningTransactionData(void);
 
 extern bool TransactionIdIsActive(TransactionId xid);
+extern TransactionId GetRecentGlobalXmin(void);
+extern TransactionId GetRecentGlobalDataXmin(void);
 extern TransactionId GetOldestXmin(Relation rel, bool ignoreVacuum);
 extern TransactionId GetOldestActiveTransactionId(void);
 extern TransactionId GetOldestSafeDecodingTransactionId(void);
index 637e38fcf4aa5593504431628ce5f5efa50a767a..2b168f327605a42c0ba3819d8ac74ad00f917328 100644 (file)
@@ -57,8 +57,6 @@ extern int64 GetOldSnapshotThresholdTimestamp(void);
 extern bool FirstSnapshotSet;
 
 extern TransactionId TransactionXmin;
-extern TransactionId RecentGlobalXmin;
-extern TransactionId RecentGlobalDataXmin;
 
 extern Snapshot GetTransactionSnapshot(void);
 extern Snapshot GetLatestSnapshot(void);