Rewrite GetOldestXmin().
authorRobert Haas <rhaas@postgresql.org>
Fri, 16 Sep 2011 21:37:49 +0000 (16:37 -0500)
committerRobert Haas <rhaas@postgresql.org>
Fri, 14 Oct 2011 18:38:14 +0000 (14:38 -0400)
src/backend/access/heap/heapam.c
src/backend/access/transam/multixact.c
src/backend/storage/ipc/procarray.c
src/backend/storage/ipc/snaparray.c
src/backend/storage/lmgr/lmgr.c
src/backend/utils/time/tqual.c
src/include/storage/procarray.h
src/include/storage/snaparray.h

index b2d19016e766d39251c6e881affbb7d279818983..88829bf866675d4855db040dd1b0ed61f29861f0 100644 (file)
@@ -58,7 +58,7 @@
 #include "storage/freespace.h"
 #include "storage/lmgr.h"
 #include "storage/predicate.h"
-#include "storage/procarray.h"
+#include "storage/snaparray.h"
 #include "storage/smgr.h"
 #include "storage/standby.h"
 #include "utils/datum.h"
index 1d159bc89cb65838d19772dc36af46b1ed608360..4fe136747f9afd19770bd166ff1a5c24ab8ff2d9 100644 (file)
@@ -57,7 +57,7 @@
 #include "miscadmin.h"
 #include "pg_trace.h"
 #include "storage/lmgr.h"
-#include "storage/procarray.h"
+#include "storage/snaparray.h"
 #include "utils/builtins.h"
 #include "utils/memutils.h"
 
index 26c51503afde996789e819ca9ec446ef8b16a651..01c91fbe4dbb905acb812ff67d073664d417caa5 100644 (file)
@@ -53,7 +53,7 @@
 #include "miscadmin.h"
 #include "storage/procarray.h"
 #include "storage/spin.h"
-#include "storage/snaparray.h" /* XXX: might not be needed, by the end */
+#include "storage/snaparray.h"
 #include "utils/builtins.h"
 #include "utils/snapmgr.h"
 
@@ -151,7 +151,6 @@ static void KnownAssignedXidsRemove(TransactionId xid);
 static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids,
                                                        TransactionId *subxids);
 static void KnownAssignedXidsRemovePreceding(TransactionId xid);
-static TransactionId KnownAssignedXidsGetOldestXmin(void);
 static void KnownAssignedXidsDisplay(int trace_level);
 
 /*
@@ -356,7 +355,6 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
                Assert(TransactionIdIsValid(proc->xid));
 
                LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
-               LWLockAcquire(SnapArrayLock, LW_EXCLUSIVE);     /* XXX: FIXME */
 
                proc->xid = InvalidTransactionId;
                proc->lxid = InvalidLocalTransactionId;
@@ -375,7 +373,6 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
                                                                  latestXid))
                        ShmemVariableCache->latestCompletedXid = latestXid;
 
-               LWLockRelease(SnapArrayLock);
                LWLockRelease(ProcArrayLock);
        }
        else
@@ -789,17 +786,15 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum)
        /* Cannot look for individual databases during recovery */
        Assert(allDbs || !RecoveryInProgress());
 
-       LWLockAcquire(ProcArrayLock, LW_SHARED);
-
        /*
-        * We initialize the MIN() calculation with latestCompletedXid + 1. This
-        * is a lower bound for the XIDs that might appear in the ProcArray later,
-        * and so protects us against overestimating the result due to future
-        * additions.
+        * Initialize the MIN() calculation.  This is a lower bound for the XIDs
+        * that might appear in the ProcArray later, and so protects us against
+        * overestimating the result due to future additions.
         */
-       result = ShmemVariableCache->latestCompletedXid;
+       result = SnapArraySetFreshXmin();
        Assert(TransactionIdIsNormal(result));
-       TransactionIdAdvance(result);
+
+       LWLockAcquire(ProcArrayLock, LW_SHARED);
 
        for (index = 0; index < arrayP->numProcs; index++)
        {
@@ -812,49 +807,20 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum)
                        proc->databaseId == MyDatabaseId ||
                        proc->databaseId == 0)          /* include WalSender */
                {
-                       /* Fetch xid just once - see GetNewTransactionId */
-                       TransactionId xid = proc->xid;
+                       /* Fetch xmin just once - see GetNewTransactionId */
+                       TransactionId xmin = proc->xmin;
 
-                       /* First consider the transaction's own Xid, if any */
-                       if (TransactionIdIsNormal(xid) &&
-                               TransactionIdPrecedes(xid, result))
-                               result = xid;
+                       if (TransactionIdIsNormal(xmin) &&
+                               TransactionIdPrecedes(xmin, result))
+                               result = xmin;
 
-                       /*
-                        * Also consider the transaction's Xmin, if set.
-                        *
-                        * We must check both Xid and Xmin because a transaction might
-                        * have an Xmin but not (yet) an Xid; conversely, if it has an
-                        * Xid, that could determine some not-yet-set Xmin.
-                        */
-                       xid = proc->xmin;       /* Fetch just once */
-                       if (TransactionIdIsNormal(xid) &&
-                               TransactionIdPrecedes(xid, result))
-                               result = xid;
                }
        }
 
-       if (RecoveryInProgress())
-       {
-               /*
-                * Check to see whether KnownAssignedXids contains an xid value older
-                * than the main procarray.
-                */
-               TransactionId kaxmin = KnownAssignedXidsGetOldestXmin();
-
-               LWLockRelease(ProcArrayLock);
+       LWLockRelease(ProcArrayLock);
 
-               if (TransactionIdIsNormal(kaxmin) &&
-                       TransactionIdPrecedes(kaxmin, result))
-                       result = kaxmin;
-       }
-       else
+       if (!RecoveryInProgress())
        {
-               /*
-                * No other information needed, so release the lock immediately.
-                */
-               LWLockRelease(ProcArrayLock);
-
                /*
                 * Compute the cutoff XID, being careful not to generate a "permanent"
                 * XID. We need do this only on the primary, never on standby.
@@ -872,6 +838,9 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum)
                        result = FirstNormalTransactionId;
        }
 
+       /* Adjust, and possibly publish, new value. */
+       result = SnapArrayAdjustGlobalXmin(result, allDbs && !ignoreVacuum);
+
        return result;
 }
 
@@ -2427,37 +2396,6 @@ KnownAssignedXidsRemovePreceding(TransactionId removeXid)
        KnownAssignedXidsCompress(false);
 }
 
-/*
- * Get oldest XID in the KnownAssignedXids array, or InvalidTransactionId
- * if nothing there.
- */
-static TransactionId
-KnownAssignedXidsGetOldestXmin(void)
-{
-       /* use volatile pointer to prevent code rearrangement */
-       volatile ProcArrayStruct *pArray = procArray;
-       int                     head,
-                               tail;
-       int                     i;
-
-       /*
-        * Fetch head just once, since it may change while we loop.
-        */
-       SpinLockAcquire(&pArray->known_assigned_xids_lck);
-       tail = pArray->tailKnownAssignedXids;
-       head = pArray->headKnownAssignedXids;
-       SpinLockRelease(&pArray->known_assigned_xids_lck);
-
-       for (i = tail; i < head; i++)
-       {
-               /* Skip any gaps in the array */
-               if (KnownAssignedXidsValid[i])
-                       return KnownAssignedXids[i];
-       }
-
-       return InvalidTransactionId;
-}
-
 /*
  * Display KnownAssignedXids to provide debug trail
  *
index 80b170844d7ae632f4f328280cc80a7c01f89a7b..7ec9a22c74a7d76ce284721f7d0d9ce5f7e25366 100644 (file)
@@ -682,7 +682,7 @@ retry:
         * that we read a slightly out-of-date, older value.  That's acceptable.
         */
        RecentXmin = xmin;
-       RecentGlobalXmin = SnapArray->global_xmin - vacuum_defer_cleanup_age;
+       RecentGlobalXmin = SnapArray->global_xmin;
        if (!TransactionIdIsNormal(RecentGlobalXmin))
                RecentGlobalXmin = FirstNormalTransactionId;
 
@@ -697,6 +697,77 @@ retry:
        return snapshot;
 }
 
+/*
+ * Prepare for global xmin calculation.
+ *
+ * This function will return a xmin which must be folded into the caller's
+ * global xmin calculation; that is, the caller must not compute a global xmin
+ * which precedes the return value of this function.  In turn, we guarantee
+ * that subsequently dervied snapshots will have an xmin greater than or equal
+ * to the value returned by this function.
+ *
+ * It's possible for xmin values preceding the return value to appear in
+ * ProcArray transiently.  However, those snapshots won't be used: we'll
+ * automatically recompute them before returning to the caller.
+ */
+TransactionId
+SnapArraySetFreshXmin(void)
+{
+       TransactionId   xmin;
+
+       /* Get latest information from shared memory. */
+       if (!SnapArrayUpdateCache(false))
+       {
+               LWLockAcquire(SnapArrayLock, LW_SHARED);
+               SnapArrayUpdateCache(true);
+               LWLockRelease(SnapArrayLock);
+       }
+
+       /* Compute xmin. */
+       if (SnapArrayCache.buffer[3] == 0)
+               xmin = SnapArrayCache.buffer[1];
+       else
+               xmin = SnapArrayCache.buffer[SNAPARRAY_SUMMARY_ITEMS];
+
+       /* Advance fresh_xmin. */
+       SpinLockAcquire(&SnapArray->misc_mutex);
+       if (TransactionIdPrecedes(xmin, SnapArray->fresh_xmin))
+               SnapArray->fresh_xmin = xmin;
+       else
+               xmin = SnapArray->fresh_xmin;
+       SpinLockRelease(&SnapArray->misc_mutex);
+
+       return xmin;
+}
+
+/*
+ * Final adjustments after computing a global xmin.
+ *
+ * We don't want the global xmin to ever move backwards, so we check whether
+ * some other backend has already published a newer global xmin.  If so, we
+ * return that value to the caller, who should use it in lieu of the computed
+ * value.  If not, we return the caller-supplied value.
+ *
+ * In some cases, the caller may not have included all backends in the global
+ * xmin calculation (e.g. because we're just looking for the minimum across
+ * a single DB).  If the caller has included all backends in the calculation,
+ * they should set publish = true; if they do, we'll advance the cached global
+ * xmin to the value provided.
+ */
+TransactionId
+SnapArrayAdjustGlobalXmin(TransactionId global_xmin, bool publish)
+{
+       SpinLockAcquire(&SnapArray->misc_mutex);
+       if (TransactionIdPrecedes(global_xmin, SnapArray->global_xmin))
+               global_xmin = SnapArray->global_xmin;
+       else if (publish &&
+               TransactionIdPrecedes(SnapArray->global_xmin, global_xmin))
+               SnapArray->global_xmin = global_xmin;
+       SpinLockRelease(&SnapArray->misc_mutex);
+
+       return global_xmin;
+}
+
 /*
  * TransactionIdIsInProgress -- is given transaction running in some backend
  *
index 25ead29a4802febf565562c9cc64037c22ac3640..24a8337761a3d6b7b0856768b3748f64dcc9e82e 100644 (file)
@@ -21,7 +21,7 @@
 #include "catalog/catalog.h"
 #include "miscadmin.h"
 #include "storage/lmgr.h"
-#include "storage/procarray.h"
+#include "storage/snaparray.h"
 #include "utils/inval.h"
 
 
index ae5a05fa7646d5af4da123cd4f1b0b0567a7eaf0..497cc714ee07ef2be160c005560afe1b1ad492d7 100644 (file)
@@ -62,7 +62,7 @@
 #include "access/transam.h"
 #include "access/xact.h"
 #include "storage/bufmgr.h"
-#include "storage/procarray.h"
+#include "storage/snaparray.h"
 #include "utils/tqual.h"
 
 
index 4b270481b0712543701a428ddeee5ecc49077dbd..ee87e8347947a7a3aa8c280b4d1d724069426472 100644 (file)
@@ -39,7 +39,6 @@ extern void ExpireOldKnownAssignedTransactionIds(TransactionId xid);
 
 extern RunningTransactions GetRunningTransactionData(void);
 
-extern bool TransactionIdIsInProgress(TransactionId xid);
 extern bool TransactionIdIsActive(TransactionId xid);
 extern TransactionId GetOldestXmin(bool allDbs, bool ignoreVacuum);
 
index 27a862fc139150e70377fd2e0265dacf659231eb..8f9ff318fe36cf60ae5191926ecf9d9fdb9a7ec9 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef SNAPARRAY_H
 #define SNAPARRAY_H
 
+#include "utils/snapshot.h"
+
 #define        SNAPARRAY_MAX_UNREPORTED_SUBXIDS                64
 
 extern Size SnapArrayShmemSize(void);
@@ -22,6 +24,10 @@ extern void SnapArrayInitNormalRunning(TransactionId xmax,
                                                                           TransactionId *prepared_xids);
 extern void SnapArrayRemoveRunningXids(uint32 xid, int nchildren,
                                                   TransactionId *children, TransactionId latest_xid);
+extern TransactionId SnapArraySetFreshXmin(void);
+extern TransactionId SnapArrayAdjustGlobalXmin(TransactionId global_xmin,
+                                                 bool publish);
 extern Snapshot        SnapArrayGetSnapshotData(Snapshot snapshot);
+extern bool TransactionIdIsInProgress(TransactionId xid);
 
 #endif   /* SNAPARRAY_H */