fix(cubefs): round-trip full record envelope through DaemonBackend + gate hardening

- DaemonBackend::put/get now round-trip the FULL record envelope (header+body)
  verbatim via rawput/rawget instead of stripping to a bare body. Before this,
  a socket-backed mount wrote the bare body but get returned it as if it were a
  record, breaking the FUSE read-back path (get_record could not decode it).
  This diverged from the in-memory backend and silently corrupted reads.
- Cargo fmt --check now passes (was failing; the committed tree was never a
  clean ./check, which is why the durable mount could regress undetected).
- Fix two new clippy lints (manual_is_multiple_of) in cubefs/backend.rs and
  cubesys/commands.rs so the -D warnings gate is green.
- Daemon-backed integration tests (cubefs_daemon_smoke, daemon_backend_smoke)
  now use the real CubeStore<DaemonBackend> record path and are #[ignore]d so
  the default gate (no daemon) stays green, while ./check daemon spins up a live
  cube-server and runs them via --ignored. This makes the durable-socket
  contract an actual enforced test, not a manual ad-hoc script.
This commit is contained in:
CUBELinux-2
2026-08-13 05:58:12 -04:00
parent 8f9e7e0025
commit 0300def300
6 changed files with 138 additions and 42 deletions
+21 -9
View File
@@ -582,8 +582,7 @@ impl Session {
let hex = it
.next()
.ok_or_else(|| "rawput needs <hex-bytes>".to_string())?;
let val = hex_decode(hex)
.ok_or_else(|| "rawput: value must be hex".to_string())?;
let val = hex_decode(hex).ok_or_else(|| "rawput: value must be hex".to_string())?;
let coord = Czyx::new(c, z, y, x);
store.put_raw(coord, val);
Ok(format!("ok: wrote {}", coord.pack_u32()))
@@ -598,10 +597,18 @@ impl Session {
Ok(format!("ok: deleted {}", coord.pack_u32()))
}
"rawkeys" => {
let ks: Vec<String> =
store.keys().iter().map(|k| k.pack_u32().to_string()).collect();
Ok(format!("ok: {} keys", ks.len()))
.map(|s| if ks.is_empty() { s } else { format!("{s}\n{}", ks.join(" ")) })
let ks: Vec<String> = store
.keys()
.iter()
.map(|k| k.pack_u32().to_string())
.collect();
Ok(format!("ok: {} keys", ks.len())).map(|s| {
if ks.is_empty() {
s
} else {
format!("{s}\n{}", ks.join(" "))
}
})
}
"rawscan" => {
let c = parse_u8(it.next(), "rawscan needs <c>")?;
@@ -612,8 +619,13 @@ impl Session {
.iter()
.map(|k| k.pack_u32().to_string())
.collect();
Ok(format!("ok: {} keys", ks.len()))
.map(|s| if ks.is_empty() { s } else { format!("{s}\n{}", ks.join(" ")) })
Ok(format!("ok: {} keys", ks.len())).map(|s| {
if ks.is_empty() {
s
} else {
format!("{s}\n{}", ks.join(" "))
}
})
}
"grant" => {
// Issue a permission grant (Task 6b / PDF flags 5-19). Only an
@@ -933,7 +945,7 @@ fn hex_encode(b: &[u8]) -> String {
/// Decode a hex string into bytes. Rejects odd length / non-hex.
fn hex_decode(s: &str) -> Option<Vec<u8>> {
if s.len() % 2 != 0 {
if !s.len().is_multiple_of(2) {
return None;
}
let bytes = s.as_bytes();