OpenGauss线程管理-告警检测线程-alarmchecker
术语解释
- 日志文件:计算机记录自身活动的记录。
- ps:在Linux上显示某个进程的线程的方式。在ps命令中,“-T”选项可以开启线程查看。
例:$ ps -T -p < pid >:查询由进程号为< pid >的进程创建的所有线程。 - 锁:是线程中的一种同步机制。通过加锁,可以实现对共享资源的互斥访问,保证同一时间一个对象只有一个线程在访问。锁又分为很多种。
- 闩锁(latch):通过多线程控制对数据页和结构的并发访问。闩锁提供数据页的物理数据一致性,并提供数据结果的同步。闩锁不可以像锁一样被用户控制。
- 私有锁(private latch):防止其他客户端超时的持有锁对象,从而避免客户端的拒绝服务攻击;
- 内存上下文:一个内存上下文相当于一个进程环境,进程环境间不互相影响。
alarmchecker线程
alarmchecker线程用来检测状态,对不正常的状态进行预警。
地址:openGauss-servers/rc/gausskernel/process/postmaster/alarmchecker.cpp
在主线程中的使用
在主函数PostmasterMain中调用startAlarmChecker()函数来启动线程。
在GaussDbThreadMain中通过thread_role来进入alarmchecker线程中的主函数
代码理解
1.AlarmCheckerMain——主函数
NON_EXEC_STATIC void AlarmCheckerMain()
{
/* 我们现在是一个 postmaster 子进程 */
IsUnderPostmaster = true;
/* 重置 t_thrd.proc_cxt.MyProcPid */
t_thrd.proc_cxt.MyProcPid = gs_thread_self();
/* 记录日志记录的开始时间 */
t_thrd.proc_cxt.MyStartTime = time(NULL);
/* 记录我的名字 */
t_thrd.proc_cxt.MyProgName = "AlarmChecker";
/* 通过ps识别自己 */
init_ps_display("AlarmChecker", "", "", "");
AlarmLog(ALM_LOG, "alarm checker started.");
InitializeLatchSupport(); /* 需要闩锁等待*/
/* 初始化私有锁存器以供信号处理程序使用 */
InitLatch(&t_thrd.alarm_cxt.AlarmCheckerLatch);
/*
* 正确接受或忽略postmaster可能发送给我们的信号
*
* 注意:我们故意忽略 SIGTERM,因为在标准的 Unix 系统关闭周期中,
* init 将立即对所有进程进行 SIGTERM。 我们想等待后端退出,
* 然后 postmaster 会告诉我们可以关闭(通过 SIGUSR2)。
*/
(void)gspqsignal(SIGHUP, acSighupHandler); /* 设置标志以读取配置文件 */
(void)gspqsignal(SIGINT, SIG_IGN);
(void)gspqsignal(SIGTERM, SIG_IGN);
(void)gspqsignal(SIGQUIT, acSigquitHandler);
(void)gspqsignal(SIGALRM, SIG_IGN);
(void)gspqsignal(SIGPIPE, SIG_IGN);
(void)gspqsignal(SIGUSR1, SIG_IGN);
(void)gspqsignal(SIGUSR2, SIG_IGN);
/*
* 重置一些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);
gs_signal_setmask(&t_thrd.libpq_cxt.UnBlockSig, NULL);
(void)gs_signal_unblock_sigusr2();
/* 一切都完成了信息顶部内存上下文。 */
(void)MemoryContextSwitchTo(THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT));
DataInstAlarmItemInitialize();
for (;;) {
/* 清除任何已挂起的唤醒 */
ResetLatch(&t_thrd.alarm_cxt.AlarmCheckerLatch);
/* 正常关机情况*/
if (t_thrd.alarm_cxt.gotSigdie)
break;
/*
* 重新加载 postgresql.conf
*/
if (t_thrd.alarm_cxt.gotSighup) {
t_thrd.alarm_cxt.gotSighup = false;
ProcessConfigFile(PGC_SIGHUP);
}
AlarmCheckerLoop(DataInstAlarmList, DataInstAlarmListSize);
/*
* 睡觉直到有事可做
*/
(void)WaitLatch(&t_thrd.alarm_cxt.AlarmCheckerLatch, WL_LATCH_SET | WL_TIMEOUT, AlarmCheckInterval * 1000);
}
AlarmLog(ALM_LOG, "alarm checker shutting down...");
proc_exit(0);
}
2.startAlarmChecker启动线程
若是第一次启动数据库,使用initialize_util_thread函数来启动alarmchecker线程
ThreadId startAlarmChecker(void)
{
if (!IsPostmasterEnvironment || !enable_alarm) {
return 0;
}
return initialize_util_thread(ALARMCHECK);
}
3.报警模块的实现。
//无报警
void AlarmFree(void* pointer)
{
if (pointer != NULL)
pfree(pointer);
}
//警报分配
void* AlarmAlloc(size_t size)
{
return palloc(size);
}
//报警日志实现
void AlarmLogImplementation(int level, const char* prefix, const char* logtext)
{
switch (level) {
case ALM_DEBUG:
ereport(DEBUG3, (errmsg("%s%s", prefix, logtext)));
break;
case ALM_LOG:
ereport(LOG, (errmsg("%s%s", prefix, logtext)));
break;
default:
break;
}
}
4.其他函数解读
函数 | 功能 |
---|---|
void DataInstAlarmItemInitialize(void) | 数据的初始化 |
static void acSighupHandler(SIGNAL_ARGS) | 处理 SIGHUP 信号并设置 t_thrd.alarm_cxt.gotSighup 标志 |
static void acSigquitHandler(SIGNAL_ARGS) | 处理 SIGTERM、SIGINT 信号并设置 t_thrd.alarm_cxt.gotSigdie 标志 |
bool isDirExist(const char* dir) | 判断dir是否存在 |
AlarmCheckResult DataOrRedoDirNotExistChecker(Alarm* alarm, AlarmAdditionalParam* additionalParam) | 检查数据或日志重做不存在 |