likes
comments
collection
share

PostgreSQL 源码级调试理解 Btree 查找

作者站长头像
站长
· 阅读数 7

前言

下载安装

下载

笔者使用的 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 以及其他相关依赖,请结合命令报错采取相应的处理

查看安装目录

PostgreSQL 源码级调试理解 Btree 查找

启动

首先创建 pg 启动需要的目录。注意下面的命令都在 pghome2 目录下执行。

cd pghome2
mkdir data

初始化 data 目录

./bin/initdb -D data

PostgreSQL 源码级调试理解 Btree 查找

修改配置文件,我将端口改成 5433,因为本地有其他的 pg 服务。

vim data/postgresql.conf

PostgreSQL 源码级调试理解 Btree 查找

启动服务

bin/pg_ctl -D data -l logfile start

PostgreSQL 源码级调试理解 Btree 查找

初始化数据库

首先创建用户

 ## 使用./bin/createuser --help 查看所有参数
./bin/createuser -d  postgres -p 5422 -P

PostgreSQL 源码级调试理解 Btree 查找

测试数据库来源为 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
PostgreSQL 源码级调试理解 Btree 查找

代码调试

接下来将调试 pg 源码,在正式进入调试之前,必须先了解 PG 的进程模型。

PG 进程模型

PG 采用的是多进程模型,即每一个链接对应一个进程。各个进程有不同的角色,负责不同的任务。使用 pstree 工具查看 PG 的进程。各个进程的职责可以参考 2.1. Process Architecture :: Hironobu SUZUKI @ InterDB。现在主要关注 pid 为 98759 的进程,它主要负责我们客户端连接并且执行查询工作。

PostgreSQL 源码级调试理解 Btree 查找

也可以使用命令查询当前客户端对应的服务端进程 id

select pg_backend_pid();
PostgreSQL 源码级调试理解 Btree 查找

源码调试

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

PostgreSQL 源码级调试理解 Btree 查找

接着设置一下客户端超时时间,避免由于服务端 debug 导致客户端超时。

show statement_timeout;

set statement_timeout to 6000000;
PostgreSQL 源码级调试理解 Btree 查找
select * from bookings where book_ref = '65BECA';

在前面的文章提到 BTree 的搜索路径为 290-> 289 -> 287,那么函数 _bt_search 的返回栈就是 287-> 289 -> 290。

在代码中打上断点,如下

PostgreSQL 源码级调试理解 Btree 查找

在终端中运行 select * from bookings where book_ref = '65BECA';,在 CLion 中可以看到

PostgreSQL 源码级调试理解 Btree 查找

由于 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,也可以与前文理论分析内容相互验证。

PostgreSQL 源码级调试理解 Btree 查找

下图可视化查找路径与源码调试结果相同

PostgreSQL 源码级调试理解 Btree 查找

在编号为 289 的叶中显示得有问题,根据插件 pageinspect 显示,第一项应为 page high key,值为 CA5FE3,指向的是编号为572的页,第二项为空白值,指向的是编号为286的页。

PostgreSQL 源码级调试理解 Btree 查找

我修复这个 bug,见 fix page high bug about parent page and report bug about leaf page by yoa1226 · Pull Request #2 · louiseGrandjonc/pageinspect_inspector (github.com)

如图在编号为 289 的叶中,参照上面图片 page high key空白 key 都正常显示。最后 Btree 的查找路径是 (290,2)-> (289,3) -> (287,?)。

PostgreSQL 源码级调试理解 Btree 查找

总结

衔接前文,本文主要介绍了 PG 源码的安装、初始化和 BTree 查找的源码调试。

参考资料

  1. PostgreSQL: Documentation: 16: Chapter 17. Installation from Source Code

  2. clion调试postgresql - 邱明成 - 博客园 (cnblogs.com)

  3. 2.1. Process Architecture :: Hironobu SUZUKI @ InterDB

  4. louiseGrandjonc/pageinspect_inspector: A little tool to display your postgres BTree indexes in an html using pageinspect data (github.com)