共计 1789 个字符,预计需要花费 5 分钟才能阅读完成。
PostgreSQL 在 shutdown 时会进行 checkpoint。其流程如下。
1、在主进程中,会首先注册一个信号处理函数 reaper,用于向 checkpoint 等子进程发送信号。向 checkpoint 进程发送 SIGUSR2 信号
PostmasterMain(int argc, char argv[])
pqsignal_no_restart(SIGCHLD, reaper); / handle child termination */
reaper:
while ((pid = waitpid(-1, &exitstatus, WNOHANG)) > 0){
…
if (pid == CheckpointerPID){
…
SignalChildren(SIGUSR2);
}
…
}
…
PostmasterStateMachine();// 向 checkpoint 进程发送 SIGUSR2 信号
|———————–
| if (pmState == PM_WAIT_BACKENDS){
| if (CountChildren(BACKEND_TYPE_NORMAL | BACKEND_TYPE_WORKER) == 0 &&
| StartupPID == 0 &&
| WalReceiverPID == 0 &&
| BgWriterPID == 0 &&
| (CheckpointerPID == 0 ||(!FatalError && Shutdown < ImmediateShutdown)) &&
| WalWriterPID == 0 &&
| AutoVacPID == 0){
| //pg_ctl stop -m immediate 不会向 checkpoint 进程发送信号,即不会做 checkpoint
| if (Shutdown >= ImmediateShutdown || FatalError){
| pmState = PM_WAIT_DEAD_END;
| }else{
| if (CheckpointerPID != 0){
| signal_child(CheckpointerPID, SIGUSR2);
| pmState = PM_SHUTDOWN;
| }
}
| }
|——-}
2、checkpoint 进程,也会注册一个信号处理函数 ReqShutdownHandler,用于处理主进程发送过来的 SIGUSR2 信号。接收到该信号后将 shutdown_requested 置为 TRUE。在 checkpoint 进程的 for 循环中,如果 shutdown_requested 为 TRUE,则进入 shutdown 流程:stop 每个 sender 进程,所有 sender 进程 stop 后,根据条件进行 checkpoint:CreateRestartPoint 后者 CreateCheckPoint
CheckpointerMain(void)->
// 为信号 SIGUSR2 安装信号处理函数 ReqShutdownHandler
pqsignal(SIGUSR2, ReqShutdownHandler); / request shutdown /
…
for (;;){
if (shutdown_requested){
/ Close down the database /
ShutdownXLOG(0, 0);
|– WalSndInitStopping();// 向每个 sender 进程发送信号修改到 stopping 状态
| WalSndWaitStopping();
| if (RecoveryInProgress())
| CreateRestartPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE);
| else{
| if (XLogArchivingActive() && XLogArchiveCommandSet())
| RequestXLogSwitch(false);
| CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE);
| }
|– …
proc_exit(0);
}
…
checkpoint
}
3、ReqShutdownHandler 函数将 shutdown_requested 置为 TRUE
ReqShutdownHandler(SIGNAL_ARGS)
{
shutdown_requested = true;
SetLatch(MyLatch);
}
: