1use std::collections::VecDeque;
9
10use crate::types::{EpochId, TxId};
11
12#[derive(Debug, Clone, Copy)]
14pub struct VersionInfo {
15 pub created_epoch: EpochId,
17 pub deleted_epoch: Option<EpochId>,
19 pub created_by: TxId,
21}
22
23impl VersionInfo {
24 #[must_use]
26 pub fn new(created_epoch: EpochId, created_by: TxId) -> Self {
27 Self {
28 created_epoch,
29 deleted_epoch: None,
30 created_by,
31 }
32 }
33
34 pub fn mark_deleted(&mut self, epoch: EpochId) {
36 self.deleted_epoch = Some(epoch);
37 }
38
39 #[must_use]
41 pub fn is_visible_at(&self, epoch: EpochId) -> bool {
42 if !self.created_epoch.is_visible_at(epoch) {
45 return false;
46 }
47
48 if let Some(deleted) = self.deleted_epoch {
49 deleted.as_u64() > epoch.as_u64()
51 } else {
52 true
53 }
54 }
55
56 #[must_use]
63 pub fn is_visible_to(&self, viewing_epoch: EpochId, viewing_tx: TxId) -> bool {
64 if self.created_by == viewing_tx {
66 return self.deleted_epoch.is_none();
67 }
68
69 self.is_visible_at(viewing_epoch)
71 }
72}
73
74#[derive(Debug, Clone)]
76pub struct Version<T> {
77 pub info: VersionInfo,
79 pub data: T,
81}
82
83impl<T> Version<T> {
84 #[must_use]
86 pub fn new(data: T, created_epoch: EpochId, created_by: TxId) -> Self {
87 Self {
88 info: VersionInfo::new(created_epoch, created_by),
89 data,
90 }
91 }
92}
93
94#[derive(Debug, Clone)]
100pub struct VersionChain<T> {
101 versions: VecDeque<Version<T>>,
103}
104
105impl<T> VersionChain<T> {
106 #[must_use]
108 pub fn new() -> Self {
109 Self {
110 versions: VecDeque::new(),
111 }
112 }
113
114 #[must_use]
116 pub fn with_initial(data: T, created_epoch: EpochId, created_by: TxId) -> Self {
117 let mut chain = Self::new();
118 chain.add_version(data, created_epoch, created_by);
119 chain
120 }
121
122 pub fn add_version(&mut self, data: T, created_epoch: EpochId, created_by: TxId) {
126 let version = Version::new(data, created_epoch, created_by);
127 self.versions.push_front(version);
128 }
129
130 #[must_use]
135 pub fn visible_at(&self, epoch: EpochId) -> Option<&T> {
136 self.versions
137 .iter()
138 .find(|v| v.info.is_visible_at(epoch))
139 .map(|v| &v.data)
140 }
141
142 #[must_use]
146 pub fn visible_to(&self, epoch: EpochId, tx: TxId) -> Option<&T> {
147 self.versions
148 .iter()
149 .find(|v| v.info.is_visible_to(epoch, tx))
150 .map(|v| &v.data)
151 }
152
153 pub fn mark_deleted(&mut self, delete_epoch: EpochId) -> bool {
157 for version in &mut self.versions {
158 if version.info.deleted_epoch.is_none() {
159 version.info.mark_deleted(delete_epoch);
160 return true;
161 }
162 }
163 false
164 }
165
166 #[must_use]
168 pub fn modified_by(&self, tx: TxId) -> bool {
169 self.versions.iter().any(|v| v.info.created_by == tx)
170 }
171
172 pub fn remove_versions_by(&mut self, tx: TxId) {
176 self.versions.retain(|v| v.info.created_by != tx);
177 }
178
179 #[must_use]
184 pub fn has_conflict(&self, start_epoch: EpochId, our_tx: TxId) -> bool {
185 self.versions.iter().any(|v| {
186 v.info.created_by != our_tx && v.info.created_epoch.as_u64() > start_epoch.as_u64()
187 })
188 }
189
190 #[must_use]
192 pub fn version_count(&self) -> usize {
193 self.versions.len()
194 }
195
196 #[must_use]
198 pub fn is_empty(&self) -> bool {
199 self.versions.is_empty()
200 }
201
202 pub fn gc(&mut self, min_epoch: EpochId) {
206 if self.versions.is_empty() {
207 return;
208 }
209
210 let mut keep_count = 0;
211 let mut found_old_visible = false;
212
213 for (i, version) in self.versions.iter().enumerate() {
214 if version.info.created_epoch.as_u64() >= min_epoch.as_u64() {
215 keep_count = i + 1;
216 } else if !found_old_visible {
217 found_old_visible = true;
219 keep_count = i + 1;
220 }
221 }
222
223 self.versions.truncate(keep_count);
224 }
225
226 #[must_use]
228 pub fn latest(&self) -> Option<&T> {
229 self.versions.front().map(|v| &v.data)
230 }
231
232 #[must_use]
234 pub fn latest_mut(&mut self) -> Option<&mut T> {
235 self.versions.front_mut().map(|v| &mut v.data)
236 }
237}
238
239impl<T> Default for VersionChain<T> {
240 fn default() -> Self {
241 Self::new()
242 }
243}
244
245impl<T: Clone> VersionChain<T> {
246 pub fn get_mut(&mut self, epoch: EpochId, tx: TxId, modify_epoch: EpochId) -> Option<&mut T> {
251 let visible_idx = self
253 .versions
254 .iter()
255 .position(|v| v.info.is_visible_to(epoch, tx))?;
256
257 let visible = &self.versions[visible_idx];
258
259 if visible.info.created_by == tx {
260 Some(&mut self.versions[visible_idx].data)
262 } else {
263 let new_data = visible.data.clone();
265 self.add_version(new_data, modify_epoch, tx);
266 Some(&mut self.versions[0].data)
267 }
268 }
269}
270
271#[cfg(test)]
272mod tests {
273 use super::*;
274
275 #[test]
276 fn test_version_visibility() {
277 let v = VersionInfo::new(EpochId::new(5), TxId::new(1));
278
279 assert!(!v.is_visible_at(EpochId::new(4)));
281
282 assert!(v.is_visible_at(EpochId::new(5)));
284 assert!(v.is_visible_at(EpochId::new(10)));
285 }
286
287 #[test]
288 fn test_deleted_version_visibility() {
289 let mut v = VersionInfo::new(EpochId::new(5), TxId::new(1));
290 v.mark_deleted(EpochId::new(10));
291
292 assert!(v.is_visible_at(EpochId::new(5)));
294 assert!(v.is_visible_at(EpochId::new(9)));
295
296 assert!(!v.is_visible_at(EpochId::new(10)));
298 assert!(!v.is_visible_at(EpochId::new(15)));
299 }
300
301 #[test]
302 fn test_version_visibility_to_transaction() {
303 let v = VersionInfo::new(EpochId::new(5), TxId::new(1));
304
305 assert!(v.is_visible_to(EpochId::new(3), TxId::new(1)));
307
308 assert!(!v.is_visible_to(EpochId::new(3), TxId::new(2)));
310 assert!(v.is_visible_to(EpochId::new(5), TxId::new(2)));
311 }
312
313 #[test]
314 fn test_version_chain_basic() {
315 let mut chain = VersionChain::with_initial("v1", EpochId::new(1), TxId::new(1));
316
317 assert_eq!(chain.visible_at(EpochId::new(1)), Some(&"v1"));
319 assert_eq!(chain.visible_at(EpochId::new(0)), None);
320
321 chain.add_version("v2", EpochId::new(5), TxId::new(2));
323
324 assert_eq!(chain.visible_at(EpochId::new(1)), Some(&"v1"));
326 assert_eq!(chain.visible_at(EpochId::new(4)), Some(&"v1"));
327 assert_eq!(chain.visible_at(EpochId::new(5)), Some(&"v2"));
328 assert_eq!(chain.visible_at(EpochId::new(10)), Some(&"v2"));
329 }
330
331 #[test]
332 fn test_version_chain_rollback() {
333 let mut chain = VersionChain::with_initial("v1", EpochId::new(1), TxId::new(1));
334 chain.add_version("v2", EpochId::new(5), TxId::new(2));
335 chain.add_version("v3", EpochId::new(6), TxId::new(2));
336
337 assert_eq!(chain.version_count(), 3);
338
339 chain.remove_versions_by(TxId::new(2));
341
342 assert_eq!(chain.version_count(), 1);
343 assert_eq!(chain.visible_at(EpochId::new(10)), Some(&"v1"));
344 }
345
346 #[test]
347 fn test_version_chain_deletion() {
348 let mut chain = VersionChain::with_initial("v1", EpochId::new(1), TxId::new(1));
349
350 assert!(chain.mark_deleted(EpochId::new(5)));
352
353 assert_eq!(chain.visible_at(EpochId::new(4)), Some(&"v1"));
355 assert_eq!(chain.visible_at(EpochId::new(5)), None);
356 assert_eq!(chain.visible_at(EpochId::new(10)), None);
357 }
358}