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)

相关推荐
LucianaiB几秒前
王炸组合!腾讯云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!
后端
白露与泡影4 分钟前
探索springboot程序打包docker的最佳方式
spring boot·后端·docker
开心就好20256 分钟前
本地执行 IPA 混淆 无需上传致云端且不修改工程的方案
后端·ios
架构师沉默20 分钟前
为什么一个视频能让全国人民同时秒开?
java·后端·架构
٩( 'ω' )و26022 分钟前
MySQL基础
数据库·mysql
生命不息战斗不止(王子晗)28 分钟前
mysql基础语法面试题
java·数据库·mysql
知识分享小能手39 分钟前
MongoDB入门学习教程,从入门到精通,MongoDB应用程序设计知识点梳理(9)
数据库·学习·mongodb
Titan202440 分钟前
map和set的封装学习笔记
数据结构·c++
一直都在5721 小时前
Redis (一)
数据库·redis·缓存
掘金码甲哥1 小时前
同样都是九年义务教育,他知道的AI算力科普好像比我多耶
后端