use std::collections::BTreeSet;
use std::path::Path;
use crate::blob::BlobStore;
use crate::error::Result;
use crate::manifest::ManifestStore;
use crate::refs::GcStats;
use crate::refs::RefStore;
use crate::refs::TurnIndex;
use crate::sweep::collect_partition;
use crate::workspace;
pub fn content_disk_usage(data_dir: &Path) -> Result<u64> {
fn walk(dir: &Path) -> u64 {
let Ok(entries) = std::fs::read_dir(dir) else {
return 0;
};
entries
.flatten()
.map(|entry| match entry.metadata() {
Ok(meta) if meta.is_dir() => walk(&entry.path()),
Ok(meta) => meta.len(),
Err(_) => 0,
})
.sum()
}
Ok(walk(&workspace::blobs_dir(&workspace::store_root(
data_dir,
)?)))
}
pub fn collect_garbage(data_dir: &Path) -> Result<GcStats> {
let root = workspace::store_root(data_dir)?;
let blobs = BlobStore::open(workspace::blobs_dir(&root))?;
let mut stats = GcStats::default();
let mut live_blobs = BTreeSet::new();
let mut complete = true;
for key in workspace::all_partitions(&root)? {
let partition = workspace::partition_dir(&root, &key);
let refs = RefStore::open(partition.join("refs"))?;
let turns = TurnIndex::open(&partition)?;
let manifests = ManifestStore::open(partition.join("manifests"))?;
stats = stats.plus(collect_partition(&refs, &turns, &manifests)?);
for dir in ["refs", "manifests", "turns", "restores", "declared"] {
crate::sweep::sweep_residue(&partition.join(dir));
}
let declared = crate::declared::DeclaredStore::open(crate::declared::dir_in(&partition))?;
crate::sweep::orphan_declared(&declared, &refs)?;
for id in manifests.ids()? {
let Ok(manifest) = manifests.load(&id) else {
complete = false;
continue;
};
for entry in manifest.entries.values() {
live_blobs.insert(entry.hash.clone());
}
}
}
crate::sweep::sweep_residue(&workspace::blobs_dir(&root));
if !complete {
stats.blobs_kept += blobs.hashes()?.len();
return Ok(stats);
}
for hash in blobs.hashes()? {
if live_blobs.contains(&hash)
|| !blobs
.path_for(&hash)
.is_ok_and(|p| crate::sweep::settled(&p))
{
stats.blobs_kept += 1;
} else {
blobs.remove(&hash)?;
stats.blobs_removed += 1;
}
}
Ok(stats)
}
#[cfg(test)]
#[path = "collect_tests.rs"]
mod tests;