cranpose_core/
snapshot_pinning.rs1use crate::{
2 snapshot_double_index_heap::{SnapshotDoubleIndexHeap, SnapshotDoubleIndexHeapDebugStats},
3 snapshot_id_set::{SnapshotId, SnapshotIdSet},
4};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub struct PinHandle(usize);
11
12impl PinHandle {
13 pub const INVALID: PinHandle = PinHandle(0);
15
16 pub fn is_valid(&self) -> bool {
18 self.0 != 0
19 }
20}
21
22pub(crate) struct PinningTable {
23 heap: SnapshotDoubleIndexHeap,
24}
25
26impl PinningTable {
27 pub(crate) const fn new() -> Self {
28 Self {
29 heap: SnapshotDoubleIndexHeap::new(),
30 }
31 }
32
33 fn add(&mut self, snapshot_id: SnapshotId) -> PinHandle {
34 let heap_handle = self.heap.add(snapshot_id);
35 PinHandle(heap_handle + 1)
36 }
37
38 fn remove(&mut self, handle: PinHandle) -> bool {
39 if !handle.is_valid() {
40 return false;
41 }
42
43 let heap_handle = handle.0 - 1;
44
45 if heap_handle < usize::MAX {
46 self.heap.remove(heap_handle);
47 true
48 } else {
49 false
50 }
51 }
52
53 fn lowest_pinned(&self) -> Option<SnapshotId> {
54 if self.heap.is_empty() {
55 None
56 } else {
57 Some(self.heap.lowest_or_default(0))
58 }
59 }
60
61 fn pin_count(&self) -> usize {
62 self.heap.len()
63 }
64
65 fn debug_stats(&self) -> SnapshotPinningDebugStats {
66 SnapshotPinningDebugStats {
67 pin_count: self.pin_count(),
68 lowest_pinned_snapshot: self.lowest_pinned(),
69 heap: self.heap.debug_stats(),
70 }
71 }
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
75pub struct SnapshotPinningDebugStats {
76 pub pin_count: usize,
77 pub lowest_pinned_snapshot: Option<SnapshotId>,
78 pub heap: SnapshotDoubleIndexHeapDebugStats,
79}
80
81pub fn track_pinning(snapshot_id: SnapshotId, invalid: &SnapshotIdSet) -> PinHandle {
96 let pinned_id = invalid.lowest(snapshot_id);
97
98 crate::thread_state::snapshots(|state| state.pinning.borrow_mut().add(pinned_id))
99}
100
101pub fn release_pinning(handle: PinHandle) {
111 if !handle.is_valid() {
112 return;
113 }
114
115 crate::thread_state::snapshots(|state| {
116 state.pinning.borrow_mut().remove(handle);
117 });
118}
119
120pub fn lowest_pinned_snapshot() -> Option<SnapshotId> {
128 crate::thread_state::snapshots(|state| state.pinning.borrow().lowest_pinned())
129}
130
131pub fn pin_count() -> usize {
134 crate::thread_state::snapshots(|state| state.pinning.borrow().pin_count())
135}
136
137pub fn debug_snapshot_pinning_stats() -> SnapshotPinningDebugStats {
138 crate::thread_state::snapshots(|state| state.pinning.borrow().debug_stats())
139}
140
141#[cfg(test)]
142pub fn reset_pinning_table() {
143 crate::thread_state::snapshots(|state| {
144 state.pinning.borrow_mut().heap = SnapshotDoubleIndexHeap::new();
145 });
146}
147
148#[cfg(test)]
149#[path = "tests/snapshot_pinning_tests.rs"]
150mod tests;