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;

PostgreSQL includes the above seven statuses during startup, shutdown or operation. In the column of Database cluster state obtained from PG ﹣ controldata, the status of DB is displayed. Among them:

DB? Startup: indicates that the database is in the startup state, which is not actually used.

DB? Shutdown: This is the status of normal shutdown (non standby) control file writing of database instance

DB? Shutdown? In? Recovery: the standby instance is closed normally, and the state of control file writing is this state. The state is modified by CreateRestartPoint.

DB ABCD shutdown: when a non standby instance is closed, do checkpoint: CreateCheckPoint. When it is started, change it to this state. When it is finished, change it to DB ABCD shutdown state.

DB in crash recovery: the instance is shut down abnormally. After restart, you need to set the instance to this state before recovery

DB in archive recovery: set to this state after the standby instance is restarted.

DB in product: This is the status after a normal restart of a non standby instance. Standby is dB in archive recovery

Analysis

1,DB_STARTUP

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

During initialization, first initialize its status to DB startup, then immediately set it to DB shutdown 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. If standby mode = on is configured, StandbyMode=TRUE. After the standby is started, the controlfile - > state is 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();
			...
			if (flags & CHECKPOINT_END_OF_RECOVERY)//Where do flags come from?
				do_restartpoint = false;
			...
			if (!do_restartpoint){
				CreateCheckPoint(flags);
				ckpt_performed = true;
			}
			else
				ckpt_performed = CreateRestartPoint(flags);
		}
	}

The standby machine makes checkpoint call CreateRestartPoint, and the host machine makes checkpoint 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 shutting down, first set the status to DB? shutdown, and finally set the status to DB? shutdown

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);
	...

Standby shutdown, set the status to DB "shutdown" in "recovery

Tags: Database PostgreSQL

Posted on Sun, 05 Jan 2020 21:52:51 -0800 by strangesoul