1use std::sync::Arc;
10
11use uqa_core::memory::BudgetedVec;
12
13use crate::mvcc::{CommitSequence, DatabaseId, PrivateRecordRevision};
14use crate::read_control::{
15 KeyReadVisitor, KeyValueReadVisitor, StorageReadControl, ValueReadVisitor,
16};
17use crate::{KeyValueBatch, StorageBackendResult};
18
19mod snapshot;
20
21pub(crate) fn for_each_key(
23 read: &dyn KeyValueRead,
24 prefix: &[u8],
25 visit: &mut dyn FnMut(&[u8]) -> StorageBackendResult<bool>,
26) -> StorageBackendResult<()> {
27 let mut after = None::<BudgetedVec<u8>>;
28 loop {
29 let mut keys = BudgetedVec::new(read.control().memory());
30 read.visit_keys_after(prefix, after.as_deref(), 128, read.control(), &mut |key| {
31 let mut owned = BudgetedVec::new(read.control().memory());
32 owned.extend_from_slice(key)?;
33 keys.push(owned)?;
34 Ok(())
35 })?;
36 let Some(last) = keys.last() else {
37 return Ok(());
38 };
39 let mut next = BudgetedVec::new(read.control().memory());
40 next.extend_from_slice(last)?;
41 after = Some(next);
42 for key in keys.iter() {
43 read.control().check()?;
44 if !visit(key)? {
45 return Ok(());
46 }
47 }
48 }
49}
50
51pub type KeyValueReadScope<'a> = dyn FnMut(&dyn KeyValueRead) -> StorageBackendResult<()> + 'a;
52pub type KeyValueMutation<'a> =
53 dyn FnMut(&dyn KeyValueRead, &mut dyn KeyValueBatch) -> StorageBackendResult<()> + 'a;
54pub type KeyValueVersionedMutation<'a> = dyn FnMut(
55 crate::mvcc::StorageMutationOrigin,
56 &dyn KeyValueRead,
57 &mut dyn KeyValueBatch,
58 ) -> StorageBackendResult<()>
59 + 'a;
60
61pub trait KeyValueRead {
63 fn control(&self) -> &StorageReadControl;
64 fn revision(&self, prefixes: &[&[u8]]) -> StorageBackendResult<KeyValueReadRevision>;
65 fn marker_fingerprint(&self, _key: &[u8]) -> StorageBackendResult<Option<[u8; 32]>> {
67 self.control().check()?;
68 Ok(None)
69 }
70 fn record_revision(&self, _key: &[u8]) -> StorageBackendResult<Option<KeyValueReadRevision>> {
72 self.control().check()?;
73 Err(super::codec::other_error(
74 "individual record revisions are not supported",
75 ))
76 }
77 fn retained_source(
79 &self,
80 _key: &[u8],
81 ) -> StorageBackendResult<Option<Arc<dyn KeyValueRead + Send + Sync>>> {
82 self.control().check()?;
83 Ok(None)
84 }
85 fn retain(
87 &self,
88 prefixes: &[&[u8]],
89 ) -> StorageBackendResult<Arc<dyn KeyValueRead + Send + Sync>> {
90 snapshot::capture(self, prefixes)
91 }
92 fn visit_value(&self, key: &[u8], visit: &mut ValueReadVisitor<'_>)
93 -> StorageBackendResult<()>;
94 fn visit_prefix(
95 &self,
96 prefix: &[u8],
97 visit: &mut KeyValueReadVisitor<'_>,
98 ) -> StorageBackendResult<()>;
99
100 fn visit_value_budgeted(
102 &self,
103 _key: &[u8],
104 control: &StorageReadControl,
105 _visit: &mut ValueReadVisitor<'_>,
106 ) -> StorageBackendResult<()> {
107 control.check()?;
108 Err(super::codec::other_error(
109 "controlled compound value reads are not supported",
110 ))
111 }
112
113 fn visit_value_bounded(
115 &self,
116 _key: &[u8],
117 _max_bytes: usize,
118 control: &StorageReadControl,
119 _visit: &mut ValueReadVisitor<'_>,
120 ) -> StorageBackendResult<()> {
121 control.check()?;
122 Err(super::codec::other_error(
123 "size-bounded compound value reads are not supported",
124 ))
125 }
126
127 fn visit_prefix_after(
129 &self,
130 _prefix: &[u8],
131 _after: Option<&[u8]>,
132 _limit: usize,
133 control: &StorageReadControl,
134 _visit: &mut KeyValueReadVisitor<'_>,
135 ) -> StorageBackendResult<()> {
136 control.check()?;
137 Err(super::codec::other_error(
138 "controlled compound prefix reads are not supported",
139 ))
140 }
141
142 fn visit_keys_after(
144 &self,
145 _prefix: &[u8],
146 _after: Option<&[u8]>,
147 _limit: usize,
148 control: &StorageReadControl,
149 _visit: &mut KeyReadVisitor<'_>,
150 ) -> StorageBackendResult<()> {
151 control.check()?;
152 Err(super::codec::other_error(
153 "compound key-only scans are not supported",
154 ))
155 }
156
157 fn contains_prefix_budgeted(
159 &self,
160 _prefix: &[u8],
161 control: &StorageReadControl,
162 ) -> StorageBackendResult<bool> {
163 control.check()?;
164 Err(super::codec::other_error(
165 "compound key-only probes are not supported",
166 ))
167 }
168
169 fn get(&self, key: &[u8]) -> StorageBackendResult<Option<BudgetedVec<u8>>> {
170 let mut result = None;
171 self.visit_value(key, &mut |value| {
172 if let Some(value) = value {
173 let mut bytes = BudgetedVec::new(self.control().memory());
174 bytes.extend_from_slice(value)?;
175 result = Some(bytes);
176 }
177 Ok(())
178 })?;
179 Ok(result)
180 }
181}
182
183#[cfg(test)]
184mod tests;
185
186#[derive(Clone)]
188pub struct KeyValueReadRevision(Revision);
189
190#[derive(Clone)]
191enum Revision {
192 Memory(Arc<()>),
193 Record(crate::mvcc::VisibleRecordRevision),
194 Records {
195 database: DatabaseId,
196 committed: CommitSequence,
197 private: Option<PrivateRecordRevision>,
198 },
199}
200
201impl KeyValueReadRevision {
202 pub(crate) fn observed_commit(&self, database: DatabaseId) -> Option<CommitSequence> {
203 match &self.0 {
204 Revision::Record(revision) => revision.committed(database),
205 _ => None,
206 }
207 }
208
209 pub fn same_private_changes(&self, other: &Self) -> bool {
211 matches!((&self.0, &other.0), (
212 Revision::Records { database: a, private: ap, .. },
213 Revision::Records { database: b, private: bp, .. }
214 ) if a == b && ap == bp)
215 }
216
217 pub fn follows_by_one_commit(&self, earlier: &Self) -> bool {
219 match (earlier.committed_state(), self.committed_state()) {
220 (Some((database, before, _)), Some((current, after, false))) => {
221 database == current && before.successor().ok() == Some(after)
222 }
223 _ => false,
224 }
225 }
226
227 pub fn same_committed_state(&self, other: &Self) -> bool {
229 match (self.committed_state(), other.committed_state()) {
230 (Some((database, sequence, _)), Some((other_database, other_sequence, _))) => {
231 database == other_database && sequence == other_sequence
232 }
233 _ => false,
234 }
235 }
236
237 fn committed_state(&self) -> Option<(DatabaseId, CommitSequence, bool)> {
239 match &self.0 {
240 Revision::Record(record) => record
241 .committed_sequence()
242 .map(|sequence| (record.database(), sequence, record.is_private())),
243 Revision::Records {
244 database,
245 committed,
246 private,
247 } => Some((*database, *committed, private.is_some())),
248 Revision::Memory(_) => None,
249 }
250 }
251
252 pub(crate) fn record_database(&self) -> Option<DatabaseId> {
253 match &self.0 {
254 Revision::Record(revision) => Some(revision.database()),
255 Revision::Memory(_) | Revision::Records { .. } => None,
256 }
257 }
258
259 pub fn has_private_changes(&self) -> bool {
261 match &self.0 {
262 Revision::Memory(_) => true,
263 Revision::Record(revision) => revision.is_private(),
264 Revision::Records { private, .. } => private.is_some(),
265 }
266 }
267
268 pub fn fresh() -> Self {
270 Self(Revision::Memory(Arc::new(())))
271 }
272
273 pub(crate) fn memory(identity: &Arc<()>) -> Self {
274 Self(Revision::Memory(Arc::clone(identity)))
275 }
276
277 pub(crate) fn record(revision: crate::mvcc::VisibleRecordRevision) -> Self {
278 Self(Revision::Record(revision))
279 }
280
281 pub(crate) fn records(
282 database: DatabaseId,
283 committed: CommitSequence,
284 private: Option<PrivateRecordRevision>,
285 ) -> Self {
286 Self(Revision::Records {
287 database,
288 committed,
289 private,
290 })
291 }
292}
293
294impl PartialEq for KeyValueReadRevision {
295 fn eq(&self, other: &Self) -> bool {
296 match (&self.0, &other.0) {
297 (Revision::Memory(a), Revision::Memory(b)) => Arc::ptr_eq(a, b),
298 (Revision::Record(a), Revision::Record(b)) => a == b,
299 (
300 Revision::Records {
301 database: a,
302 committed: ac,
303 private: ap,
304 },
305 Revision::Records {
306 database: b,
307 committed: bc,
308 private: bp,
309 },
310 ) => a == b && ac == bc && ap == bp,
311 _ => false,
312 }
313 }
314}
315impl Eq for KeyValueReadRevision {}