这个枚举类型标注的是数据库当前的状态。其中PM_RUN是一个分水岭。从PM_INIT到PM_RUN,数据库逐渐从初始化状态转换为正常的运行状态。而从PM_RUN到PM_NO_CHILDREN,数据库逐渐由正常运行状态转换到可以关闭的状态。理解了这个有助于我们理解数据库的启动和关闭的时序。上面每个状态后面的注释已经能很好地解释每个状态间的转换条件了,我这里不赘述了。
对于pg_ctl的stop参数,我们有三种模式:
模式 发送的singal singal的处理smart SIGTERM Wait for children to end their work, then shut down
fast SIGINT Abort all children with SIGTERM (rollback active transactions and exit) and shut down when they are gone
immediate SIGQUIT abort all children with SIGQUIT, wait for them to exit, terminate remaining ones with SIGKILL, then exit without attempt to properly shut down the database system.
这里我们就先以smart模式展开讨论,其他的模式其实也是类似的。
首先执行"pg_ctl stop -m smart",这个时候其实就是向postmaster发送了一个SIGTERM信号;
postmaster收到SIGTERM信号,触发pqsignal(SIGTERM, pmdie),调用pmdie()函数去处理SIGTERM信号;
pmdie |->SignalSomeChildren(SIGTERM,BACKEND_TYPE_AUTOVAC | BACKEND_TYPE_BGWORKER) 向autovacuum和bgworker子进程转发SIGTERM信号 |->PostmasterStateMachine() 更新数据库的状态PM_Statepmdie中的处理如上所示。pmdie调用SignalSomeChildren()向指定的进程发送SIGTERM信号,同样这些进程本身也有信号处理函数,在接收到postmaster的SIGTERM信号进行相关处理并终止。(子进程终止后会向父进程发送一个SIGCHLD信号,这是操作系统的固有处理)。PostmasterStateMachine()是一个工具函数,在postmaster很多的信号处理函数中都会调用该函数来根据数据库当前的PM_State和相关进程的死活来更新PM_State。
这个时候我们看backend进程:
backend:pqsignal(SIGTERM, die); //diebackend进程本身的信号处理函数在收到SIGTERM信号后调用die函数进程exit处理。
话题再回到postmaster,当它收到子进程的SIGCHLD信号时,触发pqsignal(SIGCHLD, reaper),会调用reaper()函数处理子进程发来的SIGCHLD信号:
reaper() |->switch(PID) 根据PID类型判断子进程类型,分别进行处理 |->PostmasterStateMachine() 更新数据库的状态PM_State这样postmaster会一直收到子进程的SIGCHLD信号,并进行相应处理后更新PM_State。
那什么时候确定所有的子进程都结束了呢?还是看PostmasterStateMachine()函数:
PostmasterStateMachine() 当最后一个backend(dead_end)结束时,reaper处理子进程通过调用PostmasterStateMachine更新当前状态, 将当前状态由PM_WAIT_DEAD_END转换为PM_NO_CHILDREN时: PM_WAIT_DEAD_END -> pmState = PM_NO_CHILDREN 说明说有子进程都已退出,postmaster调用ExitPostmaster结束自身: ExitPostmaster()本节讨论就是这样,下次准备讨论:
后端process的管理 DB的shoutdown的处理 backend异常结束时的处理 BootstrapMain()的处理先把flag立下来,免得自己忘了。欢迎大家点赞~