summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/commands/vacuum.c8
-rw-r--r--src/backend/storage/ipc/procarray.c91
-rw-r--r--src/backend/storage/ipc/standby.c19
-rw-r--r--src/include/storage/procarray.h1
4 files changed, 71 insertions, 48 deletions
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 2d37b8d899..bfc255016a 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -428,9 +428,13 @@ vacuum_set_xid_limits(Relation rel,
*/
*oldestSnapshot = GetOldestSnapshotLSN(rel, true);
- AdvanceRecentGlobalXmin();
+ /*
+ * Note that we no longer use the oldestXmin value for deciding which
+ * tuples can be removed. That's oldestSnapshot's charter now. oldestXmin
+ * is only used to calculate the freeze limit.
+ */
+ oldestXmin = GetOldestXmin(rel, true);
- oldestXmin = RecentGlobalXmin;
Assert(TransactionIdIsNormal(oldestXmin));
/*
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 22225afe1e..e267a86388 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -342,8 +342,6 @@ ProcArrayInitRecovery(TransactionId initializedUptoXID)
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
@@ -561,14 +559,16 @@ AdvanceRecentGlobalXmin(void)
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 */
@@ -581,7 +581,7 @@ AdvanceRecentGlobalXmin(void)
RecentGlobalXmin = ShmemVariableCache->globalXmin;
- LWLockRelease(ProcArrayLock);
+ LWLockRelease(XidGenLock);
}
/*
@@ -632,11 +632,56 @@ AdvanceRecentGlobalXmin(void)
* 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)
@@ -734,7 +779,7 @@ GetSnapshotData(Snapshot snapshot)
takenDuringRecovery = RecoveryInProgress();
- LWLockAcquire(ProcArrayLock, LW_SHARED);
+ LWLockAcquire(XidGenLock, LW_SHARED);
if (takenDuringRecovery)
{
@@ -753,7 +798,7 @@ GetSnapshotData(Snapshot snapshot)
/* update RecentGlobalXmin while we have a chance */
RecentGlobalXmin = ShmemVariableCache->globalXmin;
- LWLockRelease(ProcArrayLock);
+ LWLockRelease(XidGenLock);
snapshot->xmin = xmin;
snapshot->xmax = xmax;
@@ -805,7 +850,10 @@ ProcArrayInstallImportedSnapshot(XLogRecPtr snapshotlsn, TransactionId sourcexid
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++)
@@ -860,29 +908,20 @@ ProcArrayInstallImportedSnapshot(XLogRecPtr snapshotlsn, TransactionId sourcexid
/*
* 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)
@@ -898,7 +937,6 @@ 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;
@@ -926,14 +964,11 @@ GetRunningTransactionData(void)
/*
* 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.
@@ -1046,6 +1081,8 @@ GetOldestSafeDecodingTransactionId(void)
* 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)
{
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index 0322eba79a..013d69c3ed 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -870,27 +870,8 @@ LogStandbySnapshot(void)
*/
running = GetRunningTransactionData();
- /*
- * GetRunningTransactionData() acquired ProcArrayLock, we must release it.
- * For Hot Standby this can be done before inserting the WAL record
- * because ProcArrayApplyRecoveryInfo() rechecks the commit status using
- * the clog. For logical decoding, though, the lock can't be released
- * early becuase the clog might be "in the future" from the POV of the
- * historic snapshot. This would allow for situations where we're waiting
- * for the end of a transaction listed in the xl_running_xacts record
- * which, according to the WAL, have commit before the xl_running_xacts
- * record. Fortunately this routine isn't executed frequently, and it's
- * only a shared lock.
- */
- if (wal_level < WAL_LEVEL_LOGICAL)
- LWLockRelease(ProcArrayLock);
-
recptr = LogCurrentRunningXacts(running);
- /* Release lock if we kept it longer ... */
- if (wal_level >= WAL_LEVEL_LOGICAL)
- LWLockRelease(ProcArrayLock);
-
/* GetRunningTransactionData() acquired XidGenLock, we must release it */
LWLockRelease(XidGenLock);
diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h
index 19a6e8b248..4fd938ee5d 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -45,6 +45,7 @@ extern RunningTransactions GetRunningTransactionData(void);
extern bool TransactionIdIsActive(TransactionId xid);
extern XLogRecPtr GetOldestSnapshotLSN(Relation rel, bool ignoreVacuum);
+extern TransactionId GetOldestXmin(Relation rel, bool ignoreVacuum);
extern TransactionId GetOldestActiveTransactionId(void);
extern TransactionId GetOldestSafeDecodingTransactionId(void);