uqa_storage/mvcc/commit/
reclamation.rs1use sha2::{Digest, Sha256};
10
11use crate::mvcc::{CommittedRecordSnapshot, RecordWrite, VersionError, VersionResult};
12use crate::read_control::StorageReadControl;
13
14use super::PreparedRecordCommit;
15
16impl PreparedRecordCommit {
17 pub fn new_at_snapshot(
19 writes: &[RecordWrite<'_>],
20 snapshot: &dyn CommittedRecordSnapshot,
21 control: &StorageReadControl,
22 ) -> VersionResult<Self> {
23 Ok(Self::new(writes, control)?.with_reclamation_epoch(snapshot.reclamation_epoch()))
24 }
25
26 pub(in crate::mvcc) fn with_reclamation_epoch(mut self, epoch: Option<u64>) -> Self {
27 if let Some(epoch) = epoch {
28 let mut digest = Sha256::new();
29 digest.update(b"UQA prepared reclamation epoch 1");
30 digest.update(self.fingerprint);
31 digest.update(epoch.to_be_bytes());
32 self.fingerprint = digest.finalize().into();
33 }
34 self.reclamation_epoch = epoch;
35 self
36 }
37
38 pub fn validate_reclamation_epoch(
40 &self,
41 prefix: &[u8],
42 minimum: u64,
43 current: u64,
44 control: &StorageReadControl,
45 ) -> VersionResult<()> {
46 control.cancellation().check()?;
47 if prefix.is_empty() || minimum == 0 || minimum > current {
48 return Err(VersionError::InvalidEncoding(
49 "invalid tombstone reclamation domain",
50 ));
51 }
52 if self
53 .reclamation_epoch
54 .is_some_and(|epoch| epoch >= minimum && epoch <= current)
55 {
56 return Ok(());
57 }
58 let reclaimed = || VersionError::ReclaimedObservation {
59 observed: self.reclamation_epoch,
60 minimum,
61 current,
62 };
63 let mut writes = self.writes();
64 while let Some(write) = writes.next_metadata(control)? {
65 if write.expected().is_none() && write.key().starts_with(prefix) {
66 return Err(reclaimed());
67 }
68 }
69 let required = self.requirements.iter().flat_map(|requirements| {
70 requirements
71 .iter()
72 .filter(|requirement| requirement.expected.is_none())
73 .map(|requirement| requirement.key.bytes())
74 });
75 for key in required {
76 control.cancellation().check()?;
77 if key.starts_with(prefix) {
78 return Err(reclaimed());
79 }
80 }
81 Ok(())
82 }
83}