PostgreSQL中AutoVacLauncherMain函数的实现逻辑是什么
短信预约 -IT技能 免费直播动态提醒
本篇内容介绍了“PostgreSQL中AutoVacLauncherMain函数的实现逻辑是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
一、数据结构
宏定义
#define GetProcessingMode() Mode
#define SetProcessingMode(mode) \
do { \
AssertArg((mode) == BootstrapProcessing || \
(mode) == InitProcessing || \
(mode) == NormalProcessing); \
Mode = (mode); \
} while(0)
二、源码解读
AutoVacLauncherMain函数,autovacuum进程主循环.
NON_EXEC_STATIC void
AutoVacLauncherMain(int argc, char *argv[])
{
sigjmp_buf local_sigjmp_buf;
am_autovacuum_launcher = true;
//进程ID
init_ps_display(pgstat_get_backend_desc(B_AUTOVAC_LAUNCHER), "", "", "");
ereport(DEBUG1,
(errmsg("autovacuum launcher started")));
if (PostAuthDelay)
pg_usleep(PostAuthDelay * 1000000L);
//设置进程模式
SetProcessingMode(InitProcessing);
pqsignal(SIGHUP, av_sighup_handler);
pqsignal(SIGINT, StatementCancelHandler);
pqsignal(SIGTERM, avl_sigterm_handler);
pqsignal(SIGQUIT, quickdie);
//建立SIGALRM控制器
InitializeTimeouts();
pqsignal(SIGPIPE, SIG_IGN);//忽略SIGPIPE
pqsignal(SIGUSR1, procsignal_sigusr1_handler);
pqsignal(SIGUSR2, avl_sigusr2_handler);
pqsignal(SIGFPE, FloatExceptionHandler);
pqsignal(SIGCHLD, SIG_DFL);
//基础初始化
BaseInit();
#ifndef EXEC_BACKEND
InitProcess();
#endif
//初始化
InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL, false);
//设置进程模式
SetProcessingMode(NormalProcessing);
AutovacMemCxt = AllocSetContextCreate(TopMemoryContext,
"Autovacuum Launcher",
ALLOCSET_DEFAULT_SIZES);
MemoryContextSwitchTo(AutovacMemCxt);
if (sigsetjmp(local_sigjmp_buf, 1) != 0)
{
//由于没有使用PG_TRY,这里必须手工重置错误.
error_context_stack = NULL;
//在清理期间禁用中断
HOLD_INTERRUPTS();
//忽略所有QueryCancel或者超时请求
disable_all_timeouts(false);
QueryCancelPending = false;
//在服务器日志中记录日志.
EmitErrorReport();
//废弃当前事务,以准备恢复
AbortCurrentTransaction();
LWLockReleaseAll();
pgstat_report_wait_end();
AbortBufferIO();
UnlockBuffers();
//这可能是dead code,但可以保证安全
if (AuxProcessResourceOwner)
ReleaseAuxProcessResources(false);
AtEOXact_Buffers(false);
AtEOXact_SMgr();
AtEOXact_Files(false);
AtEOXact_HashTables(false);
MemoryContextSwitchTo(AutovacMemCxt);
FlushErrorState();
//在top-level上下文刷新所有泄漏的数据
MemoryContextResetAndDeleteChildren(AutovacMemCxt);
//不要留下悬空指针来释放内存
DatabaseListCxt = NULL;
dlist_init(&DatabaseList);
pgstat_clear_snapshot();
//可以允许中断了
RESUME_INTERRUPTS();
//如处于shutdown模式,不需要继续后续的工作了,跳转到shutdown
if (got_SIGTERM)
goto shutdown;
pg_usleep(1000000L);
}
//现在可以处理ereport(ERROR)了
PG_exception_stack = &local_sigjmp_buf;
//在调用rebuild_database_list前不能阻塞信号
PG_SETMASK(&UnBlockSig);
SetConfigOption("search_path", "", PGC_SUSET, PGC_S_OVERRIDE);
SetConfigOption("zero_damaged_pages", "false", PGC_SUSET, PGC_S_OVERRIDE);
SetConfigOption("statement_timeout", "0", PGC_SUSET, PGC_S_OVERRIDE);
SetConfigOption("lock_timeout", "0", PGC_SUSET, PGC_S_OVERRIDE);
SetConfigOption("idle_in_transaction_session_timeout", "0",
PGC_SUSET, PGC_S_OVERRIDE);
SetConfigOption("default_transaction_isolation", "read committed",
PGC_SUSET, PGC_S_OVERRIDE);
if (!AutoVacuumingActive())
{
if (!got_SIGTERM)
do_start_worker();
proc_exit(0);
}
AutoVacuumShmem->av_launcherpid = MyProcPid;
rebuild_database_list(InvalidOid);
//循环,直至请求shutdown
while (!got_SIGTERM)
{
struct timeval nap;
TimestampTz current_time = 0;
bool can_launch;
launcher_determine_sleep(!dlist_is_empty(&AutoVacuumShmem->av_freeWorkers),
false, &nap);
(void) WaitLatch(MyLatch,
WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
(nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
WAIT_EVENT_AUTOVACUUM_MAIN);
ResetLatch(MyLatch);
//在休眠过程中,进程会捕获相关的中断.
ProcessCatchupInterrupt();
//shutdonw信号
if (got_SIGTERM)
break;
if (got_SIGHUP)
{
//SIGHUP信号
got_SIGHUP = false;
ProcessConfigFile(PGC_SIGHUP);
//在配置文件中已请求shutdown?
if (!AutoVacuumingActive())
break;
//如默认的成本参数变化,则自动平衡.
LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
autovac_balance_cost();
LWLockRelease(AutovacuumLock);
//如naptime出现变化,重建链表
rebuild_database_list(InvalidOid);
}
if (got_SIGUSR2)
{
//SIGUSR2信号
got_SIGUSR2 = false;
//如需要,重平衡成本限制
if (AutoVacuumShmem->av_signal[AutoVacRebalance])
{
LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
AutoVacuumShmem->av_signal[AutoVacRebalance] = false;
autovac_balance_cost();
LWLockRelease(AutovacuumLock);
}
if (AutoVacuumShmem->av_signal[AutoVacForkFailed])
{
AutoVacuumShmem->av_signal[AutoVacForkFailed] = false;
pg_usleep(1000000L);
SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER);
continue;
}
}
current_time = GetCurrentTimestamp();
LWLockAcquire(AutovacuumLock, LW_SHARED);
can_launch = !dlist_is_empty(&AutoVacuumShmem->av_freeWorkers);
if (AutoVacuumShmem->av_startingWorker != NULL)
{
int waittime;
WorkerInfo worker = AutoVacuumShmem->av_startingWorker;
waittime = Min(autovacuum_naptime, 60) * 1000;
if (TimestampDifferenceExceeds(worker->wi_launchtime, current_time,
waittime))
{
LWLockRelease(AutovacuumLock);
LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
if (AutoVacuumShmem->av_startingWorker != NULL)
{
worker = AutoVacuumShmem->av_startingWorker;
worker->wi_dboid = InvalidOid;
worker->wi_tableoid = InvalidOid;
worker->wi_sharedrel = false;
worker->wi_proc = NULL;
worker->wi_launchtime = 0;
dlist_push_head(&AutoVacuumShmem->av_freeWorkers,
&worker->wi_links);
AutoVacuumShmem->av_startingWorker = NULL;
elog(WARNING, "worker took too long to start; canceled");
}
}
else
can_launch = false;
}
//释放锁
LWLockRelease(AutovacuumLock);
//什么都做不了,继续休眠
if (!can_launch)
continue;
//现在可以启动新的worker
if (dlist_is_empty(&DatabaseList))
{
launch_worker(current_time);
}
else
{
avl_dbase *avdb;
avdb = dlist_tail_element(avl_dbase, adl_node, &DatabaseList);
if (TimestampDifferenceExceeds(avdb->adl_next_worker,
current_time, 0))
launch_worker(current_time);
}
}
//常规的退出.
shutdown:
ereport(DEBUG1,
(errmsg("autovacuum launcher shutting down")));
AutoVacuumShmem->av_launcherpid = 0;
proc_exit(0);
}
“PostgreSQL中AutoVacLauncherMain函数的实现逻辑是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341