feat(artifacts): add immutable artifact store
This commit is contained in:
@@ -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))
|
||||
}
|
||||
Reference in New Issue
Block a user