typedefenumDBState{DB_STARTUP=0,DB_SHUTDOWNED,DB_SHUTDOWNED_IN_RECOVERY,DB_SHUTDOWNING,DB_IN_CRASH_RECOVERY,DB_IN_ARCHIVE_RECOVERY,DB_IN_PRODUCTION}DBState;

PostgreSQL启动以及关闭或运行过程中的状态包括以上七种。在pg_controldata获取的内容Database cluster state一栏显示的是DB的状态。其中:

DB_STARTUP:表示数据库正在启动状态,实际上没有使用该状态。

DB_SHUTDOWNED:数据库实例正常关闭(非standby)控制文件写入的状态就是这个状态

DB_SHUTDOWNED_IN_RECOVERY:standby实例正常关闭,控制文件写入的状态是这个状态。是由CreateRestartPoint修改该状态。

DB_SHUTDOWNING:非standby实例在关闭时,做checkpoint:CreateCheckPoint,开始做时修改为该状态,做完后修改为DB_SHUTDOWNED状态。

DB_IN_CRASH_RECOVERY:实例异常关闭,重启后,恢复时需要将实例先置为该状态

DB_IN_ARCHIVE_RECOVERY:standby实例重启后置为该状态。

DB_IN_PRODUCTION:非standby实例正常重启后就是这个状态,standby是DB_IN_ARCHIVE_RECOVERY

分析

1、DB_STARTUP

initdb->BootStrapXLOG:memset(ControlFile,0,sizeof(ControlFileData));...ControlFile->state=DB_SHUTDOWNED;...WriteControlFile();

初始化时,首先将其状态初始化为DB_STARTUP,然后立即置成DB_SHUTDOWNED并将其刷写到磁盘。

2、StartupXLOG

StartupXLOG->ReadControlFile();...readRecoveryCommandFile();->|--...|for(item=head;item;item=item->next){|if(strcmp(item->name,"restore_command")==0){|...|}...|elseif(strcmp(item->name,"standby_mode")==0){|if(!parse_bool(item->value,&StandbyModeRequested))|}...|}|...|--ArchiveRecoveryRequested=true;...if(ArchiveRecoveryRequested&&(ControlFile->minRecoveryPoint!=InvalidXLogRecPtr||ControlFile->backupEndRequired||ControlFile->backupEndPoint!=InvalidXLogRecPtr||ControlFile->state==DB_SHUTDOWNED)){InArchiveRecovery=true;if(StandbyModeRequested)StandbyMode=true;}...record=ReadCheckpointRecord(xlogreader,checkPointLoc,1,true);...if(InRecovery){if(InArchiveRecovery)//何时?ControlFile->state=DB_IN_ARCHIVE_RECOVERY;elseControlFile->state=DB_IN_CRASH_RECOVERY;...UpdateControlFile();replay...}...LWLockAcquire(ControlFileLock,LW_EXCLUSIVE);ControlFile->state=DB_IN_PRODUCTION;UpdateControlFile();LWLockRelease(ControlFileLock);...

只要有recovery.conf文件,ArchiveRecoveryRequested即为TRUE->InArchiveRecovery = true,配置了standby_mode=on,那么StandbyMode=TRUE。这样standby启动后,ControlFile->state为DB_IN_ARCHIVE_RECOVERY状态。

3、checkpoint

CheckpointerMain->for(;;){...if(shutdown_requested){ShutdownXLOG(0,0);->|--if(RecoveryInProgress()){|CreateRestartPoint(CHECKPOINT_IS_SHUTDOWN|CHECKPOINT_IMMEDIATE);|}else{|CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN|CHECKPOINT_IMMEDIATE);|}|--...proc_exit(0);}...if(do_checkpoint){do_restartpoint=RecoveryInProgress();...if(flags&CHECKPOINT_END_OF_RECOVERY)//flags从哪来?do_restartpoint=false;...if(!do_restartpoint){CreateCheckPoint(flags);ckpt_performed=true;}elseckpt_performed=CreateRestartPoint(flags);}}

备机上做checkpoint调用CreateRestartPoint,主机做checkpoint调用CreateCheckPoint

CreateCheckPoint(intflags)->if(flags&(CHECKPOINT_IS_SHUTDOWN|CHECKPOINT_END_OF_RECOVERY))shutdown=true;elseshutdown=false;...if(shutdown){LWLockAcquire(ControlFileLock,LW_EXCLUSIVE);ControlFile->state=DB_SHUTDOWNING;ControlFile->time=(pg_time_t)time(NULL);UpdateControlFile();LWLockRelease(ControlFileLock);}...LWLockAcquire(ControlFileLock,LW_EXCLUSIVE);if(shutdown)ControlFile->state=DB_SHUTDOWNED;...UpdateControlFile();LWLockRelease(ControlFileLock);

shutdown时,先将状态置为DB_SHUTDOWNING,最后将状态置为DB_SHUTDOWNED

CreateRestartPoint(intflags)->LWLockAcquire(CheckpointLock,LW_EXCLUSIVE);SpinLockAcquire(&XLogCtl->info_lck);lastCheckPointRecPtr=XLogCtl->lastCheckPointRecPtr;lastCheckPointEndPtr=XLogCtl->lastCheckPointEndPtr;lastCheckPoint=XLogCtl->lastCheckPoint;SpinLockRelease(&XLogCtl->info_lck);if(!RecoveryInProgress()){LWLockRelease(CheckpointLock);returnfalse;}...if(XLogRecPtrIsInvalid(lastCheckPointRecPtr)||lastCheckPoint.redo<=ControlFile->checkPointCopy.redo){UpdateMinRecoveryPoint(InvalidXLogRecPtr,true);if(flags&CHECKPOINT_IS_SHUTDOWN){LWLockAcquire(ControlFileLock,LW_EXCLUSIVE);ControlFile->state=DB_SHUTDOWNED_IN_RECOVERY;ControlFile->time=(pg_time_t)time(NULL);UpdateControlFile();LWLockRelease(ControlFileLock);}LWLockRelease(CheckpointLock);returnfalse;}...LWLockAcquire(ControlFileLock,LW_EXCLUSIVE);if(ControlFile->state==DB_IN_ARCHIVE_RECOVERY&&ControlFile->checkPointCopy.redo<lastCheckPoint.redo){...if(flags&CHECKPOINT_IS_SHUTDOWN)ControlFile->state=DB_SHUTDOWNED_IN_RECOVERY;UpdateControlFile();}LWLockRelease(ControlFileLock);...

备机shutdown,将状态置为DB_SHUTDOWNED_IN_RECOVERY