use crate::compaction::{compact_image, CompactionError, CompactionResult};
pub fn run(manifest_bytes: &[u8], slab_bytes: &[u8]) -> Result<CompactionResult, CompactionError> {
compact_image(manifest_bytes, slab_bytes)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::write_directory;
use std::path::Path;
#[test]
fn turnover_compacts_unreferenced_drops() {
let temp1 =
std::env::temp_dir().join(format!("limnifs-turnover-pre-{}", std::process::id()));
let temp2 =
std::env::temp_dir().join(format!("limnifs-turnover-post-{}", std::process::id()));
std::fs::create_dir_all(&temp1).unwrap();
std::fs::create_dir_all(&temp2).unwrap();
let large_a = vec![0xAAu8; 8192];
let large_b = vec![0xBBu8; 8192];
std::fs::write(temp1.join("a.bin"), &large_a).unwrap();
std::fs::write(temp1.join("b.bin"), &large_b).unwrap();
std::fs::write(temp2.join("a.bin"), &large_a).unwrap();
let before = write_directory(&temp1).expect("write before");
let after = write_directory(&temp2).expect("write after");
std::fs::remove_dir_all(&temp1).ok();
std::fs::remove_dir_all(&temp2).ok();
let slab_bytes = before.slab_bytes().expect("slab exists");
let turnover_result = run(&after.bytes, slab_bytes).expect("turnover");
assert_eq!(
turnover_result.original_drop_count - turnover_result.compacted_drop_count,
turnover_result.reclaimed_drops,
"compacted = original - reclaimed"
);
assert!(
turnover_result.compacted_drop_count < turnover_result.original_drop_count,
"turnover must reclaim the orphaned drop"
);
}
#[test]
fn turnover_preserves_referenced_drops() {
let temp =
std::env::temp_dir().join(format!("limnifs-turnover-keep-{}", std::process::id()));
std::fs::create_dir_all(&temp).unwrap();
let payload = vec![0xCCu8; 8192];
std::fs::write(temp.join("keep.bin"), &payload).unwrap();
let artifact = write_directory(&temp).expect("write");
std::fs::remove_dir_all(&temp).ok();
let slab_bytes = artifact.slab_bytes().expect("slab exists");
let turnover_result = run(&artifact.bytes, slab_bytes).expect("turnover");
assert_eq!(turnover_result.compacted_drop_count, 1);
assert_eq!(turnover_result.reclaimed_drops, 0);
let new_slab = turnover_result
.slab_bytes
.as_deref()
.expect("turnover produced slab");
let view = limnifs_core::parse_slab(new_slab).expect("slab parses");
let drop_id = limnifs_core::hash_section(&payload);
let plaintext = view
.plaintext_for(&drop_id)
.expect("drop present")
.expect("decompresses");
assert_eq!(plaintext, payload);
}
#[test]
fn turnover_history_marks_turnover_op() {
let temp =
std::env::temp_dir().join(format!("limnifs-turnover-hist-{}", std::process::id()));
std::fs::create_dir_all(&temp).unwrap();
std::fs::write(temp.join("x.bin"), vec![0x11u8; 8192]).unwrap();
let artifact = write_directory(&temp).expect("write");
std::fs::remove_dir_all(&temp).ok();
let slab_bytes = artifact.slab_bytes().expect("slab exists");
let turnover_result = run(&artifact.bytes, slab_bytes).expect("turnover");
let mut cursor = limnifs_core::ManifestCursor::new(&turnover_result.manifest_bytes);
limnifs_core::parse_manifest_header(&mut cursor).unwrap();
limnifs_core::parse_feature_flags_section(&mut cursor).unwrap();
limnifs_core::parse_metadata_reference(&mut cursor).unwrap();
limnifs_core::parse_slab_index(&mut cursor).unwrap();
let history = limnifs_core::parse_history(&mut cursor).unwrap();
assert_eq!(history.entries.len(), 1);
assert_eq!(history.entries[0].op, limnifs_core::HistoryOp::Turnover);
}
#[test]
fn turnover_drops_path_is_unused() {
fn _signature_check(_manifest: &[u8], _slab: &[u8]) {}
let _ = _signature_check;
let _ = Path::new("/this/path/does/not/exist");
}
}