Skip to content

Commit f44eedc

Browse files
Ensure no xid gaps during Hot Standby startup
In some cases with higher numbers of subtransactions it was possible for us to incorrectly initialize subtrans leading to complaints of missing pages. Bug report by Sergey Konoplev Analysis and fix by Andres Freund
1 parent 4f1490c commit f44eedc

File tree

3 files changed

+48
-4
lines changed

3 files changed

+48
-4
lines changed

src/backend/access/transam/xlog.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6117,6 +6117,9 @@ StartupXLOG(void)
61176117
oldestActiveXID = checkPoint.oldestActiveXid;
61186118
Assert(TransactionIdIsValid(oldestActiveXID));
61196119

6120+
/* Tell procarray about the range of xids it has to deal with */
6121+
ProcArrayInitRecovery(ShmemVariableCache->nextXid);
6122+
61206123
/*
61216124
* Startup commit log and subtrans only. Other SLRUs are not
61226125
* maintained during recovery and need not be started yet.

src/backend/storage/ipc/procarray.c

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,28 @@ ProcArrayClearTransaction(PGPROC *proc)
435435
proc->subxids.overflowed = false;
436436
}
437437

438+
/*
439+
* ProcArrayInitRecovery -- initialize recovery xid mgmt environment
440+
*
441+
* Remember up to where the startup process initialized the CLOG and subtrans
442+
* so we can ensure its initialized gaplessly up to the point where necessary
443+
* while in recovery.
444+
*/
445+
void
446+
ProcArrayInitRecovery(TransactionId initializedUptoXID)
447+
{
448+
Assert(standbyState == STANDBY_INITIALIZED);
449+
Assert(TransactionIdIsNormal(initializedUptoXID));
450+
451+
/*
452+
* we set latestObservedXid to the xid SUBTRANS has been initialized upto
453+
* so we can extend it from that point onwards when we reach a consistent
454+
* state in ProcArrayApplyRecoveryInfo().
455+
*/
456+
latestObservedXid = initializedUptoXID;
457+
TransactionIdRetreat(latestObservedXid);
458+
}
459+
438460
/*
439461
* ProcArrayApplyRecoveryInfo -- apply recovery info about xids
440462
*
@@ -523,7 +545,10 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
523545
Assert(standbyState == STANDBY_INITIALIZED);
524546

525547
/*
526-
* OK, we need to initialise from the RunningTransactionsData record
548+
* OK, we need to initialise from the RunningTransactionsData record.
549+
*
550+
* NB: this can be reached at least twice, so make sure new code can deal
551+
* with that.
527552
*/
528553

529554
/*
@@ -595,6 +620,19 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
595620
pfree(xids);
596621

597622
/*
623+
* latestObservedXid is set to the the point where SUBTRANS was started up
624+
* to, initialize subtrans from thereon, up to nextXid - 1.
625+
*/
626+
Assert(TransactionIdIsNormal(latestObservedXid));
627+
while (TransactionIdPrecedes(latestObservedXid, running->nextXid))
628+
{
629+
ExtendCLOG(latestObservedXid);
630+
ExtendSUBTRANS(latestObservedXid);
631+
632+
TransactionIdAdvance(latestObservedXid);
633+
}
634+
635+
/* ----------
598636
* Now we've got the running xids we need to set the global values that
599637
* are used to track snapshots as they evolve further.
600638
*
@@ -606,10 +644,8 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
606644
* but the recovery snapshot isn't fully valid yet because we know there
607645
* are some subxids missing. We don't know the specific subxids that are
608646
* missing, so conservatively assume the last one is latestObservedXid.
647+
* ----------
609648
*/
610-
latestObservedXid = running->nextXid;
611-
TransactionIdRetreat(latestObservedXid);
612-
613649
if (running->subxid_overflow)
614650
{
615651
standbyState = STANDBY_SNAPSHOT_PENDING;
@@ -669,6 +705,10 @@ ProcArrayApplyXidAssignment(TransactionId topxid,
669705

670706
Assert(standbyState >= STANDBY_INITIALIZED);
671707

708+
/* can't do anything useful unless we have more state setup */
709+
if (standbyState == STANDBY_INITIALIZED)
710+
return;
711+
672712
max_xid = TransactionIdLatest(topxid, nsubxids, subxids);
673713

674714
/*

src/include/storage/procarray.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ extern void ProcArrayRemove(PGPROC *proc, TransactionId latestXid);
2828
extern void ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid);
2929
extern void ProcArrayClearTransaction(PGPROC *proc);
3030

31+
extern void ProcArrayInitRecovery(TransactionId initializedUptoXID);
3132
extern void ProcArrayApplyRecoveryInfo(RunningTransactions running);
3233
extern void ProcArrayApplyXidAssignment(TransactionId topxid,
3334
int nsubxids, TransactionId *subxids);

0 commit comments

Comments
 (0)