前言
话接前文从 PostgreSQL 源码深入理解 BTree 索引 - 掘金 (juejin.cn),本文首先介绍 PG 的源码安装及初始化,其次介绍 Btree 查找的源码调试,最后验证源码分析的 Btree 查找路径与源码调试的实际路径相同。
下载安装
下载
笔者使用的 Mac OS 的系统,如果读者使用其他的系统,与本文不兼容的地方请在网上查阅相关资料。下载源码。
shell
## 从 github 下载源码
git clone git://git.postgresql.org/git/postgresql.git
## 切换到最新稳定分支
git checkout REL_16_STABLE
安装
注意下面的命令都在源码目录执行
shell
## --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 目录下执行。
shell
cd pghome2
mkdir data
初始化 data 目录
shell
./bin/initdb -D data

修改配置文件,我将端口改成 5433
,因为本地有其他的 pg 服务。
bash
vim data/postgresql.conf

启动服务
bash
bin/pg_ctl -D data -l logfile start

初始化数据库
首先创建用户
shell
## 使用./bin/createuser --help 查看所有参数
./bin/createuser -d postgres -p 5422 -P

测试数据库来源为 demo-small-en。解压缩文件之后使用下面命令导入到数据库。
shell
## 使用./bin/psql --help 查看所有参数
./bin/psql -p 5433 -f demo-small-en-20170815.sql -U postgres
使用下面的命令连接到数据
bash
./bin/psql demo_small -U postgres -p 5433

代码调试
接下来将调试 pg 源码,在正式进入调试之前,必须先了解 PG 的进程模型。
PG 进程模型
PG 采用的是多进程模型,即每一个链接对应一个进程。各个进程有不同的角色,负责不同的任务。使用 pstree
工具查看 PG 的进程。各个进程的职责可以参考 2.1. Process Architecture :: Hironobu SUZUKI @ InterDB。现在主要关注 pid 为 98759 的进程,它主要负责我们客户端连接并且执行查询工作。
也可以使用命令查询当前客户端对应的服务端进程 id
csharp
select pg_backend_pid();

源码调试
使用 CLion: A Cross-Platform IDE for C and C++ by JetBrains 打开 PG 项目目录,使用 attach to process
功能,找目标进程。注意下文的进程号不是前文说的 98759,是因为客户端重新连接了。

接着设置一下客户端超时时间,避免由于服务端 debug 导致客户端超时。
ini
show statement_timeout;
set statement_timeout to 6000000;

接下来以 从 PostgreSQL 源码深入理解 BTree 索引 - 掘金 (juejin.cn) 提到的查询为例。
sql
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 参数中。
c
// 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 查找的源码调试。