65 lines
2.6 KiB
Rust
65 lines
2.6 KiB
Rust
use cube_mvw::MvwBackend;
|
|
use cubecoords::{CubeHeader, Czyx};
|
|
use cubestore::{CubeBackend, CubeStore};
|
|
use std::path::{Path, PathBuf};
|
|
use std::fs;
|
|
use std::thread;
|
|
use std::sync::Arc;
|
|
|
|
fn base(name: &str) -> PathBuf { std::env::temp_dir().join(name) }
|
|
fn cleanup(b: &Path) { for i in 0..16 { let _=fs::remove_file(format!("{}-s{}.log",b.display(),i)); let _=fs::remove_file(format!("{}-s{}.ckpt",b.display(),i)); } }
|
|
|
|
#[test]
|
|
fn backend_durable_mvcc_and_concurrent() {
|
|
let b = base("mvw-backend"); cleanup(&b);
|
|
{
|
|
let back = MvwBackend::open(16, &b).unwrap();
|
|
back.put_shared(Czyx::new(1,1,1,1), b"hello".to_vec());
|
|
// MVCC: a later write is the latest visible version
|
|
back.put_shared(Czyx::new(1,1,1,1), b"world".to_vec());
|
|
assert_eq!(back.get(&Czyx::new(1,1,1,1)), Some(b"world".to_vec()));
|
|
}
|
|
// durability: drop (no graceful shard flush), reopen from per-shard WALs
|
|
let back = MvwBackend::open(16, &b).unwrap();
|
|
let latest = back.get(&Czyx::new(1,1,1,1)).unwrap();
|
|
assert!(latest == b"world".to_vec(), "WAL recovery must restore the latest MVCC version");
|
|
// keys enumeration
|
|
back.put_shared(Czyx::new(2,2,2,2), b"a".to_vec());
|
|
assert!(back.keys().contains(&Czyx::new(2,2,2,2)));
|
|
|
|
// true concurrent multi-writer (shared &self put_shared), 8 threads x 2000
|
|
let shared = Arc::new(MvwBackend::open(16, &b).unwrap());
|
|
let mut handles = Vec::new();
|
|
for t in 0..8u64 {
|
|
let s = shared.clone();
|
|
handles.push(thread::spawn(move || for i in 0..2000u64 {
|
|
let k = Czyx::unpack_u32(((t * 2000 + i) as u32) << 8 | 1);
|
|
s.put_shared(k, vec![(i as u8); 8]);
|
|
}));
|
|
}
|
|
for h in handles { h.join().unwrap(); }
|
|
// all writes readable
|
|
for t in 0..8u64 { for i in 0..2000u64 {
|
|
assert!(shared.get(&Czyx::unpack_u32(((t*2000+i) as u32) << 8 | 1)).is_some());
|
|
}}
|
|
// compact folds memtable to checkpoint and truncates WALs; values still readable
|
|
shared.compact().unwrap();
|
|
assert!(shared.get(&Czyx::new(1,1,1,1)).is_some());
|
|
cleanup(&b);
|
|
let _ = thread::current(); // silence
|
|
}
|
|
|
|
#[test]
|
|
fn cubestore_record_api_over_mvw_backend() {
|
|
let b = base("mvw-cubestore"); cleanup(&b);
|
|
let mut store = CubeStore::new(MvwBackend::open(16, &b).unwrap());
|
|
let mut h = CubeHeader::new();
|
|
h.title = Some("t".into());
|
|
h.refresh_flags();
|
|
store.put_record(Czyx::new(3,3,3,3), &h, b"body");
|
|
let (h2, body) = store.get_record(&Czyx::new(3,3,3,3)).expect("record roundtrip");
|
|
assert_eq!(body, b"body");
|
|
assert_eq!(h2.title.as_deref(), Some("t"));
|
|
cleanup(&b);
|
|
}
|