PMSIGNAL_START_WALRECEIVER

从上一篇博客看到了这样的描述:postmaster守护进程的sigusr1_handler信号处理函数用于处理子进程发过来的信号。我们可以看到CheckPostmasterSignal(PMSIGNAL_START_WALRECEIVER)这个分支会检查到postmaster进程接收到启动WalReceiver的信号,说明启动进程希望我们启动 walreceiver 进程,如果可能,请立即开始,否则请记住稍后的请求。那这个信号在什么时候发送呢。

PMSIGNAL_START_WALRECEIVER信号发送
启动进程在第七步建立起XLOG读取设施(主要是初始化XLogReaderState结构体xlogreader)时,注册了XLogPageRead函数为XLogPageReadCB类型read_page成员。

typedef int (*XLogPageReadCB) (XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *readBuf, TimeLineID *pageTLI);
static int  XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *readBuf, TimeLineID *readTLI);

PMSIGNAL_START_WALRECEIVER信号发送流程函数调用堆栈如下所示:XLogPageRead -> WaitForWALToBecomeAvailable -> Request XLog Streaming
Request XLog Streaming函数用于请求 postmaster 启动 walreceiver。ecptr 指示流应该开始的位置, conninfo 是要使用的 libpq 连接字符串,而 slotname 是可选的要获取的复制槽的名称。

void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo, const char *slotname){...latch = walrcv->latch;SpinLockRelease(&walrcv->mutex);if (launch) SendPostmasterSignal(PMSIGNAL_START_WALRECEIVER);else if (latch) SetLatch(latch);
}

WaitForWALToBecomeAvailable函数打开包含 WAL 位置“RecPtr”的 WAL 段。该段文件可以通过 restore_command 或通过流式传输记录的 walreceiver 获取,或者它可以已经存在于 pg_wal 中。检查 pg_wal 主要是为了崩溃恢复,但它也会在standby模式下被轮询,以防有人直接将新段复制到 pg_wal。但是,这没有记录或推荐。如果 ‘fetching_ckpt’ 为真,我们正在获取检查点记录,并且应该准备在此之后从 RedoStartLSN 开始读取 WAL。‘RecPtr’ 可能不指向我们感兴趣的记录的开头,它也可能指向页面或段标题。在这种情况下,‘tliRecPtr’ 是我们感兴趣的 WAL 记录的位置。它用于决定从哪个时间线流式传输请求的 WAL。如果记录不是立即可用的,那么如果我们不处于待机模式,该函数将返回 false。在待机模式下,等待它可用。当请求的记录可用时,该函数打开包含它的文件(如果尚未打开),并返回 true。当用户触发待机模式结束,并且没有更多可用的 WAL 时,返回 false。

static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, bool fetching_ckpt, XLogRecPtr tliRecPtr){case XLOG_FROM_ARCHIVE:case XLOG_FROM_PG_WAL:...//如果设置了 primary_conninfo,则启动 walreceiver 以尝试流式传输丢失的 WAL。如果 fetching_ckpt 为真,则 RecPtr 指向初始检查点位置。 在这种情况下,我们使用 RedoStartLSN 作为流式传输的开始位置而不是 RecPtr,因此当我们稍后向后跳转以在 RedoStartLSN 处开始重做时,我们将已经流式传输日志。if (PrimaryConnInfo && strcmp(PrimaryConnInfo, "") != 0){...RequestXLogStreaming(tli, ptr, PrimaryConnInfo, PrimarySlotName);   ...
}

XLogPageRead函数将包含 RecPtr 的 XLOG 页面读入 readBuf(如果尚未读取)。 如果页面读取成功,则返回读取的字节数,如果出现错误,则返回 -1。 当错误发生时,它们会被报告,但前提是它们之前没有被报告过。

static int XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *readBuf, TimeLineID *readTLI)...
retry: /* See if we need to retrieve more data */   if (readFile < 0 || (readSource == XLOG_FROM_STREAM && receivedUpto < targetPagePtr + reqLen)) {if (!WaitForWALToBecomeAvailable(targetPagePtr + reqLen, private->randAccess, private->fetching_ckpt, targetRecPtr)){if (readFile >= 0) close(readFile);readFile = -1; readLen = 0; readSource = 0;return -1;}}  ...
}

PMSIGNAL_RECOVERY_STARTED

在启动进程redo过程中,需要让 postmaster 知道我们现在已经开始重做redo xlog,这样它可以启动 checkpointer 来执行重新启动点restartpoints。 我们不会在崩溃恢复期间打扰,因为重启点restartpoints只能在存档恢复期间执行。 我们希望保持崩溃恢复流程简单一些,以避免在崩溃后恢复时引入可能影响您的错误。在此之后,启动进程不能再假设我们是除了 postmaster 之外的唯一进程! 此外,fsync 请求随后将由检查指针处理,而不是在本地处理。

     if (ArchiveRecoveryRequested && IsUnderPostmaster) {PublishStartupProcessInformation();EnableSyncRequestForwarding();SendPostmasterSignal(PMSIGNAL_RECOVERY_STARTED);bgwriterLaunched = true;}

postmaster子sigusr1_handler函数中处理,RECOVERY_STARTED 和 BEGIN_HOT_STANDBY 信号在意外状态下会被忽略。 如果启动进程快速启动,完成恢复,退出,我们可能会先处理启动进程的死亡。 在这种情况下,我们不想回到恢复状态。

 if (CheckPostmasterSignal(PMSIGNAL_RECOVERY_STARTED) && pmState == PM_STARTUP && Shutdown == NoShutdown) {/* WAL redo has started. We're out of reinitialization. */FatalError = false;Assert(AbortStartTime == 0);/* Crank up the background tasks.  It doesn't matter if this fails, we'll just try again later. */CheckpointerPID = StartCheckpointer();BgWriterPID = StartBackgroundWriter();/* Start the archiver if we're responsible for (re-)archiving received files. */if (XLogArchivingAlways()) PgArchPID = pgarch_start();/* If we aren't planning to enter hot standby mode later, treat RECOVERY_STARTED as meaning we're out of startup, and report status accordingly. */if (!EnableHotStandby) {AddToDataDirLockFile(LOCK_FILE_LINE_PM_STATUS, PM_STATUS_STANDBY);
#ifdef USE_SYSTEMDsd_notify(0, "READY=1");
#endif}pmState = PM_RECOVERY;}

PMSIGNAL_BEGIN_HOT_STANDBY

ReadRecord函数有一处调用CheckRecoveryConsistency --> SendPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY)
StartupXLOG函数有两处调用CheckRecoveryConsistency --> SendPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY)

CheckRecoveryConsistency函数用于检查恢复是否已达到一致状态。 当达到一致性并且我们有一个有效的起始备用快照时,告诉 postmaster 它可以开始接受只读连接。

postmaster子sigusr1_handler函数中处理,RECOVERY_STARTED 和 BEGIN_HOT_STANDBY 信号在意外状态下会被忽略。 如果启动进程快速启动,完成恢复,退出,我们可能会先处理启动进程的死亡。 在这种情况下,我们不想回到恢复状态。

 if (CheckPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY) && pmState == PM_RECOVERY && Shutdown == NoShutdown) {/* Likewise, start other special children as needed. */PgStatPID = pgstat_start();ereport(LOG,(errmsg("database system is ready to accept read only connections")));/* Report status */AddToDataDirLockFile(LOCK_FILE_LINE_PM_STATUS, PM_STATUS_READY);
#ifdef USE_SYSTEMDsd_notify(0, "READY=1");
#endifpmState = PM_HOT_STANDBY;connsAllowed = ALLOW_ALL_CONNS;        StartWorkerNeeded = true; /* Some workers may be scheduled to start now */}

PMSIGNAL_RECOVERY_STARTED和PMSIGNAL_BEGIN_HOT_STANDBY场景

如果是备机即data目录下有recovery.cnf文件,没有设置hot standby:startup进程向主进程发送PMSIGNAL_RECOVERY_STARTED信号;postmaster主进程接收到信号后,将pmState设置为PM_RECOVERY。

如果是备机即data目录下有recovery.cnf文件,且设置了hot standby,在实际恢复前到达一致性位置:startup进程向主进程发送PMSIGNAL_RECOVERY_STARTED信号,postmaster主进程调用信号处理函数sigusr1_handler,将pmState设置为PM_RECOVERY;CheckRecoveryConsistency函数进行一致性检查,向主进程发送PMSIGNAL_BEGIN_HOT_STANDBY信号(告诉 postmaster 它可以开始接受只读连接),主进程接收到信号后调用sigusr1_handler->AddToDataDirLockFile向postmaster.pid文件写入ready。

如果是备机即data目录下有recovery.conf文件,且设置了hot standby,在实际恢复前没有到达一致性位置:
1)startup进程向主进程发送PMSIGNAL_RECOVERY_STARTED信号,主进程调用信号处理函数sigusr1_handler,将pmState设置为PM_RECOVERY
2)每次读取下一个xlog前都会调用CheckRecoveryConsistency函数进行一致性检查:
2.1 进入一致性状态,starup进程向主进程发送PMSIGNAL_BEGIN_HOT_STANDBY信号,主进程接收到信号后调用sigusr1_handler->AddToDataDirLockFile向postmaster.pid文件写入ready
3)本地日志恢复完成,切换日志源时同样调用CheckRecoveryConsistency函数进行一致性检查
3.1 进入一致性状态,starup进程向主进程发送PMSIGNAL_BEGIN_HOT_STANDBY信号,主进程接收到信号后调用sigusr1_handler->AddToDataDirLockFile向postmaster.pid文件写入ready。

SIGCHLD

当startup进程恢复完成退出时,调用proc_exit函数向主进程发送SIGCHLD信号并退出(proc_exit(0);//exit函数向主进程发送SIGCHLD信号)。主进程接收到信号后,signal处理函数reaper调用AddToDataDirLockFile向postmaster.pid文件写入ready。

void proc_exit(int code) {   proc_exit_prepare(code); /* Clean up everything that must be cleaned up */exit(code);
}

参考自帅总文档PostgreSQL pg_ctl start超时分析

PostgreSQL数据库头胎——后台一等公民进程StartupDataBase 信号通知相关推荐

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

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

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

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

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

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

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

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

  5. PG守护进程(Postmaster)——后台二等公民进程第一波启动maybe_start_bgworkers

    PostgreSQL数据库的后台二等公民进程包括普通后端进程.walsender进程.Autovacuum进程和后台进程.Postmaster守护进程为每个上述进程分配一个Backend结构体,并被组 ...

  6. linux查找postgre进程,postgresql数据库某一个进程占用大量CPU,问题排查详解

    postgresql某一个进程占用大量 CPU,问题排查,目前服务器cpu为4核,内存8G 1.查下是不是我们的业务SQL SELECT procpid, START, now() - START A ...

  7. 12306的西天取经路 - 春节抢票与PostgreSQL数据库设计思考

    标签 PostgreSQL , 12306 , 春节 , 一票难求 , 门禁广告 , 数组 , 范围类型 , 抢购 , 排他约束 , 大盘分析 , 广告查询 , 火车票 背景 马上春节了,又到了火车票 ...

  8. Debezium系列之:使用Debezium接入PostgreSQL数据库数据到Kafka集群的详细技术文档

    Debezium系列之:使用Debezium接入PostgreSQL数据库数据到Kafka集群的详细技术文档 一.概述 二.连接器的工作原理 1.安全 2.快照 3.Ad hoc snapshots ...

  9. Debezium系列之:Debezium2.X之PostgreSQL数据库的Debezium连接器

    Debezium系列之:Debezium2.X之PostgreSQL数据库的Debezium连接器 一.概述 二.连接器的工作原理 1.安全 2.快照 3.临时快照 4.触发临时快照 5.增量快照 6 ...

最新文章

  1. 偷天换日——新型浏览器劫持木马“暗影鼠”分析
  2. 私有云Opetstack的创建与运用
  3. boost::function_types::is_member_pointer用法的测试程序
  4. Django模板语言相关内容
  5. day19-URL+视图+模板+ORM
  6. 64位Office 2010 连接SOHU IMAP服务器遇到问题
  7. 操作系统:读者-写者问题 (C语言 winapi)
  8. 快捷键查看Emacs源码
  9. 每天一道剑指offer-连续子数组的最大和
  10. sitemesh 使用整理(入门)
  11. 前端保存之前输入的值_前端基础进阶(一):内存空间详细图解
  12. get 和 post 区别
  13. MYSQL数据库ANY的用法_数据库——IN、ANY、SOME 和 ALL 操作符的使用
  14. 微型计算机主装箱中装有哪些,微型计算机及接口技术2016年10月真题试题(04732)...
  15. Unity Shader知识点(二)写一个基础漫反射Shader
  16. 计算机系统结构 之 指令系统
  17. python open 函数漏洞_python和django的目录遍历漏洞
  18. intel realsense 深度相机深度图像处理API总结
  19. 快压弹出垃圾广告如何设置
  20. vant中uploader上传图片

热门文章

  1. 一级消防工程师考试,知道这些不失分!
  2. 计算机小宝,小宝听听电脑版
  3. Python爬虫:从js逆向了解西瓜视频的下载链接的生成
  4. Linux的fork函数和进程替换
  5. 笔记本风扇声音大(处理器电源管理)
  6. 钱诚:10.11现货黄金原油价格走势实时行情分析
  7. 测量PSNR-SSIM平均值
  8. seo,就是一场资源战
  9. 前端培训机构哪家比较适合学习
  10. WOW UI 哦也!【1】