reddb_engine/transaction/
read.rs1use std::sync::Arc;
4
5#[derive(Clone)]
20pub struct SnapshotContext {
21 pub snapshot: super::snapshot::Snapshot,
22 pub manager: Arc<super::snapshot::SnapshotManager>,
23 pub own_xids: std::collections::HashSet<super::snapshot::Xid>,
24 pub requires_index_fallback: bool,
25 pub serializable_reader: Option<super::snapshot::Xid>,
26}
27
28pub fn record_serializable_read(
31 ctx: &SnapshotContext,
32 entity: &crate::storage::entity::UnifiedEntity,
33) {
34 let Some(reader) = ctx.serializable_reader else {
35 return;
36 };
37 if !matches!(
38 &entity.kind,
39 crate::storage::entity::EntityKind::TableRow { .. }
40 ) {
41 return;
42 }
43 ctx.manager
44 .record_serializable_read(reader, entity.kind.collection(), entity.logical_id());
45}
46
47#[inline]
50pub fn visibility_check(ctx: &SnapshotContext, xmin: u64, xmax: u64) -> bool {
51 if xmin != 0 && ctx.manager.is_aborted(xmin) {
55 return false;
56 }
57 let effective_xmax = if xmax != 0 && ctx.manager.is_aborted(xmax) {
59 0
60 } else {
61 xmax
62 };
63 let own_xmin = xmin != 0 && ctx.own_xids.contains(&xmin);
67 let own_xmax = effective_xmax != 0 && ctx.own_xids.contains(&effective_xmax);
68 if own_xmax {
69 return false;
71 }
72 if own_xmin {
73 return true;
74 }
75 ctx.snapshot.sees(xmin, effective_xmax)
76}
77
78pub trait TableRowVersionStore {
81 fn table_row_versions_by_logical_id(
82 &self,
83 collection: &str,
84 logical_id: crate::storage::entity::EntityId,
85 ) -> Vec<crate::storage::entity::UnifiedEntity>;
86
87 fn get_table_row_by_logical_id(
88 &self,
89 collection: &str,
90 logical_id: crate::storage::entity::EntityId,
91 ) -> Option<crate::storage::entity::UnifiedEntity>;
92}
93
94pub fn resolve_logical_id(
98 store: &impl TableRowVersionStore,
99 collection: &str,
100 logical_id: crate::storage::entity::EntityId,
101 select_versions: bool,
102 mut visible: impl FnMut(&crate::storage::entity::UnifiedEntity) -> bool,
103) -> Option<crate::storage::entity::UnifiedEntity> {
104 if select_versions {
105 return store
106 .table_row_versions_by_logical_id(collection, logical_id)
107 .into_iter()
108 .filter(|entity| visible(entity))
109 .max_by_key(|entity| entity.xmin);
110 }
111 store
112 .get_table_row_by_logical_id(collection, logical_id)
113 .filter(|entity| visible(entity))
114}
115
116pub trait FallibleTableRowVersionStore {
119 type Error;
120
121 fn try_get_table_row_by_logical_id(
122 &self,
123 collection: &str,
124 logical_id: crate::storage::entity::EntityId,
125 ) -> Result<Option<crate::storage::entity::UnifiedEntity>, Self::Error>;
126
127 fn try_for_each_table_row_version(
128 &self,
129 collection: &str,
130 logical_id: crate::storage::entity::EntityId,
131 visit: impl FnMut(&crate::storage::entity::UnifiedEntity) -> bool,
132 ) -> Result<(), Self::Error>;
133}
134
135pub fn try_resolve_logical_id<S: FallibleTableRowVersionStore>(
137 store: &S,
138 collection: &str,
139 logical_id: crate::storage::entity::EntityId,
140 select_versions: bool,
141 mut visible: impl FnMut(&crate::storage::entity::UnifiedEntity) -> bool,
142) -> Result<Option<crate::storage::entity::UnifiedEntity>, S::Error> {
143 if !select_versions {
144 return store
145 .try_get_table_row_by_logical_id(collection, logical_id)
146 .map(|entity| entity.filter(|entity| visible(entity)));
147 }
148 let mut selected: Option<crate::storage::entity::UnifiedEntity> = None;
149 store.try_for_each_table_row_version(collection, logical_id, |entity| {
150 if visible(entity) && selected.as_ref().is_none_or(|old| entity.xmin >= old.xmin) {
151 selected = Some(entity.clone());
152 }
153 true
154 })?;
155 Ok(selected)
156}