mod change;
pub(super) use change::TieredChange;
use std::iter::Peekable;
use std::ops::Bound;
use uqa_core::memory::BudgetedSharedMapIter;
use crate::mvcc::VersionResult;
use crate::read_control::StorageReadControl;
use super::run::{RunCursor, RunEntry};
use super::run_set::RunSet;
use super::Change;
use crate::mvcc::key::RecordKey;
pub(super) fn lookup<'a>(
records: &'a super::Records,
runs: &RunSet,
key: &[u8],
control: &StorageReadControl,
) -> VersionResult<Option<TieredChange<'a>>> {
if let Some(change) = records.get(key) {
return Ok(Some(TieredChange::Resident(change)));
}
runs.get(key, control)
}
struct RunHead {
cursor: RunCursor,
head: Option<RunEntry>,
}
pub(super) struct TieredCursor<'a> {
memtable: Option<Peekable<BudgetedSharedMapIter<'a, RecordKey, Change>>>,
runs: Vec<RunHead>,
key: Vec<u8>,
}
impl<'a> TieredCursor<'a> {
pub(super) fn new(
records: Option<&'a super::Records>,
runs: &RunSet,
start: Bound<&[u8]>,
control: &StorageReadControl,
) -> VersionResult<Self> {
let memtable = records.map(|records| records.range_from::<[u8]>(start).peekable());
let mut heads = Vec::new();
for run in runs.newest_first() {
let mut cursor = run.cursor(start);
let head = cursor.next(control)?;
heads.push(RunHead { cursor, head });
}
Ok(Self {
memtable,
runs: heads,
key: Vec::new(),
})
}
pub(super) fn next(
&mut self,
control: &StorageReadControl,
) -> VersionResult<Option<TieredChange<'a>>> {
control.cancellation().check()?;
let mut winner: Option<usize> = None;
{
let mut least: Option<&[u8]> = self
.memtable
.as_mut()
.and_then(Peekable::peek)
.map(|(key, _)| key.bytes());
if least.is_some() {
winner = Some(0);
}
for (index, run) in self.runs.iter().enumerate() {
if let Some(head) = &run.head {
if least.is_none_or(|least| head.key.bytes() < least) {
least = Some(head.key.bytes());
winner = Some(index + 1);
}
}
}
let Some(least) = least else {
return Ok(None);
};
self.key.clear();
self.key.extend_from_slice(least);
}
let change = match winner.expect("a least key has a source") {
0 => {
let (_, change) = self
.memtable
.as_mut()
.and_then(Iterator::next)
.expect("peeked memory change");
TieredChange::Resident(change)
}
index => {
let run = &mut self.runs[index - 1];
let entry = run.head.take().expect("least run head");
run.head = run.cursor.next(control)?;
TieredChange::Spilled {
entry,
run: std::sync::Arc::clone(run.cursor.run()),
}
}
};
for run in &mut self.runs {
if run
.head
.as_ref()
.is_some_and(|head| head.key.bytes() == self.key.as_slice())
{
run.head = run.cursor.next(control)?;
}
}
Ok(Some(change))
}
}