use std::ops::Bound;
use std::sync::Arc;
use crate::mvcc::overlay::run::{RunCursor, RunEntry, SpilledRun};
use crate::mvcc::VersionResult;
use crate::read_control::StorageReadControl;
use super::metadata::PreparedWriteMetadata;
use super::PreparedRecordWrite;
#[cfg(test)]
mod tests;
enum Source<'a> {
Resident(std::slice::Iter<'a, PreparedRecordWrite>),
Spilled(RunCursor),
}
pub struct PreparedWriteCursor<'a> {
source: Source<'a>,
}
impl<'a> PreparedWriteCursor<'a> {
pub(super) fn resident(writes: &'a [PreparedRecordWrite]) -> Self {
Self {
source: Source::Resident(writes.iter()),
}
}
pub(super) fn spilled(run: &Arc<SpilledRun>) -> Self {
Self {
source: Source::Spilled(run.cursor(Bound::Unbounded)),
}
}
pub(super) fn spilled_from(run: &Arc<SpilledRun>, start: &[u8]) -> Self {
Self {
source: Source::Spilled(run.cursor(Bound::Included(start))),
}
}
pub fn next(
&mut self,
control: &StorageReadControl,
) -> VersionResult<Option<PreparedRecordWrite>> {
self.next_matching(None, control)
}
pub fn next_where(
&mut self,
control: &StorageReadControl,
mut select: impl FnMut(&PreparedWriteMetadata) -> VersionResult<bool>,
) -> VersionResult<Option<PreparedRecordWrite>> {
match &mut self.source {
Source::Resident(writes) => {
for write in writes.by_ref() {
control.cancellation().check()?;
let metadata = PreparedWriteMetadata::new(
write.shared_key(),
write.expected(),
write.kind(),
write.value().map(|value| value.len() as u64),
);
if select(&metadata)? {
return Ok(Some(write.clone()));
}
}
control.cancellation().check()?;
Ok(None)
}
Source::Spilled(cursor) => {
while let Some(entry) = cursor.next(control)? {
let metadata = PreparedWriteMetadata::new(
entry.key.clone(),
entry.expected,
entry.kind,
entry.value.map(|location| location.len),
);
if select(&metadata)? {
return spilled_write(cursor, entry, control).map(Some);
}
}
Ok(None)
}
}
}
pub(in crate::mvcc) fn next_with_kind(
&mut self,
kind: super::RecordWriteKind,
control: &StorageReadControl,
) -> VersionResult<Option<PreparedRecordWrite>> {
self.next_matching(Some(kind), control)
}
fn next_matching(
&mut self,
kind: Option<super::RecordWriteKind>,
control: &StorageReadControl,
) -> VersionResult<Option<PreparedRecordWrite>> {
match &mut self.source {
Source::Resident(writes) => {
for write in writes.by_ref() {
control.cancellation().check()?;
if kind.is_none_or(|kind| write.kind() == kind) {
return Ok(Some(write.clone()));
}
}
control.cancellation().check()?;
Ok(None)
}
Source::Spilled(cursor) => {
while let Some(entry) = cursor.next(control)? {
if kind.is_none_or(|kind| entry.kind == kind) {
return spilled_write(cursor, entry, control).map(Some);
}
}
Ok(None)
}
}
}
pub fn next_metadata(
&mut self,
control: &StorageReadControl,
) -> VersionResult<Option<PreparedWriteMetadata>> {
match &mut self.source {
Source::Resident(writes) => {
control.cancellation().check()?;
Ok(writes.next().map(|write| {
PreparedWriteMetadata::new(
write.shared_key(),
write.expected(),
write.kind(),
write.value().map(|value| value.len() as u64),
)
}))
}
Source::Spilled(cursor) => Ok(cursor.next(control)?.map(|entry| {
let value_len = entry.value.map(|location| location.len);
PreparedWriteMetadata::new(entry.key, entry.expected, entry.kind, value_len)
})),
}
}
}
fn spilled_write(
cursor: &mut RunCursor,
entry: RunEntry,
control: &StorageReadControl,
) -> VersionResult<PreparedRecordWrite> {
let value = entry
.value
.map(|location| cursor.load_value(location, control))
.transpose()?;
Ok(PreparedRecordWrite::from_shared(entry.key, entry.expected, value).with_kind(entry.kind))
}