2.4.4 注册信号处理函数
信号是操作系统响应某些错误状况而产生的事件,它可以明确地由一个进程发给另外一个进程,用这种办法传递信息或协调操作行为。进程可以自定义信号处理函数来处理信号,PostgreSQL系统充分利用了这一点。
首先要声明的是进程有权选择响应或屏蔽信号(SIGKILL和SIGSTOP不能屏蔽)。为了方便起见,Postmaster定义了三个信号集:BlockSig是要屏蔽的信号集;UnBlockSig是不希望屏蔽的信号集;AuthBlockSig是在进行用户连接认证时需要屏蔽的信号集,它们都是位向量。
在设置响应信号的处理函数之前,要通过PG_SETMASK函数把这些信号全部屏蔽,然后通过pqsignal函数为感兴趣的信号设置处理函数,例如pqsignal(SIGHUP,SIGHUP_handler)注册了SIGHUP信号的处理函数SIGHUP_handler。下面分析几个主要的信号处理函数的功能。
1.信号处理函数SIGHUP_handler
当配置文件发生改变时产生SIGHUP信号。Postmaster进程在收到SIGHUP信号时重读配置文件postgresql.conf(注意这是在PGC_SIGHUP环境下),然后向子进程发同样的信号(Postmaster维护着一个子进程队列BackendList,以方便向子进程发消息),并重新装载pg_hba.conf和pg_ident.conf文件(这两个文件主要用来进行客户端认证)。
2.信号处理函数pmdie
pmdie处理三种信号:SIGTERM、SIGINT和SIGQUIT。这三种信号分别对应三种不同的系统关闭方式:
Smart Shutdown:Postmaster将等待所有子进程完成当前的任务后再安全关闭系统,对应于SIGTERM信号。
Fast Shutdown:Postmaster将向所有子进程发出SIGTERM信号,等待子进程接收到这个信号回滚当前事务并退出后再安全关闭系统,对应于SIGINT信号。
Immediate Shutdown:Postmaster将向所有子进程发SIGQUIT信号,子进程接收到这个信号马上退出,同时系统非正常关闭,对应于SIGQUIT信号。
全局变量Shutdown用于表示当前系统所处的关闭状态,可以有三种状态:NoShutdown、SmartShutdown和FastShutdown。三种状态值分别对应整数0、1、2。
(1)SIGTERM信号处理
若系统已经处于SmartShutdown或FastShutdown(之前已经收到了SIGTERM信号),说明Postmaster已经在准备关闭系统了,此时不予处理,直接退出信号处理函数。否则将Shutdown置为SmartShutdown状态,表示正以这种方式关闭系统。如果系统当前正处于正常运行、归档恢复模式或者一致恢复模式,需要分别向自动清理相关的子进程以及WalWriter子进程发送SIGTERM信号,并且将系统状态置为等待在线备份结束。然后调用函数PostmasterStateMachine来根据当前状态机的状态来等待在线备份结束以及子进程退出。
(2)SIGINT信号处理
若系统已经处于FastShutdown说明已经在准备关闭系统,直接退出信号处理函数。否则首先将Shutdown设为FastShutdown。如果系统当前正处于归档恢复模式,则说明当前只有BgWriter是活动的,将当前状态设置为等待后台进程退出;如果处于正常运行、等待在线备份结束、等待后台进程结束或者一致恢复模式,则以发送SIGTERM信号的方式关闭所有的后台进程。最后仍然是调用函数PostmasterStateMachine来根据当前状态机的状态来等待在线备份结束以及子进程退出。
(3)SIGQUIT信号处理
这是极其暴力的做法,Postmaster将给PostgreSQL系统中所有的活动进程发信号SIGQUIT,然后自己也退出。当收到SIGQUIT信号时,首先通过SignalChildren函数向BackendList中的所有进程发送SIGQUIT信号,然后依次检查BgWriter、WalWriter、AutoVacuum、PgArch、PgStat等辅助进程的存在状态,如果辅助进程存在,则调用signal_child函数向它们发送SIGQUIT信号。完成向各子进程发送信号的工作后,Postmaster调用ExitPostmaster函数退出。
3.信号处理函数reaper
当系统中有子进程退出的时候,子进程就会给Postmaster发送一个SIGCHLD信号。Postmaster收到SIGCHLD信号后调用reaper函数清理退出的子进程。
若这个退出的子进程是启动系统的子进程且属于异常退出,那么调用ExitPostmaster退出;否则先将StartupPID置为0(标志启动结束)、FatalError置为false(标志系统已恢复),然后重新装载权限检测所需要的文件。最后检查其他后台辅助进程是否存在,如果不存在还需要启动它们。
如果是BgWriter进程退出,首先将BgWriterPID置为0。检查全局变量pmState是否为PM_SHUTDOWN(表明系统状态是等待BgWriter做一个关闭检查点),是则向PgStat发送SIGUSER2信号要求它进行最后一次归档并退出,接着关闭PgStat进程;否则认为BgWriter是意外退出,调用HandleChildCrash来处理子进程崩溃(设置BgWriterPID为0等工作)。
如果是WalWriter或者AutoVacuum进程退出,这里将会忽略正常退出的情况(因为这两个进程会周期性地启动,执行完工作后又正常退出,且正常退出时会主动完成必要的清理),如果是意外退出则同样调用HandleChildCrash来进行崩溃处理。
如果是PgArch进程异常退出,系统正处于PM_RUN(系统正常运行)状态且允许进行归档,则调用pgarch_start函数重新启动PgArch进程。否则将pmStat改为PM_WAIT_DEAD_END表示正在等待“死亡”的子进程退出。
若是PgStat进程异常退出,且pmStat处于PM_RUN的状态,则调用pgstat_start函数重新启动PgStat进程。
如果是SysLogger进程意外退出,则调用SysLogger_Start函数重启SysLogger。
【责任编辑:云霞 TEL:(010)68476606】