PostgreSQL 源码解读(156)- 后台进程#8(walsender#4)
上节介绍了PostgreSQL的后台进程walsender中的函数WalSndLoop->WaitLatchOrSocket->WaitEventSetWait->WaitEventSetWaitBlock,在跟踪分析的时候进程退出,现就此问题进行分析.在调用函数ProcessRepliesIfAny后进程退出,因此重点分析ProcessRepliesIfAny函数.
调用栈如下:
(gdb) bt
#0 0x00007fb6e6390903 in __epoll_wait_nocancel () from /lib64/libc.so.6
#1 0x000000000088e668 in WaitEventSetWaitBlock (set=0x10ac808, cur_timeout=29999, occurred_events=0x7ffd634441b0, nevents=1) at latch.c:1048
#2 0x000000000088e543 in WaitEventSetWait (set=0x10ac808, timeout=29999, occurred_events=0x7ffd634441b0, nevents=1, wait_event_info=83886092) at latch.c:1000
#3 0x000000000088dcec in WaitLatchOrSocket (latch=0x7fb6dcbfc4d4, wakeEvents=27, sock=10, timeout=29999, wait_event_info=83886092) at latch.c:385
#4 0x000000000085405b in WalSndLoop (send_data=0x8547fe <XLogSendPhysical>) at walsender.c:2229
#5 0x0000000000851c93 in StartReplication (cmd=0x10ab750) at walsender.c:684
#6 0x00000000008532f0 in exec_replication_command (cmd_string=0x101dd78 "START_REPLICATION 0/5D000000 TIMELINE 16")at walsender.c:1539
#7 0x00000000008c0170 in PostgresMain (argc=1, argv=0x1049cb8, dbname=0x1049ba8 "", username=0x1049b80 "replicator")at postgres.c:4178
#8 0x000000000081e06c in BackendRun (port=0x103fb50) at postmaster.c:4361
#9 0x000000000081d7df in BackendStartup (port=0x103fb50) at postmaster.c:4033
#10 0x0000000000819bd9 in ServerLoop () at postmaster.c:1706
#11 0x000000000081948f in PostmasterMain (argc=1, argv=0x1018a50) at postmaster.c:1379
#12 0x0000000000742931 in main (argc=1, argv=0x1018a50) at main.c:228
一、数据结构
N/A
二、源码解读
ProcessRepliesIfAny
在streaming期间,处理接收到的消息,同时检查远程终端是否关闭了连接,执行相关处理.
代码不多也不复杂,可自行阅读.
/** Process any incoming messages while streaming. Also checks if the remote* end has closed the connection.* 在streaming期间,处理接收到的消息.* 同时检查远程终端是否关闭了连接,执行相关处理.*/
static void
ProcessRepliesIfAny(void)
{unsigned char firstchar;int r;bool received = false;//当前时间last_processing = GetCurrentTimestamp();for (;;){//---------- 循环接收相关消息pq_startmsgread();r = pq_getbyte_if_available(&firstchar);if (r < 0){/* unexpected error or EOF *///未知异常或者EOFereport(COMMERROR,(errcode(ERRCODE_PROTOCOL_VIOLATION),errmsg("unexpected EOF on standby connection")));//进程退出proc_exit(0);}if (r == 0){/* no data available without blocking *///已无阻塞的消息数据,退出pq_endmsgread();break;}/* Read the message contents *///读取消息内容resetStringInfo(&reply_message);if (pq_getmessage(&reply_message, 0)){ereport(COMMERROR,(errcode(ERRCODE_PROTOCOL_VIOLATION),errmsg("unexpected EOF on standby connection")));proc_exit(0);}/** If we already received a CopyDone from the frontend, the frontend* should not send us anything until we've closed our end of the COPY.* XXX: In theory, the frontend could already send the next command* before receiving the CopyDone, but libpq doesn't currently allow* that.* 如果已在前台接收到CopyDone消息,前台不应该再发送消息,直至关闭COPY.* XXX:理论上来说,在接收到CopyDone前,前台可能已经发送了下一个命令,但libpq不允许这种情况发生*/if (streamingDoneReceiving && firstchar != 'X')ereport(FATAL,(errcode(ERRCODE_PROTOCOL_VIOLATION),errmsg("unexpected standby message type \"%c\", after receiving CopyDone",firstchar)));/* Handle the very limited subset of commands expected in this phase *///处理有限几个命令switch (firstchar){/** 'd' means a standby reply wrapped in a CopyData packet.* 'd'意味着standby节点的应答封装了CopyData包*/case 'd':ProcessStandbyMessage();received = true;break;/** CopyDone means the standby requested to finish streaming.* Reply with CopyDone, if we had not sent that already.* CopyDone意味着standby节点请求结束streaming.* 如尚未发送,则使用CopyDone应答.*/case 'c':if (!streamingDoneSending){pq_putmessage_noblock('c', NULL, 0);streamingDoneSending = true;}streamingDoneReceiving = true;received = true;break;/** 'X' means that the standby is closing down the socket.* 'X'意味着standby节点正在关闭socket*/case 'X':proc_exit(0);default:ereport(FATAL,(errcode(ERRCODE_PROTOCOL_VIOLATION),errmsg("invalid standby message type \"%c\"",firstchar)));}}/** Save the last reply timestamp if we've received at least one reply.* 如接收到至少一条应答信息,则保存最后的应答时间戳.*/if (received){last_reply_timestamp = last_processing;waiting_for_ping_response = false;}
}
二、跟踪分析
在主节点上用gdb跟踪postmaster,在PostgresMain上设置断点后启动standby节点,进入断点
(gdb) set follow-fork-mode child
(gdb) b ProcessRepliesIfAny
Breakpoint 2 at 0x85343b: file walsender.c, line 1597.
(gdb) c
Continuing.
Breakpoint 2, ProcessRepliesIfAny () at walsender.c:1597
1597 bool received = false;
(gdb)
查看进程信息
[xdb@localhost ~]$ ps -ef|grep postgres
xdb 1376 1 0 14:16 ? 00:00:00 /appdb/xdb/pg11.2/bin/postgres
xdb 1377 1376 0 14:16 ? 00:00:00 postgres: logger
xdb 1550 1376 0 16:53 ? 00:00:00 postgres: checkpointer
xdb 1551 1376 0 16:53 ? 00:00:00 postgres: background writer
xdb 1552 1376 0 16:53 ? 00:00:00 postgres: walwriter
xdb 1553 1376 0 16:53 ? 00:00:00 postgres: autovacuum launcher
xdb 1554 1376 0 16:53 ? 00:00:00 postgres: archiver
xdb 1555 1376 0 16:53 ? 00:00:00 postgres: stats collector
xdb 1556 1376 0 16:53 ? 00:00:00 postgres: logical replication launcher
xdb 1633 1376 0 17:26 ? 00:00:00 postgres: walsender replicator 192.168.26.26(40528) idle
循环接收相关消息
(gdb) n
1599 last_processing = GetCurrentTimestamp();
(gdb)
1603 pq_startmsgread();
(gdb)
1604 r = pq_getbyte_if_available(&firstchar);
(gdb)
1605 if (r < 0)
(gdb) p r
$1 = 1
(gdb) p firstchar
$2 = 100 'd'
(gdb)
命令是’d’,执行相关处理
(gdb) n
1613 if (r == 0)
(gdb)
1621 resetStringInfo(&reply_message);
(gdb)
1622 if (pq_getmessage(&reply_message, 0))
(gdb)
1637 if (streamingDoneReceiving && firstchar != 'X')
(gdb)
1644 switch (firstchar)
(gdb)
1650 ProcessStandbyMessage();
(gdb)
1651 received = true;
(gdb)
1652 break;
(gdb)
1681 }
(gdb)
设置断点
(gdb) b walsender.c:1643
Breakpoint 3 at 0x8535b6: file walsender.c, line 1643.
(gdb) b walsender.c:1672
Breakpoint 4 at 0x85361a: file walsender.c, line 1672.
(gdb) c
Continuing.
Breakpoint 3, ProcessRepliesIfAny () at walsender.c:1644
1644 switch (firstchar)
(gdb)
Continuing.
...
Breakpoint 4, ProcessRepliesIfAny () at walsender.c:1673
1673 proc_exit(0);
(gdb)
进程即将退出,查看进程信息
[xdb@localhost ~]$ ps -ef|grep postgres
xdb 1376 1 0 14:16 ? 00:00:00 /appdb/xdb/pg11.2/bin/postgres
xdb 1377 1376 0 14:16 ? 00:00:00 postgres: logger
xdb 1550 1376 0 16:53 ? 00:00:00 postgres: checkpointer
xdb 1551 1376 0 16:53 ? 00:00:00 postgres: background writer
xdb 1552 1376 0 16:53 ? 00:00:00 postgres: walwriter
xdb 1553 1376 0 16:53 ? 00:00:00 postgres: autovacuum launcher
xdb 1554 1376 0 16:53 ? 00:00:00 postgres: archiver
xdb 1555 1376 0 16:53 ? 00:00:00 postgres: stats collector
xdb 1556 1376 0 16:53 ? 00:00:00 postgres: logical replication launcher
xdb 1633 1376 0 17:26 ? 00:00:00 postgres: walsender replicator 192.168.26.26(40528) idle
xdb 1637 1376 0 17:27 ? 00:00:00 postgres: walsender replicator 192.168.26.26(40530) streaming 0/5D075248
[xdb@localhost ~]$
进程退出(PID=1633),启动了新的进程(PID=1637)
(gdb) n
[Inferior 2 (process 1633) exited normally]
(gdb)
DONE!
四、参考资料
PG Source Code
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/6906/viewspace-2639294/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/6906/viewspace-2639294/
PostgreSQL 源码解读(156)- 后台进程#8(walsender#4)相关推荐
- PostgreSQL 源码解读(153)- 后台进程#5(walsender#1)
本节简单介绍了PostgreSQL的后台进程walsender,该进程实质上是streaming replication环境中master节点上普通的backend进程,在standby节点启动时,s ...
- PostgreSQL 源码解读(154)- 后台进程#6(walsender#2)
本节继续介绍PostgreSQL的后台进程walsender,重点介绍的是调用栈中的exec_replication_command和StartReplication函数. 调用栈如下: (gdb) ...
- PostgreSQL 源码解读(155)- 后台进程#7(walsender#3)
本节继续介绍PostgreSQL的后台进程walsender,重点介绍的是调用栈中的函数WalSndLoop->WaitLatchOrSocket->WaitEventSetWait-&g ...
- PostgreSQL 源码解读(212)- 后台进程#11(checkpointer-SyncOneBuffer)
本节介绍了checkpoint中用于刷一个脏page的函数:SyncOneBuffer,该函数在syncing期间处理一个buffer. 一.数据结构 宏定义 checkpoints request ...
- PostgreSQL 源码解读(147)- Storage Manager#3(fsm_search函数)
本节简单介绍了PostgreSQL在执行插入过程中与存储相关的函数RecordAndGetPageWithFreeSpace->fsm_search,该函数搜索FSM,找到有足够空闲空间(min ...
- PostgreSQL 源码解读(160)- 查询#80(如何实现表达式解析)
本节介绍了PostgreSQL如何解析查询语句中的表达式列并计算得出该列的值.表达式列是指除关系定义中的系统列/定义列之外的其他投影列.比如: testdb=# create table t_expr ...
- PostgreSQL 源码解读(203)- 查询#116(类型转换实现)
本节简单介绍了PostgreSQL中的类型转换的具体实现. 解析表达式,涉及不同数据类型时: 1.如有相应类型的Operator定义(pg_operator),则尝试进行类型转换,否则报错; 2.如有 ...
- PostgreSQL 源码解读(31)- 查询语句#16(查询优化-表达式预处理#1)
本节简单介绍了PG查询优化对表达式预处理中连接Var(RTE中的Var,其中RTE_KIND=RTE_JOIN)溯源的过程.处理逻辑在主函数subquery_planner中通过调用flatten_j ...
- PostgreSQL 源码解读(35)- 查询语句#20(查询优化-简化Having和Grou...
本节简单介绍了PG查询优化中对Having和Group By子句的简化处理. 一.基本概念 简化Having语句 把Having中的约束条件,如满足可以提升到Where条件中的,则移动到Where子句 ...
最新文章
- CSDN-markdown编辑器
- 启动FastDFS服务,使用python客户端对接fastdfs完成上传测试
- 我对java的理解(二)——反射是小偷的万能钥匙
- 【Oracle】恢复临时表空间数据文件
- SilverLight学习笔记--进一步学习Isolated Storage独立存储一(理论篇)
- pythotn基础篇——条件分支与循环--1
- DoIP协议:通用DoIP首部否定确认码02和03的区别
- PDF转图片实现方式
- KETTLE、spoon使用
- 被 onnx.checker.check_model 检查出的常见错误
- Linux 系统硬盘MBR转换为GPT格式并扩容
- Cheapest Flights Within K Stops
- pg之使用pg_upgrade进行大版本升级
- JAVA 7z Seven Zip 压缩和解压文件
- [感动]知道我为什么喜欢SUPER JUNIOR吗?
- 西门子plc与oracle报文,西门子PLC以太网 通讯协议 解析
- 国产的开源电子表格web网页电子表格
- 云原生(CloudNative)将成为应用云化开发的主流方式
- 宝塔面板可以建立静态网站吗?如何部署一个静态页面?
- 移动社交应用里,微创新、新奇趣可能都只是创新陷阱(虎嗅网)
热门文章
- mysql fulltext搜索_mysql 全文搜索 FULLTEXT
- 51单片机喇叭c语言,c51单片机io口直接驱动喇叭,播放《挥着翅膀的女孩》.....
- 换脸插件 php,换脸系列——整脸替换
- 几种常见的ViewResolver视图解析器
- 计算机房的英语的手写体,初二英语旅游加中文日记_事故现场_划痕
- VS2013安装 图文教程
- 人的一生应该有三段婚姻
- GBase8s连接方式
- 临期食品创业的风口已悄然来临
- 离散数学——全序/偏序关系及应用