千家信息网

PostgreSQL状态变迁

发表于:2024-11-16 作者:千家信息网编辑
千家信息网最后更新 2024年11月16日,typedef enum DBState{ DB_STARTUP = 0, DB_SHUTDOWNED, DB_SHUTDOWNED_IN_RECOVERY,
千家信息网最后更新 2024年11月16日PostgreSQL状态变迁
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


0