oldestActiveXid_fixed.v2.patch
application/octet-stream
Filename: oldestActiveXid_fixed.v2.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v2
| File | + | − |
|---|---|---|
| src/backend/access/transam/clog.c | 10 | 0 |
| src/backend/access/transam/xlog.c | 16 | 3 |
| src/backend/storage/ipc/procarray.c | 57 | 0 |
| src/backend/storage/ipc/standby.c | 1 | 2 |
| src/include/access/clog.h | 1 | 0 |
| src/include/storage/procarray.h | 1 | 0 |
| src/include/storage/standby.h | 1 | 1 |
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 3a6c391..363db0e 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -479,6 +479,16 @@ ZeroCLOGPage(int pageno, bool writeXlog)
void
StartupCLOG(void)
{
+ /* Currently this is a no-op */
+ return;
+}
+
+/*
+ * This must be called ONCE at the end of startup/recovery.
+ */
+void
+TrimCLOG(void)
+{
TransactionId xid = ShmemVariableCache->nextXid;
int pageno = TransactionIdToPage(xid);
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index befb507..1535896 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6917,6 +6917,11 @@ StartupXLOG(void)
StartupMultiXact();
}
+ /*
+ * Trim commit log to the nextxid, so that any later xid states are reset.
+ */
+ TrimCLOG();
+
/* Reload shared-memory state for prepared transactions */
RecoverPreparedTransactions();
@@ -7623,6 +7628,16 @@ CreateCheckPoint(int flags)
checkPoint.time = (pg_time_t) time(NULL);
/*
+ * For Hot Standby, derive the oldestActiveXid before we fix the redo pointer.
+ * This allows us to begin accumulating changes to assemble our starting
+ * snapshot of locks and transactions.
+ */
+ if (!shutdown && XLogStandbyInfoActive())
+ checkPoint.oldestActiveXid = GetOldestActiveTransactionId();
+ else
+ checkPoint.oldestActiveXid = InvalidTransactionId;
+
+ /*
* We must hold WALInsertLock while examining insert state to determine
* the checkpoint REDO pointer.
*/
@@ -7808,9 +7823,7 @@ CreateCheckPoint(int flags)
* Update checkPoint.nextXid since we have a later value
*/
if (!shutdown && XLogStandbyInfoActive())
- LogStandbySnapshot(&checkPoint.oldestActiveXid, &checkPoint.nextXid);
- else
- checkPoint.oldestActiveXid = InvalidTransactionId;
+ LogStandbySnapshot(&checkPoint.nextXid);
START_CRIT_SECTION();
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 9489012..bbc5f44 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -1504,6 +1504,63 @@ GetRunningTransactionData(void)
}
/*
+ * GetOldestActiveTransactionId()
+ *
+ * Similar to GetSnapshotData but returns just oldestActiveXid. We include
+ * all PGPROCs 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.
+ */
+TransactionId
+GetOldestActiveTransactionId(void)
+{
+ ProcArrayStruct *arrayP = procArray;
+ TransactionId oldestRunningXid;
+ int index;
+
+ Assert(!RecoveryInProgress());
+
+ LWLockAcquire(ProcArrayLock, LW_SHARED);
+
+ oldestRunningXid = ShmemVariableCache->nextXid;
+
+ /*
+ * Spin over procArray collecting all xids and subxids.
+ */
+ for (index = 0; index < arrayP->numProcs; index++)
+ {
+ volatile PGPROC *proc = arrayP->procs[index];
+ TransactionId xid;
+
+ /* Fetch xid just once - see GetNewTransactionId */
+ xid = proc->xid;
+
+ if (!TransactionIdIsNormal(xid))
+ continue;
+
+ if (TransactionIdPrecedes(xid, oldestRunningXid))
+ oldestRunningXid = xid;
+
+ /*
+ * Top-level XID of a transaction is always less than any of its
+ * subxids, so we don't need to check if any of the subxids are
+ * smaller than oldestRunningXid
+ */
+ }
+
+ LWLockRelease(ProcArrayLock);
+
+ return oldestRunningXid;
+}
+
+/*
* GetTransactionsInCommit -- Get the XIDs of transactions that are committing
*
* Constructs an array of XIDs of transactions that are currently in commit
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index 72c6b97..3f2fc81 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -815,7 +815,7 @@ standby_desc(StringInfo buf, uint8 xl_info, char *rec)
* making WAL entries.
*/
void
-LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid)
+LogStandbySnapshot(TransactionId *nextXid)
{
RunningTransactions running;
xl_standby_lock *locks;
@@ -845,7 +845,6 @@ LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid)
/* GetRunningTransactionData() acquired XidGenLock, we must release it */
LWLockRelease(XidGenLock);
- *oldestActiveXid = running->oldestRunningXid;
*nextXid = running->nextXid;
}
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index 7a8918e..691430c 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -40,6 +40,7 @@ extern Size CLOGShmemSize(void);
extern void CLOGShmemInit(void);
extern void BootStrapCLOG(void);
extern void StartupCLOG(void);
+extern void TrimCLOG(void);
extern void ShutdownCLOG(void);
extern void CheckPointCLOG(void);
extern void ExtendCLOG(TransactionId newestXact);
diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h
index a11d438..7eccd5f 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -44,6 +44,7 @@ extern Snapshot GetSnapshotData(Snapshot snapshot);
extern bool TransactionIdIsInProgress(TransactionId xid);
extern bool TransactionIdIsActive(TransactionId xid);
extern TransactionId GetOldestXmin(bool allDbs, bool ignoreVacuum);
+extern TransactionId GetOldestActiveTransactionId(void);
extern int GetTransactionsInCommit(TransactionId **xids_p);
extern bool HaveTransactionsInCommit(TransactionId *xids, int nxids);
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index 6ebac62..e587a5c 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -111,6 +111,6 @@ typedef RunningTransactionsData *RunningTransactions;
extern void LogAccessExclusiveLock(Oid dbOid, Oid relOid);
extern void LogAccessExclusiveLockPrepare(void);
-extern void LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid);
+extern void LogStandbySnapshot(TransactionId *nextXid);
#endif /* STANDBY_H */