use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use znippy_plugin_git::git_ops::GitStore;
fn fds_under(root: &Path) -> BTreeMap<String, usize> {
let root = root.display().to_string();
let mut by_name: BTreeMap<String, usize> = BTreeMap::new();
for entry in std::fs::read_dir("/proc/self/fd").expect("/proc/self/fd").flatten() {
let Ok(target) = std::fs::read_link(entry.path()) else {
continue;
};
let target = target.display().to_string();
if !target.starts_with(&root) {
continue;
}
let name = target.rsplit('/').next().unwrap_or(&target).to_string();
*by_name.entry(name).or_default() += 1;
}
by_name
}
fn total(m: &BTreeMap<String, usize>) -> usize {
m.values().sum()
}
#[test]
fn an_open_store_costs_three_descriptors_and_one_handle_on_the_blob_file() {
let tmp = tempfile::tempdir().expect("tempdir");
let mut open = Vec::new();
for i in 0..4 {
let root: PathBuf = tmp.path().join(format!("repo-{i}"));
open.push(GitStore::open(&root, "rickard").expect("opening a store"));
let per_store = fds_under(&root);
eprintln!("store {i}: {} descriptors {per_store:?}", total(&per_store));
assert_eq!(
per_store.get("objects.pack").copied().unwrap_or(0),
1,
"store {i}: the blob file must be held by ONE open file description — the \
writer's. A second read-only handle on an append-only file buys nothing and \
costs a kernel object and a page-cache alias per repository. Got {per_store:?}"
);
assert_eq!(
per_store.get("objects.pack.journal").copied().unwrap_or(0),
1,
"store {i}: the durable arm keeps its journal open; that one is the ack path \
and is untouchable. Got {per_store:?}"
);
assert_eq!(
per_store.get("objects.tail").copied().unwrap_or(0),
1,
"store {i}: redb's own handle on the index tail. Got {per_store:?}"
);
assert_eq!(
total(&per_store),
3,
"store {i}: an open store costs three descriptors, no more and no fewer — \
gunnar's `open_repo_budget` divides its RLIMIT by this number. Got {per_store:?}"
);
}
let all = fds_under(tmp.path());
assert_eq!(
total(&all),
12,
"four open stores hold four × three descriptors; got {all:?}"
);
drop(open);
let after = fds_under(tmp.path());
assert_eq!(
total(&after),
0,
"a dropped store releases every descriptor it held; got {after:?}"
);
}