use crate::rowid::RowId;
use roaring::RoaringBitmap;
use std::collections::HashMap;
use std::sync::Arc;
type BitmapLayer = HashMap<Vec<u8>, RoaringBitmap>;
#[derive(Clone)]
pub struct BitmapIndex {
frozen: Arc<Vec<Arc<BitmapLayer>>>,
active: BitmapLayer,
}
impl Default for BitmapIndex {
fn default() -> Self {
Self::new()
}
}
impl BitmapIndex {
pub fn new() -> Self {
Self {
frozen: Arc::new(Vec::new()),
active: HashMap::new(),
}
}
pub fn insert(&mut self, value: Vec<u8>, row_id: RowId) {
let id32 = u32::try_from(row_id.0)
.expect("bitmap index supports row_id < 2^32; shard-by-high-bits is a Phase-3 upgrade");
self.active.entry(value).or_default().insert(id32);
}
pub fn get(&self, value: &[u8]) -> RoaringBitmap {
let mut rows = self.active.get(value).cloned().unwrap_or_default();
for layer in self.frozen.iter() {
if let Some(layer_rows) = layer.get(value) {
rows |= layer_rows;
}
}
rows
}
pub fn intersect(sets: &[RoaringBitmap]) -> RoaringBitmap {
match sets {
[] => RoaringBitmap::new(),
[first, rest @ ..] => {
let mut acc = first.clone();
for s in rest {
acc &= s;
}
acc
}
}
}
pub fn value_count(&self) -> usize {
self.keys().len()
}
pub fn keys(&self) -> Vec<Vec<u8>> {
let mut keys = std::collections::HashSet::new();
keys.extend(self.active.keys().cloned());
for layer in self.frozen.iter() {
keys.extend(layer.keys().cloned());
}
keys.into_iter().collect()
}
pub fn entries(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
self.keys()
.into_iter()
.map(|k| {
let v = self.get(&k);
let mut bytes = Vec::new();
v.serialize_into(&mut bytes)
.expect("roaring serialize is infallible for Vec");
(k, bytes)
})
.collect()
}
pub fn from_entries(
entries: Vec<(Vec<u8>, Vec<u8>)>,
) -> std::result::Result<Self, &'static str> {
let mut active = HashMap::new();
for (k, bytes) in entries {
let bm = RoaringBitmap::deserialize_from(&bytes[..]).map_err(|_| "bad bitmap bytes")?;
active.insert(k, bm);
}
Ok(Self {
frozen: Arc::new(Vec::new()),
active,
})
}
pub(crate) fn seal(&mut self) {
if self.active.is_empty() {
return;
}
let active = std::mem::take(&mut self.active);
Arc::make_mut(&mut self.frozen).push(Arc::new(active));
if self.frozen.len() >= crate::MAX_READ_GENERATION_LAYERS {
self.consolidate();
}
}
fn consolidate(&mut self) {
let mut merged = HashMap::<Vec<u8>, RoaringBitmap>::new();
for layer in self.frozen.iter() {
for (key, rows) in layer.iter() {
*merged.entry(key.clone()).or_default() |= rows;
}
}
self.frozen = Arc::new(vec![Arc::new(merged)]);
}
#[cfg(test)]
pub(crate) fn frozen_layer_count(&self) -> usize {
self.frozen.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn insert_get_and_intersect() {
let mut color = BitmapIndex::new();
color.insert(b"red".to_vec(), RowId(1));
color.insert(b"red".to_vec(), RowId(3));
color.insert(b"blue".to_vec(), RowId(3));
let mut region = BitmapIndex::new();
region.insert(b"us".to_vec(), RowId(1));
region.insert(b"us".to_vec(), RowId(3));
region.insert(b"eu".to_vec(), RowId(2));
let red = color.get(b"red");
let us = region.get(b"us");
let both = BitmapIndex::intersect(&[red, us]);
let ids: Vec<u32> = both.iter().collect();
assert_eq!(ids, vec![1, 3]);
}
#[test]
fn sealed_generations_share_bitmaps_and_consolidate() {
let mut writer = BitmapIndex::new();
for id in 0..crate::MAX_READ_GENERATION_LAYERS as u64 + 2 {
writer.insert(b"all".to_vec(), RowId(id));
writer.seal();
}
assert!(writer.frozen_layer_count() < crate::MAX_READ_GENERATION_LAYERS);
let generation = writer.clone();
writer.insert(b"new".to_vec(), RowId(99));
assert!(generation.get(b"new").is_empty());
assert!(writer.get(b"new").contains(99));
}
}