1mod fingerprint;
10mod last;
11mod selected;
12pub use selected::SelectedRecordRead;
13
14use std::cmp::Ordering;
15use std::sync::Arc;
16
17use uqa_core::memory::{BudgetedVec, MemoryReservation};
18
19use crate::read_control::StorageReadControl;
20
21use super::{
22 CommitSequence, PreparedRecordWrite, PrivateRecordSnapshot, RecordVersion, ScannedRecord,
23 SharedRecordValue, VersionResult,
24};
25
26#[derive(Clone, Copy)]
27pub struct BorrowedRecord<'a> {
28 pub revision: Option<CommitSequence>,
29 pub value: Option<&'a [u8]>,
30}
31
32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
34pub struct RecordMetadata {
35 pub revision: Option<CommitSequence>,
36 pub live: bool,
37}
38
39#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41pub struct VisibleRecordRevision {
42 database: super::DatabaseId,
43 committed: Option<CommitSequence>,
44 private: Option<super::PrivateRecordRevision>,
45}
46
47impl VisibleRecordRevision {
48 pub(crate) fn committed(self, database: super::DatabaseId) -> Option<CommitSequence> {
49 (self.database == database && self.private.is_none())
50 .then_some(self.committed)
51 .flatten()
52 }
53
54 pub(crate) fn committed_sequence(self) -> Option<CommitSequence> {
56 self.committed
57 }
58
59 pub(crate) fn database(self) -> super::DatabaseId {
60 self.database
61 }
62
63 pub fn is_private(self) -> bool {
64 self.private.is_some()
65 }
66}
67
68impl From<BorrowedRecord<'_>> for RecordMetadata {
69 fn from(record: BorrowedRecord<'_>) -> Self {
70 Self {
71 revision: record.revision,
72 live: record.value.is_some(),
73 }
74 }
75}
76
77pub type RecordValueVisitor<'a> = dyn FnMut(Option<BorrowedRecord<'_>>) -> VersionResult<()> + 'a;
78pub type RecordPointVisitor<'a> =
79 dyn FnMut(&[u8], Option<BorrowedRecord<'_>>) -> VersionResult<bool> + 'a;
80pub type RecordKeyIterator<'a> = dyn Iterator<Item = VersionResult<BudgetedVec<u8>>> + 'a;
81pub type RecordScanVisitor<'a> = dyn FnMut(&[u8], BorrowedRecord<'_>) -> VersionResult<bool> + 'a;
82pub type RecordKeyVisitor<'a> = dyn FnMut(&[u8], RecordMetadata) -> VersionResult<bool> + 'a;
83
84pub trait RecordMetadataRequests {
86 fn advance(&mut self) -> VersionResult<bool>;
87 fn key(&self) -> &[u8];
88 fn accept(&mut self, metadata: Option<RecordMetadata>) -> VersionResult<()>;
89}
90
91pub trait CommittedRecordSnapshot: Send + Sync {
93 fn sequence(&self) -> CommitSequence;
94
95 fn reclamation_epoch(&self) -> Option<u64> {
97 None
98 }
99
100 fn provider_snapshot(&self) -> Option<&dyn std::any::Any> {
102 None
103 }
104
105 fn commit_monitor(&self) -> Option<u64> {
107 None
108 }
109
110 fn adopt_commit_monitor(&self, _monitor: u64) -> bool {
112 false
113 }
114
115 fn metadata(
117 &self,
118 key: &[u8],
119 control: &StorageReadControl,
120 ) -> VersionResult<Option<RecordMetadata>> {
121 let mut found = None;
122 self.visit_value(key, control, &mut |record| {
123 found = record.map(Into::into);
124 Ok(())
125 })?;
126 Ok(found)
127 }
128
129 fn visit_metadata(
131 &self,
132 requests: &mut dyn RecordMetadataRequests,
133 control: &StorageReadControl,
134 ) -> VersionResult<()> {
135 loop {
136 control.check()?;
137 if !requests.advance()? {
138 return control.check().map_err(Into::into);
139 }
140 control.check()?;
141 let metadata = self.metadata(requests.key(), control)?;
142 requests.accept(metadata)?;
143 }
144 }
145
146 fn visit_keys(
148 &self,
149 prefix: &[u8],
150 after: Option<&[u8]>,
151 limit: usize,
152 control: &StorageReadControl,
153 visit: &mut RecordKeyVisitor<'_>,
154 ) -> VersionResult<()> {
155 self.visit_prefix(prefix, after, limit, control, &mut |key, record| {
156 visit(key, record.into())
157 })
158 }
159
160 fn visit_last_key(
162 &self,
163 prefix: &[u8],
164 before: Option<&[u8]>,
165 control: &StorageReadControl,
166 visit: &mut RecordKeyVisitor<'_>,
167 ) -> VersionResult<()> {
168 last::by_scan(self, prefix, before, control, visit)
169 }
170
171 fn get(
173 &self,
174 key: &[u8],
175 control: &StorageReadControl,
176 ) -> VersionResult<Option<RecordVersion<SharedRecordValue>>>;
177
178 fn scan(
180 &self,
181 prefix: &[u8],
182 after: Option<&[u8]>,
183 limit: usize,
184 control: &StorageReadControl,
185 ) -> VersionResult<BudgetedVec<ScannedRecord>>;
186
187 fn visit_value(
189 &self,
190 key: &[u8],
191 control: &StorageReadControl,
192 visit: &mut RecordValueVisitor<'_>,
193 ) -> VersionResult<()> {
194 let record = self.get(key, control)?;
195 visit(record.as_ref().map(|record| BorrowedRecord {
196 revision: Some(record.sequence()),
197 value: record.value().map(|value| &***value),
198 }))?;
199 control.cancellation().check()?;
200 Ok(())
201 }
202
203 fn visit_value_bounded(
205 &self,
206 _key: &[u8],
207 _max_bytes: usize,
208 control: &StorageReadControl,
209 _visit: &mut RecordValueVisitor<'_>,
210 ) -> VersionResult<()> {
211 control.check()?;
212 Err(crate::StorageBackendError::Other(
213 "size-bounded committed record reads are not supported".into(),
214 )
215 .into())
216 }
217
218 fn visit_values(
220 &self,
221 keys: &mut RecordKeyIterator<'_>,
222 control: &StorageReadControl,
223 visit: &mut RecordPointVisitor<'_>,
224 ) -> VersionResult<()> {
225 loop {
226 control.check()?;
227 let Some(key) = keys.next() else {
228 return Ok(());
229 };
230 let key = key?;
231 let mut more = true;
232 self.visit_value(&key, control, &mut |record| {
233 more = visit(&key, record)?;
234 Ok(())
235 })?;
236 control.check()?;
237 if !more {
238 return Ok(());
239 }
240 }
241 }
242
243 fn visit_prefix(
245 &self,
246 prefix: &[u8],
247 after: Option<&[u8]>,
248 limit: usize,
249 control: &StorageReadControl,
250 visit: &mut RecordScanVisitor<'_>,
251 ) -> VersionResult<()> {
252 control.cancellation().check()?;
253 let mut cursor: Option<BudgetedVec<u8>> = None;
254 let mut remaining = limit;
255 while remaining != 0 {
256 let mut page = self.scan(
257 prefix,
258 cursor.as_deref().or(after),
259 remaining.min(64),
260 control,
261 )?;
262 if page.is_empty() {
263 break;
264 }
265 for record in page.iter() {
266 control.cancellation().check()?;
267 if !visit(
268 &record.key,
269 BorrowedRecord {
270 revision: Some(record.version.sequence()),
271 value: record.version.value().map(|value| &***value),
272 },
273 )? {
274 control.cancellation().check()?;
275 return Ok(());
276 }
277 remaining -= 1;
278 }
279 cursor = page.pop().map(|record| record.key);
280 }
281 control.cancellation().check()?;
282 Ok(())
283 }
284}
285
286struct RetainedSnapshot<T> {
287 snapshot: T,
288 _memory: MemoryReservation,
289}
290
291pub fn retain_record_snapshot<T: CommittedRecordSnapshot + 'static>(
293 snapshot: T,
294 control: &StorageReadControl,
295) -> VersionResult<Arc<dyn CommittedRecordSnapshot>> {
296 control.cancellation().check()?;
297 let memory = control
298 .memory()
299 .reserve(std::mem::size_of::<RetainedSnapshot<T>>())?;
300 Ok(Arc::new(RetainedSnapshot {
301 snapshot,
302 _memory: memory,
303 }))
304}
305
306impl<T: CommittedRecordSnapshot> CommittedRecordSnapshot for RetainedSnapshot<T> {
307 fn sequence(&self) -> CommitSequence {
308 self.snapshot.sequence()
309 }
310 fn reclamation_epoch(&self) -> Option<u64> {
311 self.snapshot.reclamation_epoch()
312 }
313 fn provider_snapshot(&self) -> Option<&dyn std::any::Any> {
314 self.snapshot.provider_snapshot()
315 }
316 fn commit_monitor(&self) -> Option<u64> {
317 self.snapshot.commit_monitor()
318 }
319 fn adopt_commit_monitor(&self, monitor: u64) -> bool {
320 self.snapshot.adopt_commit_monitor(monitor)
321 }
322 fn visit_last_key(
323 &self,
324 prefix: &[u8],
325 before: Option<&[u8]>,
326 control: &StorageReadControl,
327 visit: &mut RecordKeyVisitor<'_>,
328 ) -> VersionResult<()> {
329 self.snapshot.visit_last_key(prefix, before, control, visit)
330 }
331 fn metadata(
332 &self,
333 key: &[u8],
334 control: &StorageReadControl,
335 ) -> VersionResult<Option<RecordMetadata>> {
336 self.snapshot.metadata(key, control)
337 }
338 fn visit_metadata(
339 &self,
340 requests: &mut dyn RecordMetadataRequests,
341 control: &StorageReadControl,
342 ) -> VersionResult<()> {
343 self.snapshot.visit_metadata(requests, control)
344 }
345 fn visit_keys(
346 &self,
347 prefix: &[u8],
348 after: Option<&[u8]>,
349 limit: usize,
350 control: &StorageReadControl,
351 visit: &mut RecordKeyVisitor<'_>,
352 ) -> VersionResult<()> {
353 self.snapshot
354 .visit_keys(prefix, after, limit, control, visit)
355 }
356 fn get(
357 &self,
358 key: &[u8],
359 control: &StorageReadControl,
360 ) -> VersionResult<Option<RecordVersion<SharedRecordValue>>> {
361 self.snapshot.get(key, control)
362 }
363 fn scan(
364 &self,
365 prefix: &[u8],
366 after: Option<&[u8]>,
367 limit: usize,
368 control: &StorageReadControl,
369 ) -> VersionResult<BudgetedVec<ScannedRecord>> {
370 self.snapshot.scan(prefix, after, limit, control)
371 }
372 fn visit_value(
373 &self,
374 key: &[u8],
375 control: &StorageReadControl,
376 visit: &mut RecordValueVisitor<'_>,
377 ) -> VersionResult<()> {
378 self.snapshot.visit_value(key, control, visit)
379 }
380 fn visit_values(
381 &self,
382 keys: &mut RecordKeyIterator<'_>,
383 control: &StorageReadControl,
384 visit: &mut RecordPointVisitor<'_>,
385 ) -> VersionResult<()> {
386 self.snapshot.visit_values(keys, control, visit)
387 }
388 fn visit_value_bounded(
389 &self,
390 key: &[u8],
391 max_bytes: usize,
392 control: &StorageReadControl,
393 visit: &mut RecordValueVisitor<'_>,
394 ) -> VersionResult<()> {
395 self.snapshot
396 .visit_value_bounded(key, max_bytes, control, visit)
397 }
398 fn visit_prefix(
399 &self,
400 prefix: &[u8],
401 after: Option<&[u8]>,
402 limit: usize,
403 control: &StorageReadControl,
404 visit: &mut RecordScanVisitor<'_>,
405 ) -> VersionResult<()> {
406 self.snapshot
407 .visit_prefix(prefix, after, limit, control, visit)
408 }
409}
410
411pub struct VisibleRecord {
413 original: Option<CommitSequence>,
414 value: Option<SharedRecordValue>,
415 private: bool,
416}
417
418impl VisibleRecord {
419 pub fn original_revision(&self) -> Option<CommitSequence> {
420 self.original
421 }
422
423 pub fn value(&self) -> Option<&[u8]> {
424 self.value.as_ref().map(|value| &***value)
425 }
426
427 pub fn is_private(&self) -> bool {
428 self.private
429 }
430
431 fn committed(version: RecordVersion<SharedRecordValue>) -> Self {
432 let (sequence, value) = version.into_parts();
433 Self {
434 original: Some(sequence),
435 value,
436 private: false,
437 }
438 }
439
440 fn private(write: &PreparedRecordWrite) -> Self {
441 Self {
442 original: write.expected(),
443 value: write.shared_value(),
444 private: true,
445 }
446 }
447}
448
449pub struct ScannedVisibleRecord {
450 pub key: BudgetedVec<u8>,
451 pub record: VisibleRecord,
452}
453
454pub struct MergedRecordSnapshot {
456 committed: Arc<dyn CommittedRecordSnapshot>,
457 private: PrivateRecordSnapshot,
458 serializable: Option<super::SerializableReadContext>,
459}
460
461impl MergedRecordSnapshot {
462 pub(in crate::mvcc) fn retained_source(
463 &self,
464 key: &[u8],
465 control: &StorageReadControl,
466 ) -> VersionResult<Option<Arc<dyn crate::key_value::KeyValueRead + Send + Sync>>> {
467 self.private.retained_source(key, control)
468 }
469
470 pub fn record_revision(
472 &self,
473 database: super::DatabaseId,
474 key: &[u8],
475 control: &StorageReadControl,
476 ) -> VersionResult<Option<VisibleRecordRevision>> {
477 control.check()?;
478 let (metadata, private) = match self.private.revision_metadata(key, control)? {
479 Some((metadata, revision)) => (Some(metadata), Some(revision)),
480 None => (self.committed.metadata(key, control)?, None),
481 };
482 let Some(metadata) = metadata.filter(|record| record.live) else {
483 control.check()?;
484 return Ok(None);
485 };
486 control.check()?;
487 Ok(Some(VisibleRecordRevision {
488 database,
489 committed: metadata.revision,
490 private,
491 }))
492 }
493
494 pub fn try_clone(&self) -> VersionResult<Self> {
496 Ok(Self {
497 committed: Arc::clone(&self.committed),
498 private: self.private.try_clone()?,
499 serializable: self.serializable.clone(),
500 })
501 }
502
503 pub fn new(
504 committed: Arc<dyn CommittedRecordSnapshot>,
505 private: PrivateRecordSnapshot,
506 ) -> Self {
507 Self {
508 committed,
509 private,
510 serializable: None,
511 }
512 }
513
514 pub(crate) fn with_serializable(
515 mut self,
516 context: Option<super::SerializableReadContext>,
517 ) -> Self {
518 self.serializable = context;
519 self
520 }
521
522 pub fn serializable(&self) -> Option<&super::SerializableReadContext> {
524 self.serializable.as_ref()
525 }
526
527 pub fn sequence(&self) -> CommitSequence {
528 self.committed.sequence()
529 }
530
531 pub fn private_revision(&self) -> Option<super::PrivateRecordRevision> {
533 self.private.revision()
534 }
535
536 pub fn committed(&self) -> &dyn CommittedRecordSnapshot {
538 self.committed.as_ref()
539 }
540
541 pub(super) fn retain_committed(&self) -> Arc<dyn CommittedRecordSnapshot> {
542 Arc::clone(&self.committed)
543 }
544
545 pub fn private_keys(
547 &self,
548 prefix: &[u8],
549 after: Option<&[u8]>,
550 limit: usize,
551 control: &StorageReadControl,
552 ) -> VersionResult<BudgetedVec<super::PrivateRecordKey>> {
553 self.private.scan_keys(prefix, after, limit, control)
554 }
555
556 pub fn private_revision_scopes(
558 &self,
559 after: Option<&[u8]>,
560 limit: usize,
561 control: &StorageReadControl,
562 ) -> VersionResult<BudgetedVec<super::PrivateRecordKey>> {
563 self.private.revision_scopes(after, limit, control)
564 }
565
566 pub fn private_scope_revision(
568 &self,
569 scope: &[u8],
570 control: &StorageReadControl,
571 ) -> VersionResult<Option<super::PrivateRecordRevision>> {
572 self.private.scope_revision(scope, control)
573 }
574
575 pub fn private_cursor(
577 &self,
578 prefix: &[u8],
579 after: Option<&[u8]>,
580 control: &StorageReadControl,
581 ) -> VersionResult<super::PrivateRecordCursor<'_>> {
582 self.private.cursor(prefix, after, control)
583 }
584
585 pub fn visit_value(
586 &self,
587 key: &[u8],
588 control: &StorageReadControl,
589 visit: &mut RecordValueVisitor<'_>,
590 ) -> VersionResult<()> {
591 if let Some(write) = self.private.get(key, control)? {
592 visit(Some(BorrowedRecord {
593 revision: write.expected(),
594 value: write.value(),
595 }))?;
596 control.cancellation().check()?;
597 return Ok(());
598 }
599 self.committed.visit_value(key, control, visit)
600 }
601
602 pub fn visit_values(
604 &self,
605 keys: &mut RecordKeyIterator<'_>,
606 control: &StorageReadControl,
607 visit: &mut RecordPointVisitor<'_>,
608 ) -> VersionResult<()> {
609 self.selected(control).visit_values(keys, control, visit)
610 }
611
612 pub fn visit_value_bounded(
614 &self,
615 key: &[u8],
616 max_bytes: usize,
617 control: &StorageReadControl,
618 visit: &mut RecordValueVisitor<'_>,
619 ) -> VersionResult<()> {
620 control.check()?;
621 if let Some(write) = self.private.get(key, control)? {
622 if let Some(value) = write.value() {
623 control.check_value_size(value.len(), max_bytes)?;
624 }
625 visit(Some(BorrowedRecord {
626 revision: write.expected(),
627 value: write.value(),
628 }))?;
629 control.check()?;
630 return Ok(());
631 }
632 self.committed
633 .visit_value_bounded(key, max_bytes, control, visit)
634 }
635
636 pub fn visit_prefix(
637 &self,
638 prefix: &[u8],
639 after: Option<&[u8]>,
640 limit: usize,
641 control: &StorageReadControl,
642 visit: &mut RecordScanVisitor<'_>,
643 ) -> VersionResult<()> {
644 self.private.visit_merged::<super::projection::Values>(
645 &*self.committed,
646 prefix,
647 after,
648 limit,
649 control,
650 visit,
651 )
652 }
653
654 pub fn metadata(
655 &self,
656 key: &[u8],
657 control: &StorageReadControl,
658 ) -> VersionResult<Option<RecordMetadata>> {
659 if let Some(metadata) = self.private.metadata(key, control)? {
660 return Ok(Some(metadata));
661 }
662 self.committed.metadata(key, control)
663 }
664
665 pub fn visit_keys(
666 &self,
667 prefix: &[u8],
668 after: Option<&[u8]>,
669 limit: usize,
670 control: &StorageReadControl,
671 visit: &mut RecordKeyVisitor<'_>,
672 ) -> VersionResult<()> {
673 self.private.visit_merged::<super::projection::Keys>(
674 &*self.committed,
675 prefix,
676 after,
677 limit,
678 control,
679 visit,
680 )
681 }
682
683 pub fn has_private_change(
685 &self,
686 key: &[u8],
687 control: &StorageReadControl,
688 ) -> VersionResult<bool> {
689 Ok(self.private.get(key, control)?.is_some())
690 }
691
692 pub fn get(
693 &self,
694 key: &[u8],
695 control: &StorageReadControl,
696 ) -> VersionResult<Option<VisibleRecord>> {
697 if let Some(write) = self.private.get(key, control)? {
698 return Ok(Some(VisibleRecord::private(&write)));
699 }
700 Ok(self
701 .committed
702 .get(key, control)?
703 .map(VisibleRecord::committed))
704 }
705
706 pub fn scan(
708 &self,
709 prefix: &[u8],
710 after: Option<&[u8]>,
711 limit: usize,
712 control: &StorageReadControl,
713 ) -> VersionResult<BudgetedVec<ScannedVisibleRecord>> {
714 control.cancellation().check()?;
715 let mut result = BudgetedVec::new(control.memory());
716 if limit == 0 {
717 return Ok(result);
718 }
719 let (committed, _committed_memory) = self
720 .committed
721 .scan(prefix, after, limit, control)?
722 .into_parts();
723 let (private, _private_memory) = self
724 .private
725 .scan(prefix, after, limit, control)?
726 .into_parts();
727 let mut committed = committed.into_iter().peekable();
728 let mut private = private.into_iter().peekable();
729 while result.len() < limit {
730 control.cancellation().check()?;
731 let order = match (committed.peek(), private.peek()) {
732 (Some(committed), Some(private)) => committed.key.as_ref().cmp(private.key()),
733 (Some(_), None) => Ordering::Less,
734 (None, Some(_)) => Ordering::Greater,
735 (None, None) => break,
736 };
737 let record = match order {
738 Ordering::Less => {
739 let committed = committed.next().expect("peeked committed record");
740 ScannedVisibleRecord {
741 key: committed.key,
742 record: VisibleRecord::committed(committed.version),
743 }
744 }
745 Ordering::Equal => {
746 let committed = committed.next().expect("peeked committed record");
747 let private = private.next().expect("peeked private record");
748 ScannedVisibleRecord {
749 key: committed.key,
750 record: VisibleRecord::private(&private),
751 }
752 }
753 Ordering::Greater => {
754 let private = private.next().expect("peeked private record");
755 let mut key = BudgetedVec::new(control.memory());
756 key.extend_from_slice(private.key())?;
757 ScannedVisibleRecord {
758 key,
759 record: VisibleRecord::private(&private),
760 }
761 }
762 };
763 result.push(record)?;
764 }
765 Ok(result)
766 }
767}