mongreldb_core/
retention.rs1use crate::epoch::Epoch;
10use parking_lot::Mutex;
11use std::collections::BTreeMap;
12use std::collections::HashSet;
13use std::sync::Arc;
14
15#[derive(Default)]
21pub struct ActiveSpills {
22 inner: Mutex<HashSet<u64>>,
23}
24
25impl ActiveSpills {
26 pub fn new() -> Self {
27 Self {
28 inner: Mutex::new(HashSet::new()),
29 }
30 }
31
32 pub fn register(self: &Arc<Self>, txn_id: u64) -> SpillGuard {
35 self.inner.lock().insert(txn_id);
36 SpillGuard {
37 registry: Arc::clone(self),
38 txn_id,
39 }
40 }
41
42 pub fn is_active(&self, txn_id: u64) -> bool {
44 self.inner.lock().contains(&txn_id)
45 }
46
47 pub fn is_idle(&self) -> bool {
49 self.inner.lock().is_empty()
50 }
51
52 fn release(&self, txn_id: u64) {
53 self.inner.lock().remove(&txn_id);
54 }
55}
56
57pub struct SpillGuard {
59 registry: Arc<ActiveSpills>,
60 txn_id: u64,
61}
62
63impl Drop for SpillGuard {
64 fn drop(&mut self) {
65 self.registry.release(self.txn_id);
66 }
67}
68
69#[derive(Default)]
72pub struct SnapshotRegistry {
73 live: Mutex<BTreeMap<u64, u64>>,
75}
76
77impl SnapshotRegistry {
78 pub fn new() -> Self {
79 Self {
80 live: Mutex::new(BTreeMap::new()),
81 }
82 }
83
84 pub fn register(&self, epoch: Epoch) -> SnapshotGuard<'_> {
87 let mut live = self.live.lock();
88 *live.entry(epoch.0).or_insert(0) += 1;
89 SnapshotGuard {
90 registry: self,
91 epoch,
92 }
93 }
94
95 pub fn min_active(&self, visible: Epoch) -> Epoch {
99 match self.live.lock().keys().next().copied() {
100 Some(min) => Epoch(min),
101 None => visible,
102 }
103 }
104
105 pub fn min_pinned(&self) -> Option<Epoch> {
111 self.live.lock().keys().next().copied().map(Epoch)
112 }
113
114 fn release(&self, epoch: Epoch) {
115 let mut live = self.live.lock();
116 if let Some(count) = live.get_mut(&epoch.0) {
117 *count -= 1;
118 if *count == 0 {
119 live.remove(&epoch.0);
120 }
121 }
122 }
123}
124
125pub struct SnapshotGuard<'r> {
127 registry: &'r SnapshotRegistry,
128 epoch: Epoch,
129}
130
131impl Drop for SnapshotGuard<'_> {
132 fn drop(&mut self) {
133 self.registry.release(self.epoch);
134 }
135}
136
137pub struct OwnedSnapshotGuard {
140 registry: Arc<SnapshotRegistry>,
141 epoch: Epoch,
142}
143
144impl OwnedSnapshotGuard {
145 pub fn epoch(&self) -> Epoch {
147 self.epoch
148 }
149}
150
151impl Drop for OwnedSnapshotGuard {
152 fn drop(&mut self) {
153 self.registry.release(self.epoch);
154 }
155}
156
157impl SnapshotRegistry {
158 pub fn register_owned(self: &Arc<Self>, epoch: Epoch) -> OwnedSnapshotGuard {
161 {
162 let mut live = self.live.lock();
163 *live.entry(epoch.0).or_insert(0) += 1;
164 }
165 OwnedSnapshotGuard {
166 registry: Arc::clone(self),
167 epoch,
168 }
169 }
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175
176 #[test]
177 fn retention_tracks_min_active_snapshot() {
178 let r = SnapshotRegistry::new();
179 assert_eq!(r.min_active(Epoch(10)), Epoch(10));
180 let g1 = r.register(Epoch(5));
181 let g2 = r.register(Epoch(8));
182 assert_eq!(r.min_active(Epoch(10)), Epoch(5));
183 drop(g1);
184 assert_eq!(r.min_active(Epoch(10)), Epoch(8));
185 drop(g2);
186 assert_eq!(r.min_active(Epoch(10)), Epoch(10));
187 }
188
189 #[test]
190 fn retention_refcounts_duplicate_epochs() {
191 let r = SnapshotRegistry::new();
192 let a = r.register(Epoch(3));
193 let b = r.register(Epoch(3));
194 assert_eq!(r.min_active(Epoch(9)), Epoch(3));
195 drop(a);
196 assert_eq!(r.min_active(Epoch(9)), Epoch(3));
197 drop(b);
198 assert_eq!(r.min_active(Epoch(9)), Epoch(9));
199 }
200}