PostgreSQL state transition
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
The states of PostgreSQL during startup and shutdown or operation include the above seven. The Database cluster state column of the content obtained by pg_controldata shows the status of DB. Where:
DB_STARTUP: indicates that the database is in a startup state, which is not actually used.
DB_SHUTDOWNED: this is the state in which the database instance shuts down normally (non-standby) controls the writing of files
The DB_SHUTDOWNED_IN_RECOVERY:standby instance shuts down normally, which is the state in which the control file is written. The state is modified by CreateRestartPoint.
DB_SHUTDOWNING: when a non-standby instance is closed, do checkpoint:CreateCheckPoint, change it to this state at the beginning, and change it to DB_SHUTDOWNED status after completion.
DB_IN_CRASH_RECOVERY: the instance is shut down abnormally. After restarting, you need to set the instance to this state when resuming.
Set the DB_IN_ARCHIVE_RECOVERY:standby instance to this state after restarting.
DB_IN_PRODUCTION: this is what happens when a non-standby instance is restarted normally. Standby is DB_IN_ARCHIVE_RECOVERY.
Analysis.
1 、 DB_STARTUP
Initdb- > BootStrapXLOG: memset (ControlFile, 0, sizeof (ControlFileData)); ControlFile- > state = DB_SHUTDOWNED;... WriteControlFile ()
When initializing, first initialize its state to DB_STARTUP, then immediately set it to DB_SHUTDOWNED and write it to disk.
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) / / when? 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);
As long as there is a recovery.conf file, ArchiveRecoveryRequested is TRUE- > InArchiveRecovery = true, and standby_mode=on is configured, then StandbyMode=TRUE. So after standby starts, ControlFile- > state is in the DB_IN_ARCHIVE_RECOVERY state.
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 ();... Where does if (flags & CHECKPOINT_END_OF_RECOVERY) / / flags come from? Do_restartpoint = false;... If (! do_restartpoint) {CreateCheckPoint (flags); ckpt_performed = true;} else ckpt_performed = CreateRestartPoint (flags);}}
Do checkpoint on standby to call CreateRestartPoint, and host do checkpoint to call 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)
When shutdown, first set the status to DB_SHUTDOWNING, and finally set the status to 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 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);...
Standby shutdown, set the status to DB_SHUTDOWNED_IN_RECOVERY