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
The following commit(s) were added to refs/heads/refactor/rust-rewrite-design
by this push:
new 6d01a30f8 test(poc): enforce Rust format and lint gates
6d01a30f8 is described below
commit 6d01a30f8e8d483a9a10fa94fb01fa49f9767ddd
Author: vaughn <[email protected]>
AuthorDate: Thu Sep 10 02:12:50 2026 +0800
test(poc): enforce Rust format and lint gates
---
docs/rust-rewrite-partition-pilot.md | 2 +
tools/rust-partition-poc/Cargo.lock | 7 ++
tools/rust-partition-poc/Cargo.toml | 20 +---
tools/rust-partition-poc/src/lib.rs | 171 ++++++++++++++++++++++++++++++-----
tools/rust-partition-poc/src/main.rs | 13 ++-
5 files changed, 172 insertions(+), 41 deletions(-)
diff --git a/docs/rust-rewrite-partition-pilot.md
b/docs/rust-rewrite-partition-pilot.md
index 43d0a0d4a..60686c706 100644
--- a/docs/rust-rewrite-partition-pilot.md
+++ b/docs/rust-rewrite-partition-pilot.md
@@ -55,3 +55,5 @@ A standalone invariant oracle was implemented at
`tools/rust-partition-poc`. It
真实集成执行记录(2026-09-10):RAT 已通过,但 Maven 在解析 `maven-surefire-plugin:2.20`
时因当前环境无法写入 `/home/zy/.m2` 且缺少缓存而停止,未进入测试阶段。该结果标记为环境阻塞,不能计作通过;重试需提供可写 Maven
本地仓库并保存 Surefire 报告。
重试记录:改用 `-Dmaven.repo.local=/tmp/hugegraph-m2` 后,构建因 DNS 无法解析
`repo.maven.apache.org`,缺少 `org.apache:apache:23` 父 POM而停止。该环境阻塞仍未计作测试通过。
+
+Rust 工程门禁记录:`cargo fmt -- --check`、`cargo clippy --all-targets -- -D warnings`
和 `cargo test` 均通过;测试仍为 9 项通过。
diff --git a/tools/rust-partition-poc/Cargo.lock
b/tools/rust-partition-poc/Cargo.lock
new file mode 100644
index 000000000..defe85931
--- /dev/null
+++ b/tools/rust-partition-poc/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "hugegraph-partition-poc"
+version = "0.1.0"
diff --git a/tools/rust-partition-poc/Cargo.toml
b/tools/rust-partition-poc/Cargo.toml
index 5fd66a555..cc1e601b2 100644
--- a/tools/rust-partition-poc/Cargo.toml
+++ b/tools/rust-partition-poc/Cargo.toml
@@ -1,19 +1,7 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+# Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.
+# See the NOTICE file distributed with this work for additional information.
+# The ASF licenses this file under the Apache License, Version 2.0.
+# http://www.apache.org/licenses/LICENSE-2.0
[package]
name = "hugegraph-partition-poc"
diff --git a/tools/rust-partition-poc/src/lib.rs
b/tools/rust-partition-poc/src/lib.rs
index 1fff43acc..0d64740e6 100644
--- a/tools/rust-partition-poc/src/lib.rs
+++ b/tools/rust-partition-poc/src/lib.rs
@@ -16,25 +16,43 @@
*/
#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct Partition { pub start: u64, pub end: u64, pub version: u64 }
+pub struct Partition {
+ pub start: u64,
+ pub end: u64,
+ pub version: u64,
+}
pub fn validate(parts: &[Partition], max: u64) -> Result<(), &'static str> {
- if parts.is_empty() || parts[0].start != 0 { return Err("gap-at-start"); }
+ if parts.is_empty() || parts[0].start != 0 {
+ return Err("gap-at-start");
+ }
for (i, p) in parts.iter().enumerate() {
- if p.start >= p.end || p.end > max { return Err("invalid-range"); }
+ if p.start >= p.end || p.end > max {
+ return Err("invalid-range");
+ }
if i > 0 {
let prev = &parts[i - 1];
- if prev.end != p.start { return Err("gap-or-overlap"); }
- if p.version < prev.version { return Err("version-regression"); }
+ if prev.end != p.start {
+ return Err("gap-or-overlap");
+ }
+ if p.version < prev.version {
+ return Err("version-regression");
+ }
}
}
- if parts.last().unwrap().end != max { return Err("gap-at-end"); }
+ if parts.last().unwrap().end != max {
+ return Err("gap-at-end");
+ }
Ok(())
}
pub fn apply_heartbeat(current: &mut Partition, incoming: Partition) ->
Result<(), &'static str> {
- if incoming.start != current.start || incoming.end != current.end { return
Err("range-mismatch"); }
- if incoming.version < current.version { return Err("stale-heartbeat"); }
+ if incoming.start != current.start || incoming.end != current.end {
+ return Err("range-mismatch");
+ }
+ if incoming.version < current.version {
+ return Err("stale-heartbeat");
+ }
*current = incoming;
Ok(())
}
@@ -42,20 +60,86 @@ pub fn apply_heartbeat(current: &mut Partition, incoming:
Partition) -> Result<(
#[cfg(test)]
mod tests {
use super::*;
- fn base() -> Vec<Partition> { vec![Partition{start:0,end:10,version:1},
Partition{start:10,end:20,version:1}] }
- #[test] fn baseline_is_valid() { assert!(validate(&base(), 20).is_ok()); }
- #[test] fn catches_dropped_right_partition() { let mut x=base(); x.pop();
assert!(validate(&x,20).is_err()); }
- #[test] fn catches_overlap() { let mut x=base(); x[1].start=9;
assert_eq!(validate(&x,20),Err("gap-or-overlap")); }
- #[test] fn catches_version_regression() { let mut x=base();
x[1].version=0; assert_eq!(validate(&x,20),Err("version-regression")); }
- #[test] fn rejects_stale_heartbeat() { let mut
c=Partition{start:0,end:10,version:2}; assert_eq!(apply_heartbeat(&mut
c,Partition{start:0,end:10,version:1}),Err("stale-heartbeat")); }
- #[test] fn heartbeat_is_idempotent() { let mut
c=Partition{start:0,end:10,version:1}; let n=c.clone(); apply_heartbeat(&mut
c,n.clone()).unwrap(); apply_heartbeat(&mut c,n).unwrap();
assert_eq!(c.version,1); }
+ fn base() -> Vec<Partition> {
+ vec![
+ Partition {
+ start: 0,
+ end: 10,
+ version: 1,
+ },
+ Partition {
+ start: 10,
+ end: 20,
+ version: 1,
+ },
+ ]
+ }
+ #[test]
+ fn baseline_is_valid() {
+ assert!(validate(&base(), 20).is_ok());
+ }
+ #[test]
+ fn catches_dropped_right_partition() {
+ let mut x = base();
+ x.pop();
+ assert!(validate(&x, 20).is_err());
+ }
+ #[test]
+ fn catches_overlap() {
+ let mut x = base();
+ x[1].start = 9;
+ assert_eq!(validate(&x, 20), Err("gap-or-overlap"));
+ }
+ #[test]
+ fn catches_version_regression() {
+ let mut x = base();
+ x[1].version = 0;
+ assert_eq!(validate(&x, 20), Err("version-regression"));
+ }
+ #[test]
+ fn rejects_stale_heartbeat() {
+ let mut c = Partition {
+ start: 0,
+ end: 10,
+ version: 2,
+ };
+ assert_eq!(
+ apply_heartbeat(
+ &mut c,
+ Partition {
+ start: 0,
+ end: 10,
+ version: 1
+ }
+ ),
+ Err("stale-heartbeat")
+ );
+ }
+ #[test]
+ fn heartbeat_is_idempotent() {
+ let mut c = Partition {
+ start: 0,
+ end: 10,
+ version: 1,
+ };
+ let n = c.clone();
+ apply_heartbeat(&mut c, n.clone()).unwrap();
+ apply_heartbeat(&mut c, n).unwrap();
+ assert_eq!(c.version, 1);
+ }
}
-pub fn replay(mut state: Vec<Partition>, events: &[Partition], max: u64) ->
Result<Vec<Partition>, &'static str> {
+pub fn replay(
+ mut state: Vec<Partition>,
+ events: &[Partition],
+ max: u64,
+) -> Result<Vec<Partition>, &'static str> {
for event in events {
if let Some(current) = state.iter_mut().find(|p| p.start ==
event.start) {
apply_heartbeat(current, event.clone())?;
- } else { return Err("unknown-partition"); }
+ } else {
+ return Err("unknown-partition");
+ }
}
validate(&state, max)?;
Ok(state)
@@ -64,17 +148,56 @@ pub fn replay(mut state: Vec<Partition>, events:
&[Partition], max: u64) -> Resu
#[cfg(test)]
mod recovery_tests {
use super::*;
- fn base() -> Vec<Partition> { vec![Partition{start:0,end:10,version:1},
Partition{start:10,end:20,version:1}] }
- #[test] fn replay_is_deterministic() {
- let events = vec![Partition{start:0,end:10,version:2},
Partition{start:10,end:20,version:2}];
+ fn base() -> Vec<Partition> {
+ vec![
+ Partition {
+ start: 0,
+ end: 10,
+ version: 1,
+ },
+ Partition {
+ start: 10,
+ end: 20,
+ version: 1,
+ },
+ ]
+ }
+ #[test]
+ fn replay_is_deterministic() {
+ let events = vec![
+ Partition {
+ start: 0,
+ end: 10,
+ version: 2,
+ },
+ Partition {
+ start: 10,
+ end: 20,
+ version: 2,
+ },
+ ];
assert_eq!(replay(base(), &events, 20), replay(base(), &events, 20));
}
- #[test] fn replay_rejects_corrupt_restart_state() {
- let mut state = base(); state[1].start = 11;
+ #[test]
+ fn replay_rejects_corrupt_restart_state() {
+ let mut state = base();
+ state[1].start = 11;
assert_eq!(replay(state, &[], 20), Err("gap-or-overlap"));
}
- #[test] fn replay_rejects_duplicate_stale_event() {
- let events = vec![Partition{start:0,end:10,version:2},
Partition{start:0,end:10,version:1}];
+ #[test]
+ fn replay_rejects_duplicate_stale_event() {
+ let events = vec![
+ Partition {
+ start: 0,
+ end: 10,
+ version: 2,
+ },
+ Partition {
+ start: 0,
+ end: 10,
+ version: 1,
+ },
+ ];
assert_eq!(replay(base(), &events, 20), Err("stale-heartbeat"));
}
}
diff --git a/tools/rust-partition-poc/src/main.rs
b/tools/rust-partition-poc/src/main.rs
index 991205987..81014f06d 100644
--- a/tools/rust-partition-poc/src/main.rs
+++ b/tools/rust-partition-poc/src/main.rs
@@ -17,7 +17,18 @@
use hugegraph_partition_poc::{validate, Partition};
fn main() {
- let baseline = vec![Partition{start:0,end:10,version:1},
Partition{start:10,end:20,version:1}];
+ let baseline = vec![
+ Partition {
+ start: 0,
+ end: 10,
+ version: 1,
+ },
+ Partition {
+ start: 10,
+ end: 20,
+ version: 1,
+ },
+ ];
validate(&baseline, 20).expect("baseline oracle");
println!("PASS partition invariant oracle: {:?}", baseline);
}