接前文 初步学习pg_control文件之十,再看这个
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
发生了checkpoint的时候,肯定要处理的:
/* * Perform a checkpoint --- either during shutdown, or on-the-fly * * flags is a bitwise OR of the following: * CHECKPOINT_IS_SHUTDOWN: checkpoint is for database shutdown. * CHECKPOINT_END_OF_RECOVERY: checkpoint is for end of WAL recovery. * CHECKPOINT_IMMEDIATE: finish the checkpoint ASAP, * ignoring checkpoint_completion_target parameter. * CHECKPOINT_FORCE: force a checkpoint even if no XLOG activity has occured * since the last one (implied by CHECKPOINT_IS_SHUTDOWN or * CHECKPOINT_END_OF_RECOVERY). * * Note: flags contains other bits, of interest here only for logging purposes. * In particular note that this routine is synchronous and does not pay * attention to CHECKPOINT_WAIT. */ void CreateCheckPoint(int flags) { … /* * Update the control file. */ LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); if (shutdown) ControlFile->state = DB_SHUTDOWNED; ControlFile->prevCheckPoint = ControlFile->checkPoint; ControlFile->checkPoint = ProcLastRecPtr; ControlFile->checkPointCopy = checkPoint; ControlFile->time = (pg_time_t) time(NULL); /* crash recovery should always recover to the end of WAL */ MemSet(&ControlFile->minRecoveryPoint, 0, sizeof(XLogRecPtr)); UpdateControlFile(); LWLockRelease(ControlFileLock); … }
可是为何要保留这个东西呢,看下面这段代码就知道了:
/* * This must be called ONCE during postmaster or standalone-backend startup */ void StartupXLOG(void) { … if (read_backup_label(&checkPointLoc, &backupEndRequired)) { … } else { /* * Get the last valid checkpoint record. If the latest one according * to pg_control is broken, try the next-to-last one. */ checkPointLoc = ControlFile->checkPoint; RedoStartLSN = ControlFile->checkPointCopy.redo; record = ReadCheckpointRecord(checkPointLoc, 1); if (record != NULL) { ereport(DEBUG1, (errmsg("checkpoint record is at %X/%X", checkPointLoc.xlogid, checkPointLoc.xrecoff))); } else if (StandbyMode) { /* * The last valid checkpoint record required for a streaming * recovery exists in neither standby nor the primary. */ ereport(PANIC, (errmsg("could not locate a valid checkpoint record"))); } else { checkPointLoc = ControlFile->prevCheckPoint; record = ReadCheckpointRecord(checkPointLoc, 2); if (record != NULL) { ereport(LOG, (errmsg("using previous checkpoint record at %X/%X", checkPointLoc.xlogid, checkPointLoc.xrecoff))); InRecovery = true; /* force recovery even if SHUTDOWNED */ } else ereport(PANIC, (errmsg("could not locate a valid checkpoint record"))); } … } … /* REDO */ if (InRecovery) { … /* * Update pg_control to show that we are recovering and to show the * selected checkpoint as the place we are starting from. We also mark * pg_control with any minimum recovery stop point obtained from a * backup history file. */ if (InArchiveRecovery) ControlFile->state = DB_IN_ARCHIVE_RECOVERY; else { ereport(LOG, (errmsg("database system was not properly shut down; " automatic recovery in progress))); ControlFile->state = DB_IN_CRASH_RECOVERY; } ControlFile->prevCheckPoint = ControlFile->checkPoint; ControlFile->checkPoint = checkPointLoc; ControlFile->checkPointCopy = checkPoint; … } … }
就是说,如果拿不到最好的,就拿到上次的那个checkpoint1点:Get the last valid checkpoint record. If the latest one according to pg_control is broken, try the next-to-last one.
此外,我们可以看restartPoint时,也有此处理:
/* * Establish a restartpoint if possible. * * This is similar to CreateCheckPoint, but is used during WAL recovery * to establish a point from which recovery can roll forward without * replaying the entire recovery log. * * Returns true if a new restartpoint was established. We can only establish * a restartpoint if we have replayed a safe checkpoint record since last * restartpoint. */ bool CreateRestartPoint(int flags) { … /* * Update pg_control, using current time. Check that it still shows * IN_ARCHIVE_RECOVERY state and an older checkpoint, else do nothing; * this is a quick hack to make sure nothing really bad happens if somehow * we get here after the end-of-recovery checkpoint. */ LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); if (ControlFile->state == DB_IN_ARCHIVE_RECOVERY && XLByteLT(ControlFile->checkPointCopy.redo, lastCheckPoint.redo)) { ControlFile->prevCheckPoint = ControlFile->checkPoint; ControlFile->checkPoint = lastCheckPointRecPtr; ControlFile->checkPointCopy = lastCheckPoint; ControlFile->time = (pg_time_t) time(NULL); if (flags & CHECKPOINT_IS_SHUTDOWN) ControlFile->state = DB_SHUTDOWNED_IN_RECOVERY; UpdateControlFile(); } LWLockRelease(ControlFileLock); … }