文章目录
- 0.简介
- 1.调试方式
- 2.调试流程
- 3.总结
0.简介
本文主要介绍PG调试方法和PG服务端收到一条SQL后的完整执行流程,对前面各个模块做一个在代码层面的串联(从架构层面协作关系在前面文章已有介绍),后续对PG再继续分析相关功能,有此文章可以更好对应代码中的位置。
1.调试方式
调试方式主要用到gdb:
1)启动PG服务,并获取其pid,获取方式有以下三种,其中真正要调试的进程需要psql连接后才会出现,即pid为108的进程。
#第一种,直接使用ps -ef
ps -ef | grep postgre
#第二种,使用pidof 但是只能看到所有的id
pidof postgres
#第三种,使用sql语句
select pg_backend_pid();
2) 附加到进程
gdb -p 108
#不实际查询,执行简单语句,可以在如下函数打断点
b ExecResult
2.调试流程
执行如下简单语句
select 1;
命中断点后查看堆栈如下:
下面对堆栈过程中的函数来做一些简单说明,从初始的main函数开始:
1)main.c:其中关键的内容有MemoryContextInit(初始化内存管理上下文),set_pglocale_pgservice(根据环境变量设置相应信息),根据参数走到不同的启动模式,本次启动是走到了main.c:228,即PostmasterMain函数。
2)postmaster.c:PostmasterMain函数:初始化内存管理上下文,初始化配置,信号处理,监听socket。进入ServerLoop函数,ServerLoop:循环监听连接请求,有的话fork一个进程去处理,即调用BackendStartup函数,其主要是做一些初始化工作;之后会调用BackRun函数,负责参数信息的初始化和调用PostgresMain函数。
3)postgres.c:PostgresMain函数:初始化环境和参数,设置信号处理函数和其他参数,建立内存上下文,设置share buffer等;然后进入处理循环,循环监听请求(交互过程可以参考通讯协议模块)并处理。exec_simple_query函数:判断语句是简单查询语句会走该部分,其会做一些查询编译和查询执行并返回结果(可以参考查询编译和执行器文章内容)。
4)pquery.c:查询部分,PortalRun函数:查询的入口,负责一个或者一组的查询;PortalRunSelect函数:只能执行简单的查询;然后执行ExecutorRun()函数。
5)execMain.c:该文件就是执行器章节所说的四个函数:ExecutorStart() ExecutorRun() ExecutorFinish() ExecutorEnd(),
ExecutorRun函数:真正执行查询语句,调用standard_ExecutorRun()函数,standard_ExecutorRun函数会调用ExecutePlan()函数,去执行查询计划。
6)execProcnode.c:提供查询计划的调度函数并返回结果元组。
3.总结
以上,就对PG一次简单查询流程的调试做了简要说明,从进程启动,到交互协议,再到查询编译,查询计划执行,节点调度和结果返回进行了代码层级的说明,该查询不涉及元组读取,也就是存储引擎部分和事务部分,这两部分穿插在整体流程的一些判断中,可以根据其功能向流程内对应。