* ControlFileLock: must be held to read/update control file or create
* new log file.
*
- * CheckpointLock: must be held to do a checkpoint (ensures only one
- * checkpointer at a time; currently, with all checkpoints done by the
- * bgwriter, this is just pro forma).
+ * CheckpointLock: must be held to do a checkpoint or restartpoint (ensures
+ * only one checkpointer at a time)
*
*----------
*/
*/
if (shutdown_requested && InRedo)
{
- /* XXX: Is EndRecPtr always the right value? */
+ /* XXX: Is EndRecPtr always the right value here? */
UpdateMinRecoveryPoint(EndRecPtr);
proc_exit(0);
}
CheckPoint checkPoint;
bool wasShutdown;
bool reachedStopPoint = false;
- bool reachedMinRecoveryPoint = false;
bool haveBackupLabel = false;
XLogRecPtr RecPtr,
LastRec,
{
bool recoveryContinue = true;
bool recoveryApply = true;
+ bool reachedMinRecoveryPoint = false;
ErrorContextCallback errcontext;
/* use volatile pointer to prevent code rearrangement */
volatile XLogCtlData *xlogctl = XLogCtl;
/* there are no WAL records following the checkpoint */
ereport(LOG,
(errmsg("redo is not required")));
- reachedMinRecoveryPoint = true;
}
}
*/
PreallocXlogFiles(EndOfLog);
+ /*
+ * Okay, we're officially UP.
+ */
InRecovery = false;
LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
* for the main message, but what about all the flags?
*/
if (restartpoint)
- msg = "restartpoint starting:%s%s%s%s%s%s%s";
+ msg = "restartpoint starting:%s%s%s%s%s%s";
else
- msg = "checkpoint starting:%s%s%s%s%s%s%s";
+ msg = "checkpoint starting:%s%s%s%s%s%s";
elog(LOG, msg,
(flags & CHECKPOINT_IS_SHUTDOWN) ? " shutdown" : "",
/*
* Acquire CheckpointLock to ensure only one checkpoint happens at a time.
- * (This is just pro forma, since in the present system structure there is
- * only one process that is allowed to issue checkpoints at any given
- * time.)
*/
LWLockAcquire(CheckpointLock, LW_EXCLUSIVE);
XLByteToSeg(ControlFile->checkPointCopy.redo, _logId, _logSeg);
/*
- * Update the control file. This also sets state to IN_DB_PRODUCTION
- * if this is the first checkpoint after recovery.
+ * Update the control file.
*/
LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
+ if (shutdown)
+ ControlFile->state = DB_SHUTDOWNED;
ControlFile->prevCheckPoint = ControlFile->checkPoint;
ControlFile->checkPoint = ProcLastRecPtr;
ControlFile->checkPointCopy = checkPoint;
* 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).
+ * in subtrans.c). During recovery, though, we mustn't do this because
+ * StartupSUBTRANS hasn't been called yet.
*/
- TruncateSUBTRANS(GetOldestXmin(true, false));
+ if (!InRecovery)
+ TruncateSUBTRANS(GetOldestXmin(true, false));
/* All real work is done, but log before releasing lock. */
if (log_checkpoints)
volatile XLogCtlData *xlogctl = XLogCtl;
/*
- * Acquire CheckpointLock to ensure only one restartpoint happens at a
- * time. (This is just pro forma, since in the present system structure
- * there is only one process that is allowed to issue checkpoints or
- * restart points at any given time.)
+ * Acquire CheckpointLock to ensure only one restartpoint or checkpoint
+ * happens at a time.
*/
LWLockAcquire(CheckpointLock, LW_EXCLUSIVE);
ControlFile->checkPointCopy.nextXid = checkPoint.nextXid;
/*
- * TLI no longer changes at shutdown checkpoint, since as of 8.4,
+ * TLI may change in a shutdown checkpoint, but it shouldn't decrease
* shutdown checkpoints only occur at shutdown. Much less confusing.
*/
+ if (checkPoint.ThisTimeLineID != ThisTimeLineID)
+ {
+ if (checkPoint.ThisTimeLineID < ThisTimeLineID ||
+ !list_member_int(expectedTLIs,
+ (int) checkPoint.ThisTimeLineID))
+ ereport(PANIC,
+ (errmsg("unexpected timeline ID %u (after %u) in checkpoint record",
+ checkPoint.ThisTimeLineID, ThisTimeLineID)));
+ /* Following WAL records should be run with new TLI */
+ ThisTimeLineID = checkPoint.ThisTimeLineID;
+ }
RecoveryRestartPoint(&checkPoint);
}
ControlFile->checkPointCopy.nextXidEpoch = checkPoint.nextXidEpoch;
ControlFile->checkPointCopy.nextXid = checkPoint.nextXid;
- /* TLI must not change at a checkpoint */
+ /* TLI should not change in an on-line checkpoint */
if (checkPoint.ThisTimeLineID != ThisTimeLineID)
ereport(PANIC,
(errmsg("unexpected timeline ID %u (should be %u) in checkpoint record",
sigjmp_buf local_sigjmp_buf;
MemoryContext bgwriter_context;
bool BgWriterRecoveryMode = true;
- /* use volatile pointer to prevent code rearrangement */
- volatile BgWriterShmemStruct *bgs = BgWriterShmem;
BgWriterShmem->bgwriter_pid = MyProcPid;
am_bg_writer = true;
*/
PG_SETMASK(&UnBlockSig);
- /*
- * If someone requested a checkpoint before we started up, process that.
- *
- * This check exists primarily for crash recovery: after the startup
- * process is finished with WAL replay, it will request a checkpoint, but
- * the background writer might not have started yet. This check will
- * actually not notice a checkpoint that's been requested without any
- * flags, but it's good enough for the startup checkpoint.
- */
- SpinLockAcquire(&bgs->ckpt_lck);
- if (bgs->ckpt_flags)
- checkpoint_requested = true;
- SpinLockRelease(&bgs->ckpt_lck);
-
/*
* Loop forever
*/
ExitOnAnyError = true;
/* Close down the database */
ShutdownXLOG(0, 0);
-
/* Normal exit from the bgwriter is here */
proc_exit(0); /* done */
}
* Check if we've exited recovery. We do this after determining
* whether to perform a checkpoint or not, to be sure that we
* perform a real checkpoint and not a restartpoint, if someone
- * (like the startup process!) requested a checkpoint immediately
- * after exiting recovery. And we must have the right TimeLineID
- * when we perform a checkpoint.
+ * requested a checkpoint immediately after exiting recovery. And
+ * we must have the right TimeLineID when we perform a checkpoint;
+ * IsRecoveryProcessingMode() initializes that as a side-effect.
*/
if (BgWriterRecoveryMode && !IsRecoveryProcessingMode())
{
*/
if (do_checkpoint)
{
+ /* use volatile pointer to prevent code rearrangement */
+ volatile BgWriterShmemStruct *bgs = BgWriterShmem;
+
/*
* Atomically fetch the request flags to figure out what kind of a
* checkpoint we should perform, and increase the started-counter