use holt::{CheckpointImage, Durability, TreeConfig, DB};
fn sm_db() -> DB {
let mut cfg = TreeConfig::memory();
cfg.durability = Durability::StateMachine;
DB::open(cfg).expect("open state-machine DB")
}
#[test]
fn checkpoint_round_trips_all_families() {
let image = {
let db = sm_db();
let inodes = db.create_tree("inodes").unwrap();
let dentries = db.create_tree("dentries").unwrap();
for i in 0..500u32 {
inodes
.put(format!("ino/{i:06}").as_bytes(), format!("v{i}").as_bytes())
.unwrap();
dentries
.put(format!("d/{i:06}").as_bytes(), format!("e{i}").as_bytes())
.unwrap();
}
db.export_checkpoint(42).unwrap()
};
assert_eq!(image.applied_index().unwrap(), 42);
let db = sm_db();
assert_eq!(db.install_checkpoint(&image).unwrap(), 42);
assert_eq!(db.list_trees().unwrap(), vec!["dentries", "inodes"]);
let inodes = db.open_tree("inodes").unwrap();
let dentries = db.open_tree("dentries").unwrap();
for i in 0..500u32 {
assert_eq!(
inodes.get(format!("ino/{i:06}").as_bytes()).unwrap(),
Some(format!("v{i}").into_bytes()),
"inodes key {i}",
);
assert_eq!(
dentries.get(format!("d/{i:06}").as_bytes()).unwrap(),
Some(format!("e{i}").into_bytes()),
"dentries key {i}",
);
}
}
#[test]
fn checkpoint_survives_serialized_bytes() {
const N: u32 = 2000;
let value = vec![0xAB_u8; 200];
let raw: Vec<u8> = {
let db = sm_db();
let meta = db.create_tree("meta").unwrap();
for i in 0..N {
meta.put(format!("k{i:08}").as_bytes(), &value).unwrap();
}
db.export_checkpoint(7).unwrap().into_bytes()
};
let db = sm_db();
let image = CheckpointImage::from_bytes(raw);
assert_eq!(db.install_checkpoint(&image).unwrap(), 7);
let meta = db.open_tree("meta").unwrap();
for i in 0..N {
assert_eq!(
meta.get(format!("k{i:08}").as_bytes()).unwrap().as_deref(),
Some(&value[..]),
"key {i}",
);
}
}
#[test]
fn checkpoint_is_a_consistent_snapshot() {
let db = sm_db();
let m = db.create_tree("m").unwrap();
for i in 0..1000u32 {
m.put(format!("k{i:06}").as_bytes(), b"old").unwrap();
}
let image = db.export_checkpoint(1).unwrap();
for i in 0..1000u32 {
m.put(format!("k{i:06}").as_bytes(), b"new").unwrap();
}
let db2 = sm_db();
db2.install_checkpoint(&image).unwrap();
let m2 = db2.open_tree("m").unwrap();
for i in 0..1000u32 {
assert_eq!(
m2.get(format!("k{i:06}").as_bytes()).unwrap().as_deref(),
Some(&b"old"[..]),
"image must hold the pre-mutation value at key {i}",
);
}
assert_eq!(m.get(b"k000000").unwrap().as_deref(), Some(&b"new"[..]));
}
#[test]
fn install_rejects_corrupt_image() {
let db = sm_db();
assert!(db
.install_checkpoint(&CheckpointImage::from_bytes(vec![0u8; 4]))
.is_err());
assert!(db
.install_checkpoint(&CheckpointImage::from_bytes(b"holtckp1".to_vec()))
.is_err());
}