use crate::epoch::Epoch;
use crate::index::{AnnIndex, BitmapIndex, ColumnLearnedRange, FmIndex, MinHashIndex, SparseIndex};
use std::collections::HashMap;
use std::sync::Arc;
#[derive(Clone)]
pub struct IndexFamilyGeneration<T> {
indexes: Arc<HashMap<u16, T>>,
applied_through: Epoch,
}
impl<T> Default for IndexFamilyGeneration<T> {
fn default() -> Self {
Self::empty(Epoch(0))
}
}
impl<T> IndexFamilyGeneration<T> {
pub fn empty(applied_through: Epoch) -> Self {
Self {
indexes: Arc::new(HashMap::new()),
applied_through,
}
}
pub(crate) fn capture(indexes: &HashMap<u16, T>, applied_through: Epoch) -> Self
where
T: Clone,
{
Self {
indexes: Arc::new(indexes.clone()),
applied_through,
}
}
pub(crate) fn share(indexes: Arc<HashMap<u16, T>>, applied_through: Epoch) -> Self {
Self {
indexes,
applied_through,
}
}
pub fn get(&self, column_id: u16) -> Option<&T> {
self.indexes.get(&column_id)
}
pub fn len(&self) -> usize {
self.indexes.len()
}
pub fn is_empty(&self) -> bool {
self.indexes.is_empty()
}
pub fn applied_through(&self) -> Epoch {
self.applied_through
}
pub fn iter(&self) -> impl Iterator<Item = (u16, &T)> + '_ {
self.indexes
.iter()
.map(|(column_id, index)| (*column_id, index))
}
pub fn column_ids(&self) -> impl Iterator<Item = u16> + '_ {
self.indexes.keys().copied()
}
}
#[derive(Clone, Default)]
pub struct IndexGeneration {
bitmap: IndexFamilyGeneration<BitmapIndex>,
range: IndexFamilyGeneration<ColumnLearnedRange>,
fm: IndexFamilyGeneration<FmIndex>,
ann: IndexFamilyGeneration<AnnIndex>,
sparse: IndexFamilyGeneration<SparseIndex>,
minhash: IndexFamilyGeneration<MinHashIndex>,
applied_through: Epoch,
}
impl IndexGeneration {
pub(crate) fn capture(
bitmap: &HashMap<u16, BitmapIndex>,
range: &Arc<HashMap<u16, ColumnLearnedRange>>,
fm: &HashMap<u16, FmIndex>,
ann: &HashMap<u16, AnnIndex>,
sparse: &HashMap<u16, SparseIndex>,
minhash: &HashMap<u16, MinHashIndex>,
applied_through: Epoch,
) -> Self {
Self {
bitmap: IndexFamilyGeneration::capture(bitmap, applied_through),
range: IndexFamilyGeneration::share(Arc::clone(range), applied_through),
fm: IndexFamilyGeneration::capture(fm, applied_through),
ann: IndexFamilyGeneration::capture(ann, applied_through),
sparse: IndexFamilyGeneration::capture(sparse, applied_through),
minhash: IndexFamilyGeneration::capture(minhash, applied_through),
applied_through,
}
}
pub fn bitmap(&self) -> &IndexFamilyGeneration<BitmapIndex> {
&self.bitmap
}
pub fn range(&self) -> &IndexFamilyGeneration<ColumnLearnedRange> {
&self.range
}
pub fn fm(&self) -> &IndexFamilyGeneration<FmIndex> {
&self.fm
}
pub fn ann(&self) -> &IndexFamilyGeneration<AnnIndex> {
&self.ann
}
pub fn sparse(&self) -> &IndexFamilyGeneration<SparseIndex> {
&self.sparse
}
pub fn minhash(&self) -> &IndexFamilyGeneration<MinHashIndex> {
&self.minhash
}
pub fn applied_through(&self) -> Epoch {
self.applied_through
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::RowId;
#[test]
fn captured_generation_shares_frozen_layers_with_writer() {
let mut writer = BitmapIndex::new();
writer.insert(b"red".to_vec(), RowId(1));
writer.seal();
let mut map = HashMap::new();
map.insert(7u16, writer.clone());
let generation = IndexFamilyGeneration::capture(&map, Epoch(5));
writer.insert(b"blue".to_vec(), RowId(2));
let pinned = generation.get(7).expect("column 7 indexed");
assert!(pinned.get(b"red").contains(1));
assert!(pinned.get(b"blue").is_empty());
assert!(writer.get(b"blue").contains(2));
assert_eq!(generation.applied_through(), Epoch(5));
assert_eq!(generation.len(), 1);
assert_eq!(generation.column_ids().collect::<Vec<_>>(), vec![7]);
}
#[test]
fn index_generation_capture_covers_all_families() {
let mut bitmap = HashMap::new();
bitmap.insert(1u16, BitmapIndex::new());
let mut ann = HashMap::new();
ann.insert(2u16, AnnIndex::new(8));
let generation = IndexGeneration::capture(
&bitmap,
&Arc::new(HashMap::new()),
&HashMap::new(),
&ann,
&HashMap::new(),
&HashMap::new(),
Epoch(11),
);
assert_eq!(generation.applied_through(), Epoch(11));
assert_eq!(generation.bitmap().applied_through(), Epoch(11));
assert!(generation.bitmap().get(1).is_some());
assert!(generation.ann().get(2).is_some());
assert!(generation.fm().is_empty());
assert!(generation.range().is_empty());
assert!(generation.sparse().is_empty());
assert!(generation.minhash().is_empty());
}
}