PostgreSQL 源码级调试理解 Btree 查找
前言
下载安装
下载
笔者使用的 Mac OS 的系统,如果读者使用其他的系统,与本文不兼容的地方请在网上查阅相关资料。下载源码。
## 从 github 下载源码
git clone git://git.postgresql.org/git/postgresql.git
## 切换到最新稳定分支
git checkout REL_16_STABLE
安装
注意下面的命令都在源码目录执行
## --prefix=/Users/XXX/dev/pghome 指定安装目录
## --enable-debug 执行需要 debug 编译
./configure --without-icu --prefix=/Users/XXX/dev/pghome --enable-debug --enable-depend --enable-cassert
## 编译安装
make && make install
注意:编译时需要 gcc、 make 以及其他相关依赖,请结合命令报错采取相应的处理
查看安装目录
启动
首先创建 pg 启动需要的目录。注意下面的命令都在 pghome2 目录下执行。
cd pghome2
mkdir data
初始化 data 目录
./bin/initdb -D data
修改配置文件,我将端口改成 5433
,因为本地有其他的 pg 服务。
vim data/postgresql.conf
启动服务
bin/pg_ctl -D data -l logfile start
初始化数据库
首先创建用户
## 使用./bin/createuser --help 查看所有参数
./bin/createuser -d postgres -p 5422 -P
测试数据库来源为 demo-small-en。解压缩文件之后使用下面命令导入到数据库。
## 使用./bin/psql --help 查看所有参数
./bin/psql -p 5433 -f demo-small-en-20170815.sql -U postgres
使用下面的命令连接到数据
./bin/psql demo_small -U postgres -p 5433
代码调试
接下来将调试 pg 源码,在正式进入调试之前,必须先了解 PG 的进程模型。
PG 进程模型
PG 采用的是多进程模型,即每一个链接对应一个进程。各个进程有不同的角色,负责不同的任务。使用 pstree
工具查看 PG 的进程。各个进程的职责可以参考 2.1. Process Architecture :: Hironobu SUZUKI @ InterDB。现在主要关注 pid 为 98759 的进程,它主要负责我们客户端连接并且执行查询工作。
也可以使用命令查询当前客户端对应的服务端进程 id
select pg_backend_pid();
源码调试
使用 CLion: A Cross-Platform IDE for C and C++ by JetBrains 打开 PG 项目目录,使用 attach to process
功能,找目标进程。注意下文的进程号不是前文说的 98759,是因为客户端重新连接了。
接着设置一下客户端超时时间,避免由于服务端 debug 导致客户端超时。
show statement_timeout;
set statement_timeout to 6000000;
select * from bookings where book_ref = '65BECA';
在前面的文章提到 BTree 的搜索路径为 290-> 289 -> 287,那么函数 _bt_search
的返回栈就是 287-> 289 -> 290。
在代码中打上断点,如下
在终端中运行 select * from bookings where book_ref = '65BECA';
,在 CLion 中可以看到
由于 287 为叶子节点,由于下面的代码逻辑,它作为传出参数返回给调用者,并不会记录在 stack_in 参数中。
// bufP 作为传出参数申明在方法签名中
*bufP = _bt_moveright(rel, heaprel, key, *bufP, (access == BT_WRITE),
stack_in, page_access, snapshot);
if (P_ISLEAF(opaque))
break;
与理论分析验证
在 debug 截图中编号为 289 页 bts_offset
为 3, 编号为 290 页 bts_offset
为 2,也可以与前文理论分析内容相互验证。
下图可视化查找路径与源码调试结果相同
在编号为 289 的叶中显示得有问题,根据插件 pageinspect
显示,第一项应为 page high key
,值为 CA5FE3
,指向的是编号为572的页,第二项为空白值,指向的是编号为286的页。
如图在编号为 289 的叶中,参照上面图片 page high key
和 空白 key
都正常显示。最后 Btree 的查找路径是 (290,2)-> (289,3) -> (287,?)。
总结
衔接前文,本文主要介绍了 PG 源码的安装、初始化和 BTree 查找的源码调试。