mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
Fix checkpointer restartpoint assertion failure
When recovery starts from a backup without a signal file, pg_subtrans
is not started at the beginning of recovery and remains unstarted
throughout recovery. However, previously, a restartpoint run by
the checkpointer during recovery nevertheless tried to truncate
pg_subtrans, triggering the assertion failure:
TRAP: failed Assert("TransactionIdIsValid(initial)")
This commit fixes this by tracking whether pg_subtrans has been
started during recovery, and have the checkpointer check this flag
before truncating pg_subtrans at restartpoints.
Backpatch to all supported versions.
Reported-by: Imran Zaheer <imran.zhir@gmail.com>
Author: Imran Zaheer <imran.zhir@gmail.com>
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/CA+UBfamzfEReT0VOGRUW_=_AecCYQ-CNKLR_T4Q+YEmJAH3fdg@mail.gmail.com
Backpatch-through: 14
This commit is contained in:
@@ -5844,6 +5844,7 @@ StartupXLOG(void)
|
||||
* during recovery and need not be started yet.
|
||||
*/
|
||||
StartupSUBTRANS(oldestActiveXID);
|
||||
SetRecoverySubtransInitialized();
|
||||
|
||||
/*
|
||||
* If we're beginning at a shutdown checkpoint, we know that
|
||||
@@ -7856,10 +7857,10 @@ CreateRestartPoint(int flags)
|
||||
* Truncate pg_subtrans if possible. We can throw away all data before
|
||||
* the oldest XMIN of any running transaction. No future transaction will
|
||||
* attempt to reference any pg_subtrans entry older than that (see Asserts
|
||||
* in subtrans.c). When hot standby is disabled, though, we mustn't do
|
||||
* this because StartupSUBTRANS hasn't been called yet.
|
||||
* in subtrans.c). During recovery, don't truncate pg_subtrans until hot
|
||||
* standby initialization has started it.
|
||||
*/
|
||||
if (EnableHotStandby)
|
||||
if (RecoverySubtransInitialized())
|
||||
TruncateSUBTRANS(GetOldestTransactionIdConsideredRunning());
|
||||
|
||||
/* Real work is done; log and update stats. */
|
||||
|
||||
@@ -322,6 +322,12 @@ typedef struct XLogRecoveryCtlData
|
||||
*/
|
||||
bool SharedPromoteIsTriggered;
|
||||
|
||||
/*
|
||||
* SharedRecoverySubtransInitialized indicates whether hot standby
|
||||
* initialization has started pg_subtrans. Protected by info_lck.
|
||||
*/
|
||||
bool SharedRecoverySubtransInitialized;
|
||||
|
||||
/*
|
||||
* recoveryWakeupLatch is used to wake up the startup process to continue
|
||||
* WAL replay, if it is waiting for WAL to arrive or promotion to be
|
||||
@@ -4523,6 +4529,32 @@ CheckPromoteSignal(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Has hot standby initialization started pg_subtrans?
|
||||
*/
|
||||
bool
|
||||
RecoverySubtransInitialized(void)
|
||||
{
|
||||
bool result;
|
||||
|
||||
SpinLockAcquire(&XLogRecoveryCtl->info_lck);
|
||||
result = XLogRecoveryCtl->SharedRecoverySubtransInitialized;
|
||||
SpinLockRelease(&XLogRecoveryCtl->info_lck);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remember that hot standby initialization has started pg_subtrans.
|
||||
*/
|
||||
void
|
||||
SetRecoverySubtransInitialized(void)
|
||||
{
|
||||
SpinLockAcquire(&XLogRecoveryCtl->info_lck);
|
||||
XLogRecoveryCtl->SharedRecoverySubtransInitialized = true;
|
||||
SpinLockRelease(&XLogRecoveryCtl->info_lck);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wake up startup process to replay newly arrived WAL, or to notice that
|
||||
* failover has been requested.
|
||||
|
||||
@@ -146,6 +146,8 @@ extern XLogRecPtr GetCurrentReplayRecPtr(TimeLineID *replayEndTLI);
|
||||
|
||||
extern bool PromoteIsTriggered(void);
|
||||
extern bool CheckPromoteSignal(void);
|
||||
extern bool RecoverySubtransInitialized(void);
|
||||
extern void SetRecoverySubtransInitialized(void);
|
||||
extern void WakeupRecovery(void);
|
||||
|
||||
extern void StartupRequestWalReceiverRestart(void);
|
||||
|
||||
Reference in New Issue
Block a user