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
*/
static LWLockTranche ProcLWLockTranche;
static void AdvanceOldestActiveXid(TransactionId myXid);
-static void AdvanceGlobalXmin(TransactionId myXmin);
/*
* Report shared-memory space needed by CreateSharedProcArray.
{
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);
/* 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;
}
/*
/*
* 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?
*/
}
TransactionIdGetStatus(xid) != XID_INPROGRESS)
TransactionIdAdvance(xid);
- Assert(xid >= pg_atomic_read_u32(&ShmemVariableCache->globalXmin));
-
if (xid == oldValue)
{
/* nothing more to do */
}
}
+
+
/*
- * 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);
* 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++)
{
/* 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.
*/
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,
- ¤tGlobalXmin, 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;
}
/*
{
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);
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;
* 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;
* 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);
if (pairingheap_is_empty(&RegisteredSnapshots))
{
- MyPgXact->xmin = InvalidTransactionId;
+ ProcArrayResetXmin(MyProc);
return;
}
pairingheap_first(&RegisteredSnapshots));
if (TransactionIdPrecedes(MyPgXact->xmin, minSnapshot->xmin))
- MyPgXact->xmin = minSnapshot->xmin;
+ ProcArrayResetXmin(MyProc);
}
/*