pg_pathman代码结构全解析20个核心C源文件如何分工planner hook机制是怎样运作的【免费下载链接】pg_pathmanPartitioning tool for PostgreSQL项目地址: https://gitcode.com/gh_mirrors/pg/pg_pathmanpg_pathman 是一款为 PostgreSQL 提供高性能表分区Partitioning能力的扩展它通过 RANGE / HASH 两种分区方案把一张大表拆分成若干小表并借助 planner hook 让优化器直接跳过不相关的分区。本文带你快速读懂它的代码骨架20 多个核心 C 源文件各自负责什么、planner hook 是如何被挂载和触发的帮助新手在 1 小时内建立完整的项目地图 ️一、项目目录速览代码都放在哪里整个扩展的 C 语言实现集中在src/目录下结构非常清晰src/ ├── *.c # 22 个核心源文件 ├── include/ # 每个 .c 文件对应的头文件 └── compat/ # 跨 PostgreSQL 版本的兼容层 ├── pg_compat.c └── rowmarks_fix.c所有公共函数声明都在 include 目录 中主头文件是 pathman.h不同 PostgreSQL 版本1115的 API 差异由 compat/pg_compat.c 统一封装核心代码里几乎看不到#ifdef PG_VERSION_NUM每个子模块的入口头文件如 hooks.h、relation_info.h都是理解对应模块的最佳起点二、20个核心C源文件如何分工6大子系统22 个核心源文件可以归为6 个职责鲜明的子系统这种按功能域切分的组织方式是 PostgreSQL 扩展开发的经典范例。1️⃣ 计划阶段Planner分区裁剪的大脑文件行数职责pg_pathman.c2513扩展主文件设置计划、遍历 WHERE 条件树提取分区键、生成 Append 类路径hooks.c1240所有 hook 函数的定义是插件与 PostgreSQL 内核的接线板planner_tree_modification.c1211改写查询树/计划树如替换基表 RTE、插入自定义节点init.c1172扩展初始化共享内存注册、_PG_init、配置加载2️⃣ 自定义执行节点Custom Nodes执行阶段的核心文件行数职责nodes_common.c940自定义节点的公共代码状态初始化、参数传递partition_filter.c1640PartitionFilter节点替代触发器在 INSERT 时精确路由行partition_router.c771PartitionRouter节点跨分区 UPDATE 时把行路由到目标分区partition_overseer.c189PartitionOverseer节点监督跨分区更新的锁与提交runtime_append.c148RuntimeAppend节点运行时按参数值动态选择分区runtime_merge_append.c941RuntimeMergeAppend节点保持有序输出的运行时追加3️⃣ 分区管理Partition Management建表与迁移文件行数职责partition_creation.c2057分区创建的全部逻辑RANGE 边界计算、CHECK 约束生成pathman_workers.c964后台 Worker异步创建新分区、执行并发分区化pl_funcs.c1259SQL 可调用的通用 C 函数管理分区的存储过程pl_range_funcs.c1407RANGE 分区专用存储过程实现pl_hash_funcs.c158HASH 分区专用存储过程实现4️⃣ 元数据与数据结构文件行数职责relation_info.c1737分区关系元数据共享内存中缓存每个分区的边界信息rangeset.c413IndexRange区间集合算法RANGE 分区查找的基础二分搜索utils.c540通用工具函数5️⃣ 语句拦截与事务处理文件行数职责utility_stmt_hooking.c954拦截COPY、ALTER TABLE ... RENAME等工具语句xact_handling.c214事务级锁管理跨分区写操作的并发控制declarative.c382与 PostgreSQL 10 原生声明式分区的互操作6️⃣ 调试与兼容文件行数职责debug_print.c106把复杂结构体打印为字符串方便log_min_messages调试compat/pg_compat.c654PostgreSQL 各版本 API 差异的兼容封装compat/rowmarks_fix.c54修复原生内核中RowMark生成的小缺陷阅读建议想快速上手按init.c → relation_info.c → pg_pathman.c → hooks.c的顺序读即可这四条线覆盖了初始化 → 元数据 → 计划 → 挂载的完整生命周期。三、planner hook机制是怎样运作的一条SQL的完整旅程pg_pathman 的全部魔法都建立在 PostgreSQL 的hook 机制上——内核在关键流程中预留了函数指针扩展只需赋值就能插入自己的逻辑。所有 hook 声明集中在 include/hooks.h 中。挂载方式钩子链Hook Chaining每个 hook 都会保存上一个值如pathman_planner_hook_next调用完自己的逻辑后再转交给前一个插件从而保证多个扩展可以共存这是官方推荐的多插件友好写法。一次 SELECT 的分区裁剪全流程以SELECT * FROM test WHERE id 150为例SQL 语句 │ ▼ ① pathman_planner_hook (hooks.c 第738行) │ 前置处理处理继承表/视图场景随后调用 standard_planner ▼ ② standard_planner 内部 │ 内核走到 set_rel_pathlist_hook → pathman_rel_pathlist_hook │ (hooks.c 第319行) ▼ ③ walk_expr_tree (pg_pathman.c) │ 遍历 WHERE 条件树寻找 分区键 OP 常量 形式 │ 如 id 150、id BETWEEN 100 AND 200 ▼ ④ select_range_partitions (pg_pathman.c) │ 基于共享内存中缓存的分区边界做二分搜索 │ 直接命中 test_1id ∈ [100,200)跳过 test_2 ▼ ⑤ 生成路径Append / MergeAppend │ 参数化查询则生成 RuntimeAppend执行时再选分区 ▼ ⑥ 连接场景走 pathman_join_pathlist_hook (hooks.c 第84行) 生成分区表之间的 Join 路径关键设计点元数据预缓存pathman_shmem_startup_hookhooks.c 第 958 行在共享内存中缓存所有子分区的边界避免每次计划都扫系统表——这正是分区数量上千时 pg_pathman 仍快的原因条件树遍历pg_pathman.c 中的walk_expr_tree支持AND/OR、IN 数组、BETWEEN等复合条件把每个可解析的条件转成区间查询运行时兜底当 WHERE 值依赖运行时参数如游标、子查询时规划期无法裁剪于是RuntimeAppend节点在执行期按实际值动态打开分区用极小的代价保住正确性写操作也走 hookpathman_process_utility_hook拦截工具语句pathman_executor_start_hook第 1228 行在 DML 启动前注入PartitionFilter/PartitionRouter节点四、常见问题新手最容易困惑的 3 个点Q1为什么文件头几乎看不到版本宏因为版本差异被集中到了 compat/pg_compat.c核心业务代码保持干净这让维护 PG 1115 多版本成为可能。Q2pl_*前缀是 PL/pgSQL 吗不是。pl在这里指planner计划阶段pl_funcs.c系列是供 SQL 存储过程调用的 C 函数即create_partition等管理命令的实现而 SQL 层入口见 init.sql。Q3项目还在开发吗README 明确标注pg_pathman 已停止新功能开发原生分区已足够成熟但仍在维护 PG 1115 的 bug 修复新生产环境建议评估原生声明式分区。五、总结一份带走的项目地图想懂分区怎么选→ 读 pg_pathman.c 的条件树遍历 rangeset.c 的二分查找想懂如何挂载插件→ 读 hooks.c 的 7 类 hook 与钩子链写法想懂INSERT/UPDATE 如何路由→ 读 partition_filter.c 与 partition_router.c想懂分区如何自动创建→ 读 partition_creation.c 与 pathman_workers.c 的后台 Worker 模式pg_pathman 虽已功成身退但它hook 自定义执行节点 共享内存缓存的组合拳至今仍是学习 PostgreSQL 扩展开发的最佳教材之一 【免费下载链接】pg_pathmanPartitioning tool for PostgreSQL项目地址: https://gitcode.com/gh_mirrors/pg/pg_pathman创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考