
MongoDB 源码树中的 μpbgRPC 内嵌的轻量级 C 版 Protocol Buffers 运行时【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongoμpb常写作 upb是一个用 C 编写的、体积小巧且解析速度接近 protobuf C 实现的 Protocol Buffers 运行时它是 Ruby、PHP、Python 官方 protobuf 语言扩展的核心运行库。在 MongoDB 仓库中upb 并非被 mongod 直接消费而是作为 gRPC 的第三方依赖随源码一并分发位于 upb 根目录 下。读完本篇你将理解 upb 与 protobuf C 的能力差异、它在本仓库源码树中的模块组织与构建方式尤其是“amalgamation”单文件合并构建以及使用它的稳定性边界与注意事项。一、upb 定位C 语言实现的 protobuf 核心运行时根据 upb/README.md 的说明upb 是一个用 C 语言实现的 protobuf 库其角色定位是“protobuf 语言扩展的核心运行时”——Ruby、PHP 和 Python 的 protobuf 实现均链接 upb 作为底层编解码引擎而 C 实现使用 Google 官方的 protobuf 库。一个关键的稳定性事实必须在使用前明确upb 的 C API 与 C ABI 均不稳定not stable且官方没有发布版本no releases。官方因此不推荐把它作为 C 库直接对外消费它的主要消费路径是经由 RubyGemsgoogle-protobuf包、PECLprotobuf扩展和 PyPIprotobuf包这些语言层封装来使用。在 MongoDB 仓库的语境下这一点意味着 upb 源码随 gRPC 第三方树冻结在某一具体形态其内部接口不应被本仓库其他代码直接依赖。二、能力矩阵upb 支持什么、独有的是什么、缺什么README 给出了 upb 与 protobuf C 的能力对比完整继承如下并结合本仓库源码目录印证各能力的落点与 protobuf C 相当的能力速度与 protobuf C 相当但代码体积约为其十分之一an order of magnitude smaller in code size。生成的 C APIprotoc可为 upb 生成 C 代码生成代码依赖的公共支持头文件即 generated_code_support.h它集中 re-exports 了upb/message/accessors.h、upb/message/map_gencode_util.h、upb/mini_table/*与upb/wire/decode.h/encode.h等符号——这解释了“生成代码几乎零依赖”的紧凑设计。反射reflection由 reflection/ 目录提供upb_FileDef、upb_MessageDef、upb_FieldDef等定义类型。二进制与 JSON 线格式二进制解析/序列化在 wire/含decode.c、encode.c、reader.c、byte_size.cJSON 在 json/decode.c、encode.c。文本格式序列化TextFormat serialization由 text/ 目录实现。protobuf 全部标准特性oneofs、maps、unknown fields、extensions 等。map 的存储实现见 message/map.c 与 message/map.h。完整的 conformance 一致性upb 通过了 protobuf 官方一致性测试套件本仓库中对应 conformance/conformance_upb.c 这个一致性测试驱动。upb 独有C 实现没有的能力可选反射optional reflection生成的消息代码与“链接时是否带反射”完全解耦可以只链接 mini_table 不链接 reflection进一步压缩体积。无全局状态no global state没有 pre-main 的静态注册、没有任何全局状态。这与 protobuf C 依赖静态对象在main之前注册 descriptor 的模式截然不同也使其天然适合多线程与嵌入式场景。快速反射解析fast reflection-based parsing运行时动态加载 descriptor 的消息解析速度与编译期内建generated消息一样快。upb 明确不支持的能力文本格式解析TextFormat parsing只能输出文本格式不能解析文本格式。深度 descriptor 校验upb 的 descriptor 校验不如protoc全面deep descriptor verification 缺失。从源码结构看这两个短板与仓库布局相互印证text/ 目录中序列化encode 侧实现完整而解析侧没有对应模块conformance/下附带的 conformance_upb_failures.txt 仅记录了 2 条 JSON 输入相关的已知失败用例Int32 科学计数法引号值、无 type 的 Any侧面说明其线格式兼容性接近完备。三、源码树中的模块组织upb 在本仓库中位于src/third_party/grpc/dist/third_party/upb/upb/顶层 BUILD 文件用 alias 暴露了各模块库。按职责划分目录职责代表性文件base/基础原语状态码、string_view、upcaststatus.c、string_view.h、upcast.hmem/内存分配与 arenaalloc.c、arena.cport/平台可移植层原子操作、编译器特性开关atomic.h、def.inchash/字符串/整数哈希表str_table.h、int_table.hlex/词法解析atof/atoi/unicodeatoi.c、strtod.c、unicode.cwire/二进制线格式读写decode.c、encode.c、reader.h、eps_copy_input_stream.hjson/JSON 编解码decode.c、encode.ctext/文本格式序列化序列化实现与测试message/消息存储、map、拷贝/比较/合并message.c、map.c、copy.c、merge.cmini_descriptor/编译期压缩 descriptor 的解码与链接decode.c、link.cmini_table/无反射的轻量消息表字段/枚举/扩展定义field.h、message.h、extension_registry.creflection/运行时反射定义def_pool.c、message_def.c、file_def.cio/流式 I/O分块输入/输出流、tokenizerchunked_input_stream.c、tokenizer.cconformance/protobuf 官方一致性测试驱动conformance_upb.cutil/调试/转换工具def_to_proto等bazel/构建规则amalgamation 单文件合并amalgamation.bzl、amalgamate.pycmake/CMake 构建支持构建定义与过期检查其中mini_table与reflection的分层正是“可选反射”特性的物理体现生成代码只依赖mini_table中的字段/枚举/文件静态定义是否再叠加reflection由链接期决定。io/README.md 亦说明io子目录最初是 C 版protobuf/io的 C 近似移植注释可能仍引用 C 符号名。四、线格式解析实现细节无界检查的快速路径从 wire/reader.h 的接口设计可以看到 upb “快”的来源。其头注释L19-L23明确说明upb_WireReader配合upb_EpsCopyInputStream做缓冲所有解析例程都假定缓冲区中至少有kUpb_EpsCopyInputStream_SlopBytes字节的余量从而可以在读 tag、varint、fixed32/fixed64 时完全省略逐字节的边界检查// Parses a tag into tag, and returns a pointer past the end of the tag, or // NULL if there was an error in the tag data. // // REQUIRES: there must be at least 10 bytes of data available at ptr. // Bounds checks must be performed before calling this function, preferably // by calling upb_EpsCopyInputStream_IsDone(). UPB_FORCEINLINE const char* upb_WireReader_ReadTag(const char* ptr, uint32_t* tag);对应实现在 wire/reader.hupb_WireReader_ReadTag要求调用点至少有 10 字节可用恰好覆盖最长 varint直接委托内联的_upb_WireReader_ReadVarint完成upb_WireReader_ReadFixed32/ReadFixed64用memcpy 条件字节序翻转处理大小端。upb_WireReader_SkipGroup还带有depth_limit递归深度限制用于防止畸形 group 数据打爆栈。这种“用缓冲区冗余换掉热路径分支”的策略是 upb 在不牺牲安全性的前提下逼近 C 实现速度的核心工程手段。五、构建体系amalgamation 单文件合并与语言专用构建upb 面向多语言宿主分发其标志性构建产物是amalgamation单文件合并库把整个运行时压成一个.c 一个.h。在顶层 BUILD 中可以看到三套合并目标gen_amalgamationL227-L266产出upb.c/upb.h供 Rust 绑定等消费gen_php_amalgamationL276-L316产出php-upb.c/php-upb.h符号前缀php-供 PHP 扩展链接gen_ruby_amalgamationL326-L366产出ruby-upb.c/ruby-upb.h符号前缀ruby-供 Ruby gem 链接。合并规则实现在 bazel/amalgamation.bzlupb_amalgamation规则通过 aspect 收集依赖库的全部.c/.h源文件剔除.hpp再调用 bazel/amalgamate.py 把它们内联成一个文件同时支持strip_import_prefix归一化 include 路径与符号前缀。这与 README 中“为 Ruby/PHP/Python 各自内嵌一份 upb”的分发方式完全对应——每个语言包拿到的都是一份带独立符号前缀的自包含 C 库避免宿主机符号冲突。BUILD 中还定义了一个fasttable_enabled布尔构建开关默认关闭并导出UPB_DEFAULT_COPTS编译选项集合用于控制生成代码与运行时的编译行为。六、安装与使用途径README 给出的官方消费途径针对 upb 项目本体而非本仓库如下Ruby通过 RubyGems 安装官方 protobuf 包其运行时内嵌 upb$ gem install google-protobufPHP通过 PECL 安装 protobuf 扩展$ sudo pecl install protobufPython通过 PyPI 安装 protobuf 包$ sudo pip install protobufC/C 侧vcpkg也可以把 vcpkg 依赖管理器作为 CMake 工程接入依次执行引导脚本、集成 MSBuild 等工具链、然后安装upb端口./bootstrap-vcpkg.sh ./vcpkg integrate install ./vcpkg install upbvcpkg 中的 upb 端口由上游团队与社区维护者同步更新版本滞后时应向 vcpkg 仓库提交 issue 或 PR 跟进。需要再次强调使用边界由于 C API/ABI 不稳定且无正式 release直接以 C 库形式链接 upb 的下游不享有向后兼容承诺。在本仓库MongoDB中upb 的恰当使用姿势是把它当作 gRPC 第三方依赖树中不可分割的一部分整体看待单独引用其内部头文件不在受支持的用法之内。七、小结upb 在 MongoDB 仓库中随 gRPC 源码树分发位于src/third_party/grpc/dist/third_party/upb/upb/。它以 C 语言提供速度接近 protobuf C 而体积约为其十分之一的 protobuf 运行时具备可选反射、零全局状态、反射解析与生成代码同速三大独特能力并完整支持 oneof/map/unknown fields/extension 与官方一致性测试conformance_upb_failures.txt 仅余 2 条已知失败。理解它的关键在于三点模块与构建特征mini_table与reflection分层支撑可选反射wire/的余量缓冲策略消除热路径边界检查amalgamation 规则按语言生成符号前缀化的单文件库。对仓库阅读者而言掌握这些结构后即可在 gRPC 相关构建问题如 amalgamation 产物缺失、语言绑定链接问题中快速定位 upb 侧的实现与构建逻辑。【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考