fix(cubefs): make FUSE mount a durable view of cube-server daemon store

The cubefs-mount --socket path was never actually built: CubeFs<B> is
generic, so the --socket (DaemonBackend) and default (HashBackend) arms
of the match were incompatible types (E0308), and --features mount failed
to compile. The running binary was therefore the in-memory build, so
--socket was silently ignored and every FUSE write went to RAM and never
reached the daemon (rawget/rawkeys returned none / 0 keys, WAL stayed 0).

Fix: type-erase the backend. Add  (forwards to inner) in cubestore, and build
 in cubefs-mount via
Box::new(DaemonBackend::new(p)) / Box::new(HashBackend::new()). Keeps
cubefs free of a cubesys dep (acyclic graph).

Verified end-to-end on host (shared code path as the VM): a FUSE write
via  lands in the daemon store (rawget returns the
record, 5 keys present, WAL grows), and survives a  of the
daemon + relaunch with the same --store (byte-identical read-back).

Also includes (from RESUME-cubefs-daemon.md): cubesys raw* command family
(rawget/rawput/rawdel/rawkeys/rawscan + parse/hex helpers) and the
DaemonBackend client + smoke tests. Report/verification docs added.

Note: VM cubefs.service still mounts in-memory (no --socket); update the
unit to  as a
follow-up so the deployed VM FUSE is durable too.
This commit is contained in:
CUBELinux-2
2026-08-13 05:40:59 -04:00
parent ad73f42e46
commit 8f9e7e0025
10 changed files with 574 additions and 13 deletions
+25
View File
@@ -0,0 +1,25 @@
// Ad-hoc smoke test: CubeFs + DaemonBackend (NO FUSE) against a live daemon.
// Bisects whether the FUSE layer or the cubefs/cubestore layer is the culprit.
// Run: CUBE_SOCK=<sock> cargo test --test cubefs_daemon_smoke -- --nocapture
use cubecoords::Czyx;
use cubefs::{CubeFs, DaemonBackend};
use cubestore::{CubeBackend, CubeStore};
#[test]
fn cubefs_create_write_reaches_daemon() {
let sock = std::env::var("CUBE_SOCK").expect("set CUBE_SOCK");
let mut fs = CubeFs::new(CubeStore::new(DaemonBackend::new(sock)));
fs.format("cube0");
let path = "/c011/z007/y003/x009";
fs.create(path, 0, 0, 0o644).expect("create");
fs.write(path, 0, b"fuse-proof-XYZ", 0, 0).expect("write");
// Now ask the daemon directly via a second backend.
let mut probe = DaemonBackend::new(std::env::var("CUBE_SOCK").unwrap());
let k = Czyx::new(11, 7, 3, 9);
let got = probe.get(&k);
println!("daemon-side get(11,7,3,9) => {:?}", got);
assert_eq!(got.as_deref(), Some(&b"fuse-proof-XYZ"[..]), "CubeFs write must reach daemon store");
let keys = probe.keys();
println!("daemon keys => {:?}", keys);
assert!(keys.contains(&k));
}
+21
View File
@@ -0,0 +1,21 @@
// Ad-hoc smoke test for DaemonBackend end-to-end against a live cube-server.
// Run with: cargo test --test daemon_backend_smoke -- --nocapture
// Requires CUBE_SOCK env var pointing at a running cube-server socket.
use cubecoords::Czyx;
use cubefs::DaemonBackend;
use cubestore::CubeBackend;
#[test]
fn daemon_backend_put_get_roundtrip() {
let sock = std::env::var("CUBE_SOCK").expect("set CUBE_SOCK to a live cube-server socket");
let mut b = DaemonBackend::new(sock);
let k = Czyx::new(9, 2, 2, 1);
b.put(k, b"fuse-persist-proof".to_vec());
let got = b.get(&k);
println!("DaemonBackend::get(9,2,2,1) => {:?}", got);
assert_eq!(got.as_deref(), Some(&b"fuse-persist-proof"[..]), "daemon backend put/get roundtrip");
// also exercise keys()
let keys = b.keys();
println!("DaemonBackend::keys() => {:?}", keys);
assert!(keys.contains(&k), "keys() should include coord after put");
}