reifydb_core/util/
multi.rs1use std::{
5 fmt::Debug,
6 sync::{Arc, RwLock},
7};
8
9use crossbeam_skiplist::SkipMap;
10
11use crate::common::CommitVersion;
12
13#[derive(Debug)]
14pub struct MultiVersionContainer<T: Debug + Clone + Send + Sync + 'static> {
15 inner: Arc<RwLock<MultiVersionDefInner<T>>>,
16}
17
18#[derive(Debug)]
19struct MultiVersionDefInner<T: Debug + Clone + Send + Sync + 'static> {
20 versions: SkipMap<CommitVersion, Option<T>>,
21}
22
23impl<T: Debug + Clone + Send + Sync + 'static> MultiVersionContainer<T> {
24 pub fn new() -> Self {
25 Self {
26 inner: Arc::new(RwLock::new(MultiVersionDefInner {
27 versions: SkipMap::new(),
28 })),
29 }
30 }
31
32 pub fn insert(&self, version: impl Into<CommitVersion>, value: T) -> Option<Option<T>> {
33 let version = version.into();
34 let inner = self.inner.write().unwrap();
35 if let Some(entry) = inner.versions.get(&version) {
36 let old_value = entry.value().clone();
37 inner.versions.insert(version, Some(value));
38 Some(old_value)
39 } else {
40 inner.versions.insert(version, Some(value));
41 None
42 }
43 }
44
45 pub fn get(&self, version: impl Into<CommitVersion>) -> Option<T> {
46 let version = version.into();
47 let inner = self.inner.read().unwrap();
48
49 inner.versions.range(..=version).next_back().and_then(|entry| entry.value().clone())
50 }
51
52 pub fn get_or_tombstone(&self, version: impl Into<CommitVersion>) -> Option<Option<T>> {
53 let version = version.into();
54 let inner = self.inner.read().unwrap();
55
56 inner.versions.range(..=version).next_back().map(|entry| entry.value().clone())
57 }
58
59 pub fn get_latest(&self) -> Option<T> {
60 let inner = self.inner.read().unwrap();
61 inner.versions.back().and_then(|entry| entry.value().clone())
62 }
63
64 pub fn versions(&self) -> Vec<CommitVersion> {
65 let inner = self.inner.read().unwrap();
66 inner.versions.iter().map(|entry| *entry.key()).collect()
67 }
68
69 pub fn remove(&self, version: impl Into<CommitVersion>) -> Option<Option<T>> {
70 let version = version.into();
71 let inner = self.inner.write().unwrap();
72
73 if let Some(entry) = inner.versions.get(&version) {
74 let old_value = entry.value().clone();
75 inner.versions.insert(version, None);
76 Some(old_value)
77 } else {
78 inner.versions.insert(version, None);
79 None
80 }
81 }
82
83 pub fn len(&self) -> usize {
84 let inner = self.inner.read().unwrap();
85 inner.versions.len()
86 }
87
88 pub fn is_empty(&self) -> bool {
89 let inner = self.inner.read().unwrap();
90 inner.versions.is_empty()
91 }
92
93 pub fn clear(&self) {
94 let inner = self.inner.write().unwrap();
95 inner.versions.clear();
96 }
97}
98
99impl<T: Debug + Clone + Send + Sync + 'static> Clone for MultiVersionContainer<T> {
100 fn clone(&self) -> Self {
101 Self {
102 inner: Arc::clone(&self.inner),
103 }
104 }
105}
106
107impl<T: Debug + Clone + Send + Sync + 'static> Default for MultiVersionContainer<T> {
108 fn default() -> Self {
109 Self::new()
110 }
111}
112
113#[cfg(test)]
114pub mod tests {
115 use super::*;
116
117 #[derive(Debug, Clone, PartialEq)]
118 struct Test {
119 name: String,
120 }
121
122 #[test]
123 fn test_basic_operations() {
124 let multi = MultiVersionContainer::<Test>::new();
125
126 assert!(multi.is_empty());
128 assert_eq!(multi.len(), 0);
129 assert!(multi.get_latest().is_none());
130
131 let def1 = Test {
133 name: "v1".to_string(),
134 };
135 multi.insert(1, def1.clone());
136 assert!(!multi.is_empty());
137 assert_eq!(multi.len(), 1);
138
139 assert_eq!(multi.get(1), Some(def1.clone()));
141 assert_eq!(multi.get(2), Some(def1.clone())); assert_eq!(multi.get_latest(), Some(def1.clone()));
143
144 let def2 = Test {
146 name: "v2".to_string(),
147 };
148 multi.insert(5, def2.clone());
149 assert_eq!(multi.len(), 2);
150 assert_eq!(multi.get(1), Some(def1.clone()));
151 assert_eq!(multi.get(3), Some(def1.clone()));
152 assert_eq!(multi.get(5), Some(def2.clone()));
153 assert_eq!(multi.get(10), Some(def2.clone()));
154 assert_eq!(multi.get_latest(), Some(def2.clone()));
155
156 multi.remove(7);
157 assert_eq!(multi.get(7), None);
158 assert_eq!(multi.get(10), None);
159
160 assert_eq!(multi.get_latest(), None);
161 }
162}