Serialize startup prepared artifact reclamation

This commit is contained in:
ms2k 2026-07-22 03:56:44 +09:00
commit 7cd8a90af0

View file

@ -449,6 +449,60 @@ fn selected_gc_is_idempotent_only_at_the_durable_reclaim_boundary() {
assert!(fixture.store.gc_artifacts(&[id]).is_err());
}
#[test]
fn concurrent_unleased_gc_serializes_observation_with_reclaim() {
let fixture = Fixture::new();
let artifact = fixture
.store
.prepare(&fixture.request(
75,
&[(
layer(&[Entry {
path: "payload",
kind: EntryType::Regular,
data: b"concurrent-gc",
target: None,
mode: 0o644,
}]),
OCI_TAR,
)],
))
.unwrap();
let (_, first) = fixture.independent_store();
let (_, second) = fixture.independent_store();
let barrier = Arc::new(Barrier::new(3));
let first_barrier = Arc::clone(&barrier);
let first = thread::spawn(move || {
first_barrier.wait();
first.gc_unleased_artifacts()
});
let second_barrier = Arc::clone(&barrier);
let second = thread::spawn(move || {
second_barrier.wait();
second.gc_unleased_artifacts()
});
barrier.wait();
let results = [
first.join().unwrap().unwrap(),
second.join().unwrap().unwrap(),
];
assert_eq!(results.iter().map(Vec::len).sum::<usize>(), 1);
assert_eq!(
results.iter().flatten().next().unwrap().outcome,
ReclaimOutcome::Removed
);
assert!(
fixture
.catalog
.snapshot()
.unwrap()
.prepared_artifacts
.is_empty()
);
assert!(!fixture.artifact_root(&artifact).exists());
}
#[test]
fn selected_artifact_excludes_gc_until_the_claim_is_released() {
let fixture = Fixture::new();