- 数据库
- 关系型数据库
- 后端
- CLI
【免费下载链接】dolt
Dolt – Git for Data
Dolt 是一款"Git for Data"数据库,其仓库格式、schema 编码与存储布局会随版本演进持续变化,因此版本间能否安全读写彼此的数据,直接决定了用户升级与多版本混部(例如滚动升级、跨版本协作)的可行性。本文以仓库中的 Compatibility Tests 文档 为主体,结合 runner.sh、setup_repo.sh 及整套 BATS 测试用例,完整讲解 Dolt 是如何通过向后兼容、向前兼容与双向兼容三组测试,系统性守护跨版本数据可读性的。读完本文,你将掌握这套测试的目录结构、运行流程、关键环境变量,以及每个测试文件所验证的具体兼容性维度。
一、兼容性测试的整体目标:三层验证矩阵
根据 README 的说明,这套测试试图保证 Dolt 各版本之间的前向与后向兼容性,整体上分为三个层次:
- 向后兼容(Backward Compatibility):仓库由旧版本 Dolt 创建并写入数据,由当前 HEAD 构建的 Dolt 客户端读取、修改。这保证"升级到新版本后,旧数据仍然可读、可写"。
- 向前兼容(Forward Compatibility):仓库由 HEAD 构建的 Dolt 创建并写入数据,由旧版本 Dolt 客户端读取。这保证"旧客户端在数据被新版本写入后仍能正常使用"。
- 双向兼容(Bidirectional Compatibility):旧版本与当前版本在同一个仓库上交替执行读写操作,验证"两个版本可以在同一份数据库上协作而不互相破坏"。由于向前兼容在任何时候都是限制性更强的一方(同时满足向前兼容的版本更少),双向测试只针对向前兼容版本列表进行。
这一设计的核心判断是:向前兼容是更严苛的约束。当一个新版本引入新的存储字段(如自适应编码、降序索引)后,旧客户端如果无法解析这些字段,就会拒绝读写,此时向前兼容就被打破,双向协作自然也无法成立。
二、测试套件的目录结构与文件角色
整套测试位于 integration-tests/compatibility 目录下,职责划分非常清晰:
integration-tests/compatibility/ ├── README.md # 测试设计说明(本文主体) ├── runner.sh # 总调度脚本:下载旧版本、建仓、跑 BATS └── test_files/ ├── setup_repo.sh # 用指定版本 dolt 构建"标准测试仓库" ├── setup_repo_2_0_breaking.sh # 用 HEAD + 自适应编码构建 2.0 破坏性测试仓库 ├── setup_repo_desc_index.sh # 用 HEAD 构建含降序索引的测试仓库 ├── big_table.sql # 向 big 表写入 1000 行数据的 SQL ├── backward_compatible_versions.txt # 向后兼容测试的版本清单 ├── forward_compatible_versions.txt # 向前兼容测试的版本清单 ├── 2_0_breaking_versions.txt # 2.0 破坏性变更测试的版本清单 ├── 2_0_forward_compatible_versions.txt # 降序索引 + 双向测试的版本清单 └── bats/ ├── compatibility.bats # 主兼容性用例(版本/状态/schema/diff/merge) ├── types_compatibility.bats # 全类型读写与加列用例 ├── geom_types_compatibility.bats # 空间类型兼容用例 ├── 2_0_breaking/ # 自适应编码破坏性用例 ├── desc_index_breaking/ # 降序索引破坏性用例 ├── bidirectional/ # 双向兼容用例(含 SQL server 跨版本) ├── bidirectional_remote/ # 经 file remote 的双向协作用例 └── helper/ # compat-common.bash / compat-server.bash其中三个版本清单文件是测试矩阵的"输入数据":
- backward_compatible_versions.txt 当前列出的版本为:
v2.0.0, v1.86.6, v1.86.5, v1.80.0, v1.75.0, v1.59.3, v1.44.2, v1.20.0, v1.7.0, v1.2.0, v1.0.0,覆盖从 v1.0.0 到 v2.0.0 的长跨度。 - forward_compatible_versions.txt 当前列为:
v1.80.0, v1.75.0, v1.59.0。 - 2_0_breaking_versions.txt 当前列为:
v1.87.0, v1.84.0;2_0_forward_compatible_versions.txt 当前列为v2.0.0。
清单文件中的空行与#注释行会被 runner.sh 中的grep -v '^ *#'过滤掉,因此可以随时注释掉某个版本以临时排除它。
三、向后兼容测试:旧版本建库,HEAD 客户端读写
3.1 下载并识别旧版本二进制
runner.sh 首先通过get_platform_tuple探测运行平台:仅支持 Linux 与 macOS,并根据uname -m将架构映射为amd64、arm64或386(见 runner.sh)。随后download_release会为指定版本创建binaries/<ver>目录,下载名为dolt-<platform>.tar.gz的发布压缩包并解压(见 runner.sh)。
3.2 用旧版本构建标准测试仓库
核心步骤是setup_repo:将 PATH 临时指向旧版本二进制目录,然后执行 setup_repo.sh 在repos/<ver>下创建仓库(见 runner.sh)。该脚本是这个测试体系"数据样板"的关键,它会:
dolt init初始化仓库,并自动探测默认分支名(main或master),把结果写入default_branch.var供后续使用;- 创建多个分支:
no-data、init、other、check_merge,分别模拟不同数据状态的仓库; - 建立覆盖几乎所有 MySQL 类型的数据表:
abc(BIGINT 主键 + LONGTEXT/DOUBLE/BIGINT 列,作为 DML 与 DDL 演练对象);big(通过 big_table.sql 灌入 1000 行,用于验证大表读写与 diff);def(含CHECK (i > 0)约束,用于验证约束检查与合并);all_types(TINYINT/SMALLINT/MEDIUMINT/INT/BIGINT/BIGINT UNSIGNED/FLOAT/DOUBLE/DECIMAL/CHAR/VARCHAR/TINYTEXT/TEXT/MEDIUMTEXT/LONGTEXT/VARBINARY/TINYBLOB/BLOB/MEDIUMBLOB/LONGBLOB/DATE/TIME/DATETIME/TIMESTAMP/YEAR/JSON/ENUM/SET 共 28 种列,正负值、超大值(如9223372036854775807、18446744073709551615、500 字节重复字符串)全覆盖;geom_types(POINT/LINESTRING/POLYGON/GEOMETRY/MULTIPOINT/MULTILINESTRING/MULTIPOLYGON/GEOMETRYCOLLECTION,通过ST_GeomFromText写入);- 视图
view1、all_types_view、geom_view,验证视图在版本间的序列化兼容;
- 在不同分支上执行差异化 DDL/DML:
other分支对abc执行DROP COLUMN x; ADD COLUMN z,默认分支执行DROP COLUMN w; ADD COLUMN y,从而为后续dolt diff other测试构造真实的 schema 分叉; - 最后导出
abc.csv与abc_schema.json(用于dolt table import测试),并输出dolt status、dolt branch、dolt schema show、查询结果与dolt_schemas快照作为日志参考。
可见这套"标准仓库"刻意覆盖了类型系统、视图、约束、分支分叉与导出导入等最易受格式演进影响的环节,是向后兼容测试的"压力样品"。
3.3 以 HEAD 客户端跑 BATS 用例
仓库构建完成后,runner 用当前 HEAD 的 dolt 作为客户端,针对该仓库执行整批 BATS 测试(见 runner.sh)。测试通过环境变量传递上下文:
DOLT_OLD_BIN:旧版本 dolt 二进制路径;DOLT_NEW_BIN:HEAD 构建的 dolt 路径(在 PATH 被修改前用which dolt捕获);REPO_DIR:被测仓库目录(每个用例的setup()会先cp -Rpf $REPO_DIR bats_repo复制一份隔离副本);DOLT_VERSION:当前被测的旧版本号,供用例做版本判断;DEFAULT_BRANCH:仓库的默认分支名。
compatibility.bats 是这批用例的主体,覆盖:dolt version/status/ls/branch/diff基础命令;在init、默认分支、other分支上执行dolt schema show abc并逐一断言列定义(如pk bigint not null、a longtext、w bigint/y bigint等);对三个分支执行select * from abc并断言结果集表格布局;dolt diff other断言 schema 与数据两部分的精确 diff 输出;对big表执行 count、delete、insert 与 commit;dolt merge other断言"预期冲突"(Merge conflict in abc/Automatic merge failed);dolt table import -c -pk=pk abc2 abc.csv验证旧版本导出的 CSV 可被新客户端导入;dolt merge check_merge验证带 CHECK 约束的合并;以及构造唯一索引冲突后查询dolt_constraint_violations_cv_test系统表并清理的约束违规用例。
同批执行的 types_compatibility.bats 与 geom_types_compatibility.bats 则分别验证:旧版本写入的每种类型都能被 HEAD 正确读取(整数边界值、负数、500 字节大 TEXT/BLOB、ST_X/ST_AsText等空间函数);对旧表执行 INSERT/UPDATE/DELETE 与ALTER TABLE ADD COLUMN(逐类型新增列后再读写);以及旧版本创建的视图能被正确反序列化并查询。这些用例还大量使用assert_no_panic_shape辅助函数(见 compat-common.bash),专门拦截输出中泄漏的invalid hash length、panic recovered、runtime error等"panic 形状",确保兼容性问题以干净的报错而非崩溃暴露。
四、向前兼容测试:HEAD 建库,旧版本客户端读写
向前兼容测试的思路与向后相反:先用 HEAD 构建仓库(runner 的_main会先setup_repo HEAD),再让清单中的旧版本客户端去读写它。由于旧版本可能无法理解 HEAD 仓库存储中的某些引用形态,runner 在 test_forward_compatibility 中做了一个关键预处理:
- 在
repos/HEAD/file-remote创建file remote(dolt remote add file-remote file://file-remote),并把$DEFAULT_BRANCH、init、no-data、other、check_merge等分支全部 push 上去。注释说明这样做是为了"裁剪掉存储中某些旧版本不兼容的引用(refs)"; - 旧版本 dolt 从该 remoteclone出
repos/<ver>仓库,并用旧版本依次创建各本地分支(dolt branch no-data origin/no-data等); - 把 HEAD 仓库导出的
*.csv、*.json拷贝进旧版本仓库,保证导入类用例可用; - 最后以旧版本为客户端(
DOLT_OLD_BIN)跑同一批 BATS 用例,验证旧客户端能够读取、diff、merge HEAD 写入的数据。
整个 clone/setup 过程刻意使用"被测版本"的二进制执行(PATH="$relpath" dolt clone ...),并打印dolt version确认。该流程说明:向前兼容的验证不仅限于读取,还包括旧客户端能否独立完成 clone、建分支、导入导出等完整操作链。
五、双向兼容测试:新老版本交替读写同一仓库
双向兼容是这套体系中最"贴近真实混部场景"的部分。它不做setup_repo.sh的共享初始化,而是由测试自己建仓、自己组织数据。runner 对同一版本会跑两次,方向互换:第一次DOLT_OLD_BIN为旧版本、DOLT_NEW_BIN为 HEAD,第二次交换两者,从而把"谁先写、谁后写"的两个方向都覆盖到(见 runner.sh)。
5.1 同仓交替写入(bidirectional)
bidirectional_compat.bats 以"多轮交替"模式展开:每轮由一个版本写入、另一个版本验证,通常进行 4~6 轮,覆盖:
- 标量类型 DML 往返:INT/VARCHAR/DECIMAL/DATETIME 的 insert/update/delete 跨版本可见;
- 大 TEXT/BLOB 往返:用
REPEAT生成 1000~5000 字节值,验证 out-of-band(带外存储)大值由一方写入后,另一方能用LENGTH()完整读回;测试注释明确给出了自适应编码的阈值语义——TINYTEXT/TEXT恒为 inline,MEDIUMTEXT/LONGTEXT超过 64KB 阈值时转入 out-of-band; - 空间类型往返:POINT/LINESTRING/POLYGON/GEOMETRY 经
ST_GeomFromText写入、ST_X/ST_AsText读回; - 双方交替 ADD COLUMN:HEAD 加 TEXT/DATE 列、旧版本加 INT/DECIMAL 列、HEAD 再加 POINT 列,最终旧版本用包含全部新列(含空间列)的行插入,HEAD 读回;
- 跨版本分支与合并:HEAD 建特性分支提交,旧版本建自己的分支并执行 merge;HEAD 再做 DDL 变更合并,旧版本读取新列并写入;
- 综合类型覆盖:TINYINT/BIGINT/FLOAT/DOUBLE、VARCHAR/CHAR/VARBINARY、DATE/DATETIME/DECIMAL、ENUM/SET 逐轮由两个版本交替加列;
- TEXT/BLOB 家族:TINYTEXT~LONGTEXT 与 TINYBLOB~LONGBLOB 的 inline↔out-of-band 双向升降级(例如把 70000 字节值写进原本小的列,或把大值改回小值),验证"编码形态变化"也能被对端正确解析;
- JSON:含 inline 与 out-of-band 两列组合,用
JSON_EXTRACT/JSON_UNQUOTE校验(当前该用例被skip,注释说明新 JSON 编码与旧版本不兼容)。
每个测试都调用clear_branch_control删除.doltcfg/branch_control.db:因为分支控制序列化存在一次前向不兼容变更,现代客户端写入后旧客户端读取会 panic,删除该文件可避免此噪声掩盖其他真实问题(见 bidirectional_compat.bats)。
5.2 SQL server 与 CLI 客户端跨版本(server_cli_compat)
server_cli_compat.bats 将兼容性验证从"文件仓库"扩展到"网络协议"层面:旧版本dolt sql-server作为服务端,HEAD 的 CLI 作为客户端通过--host/--port/--user/--password --use-db全局连接参数连接。其中 compat-server.bash 提供了服务生命周期管理:start_old_sql_server用随机端口启动旧版 server(wait_for_old_server轮询直至可连接),new_dolt_cli封装客户端连接参数,latest_commit只用旧 server 也支持的dolt_log列做查询。用例覆盖:SELECT 1连通性、通过dolt_log读取提交历史、客户端发起add/commit/revert、--author覆盖后在旧 server 侧查询dolt_log验证 committer、以及cherry-pick跨版本应用提交。测试还通过skip_if_old_lte/skip_if_new_lte(见 compat-common.bash)按版本号门槛跳过某些旧版本不具备的能力(例如1.20.0前客户端不支持全局连接参数、1.86.6前dolt_logschema 未固定),避免对"能力缺失"误判为"兼容性破坏"。
5.3 经共享 file remote 的双向协作(bidirectional_remote)
bidirectional_remote_compat.bats 模拟了更贴近生产的多机协作:两个版本通过共享的file://remote 同步。其核心run_workflow流程为:
- 版本 A(旧)建仓、建表、写基础行并 push 到 remote,然后不提交地
ALTER TABLE tbl ADD COLUMN c_col <type>; - 版本 B(新)从 remote clone,以同名同类型
ADD COLUMN c_col,写入与 A 不相交的行并提交; - 版本 A 用自己的
c_col写入不相交行、提交并 push; - 版本 B
dolt pull,断言合并成功,最终表同时包含两边的全部 6 行且c_col值正确。
该用例针对 INT、BIGINT、BIGINT UNSIGNED、FLOAT、DECIMAL、VARCHAR、TEXT、VARBINARY、BLOB、DATETIME、TIMESTAMP、ENUM、SET、POINT、LINESTRING、GEOMETRYCOLLECTION 等类型逐一验证(JSON 因编码变更被 skip)。它的特殊意义在于:两个版本独立地对同一表做了相同 schema 变更,再经 pull 合并,必须不冲突、不丢数据——这直接检验了 schema 与行存储格式在"分叉演进后合并"路径上的兼容性。
六、显式验证破坏性变更:自适应编码与降序索引
并非所有变更都能做到向前兼容。对于已知的破坏性变更,测试套件专门设计了"必须报错、且报错要友好"的断言模式。
6.1 2.0 自适应编码(adaptive encoding)
setup_repo_2_0_breaking.sh 用 HEAD(并启用自适应编码)构建包含 TEXT/BLOB 各类变体及混合类型表的仓库,随后 2_0_breaking.bats 断言:旧客户端(v1.87.0、v1.84.0)对含 TEXT/BLOB 的表执行SELECT、dolt diff、dolt schema show时必须失败且输出table has unknown fields;而对不含 TEXT/BLOB 的no_text_blob表仍可正常读取。runner 中对应注释说明了策略:"目前我们只测试它以恰当的报错信息失败"(见 runner.sh)——即破坏性变更被接受,但必须显式、可诊断地失败。
6.2 降序索引(descending index)
setup_repo_desc_index.sh 用 HEAD 构建一张含INDEX c_int_desc (c_int DESC, c_varchar)的表与一张默认升序索引的表。 desc_index_breaking.bats 断言:旧客户端对降序索引表(SELECT、schema show、dolt diff)报table has unknown fields,对默认升序索引表仍正常读写;HEAD 客户端两张表都能读(ORDER BY c_int DESC正确返回);并且 HEAD 修改默认索引表列类型后,旧客户端仍可读该表。其原理在用例注释中写明:降序列被写为索引 schema 消息的新字段,旧客户端遇到未知字段即拒绝;没有降序列的索引不写这些字段,因此不触发。
这两组"负向用例"与前面的正向用例共同构成完整矩阵:兼容性测试不仅要证明"能读",还要证明"不能读时给出明确错误"。
七、运行编排与辅助设施
7.1 runner 的主流程
runner.sh 的_main依次执行:
- 探测平台、导出
BATS_LIB_PATH(依次指向本套件的test_files/bats/helper与主 BATS 套件的helper,使嵌套用例可bats_load_library)与DOLT_DEV_BUILD_PATH(指向新构建的 dolt,避免版本号字面匹配把 dev build 误跳过); - 创建
repos/binaries目录,注册 EXIT 清理钩子; - 对
backward_compatible_versions.txt每个版本跑向后兼容; setup_repo HEAD构建当前版本仓库;- 对
2_0_breaking_versions.txt跑自适应编码破坏性用例; - 对
2_0_forward_compatible_versions.txt跑降序索引用例; - 对同一清单跑双向兼容(同仓)与双向 remote 兼容;
- 最后以 HEAD 对 HEAD 仓库跑一遍 BATS 作为自检基线(sanity check),确保测试体系本身在无跨版本场景下也是绿的。
7.2 关键环境变量速查
| 环境变量 | 用途 |
|---|---|
DOLT_OLD_BIN | 旧版本 dolt 路径;未设置时回退到 PATH 上的dolt |
DOLT_NEW_BIN | 新版本(HEAD)dolt 路径;未设置时回退到dolt |
DOLT_LEGACY_BIN | remote 双向用例中"版本 A"的二进制 |
REPO_DIR | 被测仓库目录,用例 setup 阶段复制为bats_repo |
DOLT_VERSION | 当前被测旧版本号,供用例按版本跳过 |
DEFAULT_BRANCH | 仓库默认分支名(main/master) |
BATS_LIB_PATH | 帮助库加载路径 |
DOLT_DEV_BUILD_PATH | 新构建 dolt 的路径,豁免版本号字面比较 |
这些变量在 compat-common.bash 中被old_dolt/new_dolt两个函数封装使用;测试文件只调用old_dolt/new_dolt,从而对"哪个版本在跑"保持透明。
7.3 本地运行方式
运行前提:本机需具备 BATS 环境、可执行dolt(HEAD 构建)且能访问外网以下载历史版本二进制;支持 Linux 与 macOS(见get_platform_tuple的限定)。在integration-tests/compatibility目录下执行:
bash runner.shrunner 会自动下载版本清单中的旧版本发布包、构建标准仓库并逐批执行 BATS(带--print-output-on-failure,失败时输出完整现场)。需要临时缩小范围时,可在对应的*_versions.txt中注释掉某些版本行(#开头的行会被忽略)。
八、从测试体系看 Dolt 的兼容性工程实践
从这套测试可以提炼出几条可迁移的工程经验:
- 用"数据样板"覆盖格式敏感面:
setup_repo.sh刻意灌入全部 MySQL 类型、空间类型、视图、约束、大值与分支分叉,把易受编码演进影响的点全部固化为回归样本; - 正反用例结合:既能读(向后/向前/双向)与必须报错(2.0 breaking/desc index)并行验证,让"破坏性变更"有明确的、可断言的失败契约;
- 把"方向"作为测试参数:双向测试对同一版本正反各跑一遍,且 remote 场景将"独立加列后合并"作为一等公民,覆盖了真实混部中最危险的路径;
- 版本能力与兼容性解耦:
skip_if_old_lte/skip_if_new_lte按版本号门槛区分"旧版本没这个能力"与"跨版本不兼容",避免误报; - panic 形状拦截:
assert_no_panic_shape保证兼容性问题表现为干净的报错,而不是崩溃或内存误读——这对数据型数据库尤为重要。
无论你是 Dolt 的使用者(评估升级风险)、贡献者(判断改动是否破坏格式),还是其他数据系统的工程师(设计自己的跨版本兼容测试),这套位于 integration-tests/compatibility 的测试体系都是一份完整且可直接运行的参考实现。
- 数据库
- 关系型数据库
- 后端
- CLI
【免费下载链接】dolt
Dolt – Git for Data
相关推荐
GreptimeDB 版本兼容性测试完全指南:基于 sqlness-runner 的向后/向前兼容验证体系
GreptimeDB 版本兼容性测试完全指南:基于 sqlness runner 的向后/向前兼容验证体系 本指南系统讲解 GreptimeDB 仓库中 tes
时序数据库数据库可观测性GeneralUpdate版本兼容:向后兼容与向前兼容的策略
GeneralUpdate版本兼容:向后兼容与向前兼容的策略 引言 在软件开发生命周期中,版本兼容性(Version Compatibility)是确保应用程序
开发工具OCRmyPDF版本兼容:确保向前和向后兼容性
OCRmyPDF版本兼容:确保向前和向后兼容性 你是否曾遇到过升级OCRmyPDF后处理的PDF文件变大、格式错误或无法搜索的问题?或者尝试在旧系统上运行新版本
OCRCLI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考