Commit 86e33648 authored by Simon Riggs's avatar Simon Riggs

Derive oldestActiveXid at correct time for Hot Standby.

There was a timing window between when oldestActiveXid was derived
and when it should have been derived that only shows itself under
heavy load. Move code around to ensure correct timing of derivation.
No change to StartupSUBTRANS() code, which is where this failed.

Bug report by Chris Redekop
parent 10b7c686
...@@ -7636,6 +7636,16 @@ CreateCheckPoint(int flags) ...@@ -7636,6 +7636,16 @@ CreateCheckPoint(int flags)
MemSet(&checkPoint, 0, sizeof(checkPoint)); MemSet(&checkPoint, 0, sizeof(checkPoint));
checkPoint.time = (pg_time_t) time(NULL); 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 * We must hold WALInsertLock while examining insert state to determine
* the checkpoint REDO pointer. * the checkpoint REDO pointer.
...@@ -7822,9 +7832,7 @@ CreateCheckPoint(int flags) ...@@ -7822,9 +7832,7 @@ CreateCheckPoint(int flags)
* Update checkPoint.nextXid since we have a later value * Update checkPoint.nextXid since we have a later value
*/ */
if (!shutdown && XLogStandbyInfoActive()) if (!shutdown && XLogStandbyInfoActive())
LogStandbySnapshot(&checkPoint.oldestActiveXid, &checkPoint.nextXid); LogStandbySnapshot(&checkPoint.nextXid);
else
checkPoint.oldestActiveXid = InvalidTransactionId;
START_CRIT_SECTION(); START_CRIT_SECTION();
......
...@@ -1620,6 +1620,63 @@ GetRunningTransactionData(void) ...@@ -1620,6 +1620,63 @@ GetRunningTransactionData(void)
return CurrentRunningXacts; 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 * GetTransactionsInCommit -- Get the XIDs of transactions that are committing
* *
......
...@@ -815,7 +815,7 @@ standby_desc(StringInfo buf, uint8 xl_info, char *rec) ...@@ -815,7 +815,7 @@ standby_desc(StringInfo buf, uint8 xl_info, char *rec)
* making WAL entries. * making WAL entries.
*/ */
void void
LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid) LogStandbySnapshot(TransactionId *nextXid)
{ {
RunningTransactions running; RunningTransactions running;
xl_standby_lock *locks; xl_standby_lock *locks;
...@@ -845,7 +845,6 @@ LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid) ...@@ -845,7 +845,6 @@ LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid)
/* GetRunningTransactionData() acquired XidGenLock, we must release it */ /* GetRunningTransactionData() acquired XidGenLock, we must release it */
LWLockRelease(XidGenLock); LWLockRelease(XidGenLock);
*oldestActiveXid = running->oldestRunningXid;
*nextXid = running->nextXid; *nextXid = running->nextXid;
} }
......
...@@ -50,6 +50,7 @@ extern RunningTransactions GetRunningTransactionData(void); ...@@ -50,6 +50,7 @@ extern RunningTransactions GetRunningTransactionData(void);
extern bool TransactionIdIsInProgress(TransactionId xid); extern bool TransactionIdIsInProgress(TransactionId xid);
extern bool TransactionIdIsActive(TransactionId xid); extern bool TransactionIdIsActive(TransactionId xid);
extern TransactionId GetOldestXmin(bool allDbs, bool ignoreVacuum); extern TransactionId GetOldestXmin(bool allDbs, bool ignoreVacuum);
extern TransactionId GetOldestActiveTransactionId(void);
extern int GetTransactionsInCommit(TransactionId **xids_p); extern int GetTransactionsInCommit(TransactionId **xids_p);
extern bool HaveTransactionsInCommit(TransactionId *xids, int nxids); extern bool HaveTransactionsInCommit(TransactionId *xids, int nxids);
......
...@@ -111,6 +111,6 @@ typedef RunningTransactionsData *RunningTransactions; ...@@ -111,6 +111,6 @@ typedef RunningTransactionsData *RunningTransactions;
extern void LogAccessExclusiveLock(Oid dbOid, Oid relOid); extern void LogAccessExclusiveLock(Oid dbOid, Oid relOid);
extern void LogAccessExclusiveLockPrepare(void); extern void LogAccessExclusiveLockPrepare(void);
extern void LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid); extern void LogStandbySnapshot(TransactionId *nextXid);
#endif /* STANDBY_H */ #endif /* STANDBY_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment