TDengine 中 fast-lzma2 的 Conan 集成指南:从包构建到压缩 API 实战

📅 发布时间:2026/9/11 16:06:42
TDengine 中 fast-lzma2 的 Conan 集成指南:从包构建到压缩 API 实战
TDengine 中 fast-lzma2 的 Conan 集成指南从包构建到压缩 API 实战【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengine导读本文围绕 TDengine 仓库中 conan/fast-lzma2 这一 Conan 包配方展开系统讲解 Fast LZMA2v1.0.1这一优化型 LZMA2 压缩库如何被打包、构建、测试并集成进 TDengine 的 CMake 体系同时结合 tcompression.c 中的真实调用展示其如何作为数据库行级/列级压缩后端之一参与数据落盘。读完本文你将掌握如何用conan create生成该库的静态/动态包、如何在项目里通过fast-lzma2::fast-lzma2链接并使用FL2_*系列压缩 API以及 TDengine 内部调用它的底层路径与编译细节。一、Fast LZMA2 是什么为什么 TDengine 需要它Fast LZMA2 是一个面向高吞吐场景优化的 LZMA2 压缩算法实现与 xz 工具使用的标准 LZMA/LZMA2 格式兼容但压缩与解压速度显著更快。TDengine 作为面向工业物联网IIoT的时序数据库存储层需要兼顾压缩率与写入吞吐因此在多级压缩Level 1 与 Level 2 两级压缩设计中将 fast-lzma2 作为二级压缩的可选压缩器之一用于对已做一级差分/位压缩的数据流再压一道。本仓库中该功能的载体是一个完整的 Conan 包包名fast-lzma2版本1.0.1许可证BSD-3-Clause 与 GPL-2.0 双许可上游源码conor42/fast-lzma2本仓库通过固定 commit 拉取见下文从源码结构看仓库采用“双轨依赖”策略既保留了 cmake/external.cmake 中基于 ExternalProject 的ext_lzma2传统构建路径Linux 下下载fast-lzma2-ded964d203ca.tar.gz并用 lzma2.Makefile 编译又提供了 conan/fast-lzma2 这套现代化的 Conan 配方供启用 Conan 的构建流程使用。二、Conan 包配方解析包的核心逻辑位于 conan/fast-lzma2/conanfile.py下面分段拆解其关键设计。2.1 包元信息与版本锁定class FastLzma2Conan(ConanFile): name fast-lzma2 version 1.0.1 license BSD-3-Clause url https://github.com/conor42/fast-lzma2 description Fast LZMA2 Library - an optimized LZMA2 compression algorithm topics (compression, lzma2, fast-lzma2) settings os, compiler, build_type, arch ... # Pin upstream source to a specific commit (avoid relying on local vendored sources) _commit ded964d203cabe1a572d2c813c55e8a94b4eda48配方将上游源码钉死在 commitded964d2...保证任何环境下产出的二进制一致。注意与 cmake/external.cmake 中ext_lzma2下载的归档fast-lzma2-ded964d203ca.tar.gzSHA256 为ee71c637966a7ac429a245e2ee96a7a7ce52eb59087899f07cd1068a41c3af0e完全一致——两条依赖路径指向同一个源码版本。2.2 源码获取与镜像回退def source(self): _filename ffast-lzma2-{self._commit[:12]}.tar.gz _public_url fhttps://github.com/conor42/fast-lzma2/archive/{self._commit}.tar.gz _mirror os.environ.get(DEPS_MIRROR_URL, ) if _mirror: try: get(self, f{_mirror}/{_filename}, strip_rootTrue) return except Exception: self.output.warning(fMirror download failed, falling back to public URL) get(self, _public_url, strip_rootTrue)source()方法优先从环境变量DEPS_MIRROR_URL指向的镜像站拉取归档便于离线或受限网络环境镜像失败则回退到上游 GitHub 归档地址。strip_rootTrue会去掉归档顶层的fast-lzma2-commit/目录。2.3 构建选项选项默认值说明sharedFalse是否构建为共享库fPICTrue生成位置无关代码非 Windows 平台配方中的config_options()在 Windows 上删除fPICconfigure()在sharedTrue时移除fPIC同时移除 C 相关的compiler.libcxx/compiler.cppstd设置因为这是纯 C 库。2.4 用 make 而非 CMake 构建def build(self): cflags -Wall -O2 -pthread asflags -Wa,--noexecstack if self.options.get_safe(fPIC): cflags -fPIC if self.settings.build_type Debug: cflags cflags.replace(-O2, -O0 -g) self.run( fmake CFLAGS{cflags} ASFLAGS{asflags} CC{self.settings.get_safe(compiler, defaultgcc)} libfast-lzma2, cwdsource_folder, )该库使用上游自带 Makefile 构建配方只是透传优化与平台标志Release 默认-Wall -O2 -pthread外加非 Windows 下的-fPICDebug 切换为-O0 -g汇编标志-Wa,--noexecstack用于防止可执行栈安全加固。这些标志与 cmake/in/lzma2.Makefile 中ext_lzma2的默认值保持一致。该 Makefile 还揭示了平台相关的关键细节ifeq ($(x86_64),1) CFLAGS-DLZMA2_DEC_OPT OBJlzma_dec_x86_64.o endif即在 x86_64 架构上会自动定义LZMA2_DEC_OPT宏并额外编译lzma_dec_x86_64.o汇编优化模块大幅加速解压路径。2.5 打包与链接信息package()阶段把 LICENSE/COPYING 拷入licenses/把fast-lzma2.h、fl2_errors.h拷入include/并按 shared/static 与平台分别放置库文件Windows 共享库bin/*.dllmacOS 共享库lib/*.dylib*Linux 共享库lib/*.so*静态库lib/*.apackage_info()对外暴露的链接信息为self.cpp_info.libs [fast-lzma2] if self.settings.os in [Linux, FreeBSD]: self.cpp_info.system_libs.append(pthread) if self.settings.os Windows and self.options.shared: self.cpp_info.defines.append(FL2_DLL_IMPORT1)即 Linux/FreeBSD 消费方需自动带上pthreadWindows 上以 DLL 方式使用时通过FL2_DLL_IMPORT1宏声明导入符号。三、构建与测试完整命令行手册3.1 创建并安装包在包含conanfile.py的目录即 conan/fast-lzma2下执行# 本地构建并安装到 Conan 缓存 conan create . --buildmissing # 验证安装 conan list fast-lzma2/*conan create会依次执行 export → source → build → package → test_package其中 test_package 的验证是自动触发的。3.2 不同配置的构建# 构建共享库版本 conan create . --buildmissing -o fast-lzma2/*:sharedTrue # 构建 Debug 版本 conan create . --buildmissing -s build_typeDebug # 关闭 fPIC例如不需要位置无关代码的场景 conan create . --buildmissing -o fast-lzma2/*:fPICFalse # 交叉编译到 ARM64 conan create . --buildmissing -s archarmv8 # 使用 Android 工具链 profile 交叉编译 conan create . --buildmissing -pr:handroid-armv83.3 导出与发布到私有仓库# 导出到本地 Conan 仓库可指定 user/channel conan export . fast-lzma2/1.0.1 conan export . fast-lzma2/1.0.1mycompany/stable # 添加远程源并上传 conan remote add myremote http://my-conan-server.com conan upload fast-lzma2/1.0.1 -r myremote --all3.4 包自检test_packageconan create会自动运行 conan/fast-lzma2/test_package 下的验证工程conanfile.py 通过self.requires(self.tested_reference_str)依赖刚构建的包并使用CMakeDeps CMakeToolchain生成器CMakeLists.txt 执行find_package(fast-lzma2 REQUIRED CONFIG)并链接fast-lzma2::fast-lzma2test_package.c 实际调用FL2_versionNumber()、FL2_compressBound()、FL2_compress()、FL2_decompress()校验压缩/解压往返后数据一致打印Test PASSED才视为通过。四、在项目中使用Conan CMake 集成4.1 方式一conanfile.txt[requires] fast-lzma2/1.0.1 [generators] CMakeDeps CMakeToolchain [options] fast-lzma2/*:sharedFalse安装依赖conan install . --buildmissing4.2 方式二conanfile.pyfrom conan import ConanFile from conan.tools.cmake import cmake_layout class MyProjectConan(ConanFile): settings os, compiler, build_type, arch generators CMakeDeps, CMakeToolchain def requirements(self): self.requires(fast-lzma2/1.0.1) def layout(self): cmake_layout(self)4.3 CMakeLists.txt 链接cmake_minimum_required(VERSION 3.15) project(MyProject C) find_package(fast-lzma2 REQUIRED CONFIG) add_executable(myapp main.c) target_link_libraries(myapp fast-lzma2::fast-lzma2)然后使用 Conan 生成的预设构建cmake --preset conan-release # 或 conan-debug cmake --build --preset conan-release4.4 TDengine 中的 CMake 集成实证TDengine 的 Conan 集成层 cmake/conan.cmake 将 fast-lzma2 列为必选依赖find_package(fast-lzma2 REQUIRED)并在 cmake/conan.cmake 中通过宏把该目标链接给各业务模块target_link_libraries(${tgt} PUBLIC fast-lzma2::fast-lzma2) target_link_libraries(${tgt} PRIVATE fast-lzma2::fast-lzma2)五、API 实战单次压缩与流式压缩Fast LZMA2 的 C API 风格与 zstd 高度相似核心函数均在fast-lzma2.h中声明。包安装后头文件位于include/fast-lzma2.h与include/fl2_errors.h。5.1 单次压缩/解压one-shot API#include stdio.h #include stdlib.h #include string.h #include fast-lzma2.h int main() { const char* data Hello, Fast LZMA2!; size_t src_size strlen(data); // 1. 计算压缩所需的最大缓冲区 size_t max_size FL2_compressBound(src_size); char* compressed malloc(max_size); // 2. 压缩压缩等级 1-10推荐 6 size_t compressed_size FL2_compress(compressed, max_size, data, src_size, 6); if (FL2_isError(compressed_size)) { fprintf(stderr, Compression error: %s\n, FL2_getErrorName(compressed_size)); return 1; } // 3. 解压 char* decompressed malloc(src_size); size_t decompressed_size FL2_decompress(decompressed, src_size, compressed, compressed_size); if (FL2_isError(decompressed_size)) { fprintf(stderr, Decompression error: %s\n, FL2_getErrorName(decompressed_size)); return 1; } printf(Success!\n); free(compressed); free(decompressed); return 0; }5.2 流式压缩面向大文件/大块数据#include stdio.h #include stdlib.h #include fast-lzma2.h int compress_file(const char* input_path, const char* output_path) { FILE* fin fopen(input_path, rb); FILE* fout fopen(output_path, wb); if (!fin || !fout) return -1; FL2_CStream* cstream FL2_createCStream(); if (!cstream) { fclose(fin); fclose(fout); return -1; } size_t init_result FL2_initCStream(cstream, 6); if (FL2_isError(init_result)) { FL2_freeCStream(cstream); fclose(fin); fclose(fout); return -1; } size_t const buf_size 16 * 1024; // 16KB 缓冲 void* in_buffer malloc(buf_size); void* out_buffer malloc(buf_size); size_t read_size; while ((read_size fread(in_buffer, 1, buf_size, fin)) 0) { FL2_inBuffer input { in_buffer, read_size, 0 }; while (input.pos input.size) { FL2_outBuffer output { out_buffer, buf_size, 0 }; size_t result FL2_compressStream(cstream, output, input); if (FL2_isError(result)) goto cleanup; fwrite(out_buffer, 1, output.pos, fout); } } // 冲刷并结束流 FL2_outBuffer output { out_buffer, buf_size, 0 }; size_t result FL2_endStream(cstream, output); if (!FL2_isError(result)) fwrite(out_buffer, 1, output.pos, fout); cleanup: free(in_buffer); free(out_buffer); FL2_freeCStream(cstream); fclose(fin); fclose(fout); return 0; }5.3 版本信息unsigned version FL2_versionNumber(); printf(Fast LZMA2 version: %u.%u.%u\n, version / 10000, (version / 100) % 100, version % 100);六、TDengine 源码中的真实调用链fast-lzma2 并非“打包完即闲置”它在 TDengine 的压缩模块中被直接使用。入口位于 source/util/src/tcompression.c 的#include fast-lzma2.h核心实现在该文件中的 xz 二级压缩实现int32_t l2CompressImpl_xz(const char *const input, const int32_t inputSize, char *const output, int32_t outputSize, const char type, int8_t lvl) { size_t len FL2_compress(output 1, outputSize - 1, input, inputSize, lvl); if (len inputSize) { output[0] 0; // 压缩反而膨胀时退化为原样存储 memcpy(output 1, input, inputSize); return inputSize 1; } output[0] 1; // 标志位后续为压缩数据 return len 1; } int32_t l2DecompressImpl_xz(const char *const input, const int32_t compressedSize, char *const output, int32_t outputSize, const char type) { if (input[0] 1) { return FL2_decompress(output, outputSize, input 1, compressedSize - 1); } else if (input[0] 0) { memcpy(output, input 1, compressedSize - 1); // 原样存储分支 return compressedSize - 1; } return TSDB_CODE_THIRDPARTY_ERROR; }这段代码揭示了两点工程细节膨胀保护压缩结果比原始数据还大时会退化为“原样存储”用首个字节0/1标记区分压缩块与原始块避免病态数据导致空间浪费直接透传压缩等级lvl参数直接传给FL2_compress意味着压缩等级由上层配置决定。此外tcompression.c 中还存在以FL2_compress(dst, *dstSize, src, srcSize, 9)等级 9高压缩率进行整块压缩、FL2_decompress解压的另一处用法。这印证了 fast-lzma2 在 TDengine 压缩体系compressL1Dict/compressL2Dict两套分发表之外作为 xz 类压缩器常驻核心 util 库。七、编译标志与性能调优7.1 CFLAGS 含义标志含义-Wall开启全部常规警告-O2Release 优化等级 2-O0 -gDebug不优化 调试信息-pthread启用多线程支持-fPIC位置无关代码共享库需要-Wa,--noexecstack禁止可执行栈7.2 特殊宏LZMA2_DEC_OPT在 x86_64 上自动定义启用汇编优化的解压代码对应lzma_dec_x86_64.oFL2_DLL_EXPORTWindows DLL 导出由 Makefile 在Windows_NT下自动添加见 lzma2.MakefileFL2_DLL_IMPORTWindows DLL 导入共享库场景下由package_info()自动注入。7.3 调优建议压缩等级选择1-3 级压缩快、压缩率低4-6 级速度与压缩率均衡推荐7-10 级压缩率高、速度慢。TDengine 内部使用等级 6 与等级 9 两个档位可根据数据形态选择。内存占用等级越高内存开销越大流式 APIFL2_createCStream/FL2_compressStream可精细控制缓冲。多线程库内部基于 pthread 自动利用多核编译期默认开启-pthreadLinux 下消费方链接时需显式带上pthreadConan 配方已自动注入cpp_info.system_libs。八、常见问题排查8.1 编译/打包出错# 清空缓存重建 conan remove fast-lzma2/* -c conan create . --buildmissing8.2 链接失败确认 CMake 中正确使用 Conan 生成的 targetfind_package(fast-lzma2 REQUIRED CONFIG) target_link_libraries(your_target fast-lzma2::fast-lzma2)Linux 下如遇 pthread 相关未定义符号可显式链接线程库find_package(Threads REQUIRED) target_link_libraries(your_target fast-lzma2::fast-lzma2 Threads::Threads)8.3 包未找到conan list fast-lzma2/* # 确认是否已安装未安装则在 conan/fast-lzma2 目录下执行conan create . --buildmissing。九、许可证与注意事项Fast LZMA2 采用双许可BSD-3-Clause适用于大多数商业与开源项目GPL-2.0适用于 GPL 兼容项目。配方在package()阶段将上游的LICENSE与COPYING一并拷入包的licenses/目录见 conanfile.py消费方应保留这两份文件以履行许可义务。TDengine 的 conan/README.md 中对 fast-lzma2 与 cppstub 两个 Conan 包做了整体说明并指出这套 Conan 集成正是为了替代 cmake/external.cmake 中的ext_fast_lzma2ExternalProject 依赖换取版本固定、可复现构建与统一的跨平台依赖管理。此外需注意libfast-lzma2.a与libxxhash.a之间存在符号重叠风险cmake/external.cmake 中的 TODO 注释因此 TDengine 在链接顺序上强制先DEP_ext_xxhash再DEP_ext_lzma2在自行集成这两个库时也应保持相同的链接顺序。【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考