uqa_storage/mvcc/serializable/checkpoint/
records.rs1mod decode;
10mod encode;
11mod key;
12#[cfg(test)]
13mod tests;
14
15pub use encode::SerializableCheckpointRecord;
16pub use key::SerializableCheckpointKey;
17
18use super::{io::invalid, SerializableGraph, VersionResult};
19use crate::read_control::StorageReadControl;
20
21const MAGIC: &[u8; 8] = b"UQASREC1";
22
23impl SerializableGraph {
24 pub fn checkpoint_records_changed(&self) -> bool {
26 self.checkpoint_changed || self.checkpoint_records.is_empty()
27 }
28
29 pub fn write_checkpoint_changes<'a>(
31 &'a self,
32 control: &StorageReadControl,
33 mut update: impl FnMut(
34 SerializableCheckpointKey,
35 Option<SerializableCheckpointRecord<'a>>,
36 ) -> VersionResult<()>,
37 ) -> VersionResult<()> {
38 control.check()?;
39 if !self.checkpoint_records_changed() {
40 return Ok(());
41 }
42 let current = [
43 self.transactions.len(),
44 self.outgoing.len(),
45 self.predicates.reads.len(),
46 self.predicates.writes.len(),
47 ]
48 .into_iter()
49 .try_fold(1_usize, |total, count| {
50 total.checked_add(count).ok_or_else(invalid)
51 })?;
52 let additional = current
53 .saturating_sub(self.checkpoint_records.capacity())
54 .checked_mul(std::mem::size_of::<SerializableCheckpointKey>())
55 .ok_or_else(invalid)?;
56 let _future_keys = self.transactions.budget().reserve(additional)?;
58 let mut old = self.checkpoint_records.iter().copied().peekable();
59 let mut previous = None;
60 self.visit_checkpoint_records(|record| {
61 control.check()?;
62 let key = record.key(control)?;
63 if previous.is_some_and(|previous| previous >= key) {
64 return Err(invalid());
65 }
66 previous = Some(key);
67 while old.peek().is_some_and(|old| *old < key) {
68 update(old.next().expect("peeked checkpoint key"), None)?;
69 }
70 let present = old.peek() == Some(&key);
71 if present {
72 old.next();
73 }
74 if !present || key == SerializableCheckpointKey::HEADER {
75 update(key, Some(record))?;
76 }
77 Ok(())
78 })?;
79 for key in old {
80 control.check()?;
81 update(key, None)?;
82 }
83 Ok(())
84 }
85
86 fn visit_checkpoint_records<'a>(
87 &'a self,
88 mut visit: impl FnMut(SerializableCheckpointRecord<'a>) -> VersionResult<()>,
89 ) -> VersionResult<()> {
90 visit(SerializableCheckpointRecord::header(self))?;
91 for &entry in &*self.transactions {
92 visit(SerializableCheckpointRecord::transaction(self, entry))?;
93 }
94 for &edge in &*self.outgoing {
95 visit(SerializableCheckpointRecord::edge(self, edge))?;
96 }
97 for (writing, entries) in [
98 (false, &self.predicates.reads),
99 (true, &self.predicates.writes),
100 ] {
101 for entry in &**entries {
102 visit(SerializableCheckpointRecord::predicate(
103 self, entry, writing,
104 ))?;
105 }
106 }
107 Ok(())
108 }
109}