接前文 初步学习pg_control文件之四,继续看何时出现 DB_IN_CRASH_RECOVERY:
看下面代码就比较清楚了:如果对 InArchiveRecovery 判断值为假,而且 读取出来pg_control文件的 state不是 SHUTDOWNED状态,表明当初没有来得及把SHUTDOWNED状态写入到pg_control文件,那么就是说系统已经崩溃了。
/* * This must be called ONCE during postmaster or standalone-backend startup */ void StartupXLOG(void) { … /* * Read control file and check XLOG status looks valid. * * Note: in most control paths, *ControlFile is already valid and we need * not do ReadControlFile() here, but might as well do it to be sure. */ ReadControlFile(); … /* * Check whether we need to force recovery from WAL. If it appears to * have been a clean shutdown and we did not have a recovery.conf file, * then assume no recovery needed. */ if (XLByteLT(checkPoint.redo, RecPtr)) { if (wasShutdown) ereport(PANIC, (errmsg("invalid redo record in shutdown checkpoint"))); InRecovery = true; } else if (ControlFile->state != DB_SHUTDOWNED) InRecovery = true; else if (InArchiveRecovery) { /* force recovery due to presence of recovery.conf */ InRecovery = true; } /* 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; } … } … }
然而,还需要把整个拼图补上一块,在正常关闭的时候,是如何把SHUTDOWNED状态写入到pg_control文件中的。
注意下面出现的updateControlFile:
/* * 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) { … if (shutdown) { LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); ControlFile->state = DB_SHUTDOWNING; ControlFile->time = (pg_time_t) time(NULL); UpdateControlFile(); LWLockRelease(ControlFileLock); } … /* * 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); … }