PostgreSQL 源码级调试理解 Btree 查找

前言

话接前文从 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的页。

我修复这个 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,?)。

总结

衔接前文,本文主要介绍了 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)

相关推荐
Asthenia04121 小时前
Spring扩展点与工具类获取容器Bean-基于ApplicationContextAware实现非IOC容器中调用IOC的Bean
后端
bobz9651 小时前
ovs patch port 对比 veth pair
后端
Asthenia04121 小时前
Java受检异常与非受检异常分析
后端
uhakadotcom2 小时前
快速开始使用 n8n
后端·面试·github
JavaGuide2 小时前
公司来的新人用字符串存储日期,被组长怒怼了...
后端·mysql
bobz9652 小时前
qemu 网络使用基础
后端
Asthenia04122 小时前
面试攻略:如何应对 Spring 启动流程的层层追问
后端
Asthenia04122 小时前
Spring 启动流程:比喻表达
后端
Asthenia04123 小时前
Spring 启动流程分析-含时序图
后端
ONE_Gua3 小时前
chromium魔改——CDP(Chrome DevTools Protocol)检测01
前端·后端·爬虫