1,开源pg编译安装
首先下载postgres源码,然后切换成最新的pg15稳定分支,后续源码分析基于pg15。
git clone git@github.com:postgres/postgres.git
git checkout REL_15_STABLE
编译配置,安装可debug版本的pg,安装到/home/pg15/inst目录。
cd postgres
./configure --enable-debug --enable-cassert --prefix=/home/pg15/inst CFLAGS=-O0
make -j all
make install
2,初始化数据目录
配置pg的bin执行文件的环境变量。
vim .bash_profile
PATH=/home/pg15/inst/bin:$PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/pg15/inst/lib
export PATH
source .bash_profile
开始初始化数据目录,data目录安装在/home/pg15/data
initdb -D /home/pg15/data
3,调试数据库
启动数据库后,ps查看相关进程。pg是多进程结构,主进程负责监听新到来的连接,为其创建backend服务进程,每个backend进程对应一个连接。checkpointer进程负责执行checkpoint,具体过程为刷脏页,刷wal日志,然后创建检查点,以供回收xlog日志文件。walwriter进程负责后台异步的刷wal日志。autovacuum launcher进程负责启动autovacuum进程,logical replication launcher进程负责启动逻辑复制进程。
pg15 12420 0.0 0.0 277884 13424 ? Ss 19:54 0:00 /home/pg15/inst/bin/postgres -D data
pg15 12421 0.0 0.0 278032 1084 ? Ss 19:54 0:00 \_ postgres: checkpointer
pg15 12422 0.0 0.0 278016 1084 ? Ss 19:54 0:00 \_ postgres: background writer
pg15 12424 0.0 0.0 278016 1080 ? Ss 19:54 0:00 \_ postgres: walwriter
pg15 12425 0.0 0.0 279500 2108 ? Ss 19:54 0:00 \_ postgres: autovacuum launcher
pg15 12426 0.0 0.0 279484 1856 ? Ss 19:54 0:00 \_ postgres: logical replication launcher
下面调试一下psql连接数据库的时候主进程fork出backend进程的流程(多进程调试)。
1.gdb住主进程
gdb挂住12420,然后让放行相关的信号,不调试信号处理函数
gdb -p 12420
handle SIGUSR1 nostop
handle SIGUSR2 nostop
handle SIGTRAP nostop
handle SIGUSR1 noprint
handle SIGUSR2 noprint
handle SIGTRAP noprint
2.另起一个backend连接数据库
psql postgres连接数据库
3.gdb主进程
首先,主进程执行select函数会返回一个1,表示有一个连接到来,然后会执行到fork_process,开始fork一个子进程出来。
#0 fork_process () at fork_process.c:45
#1 0x00000000008c5563 in BackendStartup (port=0x19b20a0) at postmaster.c:4215
#2 0x00000000008c1bae in ServerLoop () at postmaster.c:1806
#3 0x00000000008c1485 in PostmasterMain (argc=3, argv=0x198ad00) at postmaster.c:1478
#4 0x00000000007c69ae in main (argc=3, argv=0x198ad00) at main.c:202
然后要调试子进程,需要执行set follow-fork-mode child,表示跟着子进程调试,默认是父进程。当pid返回0的时候,就表示当前是子进程,为有效的话,就是父进程。
至此,backend进程就等待psql客户端发起sql再处理。
(gdb) bt
#0 ReadCommand (inBuf=0x7ffc231ca310) at postgres.c:473
#1 0x0000000000987f9d in PostgresMain (dbname=0x13f47d8 "postgres", username=0x13f47b8 "pg15") at postgres.c:4525
#2 0x00000000008c5c04 in BackendRun (port=0x13ec0a0) at postmaster.c:4511
#3 0x00000000008c55a4 in BackendStartup (port=0x13ec0a0) at postmaster.c:4239
#4 0x00000000008c1bae in ServerLoop () at postmaster.c:1806
#5 0x00000000008c1485 in PostmasterMain (argc=3, argv=0x13c4d00) at postmaster.c:1478
#6 0x00000000007c69ae in main (argc=3, argv=0x13c4d00) at main.c:202
4.gdb用法总结
n:下一行
c:继续执行,直到下一个断点
b:打断点,可函数,行,条件断点(b breakpoint if XX==XX)
watch:值发生变化,就断点
info b:查看断点
d 1:删除第一个断点
set/p:设置值,p有返回再打印,set无打印