use crate::relation::{relation_dir, RelationRegistry};
use gnitz_zset::algebra::append_spans;
use gnitz_zset::repr::{Batch, KeyProducer, ReadCursor, SpillSort};
use gnitz_zset::schema::KeySpec;
pub struct KeySpans {
chunk_rows: usize,
source: Source,
chunk: Batch,
}
enum Source {
Index(Box<ReadCursor>),
Sorted(KeyProducer),
}
impl RelationRegistry {
pub fn key_spans(&self, id: u64, cols: &[u32]) -> Result<KeySpans, String> {
let relation = self.relation_or_err(id)?;
let spec = KeySpec::new(cols, &relation.schema())?;
let chunk_rows = self.config.scan_chunk_rows;
let source = match relation.index_on(cols) {
Some(index) => Source::Index(Box::new(index.cursor())),
None => {
let dir = relation_dir(&self.base_dir, id);
let mut sort = SpillSort::new(&dir, spec.key_size(), self.config.key_spans_spill_bytes);
let mut rows = relation.cursor();
let mut spans = Vec::new();
while let Some(chunk) = rows.drain_chunk(chunk_rows) {
spans.clear();
append_spans(&mut spans, sort.slot(), &chunk.as_mem_batch(), &spec, |_| true);
sort.push(&spans)?;
}
Source::Sorted(sort.finish()?)
}
};
let mut spans = KeySpans {
chunk_rows,
source,
chunk: Batch::empty_with_schema(&spec.span_schema()),
};
spans.advance();
Ok(spans)
}
}
impl KeySpans {
pub fn chunk(&self) -> &Batch {
&self.chunk
}
pub fn advance(&mut self) {
match &mut self.source {
Source::Index(cursor) => match cursor.drain_chunk(self.chunk_rows) {
Some(entries) => self.chunk = entries.keyed_by_prefix(self.chunk.schema()),
None => self.chunk.clear(),
},
Source::Sorted(spans) => spans.fill(&mut self.chunk, self.chunk_rows),
}
}
}
#[cfg(test)]
#[path = "tests/key_spans.rs"]
mod tests;