Assert(TransactionIdIsNormal(initializedUptoXID));
/*
- * FIXME: comment refers to SUBTRANS, I don't think this is needed anymore
- *
* we set latestObservedXid to the xid SUBTRANS has been initialized upto,
* so we can extend it from that point onwards in
* RecordKnownAssignedTransactionIds, and when we get consistent in
oldestSnapshot = GetOldestSnapshotLSN(NULL, false);
- LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+ LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
+ /* Do step 1, if we don't have a global xmin pending already. */
if (ShmemVariableCache->pendingGlobalXmin == InvalidTransactionId)
{
ShmemVariableCache->pendingGlobalXmin = xmin;
ShmemVariableCache->pendingLSN = pendingLSN;
}
+ /* Have we finished the wait in step 3? */
if (oldestSnapshot <= ShmemVariableCache->pendingLSN)
{
/* install new globalxmin */
RecentGlobalXmin = ShmemVariableCache->globalXmin;
- LWLockRelease(ProcArrayLock);
+ LWLockRelease(XidGenLock);
}
/*
* increasing that setting on the fly is another easy way to make
* GetOldestXmin() move backwards, with no consequences for data integrity.
*/
+TransactionId
+GetOldestXmin(Relation rel, bool ignoreVacuum)
+{
+ TransactionId result;
+
+ volatile TransactionId replication_slot_xmin = InvalidTransactionId;
+ volatile TransactionId replication_slot_catalog_xmin = InvalidTransactionId;
+
+ AdvanceRecentGlobalXmin();
+
+ result = RecentGlobalXmin;
+
+ LWLockAcquire(ProcArrayLock, LW_SHARED);
+
+ /* 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);
+
+ /*
+ * Check whether there are replication slots requiring an older xmin.
+ */
+ if (TransactionIdIsValid(replication_slot_xmin) &&
+ NormalTransactionIdPrecedes(replication_slot_xmin, result))
+ result = replication_slot_xmin;
+
+ /*
+ * After locks have been released and defer_cleanup_age has been applied,
+ * check whether we need to back up further to make logical decoding
+ * possible. We need to do so if we're computing the global limit (rel =
+ * NULL) or if the passed relation is a catalog relation of some kind.
+ */
+ if ((rel == NULL ||
+ RelationIsAccessibleInLogicalDecoding(rel)) &&
+ TransactionIdIsValid(replication_slot_catalog_xmin) &&
+ NormalTransactionIdPrecedes(replication_slot_catalog_xmin, result))
+ result = replication_slot_catalog_xmin;
+
+ return result;
+}
/*
* Get the LSN of the oldest snapshot still active.
*
* With LSN-based snapshots, this is more accurate than GetOldestXmin().
+ *
+ * FIXME: the replication_slot_xmin and replication_slot_catalog_xmin values
+ * don't affect this, so when this is used to decide if a dead tuple can be
+ * vacuumed, it breaks logical decoding.
*/
XLogRecPtr
GetOldestSnapshotLSN(Relation rel, bool ignoreVacuum)
takenDuringRecovery = RecoveryInProgress();
- LWLockAcquire(ProcArrayLock, LW_SHARED);
+ LWLockAcquire(XidGenLock, LW_SHARED);
if (takenDuringRecovery)
{
/* update RecentGlobalXmin while we have a chance */
RecentGlobalXmin = ShmemVariableCache->globalXmin;
- LWLockRelease(ProcArrayLock);
+ LWLockRelease(XidGenLock);
snapshot->xmin = xmin;
snapshot->xmax = xmax;
if (!TransactionIdIsNormal(sourcexid))
return false;
- /* Get exclusive lock so source xact can't end while we're doing this */
+ /*
+ * Get exclusive lock so source xact can't end while we're doing this.
+ * FIXME: holding the ProcArrayLock doesn't do the trick anymore
+ */
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
for (index = 0; index < arrayP->numProcs; index++)
/*
* GetRunningTransactionData -- returns information about running transactions.
*
- * Similar to GetSnapshotData but returns more information. We include
- * all PGXACTs with an assigned TransactionId, even VACUUM processes.
+ * We acquire XigGenlock, but the caller is responsible for releasing it.
+ * Acquiring XigGenLock ensures that no new XID can be assigned until
+ * the caller has WAL-logged this snapshot, and releases the lock.
+ * FIXME: I'm not sure if we need that interlock anymore.
*
- * We acquire XidGenLock and ProcArrayLock, but the caller is responsible for
- * releasing them. Acquiring XidGenLock ensures that no new XIDs enter the proc
- * array until the caller has WAL-logged this snapshot, and releases the
- * lock. Acquiring ProcArrayLock ensures that no transactions commit until the
- * lock is released.
+ * Returns the current xmin and xmax, like GetSnapshotData does.
+ * FIXME: not sure we need this separately from GetSnapshotdata anymore.
*
* The returned data structure is statically allocated; caller should not
* modify it, and must not assume it is valid past the next call.
*
- * This is never executed during recovery so there is no need to look at
- * KnownAssignedXids.
- *
* We don't worry about updating other counters, we want to keep this as
* simple as possible and leave GetSnapshotData() as the primary code for
* that bookkeeping.
- *
- * Note that if any transaction has overflowed its cached subtransactions
- * then there is no real need include any subtransactions. That isn't a
- * common enough case to worry about optimising the size of the WAL record,
- * and we may wish to see that data for diagnostic purposes anyway.
*/
RunningTransactions
GetRunningTransactionData(void)
* Ensure that no xids enter or leave the procarray while we obtain
* snapshot.
*/
- LWLockAcquire(ProcArrayLock, LW_SHARED);
LWLockAcquire(XidGenLock, LW_SHARED);
oldestRunningXid = ShmemVariableCache->nextXid;
/*
* GetOldestActiveTransactionId()
*
- * Similar to GetSnapshotData but returns just oldestActiveXid. We include
+ * Returns the oldest XID that's still running. We include
* all PGXACTs with an assigned TransactionId, even VACUUM processes.
* We look at all databases, though there is no need to include WALSender
* since this has no effect on hot standby conflicts.
*
- * This is never executed during recovery so there is no need to look at
- * KnownAssignedXids.
- *
* We don't worry about updating other counters, we want to keep this as
* simple as possible and leave GetSnapshotData() as the primary code for
* that bookkeeping.
* above, so we'll have to wait a bit longer there. We unfortunately can
* *not* use KnownAssignedXidsGetOldestXmin() since the KnownAssignedXids
* machinery can miss values and return an older value than is safe.
+ * FIXME: I don't understand this stuff, but at least the comments need
+ * adjustment because KnownAssignedXids is no more.
*/
if (!recovery_in_progress)
{