uqa_storage/mvcc/serializable/
checkpoint.rs1mod io;
10mod nodes;
11mod predicates;
12pub(super) mod records;
13#[cfg(test)]
14mod tests;
15
16use std::io::{Read, Write};
17
18use super::{DatabaseId, Edge, SerializableGraph, Transaction, VersionError, VersionResult};
19use crate::read_control::StorageReadControl;
20use io::{invalid, Decoder, Encoder};
21
22const MAGIC: &[u8; 8] = b"UQASER03";
23
24impl SerializableGraph {
25 pub fn checkpoint_changed(&self) -> bool {
27 self.checkpoint_changed
28 }
29
30 pub fn write_checkpoint(
32 &self,
33 output: &mut dyn Write,
34 control: &StorageReadControl,
35 ) -> VersionResult<()> {
36 let mut encoder = Encoder::new(output, control);
37 encoder.bytes(MAGIC)?;
38 encoder.bytes(&self.database.as_bytes())?;
39 encoder.bytes(&self.coordinator)?;
40 for value in [self.last_allocation, self.clock, self.pending_finishes] {
41 encoder.number(value)?;
42 }
43 for count in [
44 self.transactions.len(),
45 self.outgoing.len(),
46 self.predicates.reads.len(),
47 self.predicates.writes.len(),
48 ] {
49 encoder.count(count)?;
50 }
51 for &entry in &*self.transactions {
52 nodes::write(&mut encoder, entry)?;
53 }
54 for &Edge(reader, writer) in &*self.outgoing {
55 encoder.number(reader)?;
56 encoder.number(writer)?;
57 }
58 for entries in [&self.predicates.reads, &self.predicates.writes] {
59 for entry in &**entries {
60 predicates::write(&mut encoder, entry)?;
61 }
62 }
63 encoder.finish()
64 }
65
66 pub fn checkpoint_length(&self, control: &StorageReadControl) -> VersionResult<u64> {
68 let mut count = CountBytes(0);
69 self.write_checkpoint(&mut count, control)?;
70 Ok(count.0)
71 }
72
73 pub fn read_checkpoint(
75 database: DatabaseId,
76 coordinator: [u8; 16],
77 input: &mut dyn Read,
78 control: &StorageReadControl,
79 ) -> VersionResult<Self> {
80 let mut decoder = Decoder::new(input, control);
81 let magic = decoder.array::<8>()?;
82 if magic != *MAGIC && magic != *b"UQASER02" && magic != *b"UQASER01" {
83 return Err(invalid());
84 }
85 if decoder.array::<16>()? != database.as_bytes() {
86 return Err(VersionError::WrongDatabase);
87 }
88 if decoder.array::<16>()? != coordinator {
89 return Err(VersionError::WrongSerializableCoordinator);
90 }
91 let mut graph = Self::new(database, coordinator, control.memory())?;
92 graph.last_allocation = decoder.number()?;
93 graph.clock = decoder.number()?;
94 graph.pending_finishes = decoder.number()?;
95 if graph.clock.checked_add(graph.pending_finishes).is_none()
96 || (graph.clock == 0 && graph.last_allocation != 0)
97 {
98 return Err(invalid());
99 }
100 let transaction_count = decoder.count()?;
101 let edge_count = decoder.count()?;
102 let read_count = decoder.count()?;
103 let write_count = decoder.count()?;
104 nodes::restore(
105 &mut graph,
106 transaction_count,
107 magic != *b"UQASER01",
108 magic == *MAGIC,
109 &mut decoder,
110 )?;
111 graph.outgoing.reserve(edge_count)?;
112 graph.incoming.reserve(edge_count)?;
113 for _ in 0..edge_count {
114 let edge = Edge(decoder.number()?, decoder.number()?);
115 if edge.0 == edge.1
116 || graph
117 .outgoing
118 .last()
119 .is_some_and(|previous| *previous >= edge)
120 {
121 return Err(invalid());
122 }
123 lookup(&graph, edge.0)?;
124 if lookup(&graph, edge.1)?.read_only {
125 return Err(invalid());
126 }
127 graph.outgoing.push(edge)?;
128 graph.incoming.push(Edge(edge.1, edge.0))?;
129 }
130 graph.incoming.sort_unstable();
131 for (writing, count) in [(false, read_count), (true, write_count)] {
132 let entries = if writing {
133 &mut graph.predicates.writes
134 } else {
135 &mut graph.predicates.reads
136 };
137 entries.reserve(count)?;
138 for _ in 0..count {
139 let mut observed = predicates::read(&mut decoder, writing)?;
140 observed.fingerprint =
141 records::SerializableCheckpointRecord::predicate(&graph, &observed, writing)
142 .fingerprint(control)?;
143 let owner = lookup(&graph, observed.owner)?;
144 if owner.aborted
145 || (writing
146 && (owner.read_only
147 || observed.write == 0
148 || observed.write > owner.writes))
149 || (!writing && observed.write != 0)
150 {
151 return Err(invalid());
152 }
153 let entries = if writing {
154 &mut graph.predicates.writes
155 } else {
156 &mut graph.predicates.reads
157 };
158 if entries
159 .last()
160 .is_some_and(|previous| previous.predicate.object > observed.predicate.object)
161 {
162 return Err(invalid());
163 }
164 entries.push(observed)?;
165 }
166 }
167 decoder.finish()?;
168 for entries in [&mut graph.predicates.reads, &mut graph.predicates.writes] {
169 entries.sort_unstable_by_key(|entry| (entry.predicate.object, entry.fingerprint));
170 }
171 control.check()?;
172 graph.checkpoint_changed = false;
173 Ok(graph)
174 }
175}
176
177fn lookup(graph: &SerializableGraph, allocation: u64) -> VersionResult<&Transaction> {
178 let position = graph
179 .transactions
180 .binary_search_by_key(&allocation, |entry| entry.id)
181 .map_err(|_| invalid())?;
182 Ok(&graph.transactions[position])
183}
184
185struct CountBytes(u64);
186
187impl Write for CountBytes {
188 fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
189 self.0 = self
190 .0
191 .checked_add(
192 u64::try_from(bytes.len())
193 .map_err(|_| std::io::Error::other("checkpoint length overflow"))?,
194 )
195 .ok_or_else(|| std::io::Error::other("checkpoint length overflow"))?;
196 Ok(bytes.len())
197 }
198
199 fn flush(&mut self) -> std::io::Result<()> {
200 Ok(())
201 }
202}