This is an automated email from the ASF dual-hosted git repository. zyxxoo pushed a commit to branch refactor/rust-rewrite-design in repository https://gitbox.apache.org/repos/asf/hugegraph.git
commit 71fa24f239dd856839bc9362d86fba1fa2c0135e Author: vaughn <[email protected]> AuthorDate: Wed Sep 9 23:07:21 2026 +0800 refactor(docs): define Rust rewrite design and acceptance criteria --- docs/rust-engineering-standard.md | 83 ++++++++++++++ docs/rust-rewrite-acceptance-matrix.md | 105 +++++++++++++++++ docs/rust-rewrite-design.md | 202 +++++++++++++++++++++++++++++++++ docs/rust-rewrite-test-inventory.md | 48 ++++++++ 4 files changed, 438 insertions(+) diff --git a/docs/rust-engineering-standard.md b/docs/rust-engineering-standard.md new file mode 100644 index 000000000..47b8ab130 --- /dev/null +++ b/docs/rust-engineering-standard.md @@ -0,0 +1,83 @@ +# HugeGraph Rust 工程规范 + +状态:设计草案;Rust 子项目建立后应转为仓库级强制规范。 + +本规范参考 TiKV、raft-rs 和 Tokio 的公开实践。TiKV 将格式化、Clippy、静态检查和多配置测试集中到开发门禁,并维护工具链、格式、Clippy 和依赖审计配置;raft-rs 对共识代码采用更严格的评审并要求 Clippy/rustfmt【https://github.com/tikv/tikv/blob/master/Makefile】【https://github.com/tikv/raft-rs/blob/master/CONTRIBUTING.md】。Tokio 明确 MSRV、语义化版本和长期支持策略,并使用 Loom 做并发排列测试、Miri 做未定义行为检查【https://github.com/tokio-rs/tokio/blob/master/CONTRIBUTING.md】【https://github.com/tokio-rs/tokio/blob/master/docs/contributing/pull-requests.md】。 + +## 1. 工具链与目录 + +- 使用仓库锁定的 `rust-toolchain.toml`,明确 Rust 版本和组件(`rustfmt`、`clippy`)。 +- 设置并持续验证 MSRV(Minimum Supported Rust Version);升级 MSRV 必须记录兼容性影响。 +- 使用 Cargo workspace,统一依赖版本、feature 和 `Cargo.lock`;服务和库不得各自漂移版本。 +- 重大架构或公共 API 变更必须先提交 RFC;版本策略遵循 SemVer,明确 MSRV、弃用周期和回滚方案。 +- 目录按领域边界划分,例如 `api`、`domain`、`storage`、`raft`、`transport`、`runtime`,禁止通过循环依赖拼接模块。 + +## 2. 强制质量门禁 + +提交和 CI 至少执行: + +```bash +cargo fmt --all -- --check +cargo check --workspace --all-targets +cargo clippy --workspace --all-targets --all-features -- -D warnings +cargo test --workspace +cargo audit +cargo deny check +``` + +发布构建还要执行依赖许可证检查、可重复构建检查、集成测试、故障测试和基准回归。禁止用 `#[allow(...)]` 静默绕过 Clippy;例外必须有范围、理由和责任人。 + +并发原语、无锁结构和调度器相关代码必须提供 Loom 测试;涉及指针、FFI 或复杂内存模型的代码应在 nightly 环境增加 Miri 检查。Loom/Miri 是补充验证,不得替代正常集成测试。 + +## 3. API、错误和异步规范 + +- 公共库 API 使用明确的类型和生命周期;避免用 `String` 表示可枚举的协议状态。 +- 库错误使用 `thiserror`,服务边界使用可分类、可观测的错误码;`anyhow` 只允许出现在应用层。 +- 不跨线程传递未说明所有权的对象;所有后台任务必须具备取消、超时、退出和 join 策略。 +- Tokio 任务中禁止执行未隔离的阻塞磁盘或 CPU 工作;使用专门线程池并记录队列等待时间。 +- 不在持锁期间执行 RPC、磁盘 IO 或等待异步任务;锁的范围和顺序必须文档化。 +- 时间、重试、退避、超时和取消都必须显式配置,禁止无限重试。 + +## 4. `unsafe`、FFI 与数据边界 + +- 默认禁止 `unsafe`;每处 `unsafe` 必须有安全不变量、最小封装模块、审查记录和测试。 +- C/C++ FFI 只允许通过窄 C ABI;所有指针、长度、线程归属、释放函数、异常和 ABI 版本必须明确。 +- Rust panic 不得跨 FFI;C++ 异常不得跨边界传播。 +- Protobuf、JSON、RocksDB value 和快照输入都必须先做长度、版本和范围校验。 +- 序列化格式必须有版本号;禁止依赖 Rust 内存布局或 `repr` 缺省行为作为持久化格式。 + +## 5. 并发、Raft 与持久化 + +- Raft 核心只复用成熟库;HugeGraph 负责适配层、日志落盘、状态机、快照和恢复测试。 +- 提交顺序必须明确记录:持久化日志、提交索引、状态机应用和响应客户端的先后关系。 +- 所有状态机命令必须可重放;副作用必须通过幂等键或提交索引去重。 +- 快照生成、安装、日志截断和恢复必须具备崩溃点测试。 +- RocksDB 版本、编译选项、列族和 key 编码固定并纳入兼容性测试。 + +## 6. 可观测性与安全 + +- 使用 `tracing`,日志字段统一包含请求 ID、图名、分区、节点、Raft group 和 trace ID(适用时)。 +- 指标名称、单位和标签数量受控;禁止把用户输入直接作为高基数标签。 +- 密钥不得进入日志、错误文本、快照或 metrics;敏感配置使用专门的 secret provider。 +- 依赖变更必须经过漏洞、许可证和来源审查;生产构建锁定校验和并生成 SBOM。 + +## 7. 测试规范 + +- 单元测试验证局部不变量;集成测试验证协议和模块边界;端到端测试验证用户可观察行为。 +- 测试不得只复制实现逻辑作为断言,关键契约使用规范 Oracle、关系 Oracle 或独立参考模型。 +- 随机和故障测试必须记录 seed、版本、配置和最小化后的操作历史。 +- 性能测试固定数据集、并发、硬件和采样方式;基准变化必须有解释。 +- 每个 bug 修复都要增加确定性回归用例。 + +## 8. 评审清单 + +代码评审至少检查:契约是否改变、错误是否可分类、异步任务是否可退出、锁和 IO 是否安全、`unsafe`/FFI 是否有不变量、持久化是否可升级、指标和日志是否足够、测试是否独立于实现,以及是否保留回滚路径。 + +## 9. 从 TiKV/Tokio 借鉴的流程要求 + +- 大变更先 RFC,小 PR 分步合入;每个 PR 说明行为变化、测试和回滚方式。 +- CI 使用与仓库锁定的编译器/Clippy 版本一致的工具链,避免开发机版本差异造成误报。 +- 测试覆盖 feature 组合,而不是只测试默认 feature;发布 feature 必须有独立构建和测试。 +- 公共 API 生成文档并对文档构建启用 warnings-as-errors;复杂代码按模块、类型、函数写 doc comment。 +- 并发代码同时保留常规测试、Loom 小模型测试和长稳/故障测试,记录已验证的状态空间边界。 +- 贡献流程要求代码审查、变更日志、许可证/DCO(若项目采用)和安全问题单独处理。 diff --git a/docs/rust-rewrite-acceptance-matrix.md b/docs/rust-rewrite-acceptance-matrix.md new file mode 100644 index 000000000..69fe0213f --- /dev/null +++ b/docs/rust-rewrite-acceptance-matrix.md @@ -0,0 +1,105 @@ +# Rust 重构验收矩阵 + +状态:第一轮盘点完成;“已发现”不等于“已通过”。本矩阵是迁移的强制门禁。 + +## 1. 现有测试资产覆盖盘点 + +以下统计使用 `rg -l '<关键词>' --glob '*Test.java'`,用于定位测试资产,不用于证明覆盖率: + +| 能力域 | 命中测试文件 | 主要资产位置 | 当前判断 | +| --- | ---: | --- | --- | +| REST/API | 68 | `hugegraph-test`、PD REST、Store gRPC/service | 有大量测试,需抽取协议断言 | +| Gremlin/遍历 | 38 | `hugegraph-test` API、traversal、TinkerPop suites | 有覆盖,需建立规范化结果 Oracle | +| Schema | 48 | server core/API、PD metadata | 有覆盖,需补跨版本和失败恢复 | +| Index | 28 | server core/backend/API | 有覆盖,需补重启、删除和重建一致性 | +| Transaction | 26 | graph/backend/store | 有覆盖,需补并发、可见性和幂等 | +| Snapshot | 11 | Store RocksDB、PD/Store 服务 | 数量偏少,列为迁移阻断项,需补恢复矩阵 | +| Raft | 31 | PD raft、Store raftcore | 有基础测试,需补分区、崩溃、成员变更和线性一致性历史检查 | +| Partition | 23 | PD partition、Store engine | 有覆盖,需补重平衡和故障中迁移 | +| Auth/权限 | 37 | server auth/API/PD auth | 有覆盖,需拆出协议和安全不变量 | +| 升级/迁移 | 2 | 分散在配置/版本测试 | 明显不足,列为迁移阻断项 | + +执行入口不是单一套件:Server 使用 `unit-test`、`core-test`、`api-test`;PD 使用 `pd-core-test` 等 profile;Store 使用 `store-core-test`、`store-raftcore-test`。CI 还通过脚本分别执行 unit/core/API/Raft 任务,盘点必须以 CI 实际命令为准。 + +## 2. 验收契约矩阵 + +| 契约 | 独立 Oracle | 必须执行的验证 | 通过条件 | +| --- | --- | --- | --- | +| REST/gRPC 请求响应 | OpenAPI/Protobuf + 黄金样例 | Java/Rust 差分回放、非法输入、超时和错误码 | 字段、状态、错误语义无未解释差异 | +| Gremlin/遍历 | TinkerPop 语义 + 结果规范化器 | 固定语料、随机遍历、空/重复/排序边界 | 结果集合、顺序承诺和异常一致 | +| Schema/索引 | 图数据不变量 | 创建/更新/删除、重启、重建、约束失败 | 不变量始终成立,索引不丢不重 | +| 事务 | 可见性和提交不变量 | 并发、冲突、重试、崩溃点注入 | 提交/回滚/可见性符合契约 | +| 持久化格式 | 版本化格式规范 | 旧数据读取、快照、升级、回滚 | 新实现可读旧数据,失败可恢复 | +| Raft/分布式 | 线性一致性模型 | 分区、崩溃、乱序、重复、成员变更 | 历史通过模型检查,无数据丢失 | +| 认证权限 | 权限矩阵和拒绝不变量 | 全角色/资源/操作组合、过期凭证 | 无越权,错误响应稳定 | +| 性能资源 | 现有版本基线 | 固定数据集、固定并发、长稳测试 | 达到预先批准的阈值且无退化逃逸 | +| 运维升级 | 发布/回滚状态机 | 滚动升级、降级、配置兼容、备份恢复 | 任一步失败可停止并回滚 | + +## 2.1 现有入口到契约的追踪 + +这是当前已确认的测试入口;迁移实施时必须把每个入口下的方法继续展开到测试方法级。 + +| 测试入口 | Profile/执行方式 | 当前可覆盖契约 | 必须补出的 Oracle/场景 | +| --- | --- | --- | --- | +| `hugegraph-server/hugegraph-test` | `unit-test`、`core-test`、`api-test` | core、API、Gremlin、Schema、事务、序列化 | 统一请求生成器、Java/Rust 规范化差分、故障恢复 | +| `hugegraph-server/.../tinkerpop` | core/TinkerPop profile,受 filter 影响 | TinkerPop structure/process | 明确 HugeGraph 承诺的步骤子集、顺序和异常 Oracle | +| `hugegraph-pd/hg-pd-test` | `pd-core-test`、client/common/rest profile | PD 服务、客户端、分区、Raft readiness | 三节点分区历史、快照、成员变更和升级 Oracle | +| `hugegraph-store/hg-store-test` | `store-core-test`、`store-raftcore-test` | Store core、RocksDB、Raft、partition、session | 崩溃恢复、重复/乱序消息、线性一致性和数据校验 | +| `hugegraph-store/hg-store-rocksdb` | 模块测试 | RocksDB session、factory、snapshot | 旧格式读取、损坏快照、恢复后索引/计数等价 | +| `.github/workflows/*-ci.yml` | CI 脚本组合 | 实际执行集合和报告 | 固定 CI 清单,禁止 filter 静默漏测,上传差分报告 | + +## 3. Oracle 与反射防止 + +Java 版本只作为参考实现,不能单独作为 Oracle。每条关键契约必须至少有一个规范或关系 Oracle;差分测试只负责发现差异,最终由规范/不变量判定对错。随机测试必须保存 seed、生成器版本、初始快照和故障计划,并将失败缩减为确定性回归用例。 + +## 4. 小步替换闭环 + +每个 Rust 边界必须按以下状态机推进: + +```text +盘点现状 → 写契约 → 补 Oracle/测试 → Java 基线 + → Rust 实现 → 单测/集成/故障/差分 + → 双读或灰度 → 观察窗口 → 扩大范围或回滚 +``` + +### 进入条件 + +- 本边界的能力、协议和数据不变量已登记; +- 现有测试已映射到 profile 和 CI 命令; +- 所有关键行为有独立 Oracle; +- 缺口已补测试,或被明确登记为禁止迁移项; +- 已定义回滚开关、数据校验和观察指标。 + +### 退出条件 + +- 协议、语义、持久化和权限测试全部通过; +- 故障注入、恢复、升级和回滚通过; +- 差分回放无未解释差异; +- 性能、资源和长稳达到批准阈值; +- 生成带版本、配置、输入、seed、日志和差异清单的验收报告。 + +任一退出条件失败,边界保持旧实现,不得扩大迁移范围。 + +## 5. 当前阻断项 + +在完成以下工作前,不应迁移 Store 写路径或核心图执行引擎: + +1. 补齐快照/恢复、升级/回滚和分布式故障测试; +2. 确认 CI profile 的实际测试集合,清理被 filter 排除但仍属于契约的场景; +3. 为 REST、Gremlin、Schema、索引和事务建立规范化差分工具; +4. 建立 Raft 历史检查和可重复故障注入; +5. 为每项契约指定负责人、测试路径和通过阈值。 + +完成这些项目并提交验收报告后,方案才形成可执行闭环。 + +## 6. 补测任务清单 + +以下任务是从当前盘点直接得到的,不是围绕 Rust 实现临时编写的测试: + +1. 导出所有 Maven profile 和 CI 脚本实际运行的测试类/方法,生成基线清单; +2. 为 REST、gRPC、Gremlin、Schema、索引、事务定义脱离实现的规范化比较器; +3. 增加旧 RocksDB 数据、快照导入导出、版本升级和失败回滚的端到端用例; +4. 增加 PD/Store 三节点崩溃、分区、延迟、重复消息、成员变更和恢复用例; +5. 为随机图操作和事务历史保存 seed,并增加最小化失败历史的回归格式; +6. 建立测试结果报告,强制记录 profile、提交版本、配置、数据集、Oracle 版本和差异; +7. 对每个缺口指定“补测后才允许迁移”的门禁,禁止以提高覆盖率数字替代语义验证。 diff --git a/docs/rust-rewrite-design.md b/docs/rust-rewrite-design.md new file mode 100644 index 000000000..70291b09e --- /dev/null +++ b/docs/rust-rewrite-design.md @@ -0,0 +1,202 @@ +# HugeGraph Rust 重构设计 + +状态:设计草案 + +## 1. 背景与目标 + +HugeGraph 当前由 Java 服务、核心图引擎、RocksDB/HStore 后端以及 PD/Store 分布式组件组成。本方案讨论如何在保持现有用户协议和数据语义的前提下,逐步以 Rust 替换实现。 + +测试资产盘点和迁移门禁见 [Rust 重构验收矩阵](rust-rewrite-acceptance-matrix.md);该矩阵是本设计的执行入口,不满足其中的进入/退出条件就不能扩大替换范围。 + +目标是降低运行时资源开销,改善并发和故障恢复能力,统一分布式组件的实现语言,并保留 Gremlin、REST、Schema、索引和现有部署方式的兼容性。目标不是一次性重写,也不是重新设计图数据库语义。 + +## 2. 设计原则 + +1. **渐进迁移**:每个阶段都有可运行、可压测、可回滚的产物。 +2. **协议优先**:先稳定 REST、Gremlin、PD/Store RPC 和存储格式,再替换实现。 +3. **复用成熟组件**:不自研 Raft、TLS、HTTP、Protobuf 或底层 KV 存储。 +4. **数据安全优先**:任何新实现都必须通过双读校验、故障注入和恢复测试,不能以 benchmark 代替正确性证明。 +5. **边界清晰**:Rust 服务通过明确的 RPC 或 C ABI 与尚未迁移的 Java 组件协作,避免细粒度跨语言调用。 + +## 3. 目标架构 + +```text +客户端(Gremlin / REST / Cypher) + │ + Rust API Gateway(逐步替换) + │ gRPC / Protobuf + ┌──────┴──────┐ + │ │ + Rust PD Rust/Java Store + │ │ + Raft 元数据 Raft 数据分片 + │ │ + RocksDB / 快照 / 对象存储 +``` + +迁移期间,Java Server 和 Rust 服务并存。网关、PD、Store 和核心引擎可以分别切换;控制面和数据面不得绑定为一次迁移。 + +## 4. Rust 技术栈 + +| 领域 | 候选 | 采用策略 | +| --- | --- | --- | +| 异步运行时 | Tokio | 基础运行时,统一超时、取消和任务模型 | +| REST/HTTP | Axum | 新服务首选;必要时保留 Actix-Web 作为备选 | +| RPC | Tonic + Prost | 与现有/新增 Protobuf 接口配套 | +| 序列化 | Serde | 配置、JSON 和内部数据结构 | +| 共识 | raft-rs / openraft | raft-rs 优先评估数据面,openraft 优先评估 PD | +| 本地存储 | rust-rocksdb | 复用 RocksDB 的成熟格式和能力 | +| TLS | rustls | 避免 OpenSSL 运行时依赖 | +| 可观测性 | tracing、Prometheus | 保持现有指标和日志字段兼容 | +| 错误处理 | thiserror、anyhow | 库错误类型与服务边界错误分离 | + +Raft 只复用成熟实现。`raft-rs` 的生产参考是 TiKV;`openraft` 可参考 Databend Meta 和 Danube。无论选择哪个库,日志持久化、快照、网络、状态机和升级流程仍由 HugeGraph 实现并测试。 + +## 5. 迁移阶段 + +### 阶段 0:基线和契约 + +梳理模块依赖、线程模型、数据格式、RPC、配置和运维脚本,建立吞吐、P99 延迟、内存、启动时间、恢复时间和故障场景基线。为 Java 实现补充协议级回放测试。 + +### 阶段 1:Rust 基础设施与旁路服务 + +建立 Rust workspace、CI、代码规范和镜像构建流程。实现健康检查、指标、管理 API、配置加载和只读元数据服务。此阶段不改变主写路径。 + +### 阶段 2:Rust PD 原型 + +使用 Tonic 和选定的 Raft 库实现三节点 PD 原型,验证 leader 切换、成员变更、日志恢复、快照安装、网络分区和滚动升级。通过协议适配接入现有 Store。 + +### 阶段 3:存储旁路与数据校验 + +实现 Rust RocksDB 存储适配器,在 Java 后端旁路执行只读请求,并进行结果、Schema、索引和序列化格式校验。必要时采用双写,但双写必须具备幂等键、失败重放和停止开关。 + +### 阶段 4:迁移数据面 + +按表、分片或后端实例逐步切换 Store。先迁移元数据和只读路径,再迁移写路径,最后处理事务、跨分片操作和在线升级。每次切换都保留回滚点。 + +### 阶段 5:核心查询与 API + +在存储语义稳定后迁移索引、查询计划、遍历执行和 REST/Gremlin 入口。外部协议测试必须与 Java 版本共享,并支持流量分配和灰度回滚。 + +### 阶段 6:收敛发行版 + +统一配置、日志、监控、升级、备份、恢复和发行包,删除已经没有流量的 Java 路径。 + +## 6. 兼容性要求 + +- REST、Gremlin、Cypher、认证和错误码保持兼容。 +- Schema、顶点/边 ID、属性编码、索引和事务语义保持兼容。 +- 现有 RocksDB 数据可由新实现读取;任何格式变更必须有版本号、迁移工具和回滚方案。 +- PD/Store RPC 采用版本化 Protobuf,支持旧节点与新节点滚动升级。 +- 配置项和指标名称尽量保持兼容,新增配置必须有默认值和文档。 + +## 7. 正确性与验证 + +必须建立以下测试层次:单元测试、协议兼容测试、Java/Rust 双实现回放测试、故障注入测试、长时间稳定性测试和性能回归测试。 + +重点故障包括进程崩溃、磁盘满、慢盘、网络分区、重复消息、消息乱序、节点落后、快照损坏、时钟跳变和滚动升级。Raft 相关测试应验证线性一致性、成员变更安全性和恢复后的日志连续性。 + +## 8. 重构契约与验收标准 + +“新旧实现一致”必须先写成机器可执行的契约。契约分为四层,不能只验证 HTTP 状态码。 + +### 8.1 外部协议契约 + +对每个 REST、Gremlin、Cypher 和 gRPC 操作定义请求、响应、错误码、字段缺省值、分页、排序、超时和幂等行为。使用 OpenAPI/Protobuf 作为结构契约,并保留由 Java 版本生成的黄金样例。Rust 版本必须通过全部样例;新增字段只能向后兼容,不能改变已有字段含义。 + +### 8.2 数据语义契约 + +定义顶点、边、属性、Schema、索引、事务和 ID 的不变量,例如: + +- 同一合法请求在新旧实现中产生相同的可观察结果; +- 写入成功后,在承诺的可见性范围内读取必定可见; +- 重复提交幂等请求不会产生额外顶点、边或属性; +- 删除、索引更新和 Schema 约束的结果一致; +- 导出后重新导入,图数据和 Schema 等价。 + +允许存在内部实现差异(例如日志序号不同),但必须通过规范化比较器比较外部语义,而不是比较内部字节。 + +### 8.3 状态与持久化契约 + +定义每个版本可读取的数据范围、升级步骤和回滚边界。对相同初始快照执行相同操作序列,新旧实现的规范化快照、Schema、索引目录和校验摘要必须一致。任何格式变化都必须提供迁移工具、版本标记和失败恢复方案。 + +### 8.4 分布式一致性契约 + +定义线性一致性、故障期间允许的错误、选主、成员变更、快照和恢复语义。使用可重复的操作历史记录器,在节点崩溃、分区、延迟和重复消息注入后,检查历史是否满足模型;不能用“测试没有报错”代替一致性判定。 + +### 8.5 差分验证方法 + +1. **黄金测试**:固定请求与响应样例,验证协议和错误行为。 +2. **随机模型测试**:由模型生成 Schema、图操作、事务和故障序列,同时驱动 Java 与 Rust 实现。 +3. **双读校验**:迁移期间同一只读请求同时访问两套实现,使用规范化比较器比对结果。 +4. **回放测试**:记录生产流量中的脱敏操作,在两套实现上重放并比较结果、延迟和资源使用。 +5. **状态校验**:定期比较顶点/边计数、Schema 摘要、索引摘要、快照校验和及 Raft 日志连续性。 + +比较器必须明确忽略允许变化的内容(时间戳、节点地址、内部序号、无序集合排列),并对不允许变化的内容逐字段报告差异。所有差异都要归类为实现缺陷、契约错误或明确批准的行为变化。 + +### 8.6 发布门槛 + +Rust 实现只有在以下条件同时满足后才能接管一条生产路径: + +- 协议黄金测试 100% 通过; +- 关键数据语义和随机模型测试通过,且无未解释差异; +- 故障注入后数据无丢失、重复提交符合幂等契约,节点可恢复; +- 快照、升级和回滚演练通过; +- 与 Java 基线相比,关键场景的吞吐、P99 延迟、内存和恢复时间达到预先约定的阈值; +- 灰度期间双读校验无持续性差异,并具备一键切回 Java 的能力。 + +验收结果应形成版本化报告,记录测试输入、软件版本、配置、故障注入步骤、差异清单和结论。没有报告和可重复脚本,不能声称契约已经保持一致。 + +## 9. 风险与控制措施 + +| 风险 | 控制措施 | +| --- | --- | +| Java/Rust 语义不一致 | 共享协议测试和随机回放;切换前双读校验 | +| Raft 集成错误 | 使用成熟库,限制状态机边界,做分区和崩溃注入 | +| RocksDB ABI/版本差异 | 固定 RocksDB 版本,构建镜像内置依赖,做格式兼容测试 | +| 双写不一致 | 幂等操作、WAL、重放工具和明确的回滚开关 | +| 生态组件变更 | Cargo.lock、供应链审计、定期升级窗口和兼容性 CI | +| 迁移范围失控 | 每阶段只替换一个边界,设置性能和正确性退出条件 | + +## 10. 第一阶段交付物 + +1. Rust workspace、CI、容器镜像和依赖审计清单。 +2. REST/gRPC 最小服务及统一 tracing、指标和错误模型。 +3. 基于 RocksDB 的存储适配器,能够读取现有测试数据。 +4. 三节点 PD 原型及故障注入报告。 +5. Java 与 Rust 的协议回放工具和基线性能报告。 + +只有当上述交付物通过恢复、兼容性和性能门槛后,才进入 Store 写路径迁移。 + +## 11. 集成测试盘点与小步替换流程 + +重构开始前先做测试资产盘点,不能先写 Rust 实现再围绕实现补测试。盘点结果至少包括:现有测试覆盖的 API、Schema、索引、事务、后端、故障和权限场景;每个场景的前置数据、操作序列、断言类型、是否依赖时序以及是否能在独立环境重放。对测试按“契约测试、模型测试、回归测试、性能测试、故障测试”分类,并标记空白区域和仅验证实现细节的用例。 + +### 11.1 Oracle 设计 + +不能把 Rust 实现的输出直接当作期望值。Oracle 按可靠程度分层: + +1. **规范 Oracle**:来自 TinkerPop/Gremlin、公开 REST/Protobuf 定义和 HugeGraph 已承诺的数据语义。 +2. **关系 Oracle**:用可执行不变量判断结果,例如重复写入幂等、边的端点存在、索引查询结果包含所有符合谓词的元素、快照恢复前后状态等价。 +3. **参考实现 Oracle**:在 Java 行为已经被确认且没有已知缺陷的范围内,用 Java 版本做差分参考;发现差异时必须回到规范或关系 Oracle 判定,不能自动把 Java 结果当真理。 +4. **模型 Oracle**:为有限状态的 Schema/事务/成员变更场景建立小型状态模型,用模型检查或穷举结果验证实现行为。 + +随机测试的种子、生成器版本、初始快照和故障计划必须持久化。每次失败都必须能最小化为可提交的确定性回归用例,避免“射箭画靶”。 + +### 11.2 需要补齐的测试簇 + +- API:正常、边界、非法参数、分页、排序、错误码、认证和超时; +- 图语义:顶点/边生命周期、属性基数、Schema 约束、索引更新与删除; +- 查询:Gremlin 步骤组合、空结果、重复结果、遍历顺序和事务可见性; +- 持久化:重启、崩溃恢复、旧数据读取、快照导入导出、格式升级和回滚; +- 分布式:选主、日志落盘、成员变更、网络分区、重复/乱序消息、慢节点和快照安装; +- 兼容性:Java/Rust 差分回放、跨版本滚动升级、旧客户端和旧配置; +- 非功能:并发、长稳、资源上限、限流、背压和故障恢复时间。 + +每个测试簇都要有覆盖矩阵,映射到契约条款和验收门槛;没有映射的测试不能作为迁移依据。 + +### 11.3 小步替换门禁 + +替换按“一个接口或一个内部边界”进行,而不是按大模块整体重写。每一步都遵循:盘点现有用例 → 补齐 Oracle 和缺口 → 建立 Java 基线 → 实现 Rust 等价边界 → 运行集成与故障测试 → 灰度双读/回放 → 观察窗口 → 才能扩大范围。 + +任一关键契约失败、出现未解释差异、数据校验不一致或恢复测试失败,都必须停止扩大迁移范围并保留回滚路径。集成测试通过是替换的必要条件,不是替换完成后的补充检查。 diff --git a/docs/rust-rewrite-test-inventory.md b/docs/rust-rewrite-test-inventory.md new file mode 100644 index 000000000..414732e3d --- /dev/null +++ b/docs/rust-rewrite-test-inventory.md @@ -0,0 +1,48 @@ +# Rust 重构测试资产盘点(初版) + +状态:盘点进行中。本文记录可重复的现状扫描结果,不把测试数量当作完备性证明。 + +## 1. 可重复统计 + +统计命令: + +```bash +find <module> -type f -name '*Test.java' | wc -l +``` + +当前仓库扫描结果: + +| 模块 | `*Test.java` 文件数 | 初步观察 | +| --- | ---: | --- | +| `hugegraph-server` | 165 | API、core、后端和集成测试分散在多个模块;部分测试位于 `src/main/java` 的测试工程目录 | +| `hugegraph-pd` | 61 | 有 REST、gRPC、客户端、服务和 Raft 相关测试,也有多节点 live 测试资源 | +| `hugegraph-store` | 70 | 有 RocksDB、Raft、分区、服务和会话测试 | +| `hugegraph-commons` | 52 | 共享工具和 RPC 基础测试 | +| `hugegraph-struct` | 2 | 数据结构测试较少,需要单独核对序列化契约 | + +这些数字只代表文件数量,不代表测试用例数量、覆盖率、断言质量或可作为 Rust Oracle 的程度。 + +## 2. 已发现的测试资产 + +- Server:`hugegraph-test` 包含 API、Gremlin、Schema、事务、序列化、缓存、遍历和 RocksDB 单元测试;`hugegraph-core`、`hugegraph-hstore` 和 `hugegraph-dist` 另有模块测试。 +- PD:包含 REST/gRPC、客户端、分区服务、配置、元数据、Raft engine readiness 和多节点 live 测试。 +- Store:包含 RocksDB、snapshot、partition engine、session、Raft core 和服务测试。 +- 测试配置:发现 `methods.filter`、`fast-methods.filter`、多节点 application 配置和测试套件类,需要确认 CI 实际执行范围。 + +CI 和模块文档显示,测试并非一个统一套件:Server 至少分为 `unit-test`、`core-test`、`api-test`,PD 有 `pd-core-test` 等 profile,Store 有 `store-core-test` 和 `store-raftcore-test`;GitHub Actions 还分别调用 unit/core/API/Raft 脚本。另一个重要事实是 PD/Store 的大量测试位于 `src/main/java`,不能只扫描标准 `src/test` 得出结论。 + +## 3. 当前不能据此得出的结论 + +目前还不能证明以下事项: + +1. 所有测试都在默认 CI/profile 中执行; +2. REST、Gremlin、Cypher、权限、事务和索引的外部契约均有端到端断言; +3. Raft 日志持久化、分区、快照恢复、成员变更和滚动升级已有完整故障测试; +4. 测试断言来自独立规范或不变量,而不是只验证当前 Java 实现; +5. Java 与 Rust 可以共享同一批确定性输入并进行规范化差分比较。 + +## 4. 下一步盘点输出 + +盘点必须逐测试套件记录:模块、执行 profile、能力域、前置数据、操作序列、断言、Oracle 类型、是否可独立重放、是否注入故障,以及对应的重构契约条款。最终生成“能力—契约—测试—实现”追踪矩阵,并将未覆盖条目标记为迁移阻断项。 + +在矩阵完成前,不开始替换生产写路径;后续每个 Rust 小步替换都必须先补齐该边界的测试和独立 Oracle,再运行 Java 基线、Rust 实现、差分回放和集成故障测试。
