OpenGauss线程管理-数据库启动线程-Startup
术语解释
- 日志REDO(重做):让已经提交了的事务对数据库所做的修改永久生效,即使后来系统崩溃,在重启后也可以把之前的修改恢复。即在系统崩溃重启时按照记录的步骤重新更新数据页。
- 主备机:为了保证故障的可恢复,需要将数据写多份,设置主备多个副本,通过日志进行数据同步,实现节点故障、停止后重启。在主备环境下可以支持主备和一主多备两种模式。主备模式下,备机需要重做日志,可以升主;在一主多备模式下,所有的备机都需要重做日志,都可以升主。
- 备机:openGauss双机方案中的一个节点,用于作为主机的备份,在主机异常时,备机会切换到主机状态,以确保能正常提供数据服务。
- DCF:Distributed Consensus Framework,即分布式一致性共识框架。使用DCF可以提供日志复制、集群高可用(以减少服务中断时间为目的的服务器集群技术)等能力。
startup线程
Startup线程是数据库在启动时创造的第一个子线程,主要用来完成数据库的日志REDO操作,从而进行数据库的恢复。当日志REDO操作结束,数据库完成恢复后,如果不是备机,Startup线程就退出了;如果是备机,那么Startup线程一直在运行,REDO备机接收到新的日志。
数据库在启动过程初始化服务器并执行已指定的任何恢复操作。且没有“主循环”,因为启动过程在初始化完成后立即结束。
StartupProcessMain函数
路径:openGauss-server\src\gausskernel\process\postmaster\startup.cpp
主线程中的位置
startup线程在主线程中的位置是在GaussDbAuxiliaryThreadMain函数中,通过thread_role来判断是否执行startup线程
函数代码
void StartupProcessMain(void)
{
/*
* 正确接受或忽略postmaster可能发送给我们的信号。
* 注意:理想情况下,除非实际执行热备用,否则我们不会启用handle_standby_sig_alarm,
* 但我们还不知道。 依靠它不做任何不该做的事情。
*/
/*
* 重置一些被postmaster接受但未在此处接受的信号
*/
(void)gspqsignal(SIGHUP, StartupProcSigHupHandler); /* 重新加载配置文件 */
(void)gspqsignal(SIGINT, StartupProcSigIntHandler); /* 检查修复页面和文件 */
(void)gspqsignal(SIGTERM, StartupProcShutdownHandler); /* 请求关闭 */
(void)gspqsignal(SIGQUIT, startupproc_quickdie); /* 硬崩溃时间 */
if (g_instance.attr.attr_storage.EnableHotStandby)
(void)gspqsignal(SIGALRM, handle_standby_sig_alarm); /* ignored unless
* InHotStandby */
else
(void)gspqsignal(SIGALRM, SIG_IGN);
(void)gspqsignal(SIGPIPE, SIG_IGN);
(void)gspqsignal(SIGUSR1, StartupProcSigUsr1Handler);
(void)gspqsignal(SIGUSR2, StartupProcSigusr2Handler);
/*
* 重置一些被postmaster接受但未在此处接受的信号
*/
(void)gspqsignal(SIGCHLD, SIG_DFL);
(void)gspqsignal(SIGTTIN, SIG_DFL);
(void)gspqsignal(SIGTTOU, SIG_DFL);
(void)gspqsignal(SIGCONT, SIG_DFL);
(void)gspqsignal(SIGWINCH, SIG_DFL);
(void)RegisterRedoInterruptCallBack(HandleStartupProcInterrupts);
(void)RegisterRedoPageRepairCallBack(HandleStartupPageRepair);
/*
* 取消阻止信号(当postmaster创造我们时,它们被阻止)
*/
gs_signal_setmask(&t_thrd.libpq_cxt.UnBlockSig, NULL);
(void)gs_signal_unblock_sigusr2();
t_thrd.utils_cxt.CurrentResourceOwner = ResourceOwnerCreate(NULL, "StartupXLOG",
THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_STORAGE));
SetStaticConnNum();
pgstat_report_appname("Startup");
pgstat_report_activity(STATE_IDLE, NULL);
if (dummyStandbyMode) {
StartupDummyStandby();
} else {
on_shmem_exit(StartupReleaseAllLocks, 0);
#ifdef ENABLE_MOT
/*
* 初始化 MOT 第一
*/
InitMOT();
/*
* MOT恢复是StartupXlog的一部分
*/
#endif
DeleteDisConnFileInClusterStandby();
if (!dummyStandbyMode) {
Assert(g_instance.startup_cxt.badPageHashTbl == NULL);
g_instance.startup_cxt.badPageHashTbl = parallel_recovery::BadBlockHashTblCreate();
}
StartupXLOG();
}
/*
* 正常退出。退出代码 0 告诉postmaster我们已成功完成恢复。
*/
proc_exit(0);
}
startup.cpp中其他函数的简要解读
函数 | 功能 |
---|---|
static void startupproc_quickdie(SIGNAL_ARGS) | 进行信号处理程序例程 |
static void StartupProcSigUsr1Handler(SIGNAL_ARGS) | SIGUSR1:让锁存器处理信号 |
static void WaitApplyAllDCFLog(void) | 检查 walreceiver 是否已将所有 DCF 日志写入且应用 xlog |
static void StartupProcSigusr2Handler(SIGNAL_ARGS) | SIGUSR2:设置标志以完成恢复 |
static void StartupProcSigHupHandler(SIGNAL_ARGS) | SIGHUP:设置标志以在下一个方便的时间重新读取配置文件 |
static void StartupProcSigIntHandler(SIGNAL_ARGS) | SIGINT:设置标志以检查修复页面 |
static void StartupProcShutdownHandler(SIGNAL_ARGS) | SIGTERM:设置标志以中止重做并退出 |
void HandleStartupProcInterrupts(void) | 处理启动过程的 SIGHUP 和 SIGTERM 信号 |
static void StartupReleaseAllLocks(int code, Datum arg) | 释放所有锁 |
void DeleteDisConnFileInClusterStandby() | 删除群集备用中的文件 |
void PreRestoreCommand(void) | 预恢复命令 |
void PostRestoreCommand(void) | 发布恢复命令 |
bool IsFailoverTriggered(void) | 判断是否触发了故障转移 |
bool IsSwitchoverTriggered(void) | 判断是否触发切换 |
bool IsPrimaryTriggered(void) | 判断是否主要触发 |
bool IsStandbyTriggered(void) | 判断是否触发待机 |
void SendNotifySignal(NotifyReason reason, ThreadId ProcPid) | 在通知信号共享内存中设置原因,并将 SIGUSR2 发送到进程 |
bool CheckNotifySignal(NotifyReason reason) | 检查通知信号 |
static void SetStaticConnNum(void) | 更新 HaSHmData 中的静态连接号 |