PostgreSQL数据库的后台二等公民进程包括普通后端进程、walsender进程、Autovacuum进程和后台进程。Postmaster守护进程为每个上述进程分配一个Backend结构体,并被组织成双向链表BackendList。如下所示是这些子进程加入该双向链表的调用栈。

普通后端进程
BackendStartup --> malloc申请Backend内存,调用AssginPostmasterChildSlot为MyPMChildSlot和child_slot成员初始化
–> dlist_push_head(&BackendList, &bn->elem)

walsender进程
walsender进程同样走BackendStartup函数,其bkend_type由SignalSomeChildren和CountChildren设置

Autovacuum进程
StartAutovacuumWorker --> dlist_push_head(&BackendList, &bn->elem)
postmaster检测到vaculauncher发送的PMSIGNAL_START_AUTOVAC_WORKER信号后启动vacuumworker后台进程

后台进程
maybe_start_bgworkers --> do_start_bgworker --> assign_backendlist_entry --> bn = malloc(sizeof(Backend)) --> rw->rw_backend = bn
–> dlist_push_head(&BackendendList, &bn->elem)

后台二等公民进程保活

后台二等公民进程保活和启动的代码就是maybe_start_bgworkers函数,maybe_start_bgworkers函数调用处就是后台二等公民进程保活:

  • StartupDataBase之后
  • ServerLoop如果设置了StartWorkerNeeded或HaveCrashedWorker
  • reaper在检测到启动进程正常退出后
  • sigusr1_handler信号处理函数中如果设置了StartWorkerNeeded或HaveCrashedWorker

maybe_start_bgworkers函数

maybe_start_bgworkers函数在时间合适的时候,启动后台进程。作为副作用,bgworker 控制变量的设置或重置取决于是否需要启动更多的工作程序。我们限制了每次调用启动的工作人员数量,以避免在许多此类请求待处理时花费太长时间来占用Postmaster的注意力。 只要 StartWorkerNeeded 为 true,ServerLoop 就不会阻塞,在处理完其他问题后会再次调用该函数。maybe_start_bgworkers函数的主要执行流程:

  1. 遍历BackgroundWorkerList链表,取出RegisteredBgWorker条目
  2. 如果后台进程RegisteredBgWorker结构体中的rw_pid不为0,说明进程正在运行,不处理该后台进程
  3. 如果后台进程RegisteredBgWorker结构体标记为死亡,调用ForgetBackgroundWorker函数清理并从列表中删除
  4. 如果worker之前已崩溃,则可能需要重新启动它(除非在注册时指定它根本不想重新启动)。 检查上次发生崩溃是多久以前。 如果上次崩溃太近,不要立即启动它; 让它在足够的时间过去后重新启动。如果进程指定需要通知的兄弟进程且注册时指定它根本不想重新启动,就使用kill SIGUSR1通知它
  5. 设置标志以记住我们有worker稍后需要启动,这个就是上面描述的让它在足够的时间过去后重新启动的流程。
  6. 调用bgworker_should_start_now函数判定该后台进程是否需要现在启动,如果有就调用do_start_bgworker函数启动(如果失败,请暂时放弃处理后台进程,但设置 StartWorkerNeeded标记,以便我们在下一次 ServerLoop 迭代时回到这里再试一次。 我们不想等待,因为可能还有其他准备运行的后台进程。我们也可以设置 HaveCrashedWorker,因为这个工作人员现在被标记为崩溃,但没有必要,因为这个函数的下一次运行会做)。如果我们已经启动了尽可能多的后台进程,请退出,但让 ServerLoop 再次调用我们以寻找其他准备运行的后台进程。 可能没有,但我们下次运行时会发现。
static void maybe_start_bgworkers(void) {#define MAX_BGWORKERS_TO_LAUNCH 100int          num_launched = 0;TimestampTz now = 0;slist_mutable_iter iter;/* During crash recovery, we have no need to be called until the state transition out of recovery. */// 在崩溃恢复期间,我们不需要被调用,直到状态转换出恢复,代码逻辑就是下面if (FatalError) {StartWorkerNeeded = false;HaveCrashedWorker = false;return;}/* Don't need to be called again unless we find a reason for it below */// 除非我们在下面找到原因,否则不需要再次调用StartWorkerNeeded = false;HaveCrashedWorker = false;slist_foreach_modify(iter, &BackgroundWorkerList) { // 遍历BackgroundWorkerList链表RegisteredBgWorker *rw;rw = slist_container(RegisteredBgWorker, rw_lnode, iter.cur);        if (rw->rw_pid != 0) continue; /* ignore if already running */      if (rw->rw_terminate) { /* if marked for death, clean up and remove from list 如果标记为死亡,清理并从列表中删除 */ForgetBackgroundWorker(&iter);continue;}/* If this worker has crashed previously, maybe it needs to be restarted (unless on registration it specified it doesn't want to be restarted at all).  Check how long ago did a crash last happen. If the last crash is too recent, don't start it right away; let it be restarted once enough time has passed. 如果worker之前已崩溃,则可能需要重新启动它(除非在注册时指定它根本不想重新启动)。 检查上次发生崩溃是多久以前。 如果上次崩溃太近,不要立即启动它; 让它在足够的时间过去后重新启动 */if (rw->rw_crashed_at != 0) {if (rw->rw_worker.bgw_restart_time == BGW_NEVER_RESTART) {int           notify_pid;notify_pid = rw->rw_worker.bgw_notify_pid;ForgetBackgroundWorker(&iter);             if (notify_pid != 0) kill(notify_pid, SIGUSR1); /* Report worker is gone now. 如果进程指定需要通知的兄弟进程,就使用kill SIGUSR1通知它 */continue;}if (now == 0) now = GetCurrentTimestamp(); /* read system time only when needed */if (!TimestampDifferenceExceeds(rw->rw_crashed_at, now, rw->rw_worker.bgw_restart_time * 1000)) {           HaveCrashedWorker = true; /* Set flag to remember that we have workers to start later 设置标志以记住我们有worker稍后需要启动 */continue;}}if (bgworker_should_start_now(rw->rw_worker.bgw_start_time)) {            rw->rw_crashed_at = 0; /* reset crash time before trying to start worker *//* Try to start the worker.* On failure, give up processing workers for now, but set StartWorkerNeeded so we'll come back here on the next iteration of ServerLoop to try again.  (We don't want to wait, because there might be additional ready-to-run workers.)  We could set HaveCrashedWorker as well, since this worker is now marked crashed, but there's no need because the next run of this function will do that. 如果失败,请暂时放弃处理工作人员,但设置 StartWorkerNeeded,以便我们在下一次 ServerLoop 迭代时回到这里再试一次。 (我们不想等待,因为可能还有其他准备运行的工作人员。)我们也可以设置 HaveCrashedWorker,因为这个工作人员现在被标记为崩溃,但没有必要,因为这个函数的下一次运行会做 那。*/if (!do_start_bgworker(rw)){StartWorkerNeeded = true;return;}/* If we've launched as many workers as allowed, quit, but have ServerLoop call us again to look for additional ready-to-run workers.  There might not be any, but we'll find out the next time we run. 如果我们已经启动了尽可能多的工作人员,请退出,但让 ServerLoop 再次调用我们以寻找其他准备运行的工作人员。 可能没有,但我们下次运行时会发现 */if (++num_launched >= MAX_BGWORKERS_TO_LAUNCH) {StartWorkerNeeded = true;return;}}}
}

PG守护进程(Postmaster)——后台二等公民进程第一波启动maybe_start_bgworkers相关推荐

  1. PG守护进程(Postmaster)——后台一等公民进程

    AuxiliaryProcessMain函数是后台一等公民进程的入口,我们来看一看哪里调用了该入口函数: src/backend/main/main.c main函数,如下图所示,argv第二个参数为 ...

  2. PostgreSQL数据库头胎——后台一等公民进程StartupDataBase StartupXLOG函数恢复模式和目标

    StartupXLOG函数在PostgreSQL中有两处调用: 后台一等公民进程StartupDataBase子进程主要的活路就是StartupXLOG postinit.c中的InitPostgre ...

  3. PostgreSQL数据库头胎——后台一等公民进程StartupDataBase 信号通知

    PMSIGNAL_START_WALRECEIVER 从上一篇博客看到了这样的描述:postmaster守护进程的sigusr1_handler信号处理函数用于处理子进程发过来的信号.我们可以看到Ch ...

  4. PostgreSQL数据库头胎——后台一等公民进程StartupDataBase StartupXLOG函数进入Recovery模式

    检查我们是否需要强制从 WAL 中恢复. 如果数据库似乎是完全关闭并且我们没有恢复信号文件,则假设不需要恢复(InRecovery = false). /* Check whether we need ...

  5. PostgreSQL数据库头胎——后台一等公民进程StartupDataBase StartupXLOG函数初始化

    StartupXLOG函数流程 第一步从checkpoint xlog记录中提取信息,更新共享内存变量,比如nextFullXid.nextOid.oidCount. LastRec = RecPtr ...

  6. Linux进程的后台运行

    文章目录 一. 什么是进程? 二. 进程后台运行 在了解三种进程后台运行的方式前,小编觉得有必要先简单讲解一下什么是进程. PS: 本篇博客技术参考价值不大,只是类似随笔比较水,详细的知识点可以关注一 ...

  7. php 后台运行函数,php守护进程函数 后台执行脚本的实例详解

    我们经常通过crontab定时执行后端脚本.比如每10秒检查一下用户状态. 例子: 复制代码 代码示例: @file: /php_scripts/scan_userstatus.php #!/usr/ ...

  8. C# Net6开发Linux守护进程(后台服务程序,类似Windows服务)案例

    C# Net6开发Linux守护进程(后台服务程序,类似Windows服务)案例 背景 C# net6开发Linux守护进程要点 背景 在使用net6开发Linux程序时,除了AspNet Core项 ...

  9. 2进程之间的关系:进程组,会话,守护进程

     1进程组 一个或多个进程的集合,进程组ID是一个正整数.用来获得当前进程组ID的函数. pid_t getpgid(pid_t pid) pid_t getpgrp(void) 获得父子进程进程 ...

最新文章

  1. mysql delete 注意
  2. wget抓取数据,需要用户登录验证
  3. java代码如何能运行起来_Java代码如何运行
  4. 中国火电设备市场发展方向与投资策略研究报告2022版
  5. Java设计模式之行为型:责任链模式
  6. Python之打造专属Python开发者的完美终端工具Rich
  7. 简介浏览器内核与JavaScript引擎
  8. javascript正则表达式入门
  9. Underlay网络:如何立住可靠又支持大规模无收敛的“人设”
  10. 企鹅电竞宣布将于6月7日终止运营
  11. 任务之间的依赖(NSOperation)
  12. 2017-3-17 SQL server 数据库 视图,事务,备份还原,分离附加
  13. 使用JAVA调用MATLAB算法程序方式——使用复杂算例进行完整说明,包括参数传递
  14. 【物联网设计记录】基于机智云云平台的Wi-Fi控制开发板
  15. Between Us 2 进化的史诗
  16. 0 0 0 ’\0’ 区别
  17. 刚体质量分布与牛顿-欧拉方程
  18. 华为nova6计算机历史在哪可以看,写在华为nova6发布前:一文看出nova手机使用芯片的变迁历程...
  19. Visual C++ Redistributable for VS2005/VS2008/VS2010/VS2012/VS2013/VS2015/VS2017/VS2019 下载地址
  20. Android:展锐battery

热门文章

  1. 软件著作权变更收费吗
  2. 当黑客说:我入侵了你的电脑,并拍下你看XXOO的画面时,你该怎么办?
  3. 如何在海思 Hi3519AV100上移植YOLOV3 (3)
  4. 给定一个非负整数num,范围中的每个数字i 计算其二进制中1的个数
  5. python图画制作_python语言创意绘画-用python画画
  6. Compiling Cpp
  7. 四川初中计算机老师工资多少,揭秘四川中小学教师工资待遇,你觉得高吗?
  8. 第五章 卡耐基驾驭竞争与合作 三 征服畏惧建立自信
  9. 趣米征文,木头来拉票了,噗哈哈
  10. 2023跨年烟花3D最炫烟花,html最酷炫动态烟花源码分享,点击即可直接运行