harn_vm/
persistent_state.rs1use std::cell::RefCell;
4use std::marker::PhantomData;
5use std::path::{Path, PathBuf};
6use std::rc::Rc;
7
8use crate::Vm;
9
10thread_local! {
11 static SCOPED_PERSISTENT_STATE_ROOT: RefCell<Option<PathBuf>> = const { RefCell::new(None) };
12}
13
14#[derive(Clone, Copy, Debug)]
16pub struct PersistentStateRoot<'a>(&'a Path);
17
18impl<'a> PersistentStateRoot<'a> {
19 #[must_use]
20 pub fn new(path: &'a Path) -> Self {
21 Self(path)
22 }
23
24 fn as_path(self) -> &'a Path {
25 self.0
26 }
27}
28
29#[derive(Debug)]
34#[must_use = "retain this guard for the isolated VM execution"]
35pub struct ScopedPersistentStateRoot {
36 previous: Option<PathBuf>,
37 _not_send: PhantomData<Rc<()>>,
38}
39
40pub fn scope_persistent_state_root(root: PersistentStateRoot<'_>) -> ScopedPersistentStateRoot {
47 let previous =
48 SCOPED_PERSISTENT_STATE_ROOT.with(|slot| slot.replace(Some(root.as_path().to_path_buf())));
49 ScopedPersistentStateRoot {
50 previous,
51 _not_send: PhantomData,
52 }
53}
54
55impl Drop for ScopedPersistentStateRoot {
56 fn drop(&mut self) {
57 SCOPED_PERSISTENT_STATE_ROOT.with(|slot| {
58 slot.replace(self.previous.take());
59 });
60 }
61}
62
63pub(crate) fn current_persistent_state_root() -> Option<PathBuf> {
64 SCOPED_PERSISTENT_STATE_ROOT.with(|slot| slot.borrow().clone())
65}
66
67pub fn register_persistent_state_builtins_at_root(
73 vm: &mut Vm,
74 base_dir: &Path,
75 state_root: PersistentStateRoot<'_>,
76 pipeline_name: &str,
77) {
78 let state_root = state_root.as_path();
79 crate::store::register_store_builtins_at_state_root(vm, state_root);
80 crate::metadata::register_metadata_builtins_at_state_root(vm, base_dir, state_root);
81 crate::checkpoint::register_checkpoint_builtins_at_state_root(vm, state_root, pipeline_name);
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn scoped_persistent_state_root_restores_nested_owner() {
90 let outer = Path::new("/isolated/outer/.harn");
91 let inner = Path::new("/isolated/inner/.harn");
92 assert_eq!(current_persistent_state_root(), None);
93 let outer_guard = scope_persistent_state_root(PersistentStateRoot::new(outer));
94 assert_eq!(current_persistent_state_root().as_deref(), Some(outer));
95 {
96 let _inner_guard = scope_persistent_state_root(PersistentStateRoot::new(inner));
97 assert_eq!(current_persistent_state_root().as_deref(), Some(inner));
98 }
99 assert_eq!(current_persistent_state_root().as_deref(), Some(outer));
100 drop(outer_guard);
101 assert_eq!(current_persistent_state_root(), None);
102 }
103}