Skip to main content

reifydb_core/util/
multi.rs

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