cranpose_core/snapshot_v2/
global.rs1use super::*;
2
3#[allow(clippy::arc_with_non_send_sync)]
13pub struct GlobalSnapshot {
14 state: SnapshotState,
15 nested_count: Cell<usize>,
16}
17
18impl GlobalSnapshot {
19 pub fn new(id: SnapshotId, invalid: SnapshotIdSet) -> Arc<Self> {
24 Arc::new(Self {
25 state: SnapshotState::new_with_pinning(id, invalid, None, None, false, false),
26 nested_count: Cell::new(0),
27 })
28 }
29
30 pub fn get_or_create() -> Arc<Self> {
32 GLOBAL_SNAPSHOT.with(|cell| {
33 let mut snapshot = cell.borrow_mut();
34 if let Some(global) = snapshot.as_ref() {
35 return Arc::clone(global);
36 }
37
38 let id = with_runtime(|runtime| runtime.global_snapshot_id());
39 let invalid = super::runtime::open_snapshots();
40 let global = GlobalSnapshot::new(id, invalid);
41 *snapshot = Some(Arc::clone(&global));
42 global
43 })
44 }
45
46 pub fn advance(&self, new_id: SnapshotId) {
48 let invalid = super::runtime::advance_global_snapshot(new_id);
49 self.state.id.set(new_id);
50 self.state.invalid.replace(invalid);
51 }
52}
53
54thread_local! {
55 static GLOBAL_SNAPSHOT: RefCell<Option<Arc<GlobalSnapshot>>> = const { RefCell::new(None) };
56}
57
58#[cfg(test)]
59pub(crate) fn clear_global_snapshot_for_tests() {
60 GLOBAL_SNAPSHOT.with(|cell| {
61 *cell.borrow_mut() = None;
62 });
63}
64
65impl GlobalSnapshot {
66 pub fn snapshot_id(&self) -> SnapshotId {
67 self.state.id.get()
68 }
69
70 pub fn invalid(&self) -> SnapshotIdSet {
71 self.state.invalid.borrow().clone()
72 }
73
74 pub fn read_only(&self) -> bool {
75 false
76 }
77
78 pub fn root_global(&self) -> Arc<Self> {
79 GlobalSnapshot::get_or_create()
80 }
81
82 pub fn enter<T>(&self, f: impl FnOnce() -> T) -> T {
83 enter_snapshot_scope(AnySnapshot::Global(self.root_global()), f)
84 }
85
86 pub fn take_nested_snapshot(
87 &self,
88 read_observer: Option<ReadObserver>,
89 ) -> Arc<ReadonlySnapshot> {
90 ReadonlySnapshot::new(
91 self.state.id.get(),
92 self.state.invalid.borrow().clone(),
93 read_observer,
94 )
95 }
96
97 pub fn has_pending_changes(&self) -> bool {
98 !self.state.modified.borrow().is_empty()
99 }
100
101 pub fn pending_children(&self) -> Vec<SnapshotId> {
102 self.state.pending_children()
103 }
104
105 pub fn has_pending_children(&self) -> bool {
106 self.state.has_pending_children()
107 }
108
109 pub fn dispose(&self) {}
110
111 pub fn record_read(&self, state: &dyn StateObject) {
112 self.state.record_read(state);
113 }
114
115 pub fn record_write(&self, state: Arc<dyn StateObject>) {
116 self.state.record_write(state, self.state.id.get());
117 }
118
119 pub fn close(&self) {}
120
121 pub fn is_disposed(&self) -> bool {
122 false
123 }
124
125 pub fn apply(&self) -> SnapshotApplyResult {
126 SnapshotApplyResult::Success
127 }
128
129 pub fn take_nested_mutable_snapshot(
130 &self,
131 read_observer: Option<ReadObserver>,
132 write_observer: Option<WriteObserver>,
133 ) -> Arc<MutableSnapshot> {
134 let base_parent_id = self.state.id.get();
135
136 let (new_id, child_invalid, new_global_invalid) =
137 super::runtime::with_runtime(|runtime| runtime.take_new_snapshot_advancing_global());
138
139 let new_global_id = super::runtime::with_runtime(|runtime| runtime.global_snapshot_id());
140 self.state.id.set(new_global_id);
141 self.state.invalid.replace(new_global_invalid);
142
143 let child = MutableSnapshot::from_parts(
144 new_id,
145 child_invalid,
146 read_observer,
147 write_observer,
148 base_parent_id,
149 true,
150 );
151
152 self.nested_count.set(self.nested_count.get() + 1);
153 self.state.add_pending_child(new_id);
154
155 child.set_on_dispose(clear_nested_child_on_dispose(&self.root_global(), new_id));
156
157 child
158 }
159}
160
161impl NestedMutableHost for GlobalSnapshot {
162 fn snapshot_state(&self) -> &SnapshotState {
163 &self.state
164 }
165
166 fn nested_count(&self) -> &Cell<usize> {
167 &self.nested_count
168 }
169}
170
171pub fn advance_global_snapshot(new_id: SnapshotId) {
173 let global = GlobalSnapshot::get_or_create();
174 global.advance(new_id);
175 super::maybe_check_and_overwrite_unused_records_locked(new_id);
176}
177
178#[cfg(test)]
179pub fn global_snapshot_id() -> SnapshotId {
180 let global = GlobalSnapshot::get_or_create();
181 global.snapshot_id()
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187 use crate::snapshot_v2::runtime::TestRuntimeGuard;
188
189 fn reset_runtime() -> TestRuntimeGuard {
190 let guard = reset_runtime_for_tests();
191 GLOBAL_SNAPSHOT.with(|cell| {
192 *cell.borrow_mut() = None;
193 });
194 guard
195 }
196
197 #[test]
198 fn test_global_snapshot_creation() {
199 let _guard = reset_runtime();
200 let snapshot = GlobalSnapshot::new(1, SnapshotIdSet::new());
201 assert_eq!(snapshot.snapshot_id(), 1);
202 assert!(!snapshot.read_only());
203 assert!(!snapshot.is_disposed());
204 }
205
206 #[test]
207 fn test_global_snapshot_get_or_create() {
208 let _guard = reset_runtime();
209
210 let snapshot1 = GlobalSnapshot::get_or_create();
211 let snapshot2 = GlobalSnapshot::get_or_create();
212
213 assert_eq!(snapshot1.snapshot_id(), snapshot2.snapshot_id());
214 }
215
216 #[test]
217 fn test_global_snapshot_advance() {
218 let _guard = reset_runtime();
219 let snapshot = GlobalSnapshot::new(1, SnapshotIdSet::new());
220 assert_eq!(snapshot.snapshot_id(), 1);
221
222 snapshot.state.id.set(5);
223 assert_eq!(snapshot.snapshot_id(), 5);
224
225 snapshot.state.id.set(10);
226 assert_eq!(snapshot.snapshot_id(), 10);
227 }
228
229 #[test]
230 fn test_global_snapshot_never_disposed() {
231 let _guard = reset_runtime();
232 let snapshot = GlobalSnapshot::new(1, SnapshotIdSet::new());
233 assert!(!snapshot.is_disposed());
234
235 snapshot.dispose();
236 assert!(!snapshot.is_disposed());
237 }
238
239 #[test]
240 fn test_global_snapshot_apply_always_succeeds() {
241 let _guard = reset_runtime();
242 let snapshot = GlobalSnapshot::new(1, SnapshotIdSet::new());
243 let result = snapshot.apply();
244 assert!(result.is_success());
245 }
246
247 #[test]
248 fn test_global_snapshot_nested() {
249 let _guard = reset_runtime();
250 let global = GlobalSnapshot::new(1, SnapshotIdSet::new());
251 let nested = global.take_nested_snapshot(None);
252
253 assert_eq!(nested.snapshot_id(), 1);
254 assert!(nested.read_only());
255 assert_eq!(global.nested_count.get(), 0);
256 }
257
258 #[test]
259 fn test_global_snapshot_nested_mutable() {
260 let _guard = reset_runtime();
261 let global = GlobalSnapshot::new(1, SnapshotIdSet::new());
262 let nested = global.take_nested_mutable_snapshot(None, None);
263
264 assert!(nested.snapshot_id() < global.snapshot_id());
265 assert!(!nested.read_only());
266 }
267
268 #[test]
269 fn test_global_snapshot_nested_mutable_dispose_clears_invalid() {
270 let _guard = reset_runtime();
271 let global = GlobalSnapshot::get_or_create();
272 let nested = global.take_nested_mutable_snapshot(None, None);
273 let child_id = nested.snapshot_id();
274
275 assert!(global.state.invalid.borrow().get(child_id));
276 assert_eq!(global.nested_count.get(), 1);
277
278 nested.dispose();
279
280 assert_eq!(global.nested_count.get(), 0);
281 assert!(!global.state.invalid.borrow().get(child_id));
282 }
283
284 #[test]
285 fn test_advance_global_snapshot_function() {
286 let _guard = reset_runtime();
287
288 let initial_id = global_snapshot_id();
289
290 advance_global_snapshot(initial_id + 10);
291 assert_eq!(global_snapshot_id(), initial_id + 10);
292
293 advance_global_snapshot(initial_id + 20);
294 assert_eq!(global_snapshot_id(), initial_id + 20);
295 }
296
297 #[test]
298 fn test_global_snapshot_has_no_pending_changes_initially() {
299 let _guard = reset_runtime();
300 let snapshot = GlobalSnapshot::new(1, SnapshotIdSet::new());
301 assert!(!snapshot.has_pending_changes());
302 }
303
304 #[test]
305 fn test_global_snapshot_enter() {
306 let _guard = reset_runtime();
307 let snapshot = GlobalSnapshot::new(1, SnapshotIdSet::new());
308
309 set_current_snapshot(None);
310 snapshot.enter(|| {
311 let current = current_snapshot();
312 assert!(current.is_some());
313 });
314 }
315}