use std::sync::Arc;
use super::{
commit::RecordWriteKind, CommittedRecordSnapshot, PreparedRecordCommit, VersionResult,
VersionedPersistence,
};
use crate::read_control::StorageReadControl;
#[derive(Clone, Copy, PartialEq, Eq)]
pub(super) enum ResolutionMode {
Publication,
Command,
}
impl ResolutionMode {
pub(super) fn kind(self, private: RecordWriteKind) -> RecordWriteKind {
match self {
Self::Publication => RecordWriteKind::Canonical,
Self::Command => private,
}
}
}
pub(super) fn has_effects(prepared: &PreparedRecordCommit) -> bool {
prepared.graph.is_some()
|| prepared.notification.is_some()
|| prepared.vector.is_some()
|| prepared.populations.is_some()
|| prepared.typed()
}
pub(super) fn resolve(
prepared: &PreparedRecordCommit,
base: &dyn CommittedRecordSnapshot,
current: &Arc<dyn CommittedRecordSnapshot>,
persistence: &dyn VersionedPersistence,
mode: ResolutionMode,
control: &StorageReadControl,
) -> VersionResult<Option<PreparedRecordCommit>> {
prepared.validate_requirements(control.cancellation(), |key| {
Ok(current
.metadata(key, control)?
.and_then(|record| record.revision))
})?;
let mut resolved = if prepared.vector.is_some() {
Some(super::vector::resolve(
prepared,
base,
current.as_ref(),
persistence,
mode,
control,
)?)
} else {
None
};
resolved =
super::populations::resolve(prepared, resolved, current, persistence, mode, control)?;
if prepared.has_kind(RecordWriteKind::Occurrence)
|| prepared.has_kind(RecordWriteKind::OccurrenceCache)
{
resolved = Some(super::occurrence::resolve(
resolved.as_ref().unwrap_or(prepared),
base,
current.as_ref(),
persistence.occurrence_record_layout(),
mode,
control,
)?);
}
if prepared.graph.is_some() {
let layout =
persistence
.graph_record_layout()
.ok_or(super::VersionError::InvalidEncoding(
"provider has no graph record layout",
))?;
resolved = Some(super::graph::resolve(
resolved.as_ref().unwrap_or(prepared),
current.clone(),
layout,
persistence.database_id(),
mode,
control,
)?);
}
if prepared.has_kind(RecordWriteKind::IdempotentDelete) {
resolved = Some(super::deletions::resolve(
resolved.as_ref().unwrap_or(prepared),
current.as_ref(),
mode,
control,
)?);
}
if prepared.has_kind(RecordWriteKind::StatisticsMaintenance) {
resolved = Some(super::maintenance::resolve(
resolved.as_ref().unwrap_or(prepared),
base,
current.as_ref(),
persistence.maintenance_record_layout(),
mode,
control,
)?);
}
if prepared.has_kind(RecordWriteKind::Marker) {
resolved = Some(super::markers::resolve(
resolved.as_ref().unwrap_or(prepared),
current.as_ref(),
mode,
control,
)?);
}
if mode == ResolutionMode::Publication {
if let Some(effect) = &prepared.notification {
resolved = Some(super::notifications::resolve(
resolved.as_ref().unwrap_or(prepared),
effect,
current.as_ref(),
persistence.notification_record_layout(),
control,
)?);
}
}
Ok(resolved)
}