lightdbpg_reload_guc__0">lightdb/pg reload guc 参数机制
本文主要讲述调用pg_reload_conf 后,到guc被真正修改之间发送的故事。(基于pg13)
pg_reload_conf 函数实现如下:
Datum
pg_reload_conf(PG_FUNCTION_ARGS)
{
if (kill(PostmasterPid, SIGHUP))
{
ereport(WARNING,
(errmsg("failed to send signal to postmaster: %m")));
PG_RETURN_BOOL(false);
}
PG_RETURN_BOOL(true);
}
pg_reload_conf 会发送SIGHUP到postmaster 进程。而postmaster 进程中 SIGHUP 信号的处理函数为 SIGHUP_handler( pqsignal_pm(SIGHUP, SIGHUP_handler);
),其实现主要如下:
ProcessConfigFile(PGC_SIGHUP); //reload conf
SignalChildren(SIGHUP); // 给其他子进程发送 SIGHUP 信号
// 给其他后台进程发送SIGHUP
if (StartupPID != 0)
signal_child(StartupPID, SIGHUP);
if (BgWriterPID != 0)
signal_child(BgWriterPID, SIGHUP);
if (CheckpointerPID != 0)
signal_child(CheckpointerPID, SIGHUP);
if (WalWriterPID != 0)
signal_child(WalWriterPID, SIGHUP);
if (WalReceiverPID != 0)
signal_child(WalReceiverPID, SIGHUP);
if (AutoVacPID != 0)
signal_child(AutoVacPID, SIGHUP);
if (PgArchPID != 0)
signal_child(PgArchPID, SIGHUP);
if (SysLoggerPID != 0)
signal_child(SysLoggerPID, SIGHUP);
if (PgStatPID != 0)
signal_child(PgStatPID, SIGHUP);
/* Reload authentication config files too */
if (!load_hba())
ereport(LOG,
/* translator: %s is a configuration file */
(errmsg("%s was not reloaded", "lt_hba.conf")));
if (!load_ident())
ereport(LOG,
(errmsg("%s was not reloaded", "lt_ident.conf")));
主要流程是先在本进程reload conf(ProcessConfigFile), 然后给其他子进程发送 SIGHUP 信号。
下面讲一下 postgres (客户端连接进程)收到 SIGHUP 的处理
PostgresMain postgres main loop – all backends, interactive or otherwise start here
postgres 为 SIGHUP 注册的处理函数为 SignalHandlerForConfigReload (pqsignal(SIGHUP, SignalHandlerForConfigReload);
)。其实现如下:
void
SignalHandlerForConfigReload(SIGNAL_ARGS)
{
int save_errno = errno;
ConfigReloadPending = true;
SetLatch(MyLatch);
errno = save_errno;
}
主要为设置 ConfigReloadPending = tue
, 然后通过 SetLatch(MyLatch)
来唤醒当前进程。当前进程被唤醒后处理如下(如果当前正在执行SQL, 则会被中断来处理信号,处理完信号,继续执行SQL,执行完SQL,在需要等待下一条SQL时 会不等待而直接处理latch的唤醒):
/* Handle interrupt. */
if (event.events & WL_LATCH_SET)
{
ResetLatch(MyLatch);
ProcessClientReadInterrupt(true);
/*
* We'll retry the read. Most likely it will return immediately
* because there's still no data available, and we'll wait for the
* socket to become ready again.
*/
}
goto retry;
唤醒后会进行ResetLatch等操作,然后会尝试读取数据流, 若没有,则继续等待下一个query 的到来才会去真正的reload conf(执行query前, 先reload).,若有直接返回。
在进程被 query 唤醒后,会执行如下代码:
if (ConfigReloadPending)
{
ConfigReloadPending = false;
ProcessConfigFile(PGC_SIGHUP);
}
最终调用ProcessConfigFile执行配置文件的reload。 reload 结束后,会执行接受到的query。
这个机制可以保证,在 reload 的时候,不会执行其他命令, 可以保证执行命令过程中 guc 不会被修改。
但也会出现在执行 pg_reload_conf 函数后, guc 参数没有被及时修改的情况(从postmaster收到信号,处理reload, 发送信号给postgres 进程, 到postgres 进程被唤醒这段时间内,如果执行了SQL,GUC 参数还是原先的值。 一般情况下,时间极短)。
ProcessConfigFile 实现
ProcessConfigFile 最终调用 ProcessConfigFileInternal, 对于postmaster 进程会记录修改后的值。通过如下判断来使只有postmaster可以获取到prev_guc, 有prev_guc 才会记录日志。
if (context == PGC_SIGHUP && applySettings && !IsUnderPostmaster)