diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 63154a1675..720edf75d0 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -610,11 +610,14 @@ typedef struct XLogCtlData /* * During recovery, we keep a copy of the latest checkpoint record here. - * Used by the background writer when it wants to create a restartpoint. + * lastCheckPointRecPtr points to start of checkpoint record and + * lastCheckPointEndPtr points to end+1 of checkpoint record. Used by the + * background writer when it wants to create a restartpoint. * * Protected by info_lck. */ XLogRecPtr lastCheckPointRecPtr; + XLogRecPtr lastCheckPointEndPtr; CheckPoint lastCheckPoint; /* @@ -8644,6 +8647,7 @@ RecoveryRestartPoint(const CheckPoint *checkPoint) */ SpinLockAcquire(&XLogCtl->info_lck); XLogCtl->lastCheckPointRecPtr = ReadRecPtr; + XLogCtl->lastCheckPointEndPtr = EndRecPtr; XLogCtl->lastCheckPoint = *checkPoint; SpinLockRelease(&XLogCtl->info_lck); } @@ -8663,6 +8667,7 @@ bool CreateRestartPoint(int flags) { XLogRecPtr lastCheckPointRecPtr; + XLogRecPtr lastCheckPointEndPtr; CheckPoint lastCheckPoint; XLogRecPtr PriorRedoPtr; TimestampTz xtime; @@ -8676,6 +8681,7 @@ CreateRestartPoint(int flags) /* Get a local copy of the last safe checkpoint record. */ SpinLockAcquire(&XLogCtl->info_lck); lastCheckPointRecPtr = XLogCtl->lastCheckPointRecPtr; + lastCheckPointEndPtr = XLogCtl->lastCheckPointEndPtr; lastCheckPoint = XLogCtl->lastCheckPoint; SpinLockRelease(&XLogCtl->info_lck); @@ -8779,6 +8785,27 @@ CreateRestartPoint(int flags) ControlFile->checkPoint = lastCheckPointRecPtr; ControlFile->checkPointCopy = lastCheckPoint; ControlFile->time = (pg_time_t) time(NULL); + + /* + * Ensure minRecoveryPoint is past the checkpoint record. Normally, + * this will have happened already while writing out dirty buffers, + * but not necessarily - e.g. because no buffers were dirtied. We do + * this because a non-exclusive base backup uses minRecoveryPoint to + * determine which WAL files must be included in the backup, and the + * file (or files) containing the checkpoint record must be included, + * at a minimum. Note that for an ordinary restart of recovery there's + * no value in having the minimum recovery point any earlier than this + * anyway, because redo will begin just after the checkpoint record. + */ + if (ControlFile->minRecoveryPoint < lastCheckPointEndPtr) + { + ControlFile->minRecoveryPoint = lastCheckPointEndPtr; + ControlFile->minRecoveryPointTLI = lastCheckPoint.ThisTimeLineID; + + /* update local copy */ + minRecoveryPoint = ControlFile->minRecoveryPoint; + minRecoveryPointTLI = ControlFile->minRecoveryPointTLI; + } if (flags & CHECKPOINT_IS_SHUTDOWN) ControlFile->state = DB_SHUTDOWNED_IN_RECOVERY; UpdateControlFile();