uqa_storage/mvcc/serializable/
observations.rs1#[cfg(test)]
10mod tests;
11
12use uqa_core::memory::{BudgetedVec, MemoryBudget};
13
14use super::{
15 conflicts::DependencyAction, predicates::OwnedPredicate, SerializableGraph,
16 SerializablePredicate, SerializableTransactionId, Transaction, VersionError, VersionResult,
17};
18use crate::read_control::StorageReadControl;
19
20#[derive(Debug, Clone, Copy)]
22pub struct SerializableWriteMark {
23 transaction: SerializableTransactionId,
24 writes: u64,
25}
26
27pub(super) struct Observation {
28 pub(super) owner: u64,
29 pub(super) write: u64,
30 pub(super) predicate: OwnedPredicate,
31 pub(super) fingerprint: [u8; 32],
32}
33
34pub(super) struct Observations {
35 pub(super) reads: BudgetedVec<Observation>,
36 pub(super) writes: BudgetedVec<Observation>,
37}
38
39impl Observations {
40 pub(super) fn new(memory: &MemoryBudget) -> Self {
41 Self {
42 reads: BudgetedVec::new(memory),
43 writes: BudgetedVec::new(memory),
44 }
45 }
46
47 pub(super) fn clear(&mut self) -> bool {
48 let changed = !self.reads.is_empty() || !self.writes.is_empty();
49 self.reads = BudgetedVec::new(self.reads.budget());
50 self.writes = BudgetedVec::new(self.writes.budget());
51 changed
52 }
53
54 pub(super) fn forget(&mut self, owner: u64) -> bool {
55 let reads = retain(&mut self.reads, |entry| entry.owner != owner);
56 let writes = retain(&mut self.writes, |entry| entry.owner != owner);
57 reads || writes
58 }
59
60 pub(super) fn reclaim(&mut self, transactions: &[Transaction], oldest: u64) -> bool {
61 let retained = |entry: &Observation| {
62 transactions
63 .binary_search_by_key(&entry.owner, |transaction| transaction.id)
64 .is_ok_and(|position| transactions[position].retains_history(oldest))
65 };
66 let reads = retain(&mut self.reads, retained);
67 let writes = retain(&mut self.writes, retained);
68 reads || writes
69 }
70
71 fn selected(&self, writing: bool) -> &BudgetedVec<Observation> {
72 if writing {
73 &self.writes
74 } else {
75 &self.reads
76 }
77 }
78
79 fn selected_mut(&mut self, writing: bool) -> &mut BudgetedVec<Observation> {
80 if writing {
81 &mut self.writes
82 } else {
83 &mut self.reads
84 }
85 }
86}
87
88impl SerializableGraph {
89 pub fn observe_read(
91 &mut self,
92 transaction: SerializableTransactionId,
93 predicate: SerializablePredicate<'_>,
94 control: &StorageReadControl,
95 ) -> VersionResult<()> {
96 self.observe_predicate(transaction, predicate, false, control)
97 }
98
99 pub fn observe_write(
101 &mut self,
102 transaction: SerializableTransactionId,
103 predicate: SerializablePredicate<'_>,
104 control: &StorageReadControl,
105 ) -> VersionResult<()> {
106 self.observe_predicate(transaction, predicate, true, control)
107 }
108
109 pub fn write_mark(
110 &self,
111 transaction: SerializableTransactionId,
112 ) -> VersionResult<SerializableWriteMark> {
113 self.check_active(transaction)?;
114 Ok(SerializableWriteMark {
115 transaction,
116 writes: self.transactions[self.position(transaction)?].writes,
117 })
118 }
119
120 pub fn rollback_writes(&mut self, mark: SerializableWriteMark) -> VersionResult<()> {
122 let entry = self.transactions[self.position(mark.transaction)?];
123 if !entry.live() {
124 return Err(VersionError::TransactionFinished);
125 }
126 if entry.prepared.is_some() {
127 return Err(VersionError::TransactionSealed);
128 }
129 if mark.writes > entry.writes {
130 return Err(VersionError::InvalidEncoding(
131 "invalid serializable write checkpoint",
132 ));
133 }
134 self.checkpoint_changed |= retain(&mut self.predicates.writes, |observed| {
135 observed.owner != entry.id || observed.write <= mark.writes
136 });
137 Ok(())
138 }
139
140 fn observe_predicate(
141 &mut self,
142 transaction: SerializableTransactionId,
143 predicate: SerializablePredicate<'_>,
144 writing: bool,
145 control: &StorageReadControl,
146 ) -> VersionResult<()> {
147 control.check()?;
148 self.check_active(transaction)?;
149 predicate.validate(writing)?;
150 let position = self.position(transaction)?;
151 let entry = self.transactions[position];
152 if writing && entry.read_only {
153 return Err(VersionError::InvalidEncoding(
154 "read-only serializable transaction cannot observe writes",
155 ));
156 }
157 if predicate.is_empty() {
158 return Ok(());
159 }
160 for observed in object_entries(self.predicates.selected(writing), predicate.object) {
161 control.check()?;
162 if observed.owner == entry.id && observed.predicate.borrowed() == predicate {
163 return Ok(());
164 }
165 }
166 let write = if writing {
167 entry
168 .writes
169 .checked_add(1)
170 .ok_or(VersionError::SequenceExhausted)?
171 } else {
172 0
173 };
174 let owned = OwnedPredicate::new(predicate, self.transactions.budget())?;
175 let mut actions = BudgetedVec::<DependencyAction>::new(self.transactions.budget());
176 for observed in object_entries(self.predicates.selected(!writing), predicate.object) {
177 control.check()?;
178 if observed.owner == entry.id {
179 continue;
180 }
181 let other = observed.predicate.borrowed();
182 let matches = if writing {
183 other.overlaps_write(predicate)
184 } else {
185 predicate.overlaps_write(other)
186 };
187 if !matches {
188 continue;
189 }
190 let peer =
191 SerializableTransactionId::new(self.database, self.coordinator, observed.owner)?;
192 let (reader, writer) = if writing {
193 (peer, transaction)
194 } else {
195 (transaction, peer)
196 };
197 if let Some(action) = self.plan_dependency(transaction, reader, writer, control)? {
198 if let Err(index) =
199 actions.binary_search_by_key(&action.edge, |planned| planned.edge)
200 {
201 actions.push(action)?;
202 actions[index..].rotate_right(1);
203 }
204 }
205 }
206 let mut observed = Observation {
207 owner: entry.id,
208 write,
209 predicate: owned,
210 fingerprint: [0; 32],
211 };
212 observed.fingerprint = super::checkpoint::records::SerializableCheckpointRecord::predicate(
213 self, &observed, writing,
214 )
215 .fingerprint(control)?;
216 let index = self
217 .predicates
218 .selected(writing)
219 .binary_search_by_key(&(predicate.object, observed.fingerprint), |entry| {
220 (entry.predicate.object, entry.fingerprint)
221 })
222 .err()
223 .ok_or(VersionError::InvalidEncoding(
224 "serializable predicate fingerprint collision",
225 ))?;
226 self.predicates.selected_mut(writing).reserve(1)?;
228 self.reserve_dependencies(
229 actions
230 .iter()
231 .filter(|action| action.victim.is_none())
232 .count(),
233 )?;
234 control.check()?;
235 let observations = self.predicates.selected_mut(writing);
236 observations.push(observed)?;
237 self.checkpoint_changed = true;
238 observations[index..].rotate_right(1);
239 for &action in &*actions {
240 self.publish_dependency(action)?;
241 }
242 if writing {
243 self.transactions[position].writes = write;
244 }
245 Ok(())
246 }
247}
248
249fn object_entries(observations: &[Observation], object: [u8; 16]) -> &[Observation] {
250 let start = observations.partition_point(|entry| entry.predicate.object < object);
251 let end = observations.partition_point(|entry| entry.predicate.object <= object);
252 &observations[start..end]
253}
254
255fn retain(
256 values: &mut BudgetedVec<Observation>,
257 mut predicate: impl FnMut(&Observation) -> bool,
258) -> bool {
259 let previous = values.len();
260 let mut kept = 0;
261 for index in 0..values.len() {
262 if predicate(&values[index]) {
263 values.swap(kept, index);
264 kept += 1;
265 }
266 }
267 values.truncate(kept);
268 if values.is_empty() {
269 *values = BudgetedVec::new(values.budget());
270 }
271 kept != previous
272}