1mod fingerprint;
10
11use std::cmp::Ordering;
12use std::sync::Arc;
13
14use uqa_core::memory::{BudgetedVec, MemoryReservation};
15
16use crate::read_control::StorageReadControl;
17
18use super::{
19 CommitSequence, PreparedRecordWrite, PrivateRecordSnapshot, RecordVersion, ScannedRecord,
20 SharedRecordValue, VersionResult,
21};
22
23#[derive(Clone, Copy)]
24pub struct BorrowedRecord<'a> {
25 pub revision: Option<CommitSequence>,
26 pub value: Option<&'a [u8]>,
27}
28
29#[derive(Clone, Copy, Debug, PartialEq, Eq)]
31pub struct RecordMetadata {
32 pub revision: Option<CommitSequence>,
33 pub live: bool,
34}
35
36#[derive(Clone, Copy, Debug, PartialEq, Eq)]
38pub struct VisibleRecordRevision {
39 database: super::DatabaseId,
40 committed: Option<CommitSequence>,
41 private: Option<super::PrivateRecordRevision>,
42}
43
44impl VisibleRecordRevision {
45 pub(crate) fn committed(self, database: super::DatabaseId) -> Option<CommitSequence> {
46 (self.database == database && self.private.is_none())
47 .then_some(self.committed)
48 .flatten()
49 }
50
51 pub(crate) fn database(self) -> super::DatabaseId {
52 self.database
53 }
54
55 pub fn is_private(self) -> bool {
56 self.private.is_some()
57 }
58}
59
60impl From<BorrowedRecord<'_>> for RecordMetadata {
61 fn from(record: BorrowedRecord<'_>) -> Self {
62 Self {
63 revision: record.revision,
64 live: record.value.is_some(),
65 }
66 }
67}
68
69pub type RecordValueVisitor<'a> = dyn FnMut(Option<BorrowedRecord<'_>>) -> VersionResult<()> + 'a;
70pub type RecordScanVisitor<'a> = dyn FnMut(&[u8], BorrowedRecord<'_>) -> VersionResult<bool> + 'a;
71pub type RecordKeyVisitor<'a> = dyn FnMut(&[u8], RecordMetadata) -> VersionResult<bool> + 'a;
72
73pub trait CommittedRecordSnapshot: Send + Sync {
75 fn sequence(&self) -> CommitSequence;
76
77 fn reclamation_epoch(&self) -> Option<u64> {
79 None
80 }
81
82 fn metadata(
84 &self,
85 key: &[u8],
86 control: &StorageReadControl,
87 ) -> VersionResult<Option<RecordMetadata>> {
88 let mut found = None;
89 self.visit_value(key, control, &mut |record| {
90 found = record.map(Into::into);
91 Ok(())
92 })?;
93 Ok(found)
94 }
95
96 fn visit_keys(
98 &self,
99 prefix: &[u8],
100 after: Option<&[u8]>,
101 limit: usize,
102 control: &StorageReadControl,
103 visit: &mut RecordKeyVisitor<'_>,
104 ) -> VersionResult<()> {
105 self.visit_prefix(prefix, after, limit, control, &mut |key, record| {
106 visit(key, record.into())
107 })
108 }
109
110 fn get(
112 &self,
113 key: &[u8],
114 control: &StorageReadControl,
115 ) -> VersionResult<Option<RecordVersion<SharedRecordValue>>>;
116
117 fn scan(
119 &self,
120 prefix: &[u8],
121 after: Option<&[u8]>,
122 limit: usize,
123 control: &StorageReadControl,
124 ) -> VersionResult<BudgetedVec<ScannedRecord>>;
125
126 fn visit_value(
128 &self,
129 key: &[u8],
130 control: &StorageReadControl,
131 visit: &mut RecordValueVisitor<'_>,
132 ) -> VersionResult<()> {
133 let record = self.get(key, control)?;
134 visit(record.as_ref().map(|record| BorrowedRecord {
135 revision: Some(record.sequence()),
136 value: record.value().map(|value| &***value),
137 }))?;
138 control.cancellation().check()?;
139 Ok(())
140 }
141
142 fn visit_value_bounded(
144 &self,
145 _key: &[u8],
146 _max_bytes: usize,
147 control: &StorageReadControl,
148 _visit: &mut RecordValueVisitor<'_>,
149 ) -> VersionResult<()> {
150 control.check()?;
151 Err(crate::StorageBackendError::Other(
152 "size-bounded committed record reads are not supported".into(),
153 )
154 .into())
155 }
156
157 fn visit_prefix(
159 &self,
160 prefix: &[u8],
161 after: Option<&[u8]>,
162 limit: usize,
163 control: &StorageReadControl,
164 visit: &mut RecordScanVisitor<'_>,
165 ) -> VersionResult<()> {
166 control.cancellation().check()?;
167 let mut cursor: Option<BudgetedVec<u8>> = None;
168 let mut remaining = limit;
169 while remaining != 0 {
170 let mut page = self.scan(
171 prefix,
172 cursor.as_deref().or(after),
173 remaining.min(64),
174 control,
175 )?;
176 if page.is_empty() {
177 break;
178 }
179 for record in page.iter() {
180 control.cancellation().check()?;
181 if !visit(
182 &record.key,
183 BorrowedRecord {
184 revision: Some(record.version.sequence()),
185 value: record.version.value().map(|value| &***value),
186 },
187 )? {
188 control.cancellation().check()?;
189 return Ok(());
190 }
191 remaining -= 1;
192 }
193 cursor = page.pop().map(|record| record.key);
194 }
195 control.cancellation().check()?;
196 Ok(())
197 }
198}
199
200struct RetainedSnapshot<T> {
201 snapshot: T,
202 _memory: MemoryReservation,
203}
204
205pub fn retain_record_snapshot<T: CommittedRecordSnapshot + 'static>(
207 snapshot: T,
208 control: &StorageReadControl,
209) -> VersionResult<Arc<dyn CommittedRecordSnapshot>> {
210 control.cancellation().check()?;
211 let memory = control
212 .memory()
213 .reserve(std::mem::size_of::<RetainedSnapshot<T>>())?;
214 Ok(Arc::new(RetainedSnapshot {
215 snapshot,
216 _memory: memory,
217 }))
218}
219
220impl<T: CommittedRecordSnapshot> CommittedRecordSnapshot for RetainedSnapshot<T> {
221 fn sequence(&self) -> CommitSequence {
222 self.snapshot.sequence()
223 }
224 fn reclamation_epoch(&self) -> Option<u64> {
225 self.snapshot.reclamation_epoch()
226 }
227 fn metadata(
228 &self,
229 key: &[u8],
230 control: &StorageReadControl,
231 ) -> VersionResult<Option<RecordMetadata>> {
232 self.snapshot.metadata(key, control)
233 }
234 fn visit_keys(
235 &self,
236 prefix: &[u8],
237 after: Option<&[u8]>,
238 limit: usize,
239 control: &StorageReadControl,
240 visit: &mut RecordKeyVisitor<'_>,
241 ) -> VersionResult<()> {
242 self.snapshot
243 .visit_keys(prefix, after, limit, control, visit)
244 }
245 fn get(
246 &self,
247 key: &[u8],
248 control: &StorageReadControl,
249 ) -> VersionResult<Option<RecordVersion<SharedRecordValue>>> {
250 self.snapshot.get(key, control)
251 }
252 fn scan(
253 &self,
254 prefix: &[u8],
255 after: Option<&[u8]>,
256 limit: usize,
257 control: &StorageReadControl,
258 ) -> VersionResult<BudgetedVec<ScannedRecord>> {
259 self.snapshot.scan(prefix, after, limit, control)
260 }
261 fn visit_value(
262 &self,
263 key: &[u8],
264 control: &StorageReadControl,
265 visit: &mut RecordValueVisitor<'_>,
266 ) -> VersionResult<()> {
267 self.snapshot.visit_value(key, control, visit)
268 }
269 fn visit_value_bounded(
270 &self,
271 key: &[u8],
272 max_bytes: usize,
273 control: &StorageReadControl,
274 visit: &mut RecordValueVisitor<'_>,
275 ) -> VersionResult<()> {
276 self.snapshot
277 .visit_value_bounded(key, max_bytes, control, visit)
278 }
279 fn visit_prefix(
280 &self,
281 prefix: &[u8],
282 after: Option<&[u8]>,
283 limit: usize,
284 control: &StorageReadControl,
285 visit: &mut RecordScanVisitor<'_>,
286 ) -> VersionResult<()> {
287 self.snapshot
288 .visit_prefix(prefix, after, limit, control, visit)
289 }
290}
291
292pub struct VisibleRecord {
294 original: Option<CommitSequence>,
295 value: Option<SharedRecordValue>,
296 private: bool,
297}
298
299impl VisibleRecord {
300 pub fn original_revision(&self) -> Option<CommitSequence> {
301 self.original
302 }
303
304 pub fn value(&self) -> Option<&[u8]> {
305 self.value.as_ref().map(|value| &***value)
306 }
307
308 pub fn is_private(&self) -> bool {
309 self.private
310 }
311
312 fn committed(version: RecordVersion<SharedRecordValue>) -> Self {
313 let (sequence, value) = version.into_parts();
314 Self {
315 original: Some(sequence),
316 value,
317 private: false,
318 }
319 }
320
321 fn private(write: &PreparedRecordWrite) -> Self {
322 Self {
323 original: write.expected(),
324 value: write.shared_value(),
325 private: true,
326 }
327 }
328}
329
330pub struct ScannedVisibleRecord {
331 pub key: BudgetedVec<u8>,
332 pub record: VisibleRecord,
333}
334
335pub struct MergedRecordSnapshot {
337 committed: Arc<dyn CommittedRecordSnapshot>,
338 private: PrivateRecordSnapshot,
339 serializable: Option<super::SerializableReadContext>,
340}
341
342impl MergedRecordSnapshot {
343 pub(in crate::mvcc) fn retained_source(
344 &self,
345 key: &[u8],
346 control: &StorageReadControl,
347 ) -> VersionResult<Option<Arc<dyn crate::key_value::KeyValueRead + Send + Sync>>> {
348 self.private.retained_source(key, control)
349 }
350
351 pub fn record_revision(
353 &self,
354 database: super::DatabaseId,
355 key: &[u8],
356 control: &StorageReadControl,
357 ) -> VersionResult<Option<VisibleRecordRevision>> {
358 control.check()?;
359 let Some(metadata) = self.metadata(key, control)?.filter(|record| record.live) else {
360 control.check()?;
361 return Ok(None);
362 };
363 let private = self.private_keys(key, None, 1, control)?;
364 let private = private
365 .first()
366 .filter(|record| record.key() == key)
367 .map(super::PrivateRecordKey::revision);
368 control.check()?;
369 Ok(Some(VisibleRecordRevision {
370 database,
371 committed: metadata.revision,
372 private,
373 }))
374 }
375
376 pub fn try_clone(&self) -> VersionResult<Self> {
378 Ok(Self {
379 committed: Arc::clone(&self.committed),
380 private: self.private.try_clone()?,
381 serializable: self.serializable.clone(),
382 })
383 }
384
385 pub fn new(
386 committed: Arc<dyn CommittedRecordSnapshot>,
387 private: PrivateRecordSnapshot,
388 ) -> Self {
389 Self {
390 committed,
391 private,
392 serializable: None,
393 }
394 }
395
396 pub(crate) fn with_serializable(
397 mut self,
398 context: Option<super::SerializableReadContext>,
399 ) -> Self {
400 self.serializable = context;
401 self
402 }
403
404 pub fn serializable(&self) -> Option<&super::SerializableReadContext> {
406 self.serializable.as_ref()
407 }
408
409 pub fn sequence(&self) -> CommitSequence {
410 self.committed.sequence()
411 }
412
413 pub fn committed(&self) -> &dyn CommittedRecordSnapshot {
415 self.committed.as_ref()
416 }
417
418 pub(super) fn retain_committed(&self) -> Arc<dyn CommittedRecordSnapshot> {
419 Arc::clone(&self.committed)
420 }
421
422 pub fn private_keys(
424 &self,
425 prefix: &[u8],
426 after: Option<&[u8]>,
427 limit: usize,
428 control: &StorageReadControl,
429 ) -> VersionResult<BudgetedVec<super::PrivateRecordKey>> {
430 self.private.scan_keys(prefix, after, limit, control)
431 }
432
433 pub fn visit_value(
434 &self,
435 key: &[u8],
436 control: &StorageReadControl,
437 visit: &mut RecordValueVisitor<'_>,
438 ) -> VersionResult<()> {
439 if let Some(write) = self.private.get(key, control)? {
440 visit(Some(BorrowedRecord {
441 revision: write.expected(),
442 value: write.value(),
443 }))?;
444 control.cancellation().check()?;
445 return Ok(());
446 }
447 self.committed.visit_value(key, control, visit)
448 }
449
450 pub fn visit_value_bounded(
452 &self,
453 key: &[u8],
454 max_bytes: usize,
455 control: &StorageReadControl,
456 visit: &mut RecordValueVisitor<'_>,
457 ) -> VersionResult<()> {
458 control.check()?;
459 if let Some(write) = self.private.get(key, control)? {
460 if let Some(value) = write.value() {
461 control.check_value_size(value.len(), max_bytes)?;
462 }
463 visit(Some(BorrowedRecord {
464 revision: write.expected(),
465 value: write.value(),
466 }))?;
467 control.check()?;
468 return Ok(());
469 }
470 self.committed
471 .visit_value_bounded(key, max_bytes, control, visit)
472 }
473
474 pub fn visit_prefix(
475 &self,
476 prefix: &[u8],
477 after: Option<&[u8]>,
478 limit: usize,
479 control: &StorageReadControl,
480 visit: &mut RecordScanVisitor<'_>,
481 ) -> VersionResult<()> {
482 self.private.visit_merged::<super::projection::Values>(
483 &*self.committed,
484 prefix,
485 after,
486 limit,
487 control,
488 visit,
489 )
490 }
491
492 pub fn metadata(
493 &self,
494 key: &[u8],
495 control: &StorageReadControl,
496 ) -> VersionResult<Option<RecordMetadata>> {
497 if let Some(write) = self.private.get(key, control)? {
498 return Ok(Some(RecordMetadata {
499 revision: write.expected(),
500 live: write.value().is_some(),
501 }));
502 }
503 self.committed.metadata(key, control)
504 }
505
506 pub fn visit_keys(
507 &self,
508 prefix: &[u8],
509 after: Option<&[u8]>,
510 limit: usize,
511 control: &StorageReadControl,
512 visit: &mut RecordKeyVisitor<'_>,
513 ) -> VersionResult<()> {
514 self.private.visit_merged::<super::projection::Keys>(
515 &*self.committed,
516 prefix,
517 after,
518 limit,
519 control,
520 visit,
521 )
522 }
523
524 pub fn get(
525 &self,
526 key: &[u8],
527 control: &StorageReadControl,
528 ) -> VersionResult<Option<VisibleRecord>> {
529 if let Some(write) = self.private.get(key, control)? {
530 return Ok(Some(VisibleRecord::private(&write)));
531 }
532 Ok(self
533 .committed
534 .get(key, control)?
535 .map(VisibleRecord::committed))
536 }
537
538 pub fn scan(
540 &self,
541 prefix: &[u8],
542 after: Option<&[u8]>,
543 limit: usize,
544 control: &StorageReadControl,
545 ) -> VersionResult<BudgetedVec<ScannedVisibleRecord>> {
546 control.cancellation().check()?;
547 let mut result = BudgetedVec::new(control.memory());
548 if limit == 0 {
549 return Ok(result);
550 }
551 let (committed, _committed_memory) = self
552 .committed
553 .scan(prefix, after, limit, control)?
554 .into_parts();
555 let (private, _private_memory) = self
556 .private
557 .scan(prefix, after, limit, control)?
558 .into_parts();
559 let mut committed = committed.into_iter().peekable();
560 let mut private = private.into_iter().peekable();
561 while result.len() < limit {
562 control.cancellation().check()?;
563 let order = match (committed.peek(), private.peek()) {
564 (Some(committed), Some(private)) => committed.key.as_ref().cmp(private.key()),
565 (Some(_), None) => Ordering::Less,
566 (None, Some(_)) => Ordering::Greater,
567 (None, None) => break,
568 };
569 let record = match order {
570 Ordering::Less => {
571 let committed = committed.next().expect("peeked committed record");
572 ScannedVisibleRecord {
573 key: committed.key,
574 record: VisibleRecord::committed(committed.version),
575 }
576 }
577 Ordering::Equal => {
578 let committed = committed.next().expect("peeked committed record");
579 let private = private.next().expect("peeked private record");
580 ScannedVisibleRecord {
581 key: committed.key,
582 record: VisibleRecord::private(&private),
583 }
584 }
585 Ordering::Greater => {
586 let private = private.next().expect("peeked private record");
587 let mut key = BudgetedVec::new(control.memory());
588 key.extend_from_slice(private.key())?;
589 ScannedVisibleRecord {
590 key,
591 record: VisibleRecord::private(&private),
592 }
593 }
594 };
595 result.push(record)?;
596 }
597 Ok(result)
598 }
599}