diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 9f858995d1218137465eba78689a3daef963dfb8..664470336958796c04000e540085342c2af0ef9d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -5391,6 +5391,9 @@ StartupXLOG(void) oldestActiveXID = checkPoint.oldestActiveXid; Assert(TransactionIdIsValid(oldestActiveXID)); + /* Tell procarray about the range of xids it has to deal with */ + ProcArrayInitRecovery(ShmemVariableCache->nextXid); + /* * Startup commit log and subtrans only. Other SLRUs are not * maintained during recovery and need not be started yet. diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index b5f66fbfb0415dcd4acaabb8c2671a6d883bf233..c2f86ff2c4a7cc1bbb3dabbd5a39fe053ef6e223 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -469,6 +469,28 @@ ProcArrayClearTransaction(PGPROC *proc) pgxact->overflowed = false; } +/* + * ProcArrayInitRecovery -- initialize recovery xid mgmt environment + * + * Remember up to where the startup process initialized the CLOG and subtrans + * so we can ensure its initialized gaplessly up to the point where necessary + * while in recovery. + */ +void +ProcArrayInitRecovery(TransactionId initializedUptoXID) +{ + Assert(standbyState == STANDBY_INITIALIZED); + Assert(TransactionIdIsNormal(initializedUptoXID)); + + /* + * we set latestObservedXid to the xid SUBTRANS has been initialized upto + * so we can extend it from that point onwards when we reach a consistent + * state in ProcArrayApplyRecoveryInfo(). + */ + latestObservedXid = initializedUptoXID; + TransactionIdRetreat(latestObservedXid); +} + /* * ProcArrayApplyRecoveryInfo -- apply recovery info about xids * @@ -564,7 +586,10 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running) Assert(standbyState == STANDBY_INITIALIZED); /* - * OK, we need to initialise from the RunningTransactionsData record + * OK, we need to initialise from the RunningTransactionsData record. + * + * NB: this can be reached at least twice, so make sure new code can deal + * with that. */ /* @@ -636,20 +661,32 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running) pfree(xids); /* + * latestObservedXid is set to the the point where SUBTRANS was started up + * to, initialize subtrans from thereon, up to nextXid - 1. + */ + Assert(TransactionIdIsNormal(latestObservedXid)); + while (TransactionIdPrecedes(latestObservedXid, running->nextXid)) + { + ExtendCLOG(latestObservedXid); + ExtendSUBTRANS(latestObservedXid); + + TransactionIdAdvance(latestObservedXid); + } + + /* ---------- * Now we've got the running xids we need to set the global values that * are used to track snapshots as they evolve further. * - * - latestCompletedXid which will be the xmax for snapshots - - * lastOverflowedXid which shows whether snapshots overflow - nextXid + * - latestCompletedXid which will be the xmax for snapshots + * - lastOverflowedXid which shows whether snapshots overflow + * - nextXid * * If the snapshot overflowed, then we still initialise with what we know, * but the recovery snapshot isn't fully valid yet because we know there * are some subxids missing. We don't know the specific subxids that are * missing, so conservatively assume the last one is latestObservedXid. + * ---------- */ - latestObservedXid = running->nextXid; - TransactionIdRetreat(latestObservedXid); - if (running->subxid_overflow) { standbyState = STANDBY_SNAPSHOT_PENDING; @@ -719,6 +756,10 @@ ProcArrayApplyXidAssignment(TransactionId topxid, Assert(standbyState >= STANDBY_INITIALIZED); + /* can't do anything useful unless we have more state setup */ + if (standbyState == STANDBY_INITIALIZED) + return; + max_xid = TransactionIdLatest(topxid, nsubxids, subxids); /* diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index d5fdfea6f20b2c3ef9c2d27664499a47a5615ac0..c5f58b413db73ed4b74534f5289058a612126780 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -26,6 +26,7 @@ extern void ProcArrayRemove(PGPROC *proc, TransactionId latestXid); extern void ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid); extern void ProcArrayClearTransaction(PGPROC *proc); +extern void ProcArrayInitRecovery(TransactionId initializedUptoXID); extern void ProcArrayApplyRecoveryInfo(RunningTransactions running); extern void ProcArrayApplyXidAssignment(TransactionId topxid, int nsubxids, TransactionId *subxids);