1use std::collections::VecDeque;
7
8use crate::types::{EpochId, TxId};
9
10#[derive(Debug, Clone, Copy)]
12pub struct VersionInfo {
13 pub created_epoch: EpochId,
15 pub deleted_epoch: Option<EpochId>,
17 pub created_by: TxId,
19}
20
21impl VersionInfo {
22 #[must_use]
24 pub fn new(created_epoch: EpochId, created_by: TxId) -> Self {
25 Self {
26 created_epoch,
27 deleted_epoch: None,
28 created_by,
29 }
30 }
31
32 pub fn mark_deleted(&mut self, epoch: EpochId) {
34 self.deleted_epoch = Some(epoch);
35 }
36
37 #[must_use]
39 pub fn is_visible_at(&self, epoch: EpochId) -> bool {
40 if !self.created_epoch.is_visible_at(epoch) {
43 return false;
44 }
45
46 if let Some(deleted) = self.deleted_epoch {
47 deleted.as_u64() > epoch.as_u64()
49 } else {
50 true
51 }
52 }
53
54 #[must_use]
61 pub fn is_visible_to(&self, viewing_epoch: EpochId, viewing_tx: TxId) -> bool {
62 if self.created_by == viewing_tx {
64 return self.deleted_epoch.is_none();
65 }
66
67 self.is_visible_at(viewing_epoch)
69 }
70}
71
72#[derive(Debug, Clone)]
74pub struct Version<T> {
75 pub info: VersionInfo,
77 pub data: T,
79}
80
81impl<T> Version<T> {
82 #[must_use]
84 pub fn new(data: T, created_epoch: EpochId, created_by: TxId) -> Self {
85 Self {
86 info: VersionInfo::new(created_epoch, created_by),
87 data,
88 }
89 }
90}
91
92#[derive(Debug, Clone)]
97pub struct VersionChain<T> {
98 versions: VecDeque<Version<T>>,
100}
101
102impl<T> VersionChain<T> {
103 #[must_use]
105 pub fn new() -> Self {
106 Self {
107 versions: VecDeque::new(),
108 }
109 }
110
111 #[must_use]
113 pub fn with_initial(data: T, created_epoch: EpochId, created_by: TxId) -> Self {
114 let mut chain = Self::new();
115 chain.add_version(data, created_epoch, created_by);
116 chain
117 }
118
119 pub fn add_version(&mut self, data: T, created_epoch: EpochId, created_by: TxId) {
123 let version = Version::new(data, created_epoch, created_by);
124 self.versions.push_front(version);
125 }
126
127 #[must_use]
132 pub fn visible_at(&self, epoch: EpochId) -> Option<&T> {
133 self.versions
134 .iter()
135 .find(|v| v.info.is_visible_at(epoch))
136 .map(|v| &v.data)
137 }
138
139 #[must_use]
143 pub fn visible_to(&self, epoch: EpochId, tx: TxId) -> Option<&T> {
144 self.versions
145 .iter()
146 .find(|v| v.info.is_visible_to(epoch, tx))
147 .map(|v| &v.data)
148 }
149
150 pub fn mark_deleted(&mut self, delete_epoch: EpochId) -> bool {
154 for version in &mut self.versions {
155 if version.info.deleted_epoch.is_none() {
156 version.info.mark_deleted(delete_epoch);
157 return true;
158 }
159 }
160 false
161 }
162
163 #[must_use]
165 pub fn modified_by(&self, tx: TxId) -> bool {
166 self.versions.iter().any(|v| v.info.created_by == tx)
167 }
168
169 pub fn remove_versions_by(&mut self, tx: TxId) {
173 self.versions.retain(|v| v.info.created_by != tx);
174 }
175
176 #[must_use]
181 pub fn has_conflict(&self, start_epoch: EpochId, our_tx: TxId) -> bool {
182 self.versions.iter().any(|v| {
183 v.info.created_by != our_tx && v.info.created_epoch.as_u64() > start_epoch.as_u64()
184 })
185 }
186
187 #[must_use]
189 pub fn version_count(&self) -> usize {
190 self.versions.len()
191 }
192
193 #[must_use]
195 pub fn is_empty(&self) -> bool {
196 self.versions.is_empty()
197 }
198
199 pub fn gc(&mut self, min_epoch: EpochId) {
203 if self.versions.is_empty() {
204 return;
205 }
206
207 let mut keep_count = 0;
208 let mut found_old_visible = false;
209
210 for (i, version) in self.versions.iter().enumerate() {
211 if version.info.created_epoch.as_u64() >= min_epoch.as_u64() {
212 keep_count = i + 1;
213 } else if !found_old_visible {
214 found_old_visible = true;
216 keep_count = i + 1;
217 }
218 }
219
220 self.versions.truncate(keep_count);
221 }
222
223 #[must_use]
225 pub fn latest(&self) -> Option<&T> {
226 self.versions.front().map(|v| &v.data)
227 }
228
229 #[must_use]
231 pub fn latest_mut(&mut self) -> Option<&mut T> {
232 self.versions.front_mut().map(|v| &mut v.data)
233 }
234}
235
236impl<T> Default for VersionChain<T> {
237 fn default() -> Self {
238 Self::new()
239 }
240}
241
242impl<T: Clone> VersionChain<T> {
243 pub fn get_mut(&mut self, epoch: EpochId, tx: TxId, modify_epoch: EpochId) -> Option<&mut T> {
248 let visible_idx = self
250 .versions
251 .iter()
252 .position(|v| v.info.is_visible_to(epoch, tx))?;
253
254 let visible = &self.versions[visible_idx];
255
256 if visible.info.created_by == tx {
257 Some(&mut self.versions[visible_idx].data)
259 } else {
260 let new_data = visible.data.clone();
262 self.add_version(new_data, modify_epoch, tx);
263 Some(&mut self.versions[0].data)
264 }
265 }
266}
267
268#[cfg(test)]
269mod tests {
270 use super::*;
271
272 #[test]
273 fn test_version_visibility() {
274 let v = VersionInfo::new(EpochId::new(5), TxId::new(1));
275
276 assert!(!v.is_visible_at(EpochId::new(4)));
278
279 assert!(v.is_visible_at(EpochId::new(5)));
281 assert!(v.is_visible_at(EpochId::new(10)));
282 }
283
284 #[test]
285 fn test_deleted_version_visibility() {
286 let mut v = VersionInfo::new(EpochId::new(5), TxId::new(1));
287 v.mark_deleted(EpochId::new(10));
288
289 assert!(v.is_visible_at(EpochId::new(5)));
291 assert!(v.is_visible_at(EpochId::new(9)));
292
293 assert!(!v.is_visible_at(EpochId::new(10)));
295 assert!(!v.is_visible_at(EpochId::new(15)));
296 }
297
298 #[test]
299 fn test_version_visibility_to_transaction() {
300 let v = VersionInfo::new(EpochId::new(5), TxId::new(1));
301
302 assert!(v.is_visible_to(EpochId::new(3), TxId::new(1)));
304
305 assert!(!v.is_visible_to(EpochId::new(3), TxId::new(2)));
307 assert!(v.is_visible_to(EpochId::new(5), TxId::new(2)));
308 }
309
310 #[test]
311 fn test_version_chain_basic() {
312 let mut chain = VersionChain::with_initial("v1", EpochId::new(1), TxId::new(1));
313
314 assert_eq!(chain.visible_at(EpochId::new(1)), Some(&"v1"));
316 assert_eq!(chain.visible_at(EpochId::new(0)), None);
317
318 chain.add_version("v2", EpochId::new(5), TxId::new(2));
320
321 assert_eq!(chain.visible_at(EpochId::new(1)), Some(&"v1"));
323 assert_eq!(chain.visible_at(EpochId::new(4)), Some(&"v1"));
324 assert_eq!(chain.visible_at(EpochId::new(5)), Some(&"v2"));
325 assert_eq!(chain.visible_at(EpochId::new(10)), Some(&"v2"));
326 }
327
328 #[test]
329 fn test_version_chain_rollback() {
330 let mut chain = VersionChain::with_initial("v1", EpochId::new(1), TxId::new(1));
331 chain.add_version("v2", EpochId::new(5), TxId::new(2));
332 chain.add_version("v3", EpochId::new(6), TxId::new(2));
333
334 assert_eq!(chain.version_count(), 3);
335
336 chain.remove_versions_by(TxId::new(2));
338
339 assert_eq!(chain.version_count(), 1);
340 assert_eq!(chain.visible_at(EpochId::new(10)), Some(&"v1"));
341 }
342
343 #[test]
344 fn test_version_chain_deletion() {
345 let mut chain = VersionChain::with_initial("v1", EpochId::new(1), TxId::new(1));
346
347 assert!(chain.mark_deleted(EpochId::new(5)));
349
350 assert_eq!(chain.visible_at(EpochId::new(4)), Some(&"v1"));
352 assert_eq!(chain.visible_at(EpochId::new(5)), None);
353 assert_eq!(chain.visible_at(EpochId::new(10)), None);
354 }
355}