typedef enum DBState
{
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){
| ...
| }...
| else if (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;
else
ControlFile->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;
}
else
ckpt_performed = CreateRestartPoint(flags);
}
}
备机上做checkpoint调用CreateRestartPoint,主机做checkpoint调用CreateCheckPoint
CreateCheckPoint(int flags)->
if (flags & (CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_END_OF_RECOVERY))
shutdown = true;
else
shutdown = 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(int flags)->
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);
return false;
}
...
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);
return false;
}
...
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
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。