use std::path::PathBuf;
use prikk_store::{
CompactionReport, compact_received_index, compact_ref_pointer_index, compact_trust_policy,
plan_compact_received_index, plan_compact_ref_pointer_index, plan_compact_trust_policy,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Target {
PointerIndex,
ReceivedIndex,
TrustPolicy,
}
const ALL_TARGETS: [Target; 3] = [
Target::PointerIndex,
Target::ReceivedIndex,
Target::TrustPolicy,
];
pub(crate) fn run_compact(root: PathBuf, args: Vec<String>) -> std::result::Result<(), String> {
let mut targets: Vec<Target> = Vec::new();
let mut plan_only = false;
for arg in args {
match arg.as_str() {
"--pointer-index" => targets.push(Target::PointerIndex),
"--received-index" => targets.push(Target::ReceivedIndex),
"--trust-policy" => targets.push(Target::TrustPolicy),
"--all" => targets.extend(ALL_TARGETS),
"--plan-only" => plan_only = true,
other => return Err(format!("unknown compact argument: {other}")),
}
}
if targets.is_empty() {
return Err(
"compact requires a target: --pointer-index, --received-index, --trust-policy, or \
--all (add --plan-only to preview without writing)"
.to_string(),
);
}
targets.dedup();
let layout = crate::open_repository(root)?;
for target in targets {
let report = run_one(&layout, target, plan_only).map_err(|err| err.to_string())?;
print_report(&report, plan_only);
}
Ok(())
}
fn run_one(
layout: &prikk_store::RepositoryLayout,
target: Target,
plan_only: bool,
) -> prikk_error::Result<CompactionReport> {
match (target, plan_only) {
(Target::PointerIndex, false) => compact_ref_pointer_index(layout),
(Target::PointerIndex, true) => plan_compact_ref_pointer_index(layout),
(Target::ReceivedIndex, false) => compact_received_index(layout),
(Target::ReceivedIndex, true) => plan_compact_received_index(layout),
(Target::TrustPolicy, false) => compact_trust_policy(layout),
(Target::TrustPolicy, true) => plan_compact_trust_policy(layout),
}
}
fn print_report(report: &CompactionReport, plan_only: bool) {
let name = match report.container {
prikk_store::LockableContainer::RefPointerIndex => "pointer-index",
prikk_store::LockableContainer::ReceivedIndex => "received-index",
prikk_store::LockableContainer::TrustPolicy => "trust-policy",
prikk_store::LockableContainer::RefLog => "ref-log",
};
let verb = if plan_only {
"would reclaim"
} else {
"reclaimed"
};
let reclaimed = report.entries_before.saturating_sub(report.entries_after);
println!(
"{name}: {reclaimed} {verb} ({} -> {} live records)",
report.entries_before, report.entries_after
);
}