#![forbid(unsafe_code)]
use std::path::Path;
use crate::evidence::corpus::source_tree_files;
use crate::optimizer::policy::OptimizeOptions;
use crate::store::transaction::CrashHooks;
use crate::store::{NewEntry, Store, StoreConfig};
use tempfile::TempDir;
fn create_store(dir: &TempDir) -> Store {
let cfg = StoreConfig {
segment_size: 4 * 1024 * 1024,
..Default::default()
};
Store::create(dir.path(), &cfg, [0x9a; 16]).unwrap()
}
fn write_tree(store: &Store, files: &[(String, Vec<u8>)]) -> Vec<(u64, u64, Vec<u8>)> {
use std::collections::HashMap;
let mut dir_cache: HashMap<String, u64> = HashMap::new();
dir_cache.insert(String::new(), store.current_root().root_dir_ino);
let mut out: Vec<(u64, u64, Vec<u8>)> = Vec::new();
for (rel, bytes) in files {
let (dir_part, name) = match rel.rsplit_once('/') {
Some((d, n)) => (d.to_string(), n.to_string()),
None => (String::new(), rel.clone()),
};
if !dir_cache.contains_key(&dir_part) {
let mut cur = String::new();
let mut cur_ino = store.current_root().root_dir_ino;
for comp in dir_part.split('/') {
if comp.is_empty() {
continue;
}
let next_path = if cur.is_empty() {
comp.to_string()
} else {
format!("{cur}/{comp}")
};
let ino = match dir_cache.get(&next_path) {
Some(&c) => c,
None => {
let existing = store.dir_lookup(cur_ino, comp.as_bytes()).unwrap();
let ino = match existing {
Some(e) => e.ino,
None => store
.create_entry(
cur_ino,
comp.as_bytes(),
NewEntry::dir(0o755, 1000, 1000),
&CrashHooks::none(),
)
.unwrap(),
};
dir_cache.insert(next_path.clone(), ino);
ino
}
};
cur = next_path;
cur_ino = ino;
}
dir_cache.insert(dir_part.clone(), cur_ino);
}
let ino = store
.create_entry(
dir_cache[&dir_part],
name.as_bytes(),
NewEntry::file(0o644, 1000, 1000),
&CrashHooks::none(),
)
.unwrap();
let mut writes: Vec<(u64, Vec<u8>)> = Vec::new();
let mut off = 0u64;
while off < bytes.len() as u64 {
let len = 65536u64.min(bytes.len() as u64 - off);
writes.push((off, bytes[off as usize..(off + len) as usize].to_vec()));
off += len;
}
store
.write_region_batch(ino, &writes, OptimizeOptions::default())
.unwrap();
out.push((ino, dir_cache[&dir_part], bytes.clone()));
}
out
}
fn reachable(store: &Store) -> u64 {
let unreachable = crate::store::gc::unreachable_bytes(store).unwrap();
let records_total: u64 = store
.object_index()
.iter()
.into_iter()
.map(|(_, loc)| loc.total_size())
.sum();
records_total.saturating_sub(unreachable)
}
fn verify_bytes(store: &Store, files: &[(u64, u64, Vec<u8>)]) {
for (ino, _dir, bytes) in files {
let mut got = Vec::new();
let mut off = 0u64;
while off < bytes.len() as u64 {
let len = 65536u64.min(bytes.len() as u64 - off);
got.extend_from_slice(&store.read_file(*ino, off, len).unwrap());
off += len;
}
assert_eq!(got, *bytes, "byte-exactness violated for ino {ino}");
}
}
#[test]
fn model_bundle_pass_is_byte_exact_idempotent_and_shrinks_the_real_tree() {
let root = Path::new(env!("CARGO_MANIFEST_DIR"));
let files = source_tree_files(root).unwrap();
let dir = TempDir::new().unwrap();
let store = create_store(&dir);
let tree = write_tree(&store, &files);
crate::optimizer::background::shared_dict_pass(&store, OptimizeOptions::default(), None)
.unwrap();
let before_models = reachable(&store);
let first =
crate::optimizer::background::model_bundle_pass(&store, OptimizeOptions::default(), None)
.unwrap();
crate::store::gc::collect(&store, &CrashHooks::none()).unwrap();
let after_models = reachable(&store);
verify_bytes(&store, &tree);
println!(
"model-bundle pass (real tree): scanned {}, rewrote {}, saved {} B (cohort-accounted); reachable {} -> {} B ({:.1} KiB)",
first.scanned,
first.rewritten,
first.saved_bytes,
before_models,
after_models,
before_models.saturating_sub(after_models) as f64 / 1024.0
);
let stats =
crate::optimizer::background::model_bundle_pass(&store, OptimizeOptions::default(), None)
.unwrap();
assert_eq!(stats.errors, 0, "second pass must not error");
assert_eq!(
stats.rewritten, 0,
"second pass must be a no-op (rewrote {})",
stats.rewritten
);
drop(store);
let store2 = Store::open(dir.path(), &StoreConfig::default()).unwrap();
verify_bytes(&store2, &tree);
let report = crate::fsck::fsck(dir.path(), &crate::fsck::FsckOptions::default()).unwrap();
assert!(report.is_clean(), "fsck: {}", report.render());
drop(store2);
let dir2 = TempDir::new().unwrap();
let store3 = create_store(&dir2);
let tree3 = write_tree(&store3, &files);
crate::optimizer::background::shared_dict_pass(&store3, OptimizeOptions::default(), None)
.unwrap();
crate::store::gc::collect(&store3, &CrashHooks::none()).unwrap();
let baseline = reachable(&store3);
assert!(
after_models <= baseline,
"model pass must not regress the footprint: {after_models} vs {baseline}"
);
verify_bytes(&store3, &tree3);
}
#[test]
fn model_bundle_pass_never_rewrites_noise() {
let dir = TempDir::new().unwrap();
let store = create_store(&dir);
let noise_dir = store
.create_entry(
store.current_root().root_dir_ino,
b"noise",
NewEntry::dir(0o755, 1000, 1000),
&CrashHooks::none(),
)
.unwrap();
let mut inos = Vec::new();
for i in 0..4u64 {
let ino = store
.create_entry(
noise_dir,
format!("n{i}.bin").as_bytes(),
NewEntry::file(0o644, 1000, 1000),
&CrashHooks::none(),
)
.unwrap();
let mut bytes = Vec::with_capacity(8192);
let mut state = 0x9e37_79b9_7f4a_7c15u64 ^ (0x1234_0000 + i);
for _ in 0..8192 {
state = state
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
bytes.push((state >> 33) as u8);
}
store.write_region(ino, 0, &bytes).unwrap();
inos.push((ino, bytes));
}
let stats =
crate::optimizer::background::model_bundle_pass(&store, OptimizeOptions::default(), None)
.unwrap();
assert_eq!(
stats.rewritten, 0,
"noise cohort must not be rewritten (group gate failed): {stats:?}"
);
for (ino, bytes) in &inos {
assert_eq!(store.read_file(*ino, 0, 8192).unwrap(), *bytes);
}
}