use std::sync::Arc;
#[derive(Clone)]
pub struct SnapshotContext {
pub snapshot: super::snapshot::Snapshot,
pub manager: Arc<super::snapshot::SnapshotManager>,
pub own_xids: std::collections::HashSet<super::snapshot::Xid>,
pub requires_index_fallback: bool,
pub serializable_reader: Option<super::snapshot::Xid>,
}
pub fn record_serializable_read(
ctx: &SnapshotContext,
entity: &crate::storage::entity::UnifiedEntity,
) {
let Some(reader) = ctx.serializable_reader else {
return;
};
if !matches!(
&entity.kind,
crate::storage::entity::EntityKind::TableRow { .. }
) {
return;
}
ctx.manager
.record_serializable_read(reader, entity.kind.collection(), entity.logical_id());
}
#[inline]
pub fn visibility_check(ctx: &SnapshotContext, xmin: u64, xmax: u64) -> bool {
if xmin != 0 && ctx.manager.is_aborted(xmin) {
return false;
}
let effective_xmax = if xmax != 0 && ctx.manager.is_aborted(xmax) {
0
} else {
xmax
};
let own_xmin = xmin != 0 && ctx.own_xids.contains(&xmin);
let own_xmax = effective_xmax != 0 && ctx.own_xids.contains(&effective_xmax);
if own_xmax {
return false;
}
if own_xmin {
return true;
}
ctx.snapshot.sees(xmin, effective_xmax)
}
pub trait TableRowVersionStore {
fn table_row_versions_by_logical_id(
&self,
collection: &str,
logical_id: crate::storage::entity::EntityId,
) -> Vec<crate::storage::entity::UnifiedEntity>;
fn get_table_row_by_logical_id(
&self,
collection: &str,
logical_id: crate::storage::entity::EntityId,
) -> Option<crate::storage::entity::UnifiedEntity>;
}
pub fn resolve_logical_id(
store: &impl TableRowVersionStore,
collection: &str,
logical_id: crate::storage::entity::EntityId,
select_versions: bool,
mut visible: impl FnMut(&crate::storage::entity::UnifiedEntity) -> bool,
) -> Option<crate::storage::entity::UnifiedEntity> {
if select_versions {
return store
.table_row_versions_by_logical_id(collection, logical_id)
.into_iter()
.filter(|entity| visible(entity))
.max_by_key(|entity| entity.xmin);
}
store
.get_table_row_by_logical_id(collection, logical_id)
.filter(|entity| visible(entity))
}