MemSet(&checkPoint, 0, sizeof(checkPoint));
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.
* 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();
return CurrentRunningXacts;
}
+/*
+ * 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
*
* making WAL entries.
*/
void
-LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid)
+LogStandbySnapshot(TransactionId *nextXid)
{
RunningTransactions running;
xl_standby_lock *locks;
/* GetRunningTransactionData() acquired XidGenLock, we must release it */
LWLockRelease(XidGenLock);
- *oldestActiveXid = running->oldestRunningXid;
*nextXid = running->nextXid;
}
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);
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 */