feat(artifacts): add immutable artifact store

This commit is contained in:
2026-08-25 18:06:33 +03:00
parent 182bde8ac0
commit 497e1b740f
13 changed files with 2198 additions and 3 deletions
@@ -0,0 +1,81 @@
//! Test-only crash and fault control for syscall-coupled storage checkpoints.
use std::{
sync::{Condvar, Mutex, OnceLock},
time::Duration,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FaultAction {
Exit,
Fail,
Hold,
}
struct State {
checkpoint: Option<(String, FaultAction)>,
held: bool,
}
fn slot() -> &'static (Mutex<State>, Condvar) {
static SLOT: OnceLock<(Mutex<State>, Condvar)> = OnceLock::new();
SLOT.get_or_init(|| {
(
Mutex::new(State {
checkpoint: None,
held: false,
}),
Condvar::new(),
)
})
}
pub fn set_checkpoint(stage: impl Into<String>, action: FaultAction) {
let (lock, _) = slot();
lock.lock()
.expect("artifact test checkpoint lock poisoned")
.checkpoint = Some((stage.into(), action));
}
pub fn clear_checkpoint() {
let (lock, wake) = slot();
let mut state = lock.lock().expect("artifact test checkpoint lock poisoned");
state.checkpoint = None;
state.held = false;
wake.notify_all();
}
pub fn wait_until_held(timeout: Duration) -> bool {
let (lock, wake) = slot();
let state = lock.lock().expect("artifact test checkpoint lock poisoned");
let (state, _) = wake
.wait_timeout_while(state, timeout, |state| !state.held)
.expect("artifact test checkpoint lock poisoned");
state.held
}
pub(crate) fn checkpoint(stage: &str) -> Option<FaultAction> {
let (lock, wake) = slot();
let mut state = lock.lock().expect("artifact test checkpoint lock poisoned");
let action = state
.checkpoint
.as_ref()
.and_then(|(expected, action)| (expected == stage).then_some(*action));
if action == Some(FaultAction::Hold) {
state.held = true;
wake.notify_all();
while state.checkpoint.is_some() {
state = wake
.wait(state)
.expect("artifact test checkpoint lock poisoned");
}
}
action
}
pub(crate) fn action(stage: &str) -> Option<FaultAction> {
let (lock, _) = slot();
let state = lock.lock().expect("artifact test checkpoint lock poisoned");
state
.checkpoint
.as_ref()
.and_then(|(expected, action)| (expected == stage).then_some(*action))
}