mod memtables;
use std::sync::Arc;
use tessarikv_format::{Table, TableMeta};
use tessarikv_types::compare_internal;
use super::table_blocks::TableBlocks;
use super::tables;
use crate::memtable::Memtable;
pub(crate) struct View {
tables: Vec<EpochTables>,
files: Vec<TableFile>,
names: Names,
next_keyspace: u32,
}
pub(crate) type Names = Arc<[(u32, String)]>;
#[derive(Clone)]
pub(crate) struct TableFile {
pub(crate) meta: Arc<TableMeta>,
pub(crate) table: Table,
pub(crate) blocks: Arc<TableBlocks>,
}
struct EpochTables {
epoch: u8,
keyspaces: Vec<(u32, Arc<Memtable>)>,
}
impl View {
#[cfg(test)]
pub(crate) fn new(epoch: u8, table: Memtable) -> Self {
Self {
tables: vec![EpochTables {
epoch,
keyspaces: vec![(0, Arc::new(table))],
}],
files: Vec::new(),
names: Arc::new([]),
next_keyspace: 1,
}
}
pub(crate) fn recovered(
mut tables: Vec<(u32, Memtable)>,
names: Names,
mut files: Vec<TableFile>,
) -> Self {
tables.sort_by_key(|(keyspace, _)| *keyspace);
files.sort_by_key(|file| (file.meta.keyspace, file.meta.level));
let next_keyspace = names
.iter()
.map(|(id, _)| id.saturating_add(1))
.max()
.unwrap_or(1);
Self {
tables: vec![EpochTables {
epoch: 0,
keyspaces: tables
.into_iter()
.map(|(keyspace, table)| (keyspace, Arc::new(table)))
.collect(),
}],
files,
names,
next_keyspace,
}
}
pub(crate) fn names(&self) -> &Names {
&self.names
}
pub(crate) fn keyspace_named(&self, name: &str) -> Option<u32> {
if name == "default" {
return Some(0);
}
self.names
.iter()
.find(|(_, held)| held == name)
.map(|(id, _)| *id)
}
pub(crate) fn after_compaction(
&self,
keyspace: u32,
removed: &[u64],
added: Vec<TableFile>,
) -> Self {
let mut files: Vec<TableFile> = self
.files
.iter()
.filter(|file| file.meta.keyspace != keyspace || !removed.contains(&file.meta.id))
.cloned()
.collect();
files.extend(added);
files.sort_by(|left, right| {
(left.meta.keyspace, left.meta.level)
.cmp(&(right.meta.keyspace, right.meta.level))
.then_with(|| match left.meta.level {
0 => right.meta.max_sequence.cmp(&left.meta.max_sequence),
_ => compare_internal(&left.meta.smallest, &right.meta.smallest),
})
});
Self {
tables: self.shared_tables(),
files,
names: Arc::clone(&self.names),
next_keyspace: self.next_keyspace,
}
}
pub(crate) fn all_files(&self) -> &[TableFile] {
&self.files
}
pub(crate) fn files(&self, keyspace: u32) -> impl Iterator<Item = &TableFile> {
self.keyspace_files(keyspace).iter()
}
pub(crate) fn candidates<'a>(
&'a self,
keyspace: u32,
key: &'a [u8],
) -> impl Iterator<Item = &'a TableFile> {
let files = self.keyspace_files(keyspace);
let (level_zero, sorted) =
files.split_at(files.partition_point(|file| file.meta.level == 0));
let deeper = sorted
.chunk_by(|left, right| left.meta.level == right.meta.level)
.filter_map(move |level| {
let at = level.partition_point(|file| tables::user_key(&file.meta.largest) < key);
level.get(at).filter(|file| holds(file, key))
});
level_zero
.iter()
.filter(move |file| holds(file, key))
.chain(deeper)
}
pub(crate) fn level0_files(&self, keyspace: u32) -> usize {
self.keyspace_files(keyspace)
.partition_point(|file| file.meta.level == 0)
}
fn keyspace_files(&self, keyspace: u32) -> &[TableFile] {
let start = self
.files
.partition_point(|file| file.meta.keyspace < keyspace);
let end = self
.files
.partition_point(|file| file.meta.keyspace <= keyspace);
self.files.get(start..end).unwrap_or_default()
}
}
fn holds(file: &TableFile, key: &[u8]) -> bool {
tables::user_key(&file.meta.smallest) <= key && key <= tables::user_key(&file.meta.largest)
}