diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 7cddc460eb3..312a3e3d5dc 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -455,11 +455,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; /* @@ -8553,6 +8556,7 @@ RecoveryRestartPoint(const CheckPoint *checkPoint) */ SpinLockAcquire(&xlogctl->info_lck); XLogCtl->lastCheckPointRecPtr = ReadRecPtr; + XLogCtl->lastCheckPointEndPtr = EndRecPtr; memcpy(&XLogCtl->lastCheckPoint, checkPoint, sizeof(CheckPoint)); SpinLockRelease(&xlogctl->info_lck); } @@ -8572,6 +8576,7 @@ bool CreateRestartPoint(int flags) { XLogRecPtr lastCheckPointRecPtr; + XLogRecPtr lastCheckPointEndPtr; CheckPoint lastCheckPoint; uint32 _logId; uint32 _logSeg; @@ -8589,6 +8594,7 @@ CreateRestartPoint(int flags) /* Get a local copy of the last safe checkpoint record. */ SpinLockAcquire(&xlogctl->info_lck); lastCheckPointRecPtr = xlogctl->lastCheckPointRecPtr; + lastCheckPointEndPtr = xlogctl->lastCheckPointEndPtr; memcpy(&lastCheckPoint, &XLogCtl->lastCheckPoint, sizeof(CheckPoint)); SpinLockRelease(&xlogctl->info_lck); @@ -8688,6 +8694,25 @@ 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 (XLByteLT(ControlFile->minRecoveryPoint, lastCheckPointEndPtr)) + { + ControlFile->minRecoveryPoint = lastCheckPointEndPtr; + + /* update local copy */ + minRecoveryPoint = ControlFile->minRecoveryPoint; + } if (flags & CHECKPOINT_IS_SHUTDOWN) ControlFile->state = DB_SHUTDOWNED_IN_RECOVERY; UpdateControlFile();