深入解读 MongoDB 内置 WiredTiger 的 C/C++ 编码规范与贡献流程
【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo
WiredTiger 是 MongoDB 默认的存储引擎,其完整源码以第三方库形式内嵌于本仓库的 src/third_party/wiredtiger 目录中。本文以该目录下的 CONTRIBUTING.rst 为骨架,系统梳理 WiredTiger 的社区贡献流程、C 与 C++ 双编码规范、命名体系、注释约定以及自动化校验工具s_all的用法,并结合仓库内真实源码给出可验证的示例,帮助你在向 WiredTiger 提交 PR 前写出风格统一、易于审查的代码。
读完本文,你将掌握:WiredTiger 的 PR 提交入口与 Jira 工单规则、C 代码必须遵守的缩进/命名/注释/错误处理约定、FIXME-WT-XXXX与自动旗标宏的用法,以及如何运行dist/s_all在本地完成提交前的一站式风格校验。
WiredTiger 项目与贡献入口
WiredTiger 12.0.0 版本随 MongoDB 一并分发,源码中附带的 README 明确了项目事实:完整源码与文档发布在 WiredTiger 官方网站,问题管理统一使用 WiredTiger 的 Jira 实例(issue 前缀为WT),并且不通过 GitHub Issues 报告问题。
CONTRIBUTING.rst 开篇即表明态度:Pull requests 永远欢迎,WiredTiger 开发团队感激社区提供的任何帮助。关于贡献细节(提交 PR 前的完整流程、代码评审要求等),文档要求参考 WiredTiger Wiki 上专门的 "Contributing to WiredTiger" 页面。
从仓库结构看,WiredTiger 的工程化程度相当高,dist/目录下集中了数十个配套的检查与生成脚本(如s_clang_format、s_style、s_whitespace、s_define、s_docs、s_export等),配合dist/s_all一键执行全部预提交校验,这一点在后文专门展开。
为什么需要 C 与 C++ 两套编码风格
WiredTiger 对 C 和 C++ 分别维护编码规范,核心原因是:C 中很多合理甚至必要的写法,在 C++ 里恰恰是糟糕实践(bad practice)。例如 C 里常见的宏封装、void *自由转换、手工错误码传递等,在 C++ 中都有更安全的替代方案,强行套用反而掩盖问题。
具体分工如下:
- C:WiredTiger 存储引擎主体,全部由 C 编写;
- C++:面向开发者的辅助工具,例如
cppsuite(C++ 测试套件)与workgen(负载生成工具)。
因此评审代码时,先确认目标文件属于引擎主体(C)还是工具(C++),再套用对应的规范,而不是笼统地用同一把尺子。
WiredTiger C 编码规范全解
文档明确指出:C 编码标准“松散地”基于 K&R 缩进风格,并交由Clang-Format统一格式化,因此下面列出的规则主要服务于人工阅读与命名纪律。遇到规则没有覆盖的模糊地带,最好的做法是在源码里找一个现成例子照抄——这是 WiredTiger 官方给出的建议,也说明仓库源码本身就是规范的最佳范本。
缩进、空白与字符集
- 缩进一律使用空格而非制表符 Tab;
- 行尾不得残留空白字符(trailing whitespace);
- 源文件只允许7-bit ASCII字符;
- 换行缩进(re-indent)固定为2 个空格;
- 行宽上限100 字符,换行时在运算符之后断开。
上述 100 列与 2 空格续行缩进在仓库根目录的 .clang-format 中得到印证:ColumnLimit: 100、ContinuationIndentWidth: 2,同时UseTab: Never强制禁 Tab、PointerAlignment: Right将指针星号靠右对齐,与文档中“指针右对齐”的示例一致。
声明顺序与字母序
凡是成组的声明都应尽量按字母序排列,包括局部变量、旗标(flags)、统计字段(stat fields)等。文档给出的函数内声明顺序是:先放struct变量声明,再放WT_*结构声明,且WT_*之间按字母序:
struct timeval start, end; WT_CKPT *ckpt; WT_CONNECTION_IMPL *conn;这一约定在真实源码中随处可见,例如 btmem.h 中WT_READ_*旗标宏按字母序连续排列。
注释规范
注释是 WiredTiger 风格检查的重点,要求如下:
- 描述预期功能(intended functionality),而非记录已发生的事;
- 尽量不引用变量名;
- 不得引用已关闭的 Jira 工单号,也不得引用 PR 编号;
- 描述缺陷或改进机会时,使用
FIXME-WT-XXXX关键字,且必须对应一个仍处于打开状态的 WiredTiger Jira 工单;工单一旦关闭,就要移除或重新定向该注释; - 必须写成完整句子;
- 使用 C 风格
/* ... */注释,禁止C++ 风格的//双斜杠注释; - 单行注释的定界符与正文同行;多行注释的定界符独占一行,且正文每行以星号开头:
/* This is a valid comment. */ // This is not a valid comment. /* * This is a valid * multi-line comment. */ // This is not a // valid multi-line comment.FIXME-WT-XXXX约定在源码中有大量真实落点,例如 block_open.c 的FIXME-WT-5832、block_cache.c 的FIXME-WT-15663、block_io.c 的FIXME-WT-14608。配套的 s_outdated_fixmes.py 脚本会专门扫描这些引用是否已失效,形成“写注释—工单绑定—自动校验”的闭环。
函数头注释与字段注释
每个函数定义之前都必须有固定格式的头注释:
/* * __wt_foo -- * One-sentence description of what the function does. */ int __wt_foo(WT_SESSION_IMPL *session, ...)要点:函数名独占一行,后跟空格和--;描述正文相对星号缩进 4 个空格(即文本起始于第 8 列);多个段落之间用独立的*空行分隔。
结构体与 typedef 字段的注释采用行尾短名词短语:
uint32_t id; /* File ID, for logging */ const char *key_format; /* Key format */分组级别的说明应放在结构体上方或字段组上方的块注释中,永远不要放在单个字段之上。另外,版权块与第一个#include之间不得放置任何文件级总览注释。
旗标定义区间
旗标宏定义必须包裹在自动生成标记对之间:
/* AUTOMATIC FLAG VALUE GENERATION START 0 */ #define WT_READ_CACHE 0x00001u ... /* AUTOMATIC FLAG VALUE GENERATION STOP 32 */真实例子见 btmem.h,dist/flags.py等生成脚本会维护这段区间内的位值,手工添加或修改其中的宏都会与自动生成逻辑冲突。
命名体系:前缀即作用域
WiredTiger 通过前缀精确表达符号的可见范围,这是理解其代码库的关键地图:
| 前缀 | 作用域 | 示例 |
|---|---|---|
wiredtiger | 公开 API 函数 | wiredtiger_open |
WT_ | 公开的宏与结构体 typedef | WT_ERR、WT_SESSION |
__wt_ | 跨文件、跨子系统使用的内部函数 | __wt_cursor_set_key |
__wti_ | 同一子系统目录内、跨文件使用的内部函数 | 各子系统内共享函数 |
__(双下划线) | 静态函数 | 子系统内部私有函数 |
__wt_与__wti_中的“前缀”是子系统标识符(如log、btree)。以__wt_cursor_set_key为例,它在 cur_backup_incr.c 等跨目录文件中被调用,符合“跨文件跨子系统使用__wt_”的规则。
同时,命名空间隔离还要求避免与应用程序代码和系统头文件冲突:公有 API 以wiredtiger开头,公有宏/类型以WT_开头,私有函数以__wt_开头。
函数签名与返回值约定
函数声明中返回值独占一行,函数名顶到左边界:
int __wt_square(int x) { return (x * x); }输出参数命名以p结尾,且放在参数列表末尾:
static inline void __ref_index_slot(WT_SESSION_IMPL *session, WT_REF *ref, WT_PAGE_INDEX **pindexp, uint32_t *slotp)返回指针填充约定:若函数通过输出参数返回指针(如WT_FH **fhpp),且成功路径上总会填充该指针,则函数开头必须先把它置为 NULL。这样调用方无需自行初始化,也保证失败或异常路径上调用方永远不会读到随机数据。
变量命名与初始化
- 使用描述性变量名与函数名,全小写加下划线分隔;常用 WiredTiger 结构有标准简称:
WT_SESSION/WT_CONNECTION写作wt_session/wt_conn,WT_SESSION_IMPL/WT_CONNECTION_IMPL写作session/conn; - 强烈建议(非强制)在使用处就近声明并初始化变量,把变量作用域压缩到最小;
- 优先“声明即初始化”;若初始化并非必需、只是编译器要求,则用注释
/* -Werror=maybe-uninitialized */标注。
表达式与语句习惯
- 指针与
NULL比较,写(p == NULL),不要写(p == 0)或(!p); - 无限循环用
for(;;),不要用while(true); - 函数返回值用括号包裹:
return (0);; - 单语句的 if/循环不加花括号,除非不加会引发歧义;
- 换行时让后续行尽可能更长(successive lines are longer if possible),函数签名同样适用;拿不准就交给 Clang-Format 处理。
错误处理的两段式风格
文档给出了错误处理的两种标准形态,这是 WiredTiger 代码中最具辨识度的模式:
情形一:失败与非失败路径有共享代码,采用if (0) { err: ... }模式:
if (0) { err: <non-shared fail code> } <shared fail/non-fail code> return (ret);情形二:失败与非失败路径无共享代码,采用跳转标签直落模式:
<non-fail code> return (0); err: <fail code> return (ret);注意情形二中没有if (0)包装,直接以err:标签结束失败分支。结合WT_ERR宏(公开命名空间示例)理解,这种“错误码 + 标签跳转”是 WiredTiger 一贯的错误传播方式。
C++ 编码风格(cppsuite 与 workgen)
CONTRIBUTING.rst 明确说明 WiredTiger只为 C 提供独立规范章节,C++ 部分由cppsuite与workgen等工具遵循各自的 C++ 惯例。仓库中 cppsuite 相关源码位于 src/third_party/wiredtiger/test 下的对应子目录,workgen作为基准测试工具同样使用 C++ 实现。撰写 C++ 代码时应遵循通用 C++ 最佳实践,并同样通过 Clang-Format(仓库 .clang-format 的Language: Cpp配置对 C/C++ 一并生效)保证格式一致。
提交前的终极校验:运行 dist/s_all
编码完成后,文档要求运行./s_all脚本(即仓库中的 dist/s_all),它会自动重排代码以贴合规范的大部分要求。文档同时提醒:没有任何工具能检查所有事项——比如“函数名是否足够描述性”,工具就无从判断,最终仍依赖人的审查。
s_all的实际能力远超单纯格式化。从 dist/s_all 脚本源码看,它是一站式预提交套件,内部先串行执行s_version、s_readme、s_install、api_config_gen.py、api_err.py、flags.py、stat.py、s_copyright、s_style、s_clang_format、prototypes.py、s_typedef、ruff_check.py等脚本,再并行跑s_define、s_docs、s_export、s_funcs、s_lang、s_longlines、s_whitespace、s_charset、s_include_guards、s_bazel.py等二十余项检查,覆盖版权头、风格、空白、字符集、函数原型、typedef、导出符号、文档一致性、Python 代码(Ruff)等方方面面。
s_all 命令行选项
| 选项 | 含义 |
|---|---|
-E | 失败时返回非零错误码(适合 CI 集成) |
-f | 强制更新版本号相关文件 |
-F | 快速模式:仅处理从 develop 分支分叉后发生变更的文件 |
--no-interactive | 禁用交互式终端状态显示 |
-h, --help | 显示帮助 |
在本地开发流程中,-F快速模式适合改动较小时使用;提交 CI 前用-E确保脚本失败即报错。运行前置条件包括python3与clang-format,脚本启动时会显式检查两者是否存在。
提交 PR 的完整工作流建议
综合文档与仓库工具链,向 WiredTiger 提交贡献的推荐流程如下:
- 对照本文规范自检:命名(
wiredtiger/WT_/__wt_/__wti_/__)、注释(FIXME-WT-XXXX指向打开中的工单)、错误处理两段式、指针置 NULL 约定; - 运行
dist/s_all:在src/third_party/wiredtiger目录下执行./dist/s_all,或使用./dist/s_all -F快速模式、-E失败即报错模式,修复全部报错项; - 提交 PR:按 WiredTiger Wiki 的贡献指南走完 Pull Request 流程;
- 工单纪律:涉及缺陷/改进点的注释必须绑定打开的 WiredTiger Jira 工单,工单关闭后及时清理对应
FIXME-WT-XXXX注释。
结语
WiredTiger 的贡献规范与其代码库一样追求“机器可解析 + 人类可读”的双重目标:机器层面由dist/s_all与 Clang-Format 完成格式、空白、原型、符号等一切可自动化的检查;人的层面则依靠命名前缀、注释纪律与错误处理模式来传达代码意图。对 MongoDB 开发者而言,这套规范既是贡献 WiredTiger 的门槛,也是阅读 src/third_party/wiredtiger/src 海量引擎源码时最实用的“解码手册”。
【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考