use super::{
epoch_is_after, lock_strengths_conflict, table_hash, CommittedRowChange,
CommittedRowChangeKind, CrossAttachment, DocId, LockStrength, RowChangeBaseline, RowLockKey,
RowLockManager, SQLError,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum PhysicalRowChangeTarget {
Unchanged,
Present { table_hash: u64, doc_id: DocId },
Deleted,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) enum LocalPhysicalRowChangeTarget {
Unchanged,
Present(RowLockKey),
Deleted,
}
impl RowLockManager {
pub(crate) fn physical_row_successor_after(
&self,
table: &str,
doc_id: DocId,
baseline: RowChangeBaseline,
) -> Result<PhysicalRowChangeTarget, SQLError> {
let key = RowLockKey {
table: self.table_key(table),
doc_id,
};
if let Some(CrossAttachment::Active(coordinator)) = self.cross.as_ref() {
return coordinator
.physical_change_target_after(
table_hash(table.as_bytes()),
doc_id,
baseline.cross_sequence,
LockStrength::ForUpdate,
)
.map_err(SQLError::Internal);
}
Ok(
match resolve_local_physical_change_target(
&self.state.lock().changes,
key,
baseline.epoch,
LockStrength::ForUpdate,
) {
LocalPhysicalRowChangeTarget::Unchanged => PhysicalRowChangeTarget::Unchanged,
LocalPhysicalRowChangeTarget::Deleted => PhysicalRowChangeTarget::Deleted,
LocalPhysicalRowChangeTarget::Present(target) => PhysicalRowChangeTarget::Present {
table_hash: table_hash(&self.relation_bytes(target.table)),
doc_id: target.doc_id,
},
},
)
}
}
pub(super) fn resolve_local_physical_change_target(
changes: &[CommittedRowChange],
key: RowLockKey,
baseline: u64,
wanted: LockStrength,
) -> LocalPhysicalRowChangeTarget {
let mut current = key;
let mut requires_recheck = false;
for change in changes {
if !epoch_is_after(change.epoch, baseline) || change.key != current {
continue;
}
match change.kind {
CommittedRowChangeKind::Update => {
requires_recheck |= lock_strengths_conflict(change.strength, wanted);
}
CommittedRowChangeKind::Delete => {
if lock_strengths_conflict(change.strength, wanted) {
return LocalPhysicalRowChangeTarget::Deleted;
}
}
CommittedRowChangeKind::Rewrite(successor) => {
if lock_strengths_conflict(change.strength, wanted) {
requires_recheck = true;
current = successor;
}
}
}
}
if requires_recheck {
LocalPhysicalRowChangeTarget::Present(current)
} else {
LocalPhysicalRowChangeTarget::Unchanged
}
}