mindb 0.1.2

Lightweight embedded key–value store with write-ahead log and zstd compression.
Documentation
//! Simplified roaring bitmap sidecar that tracks tag-to-key mappings.
#![allow(dead_code)]

use std::collections::{HashMap, HashSet};
use std::sync::Arc;

use parking_lot::RwLock;

use crate::index::{SequenceNumber, VersionPointer};

#[derive(Clone, Default)]
pub struct RoaringBitmapSidecar {
    inner: Arc<RwLock<HashMap<String, HashMap<Vec<u8>, VersionPointer>>>>,
}

impl RoaringBitmapSidecar {
    /// Creates a new empty roaring bitmap sidecar.
    pub fn new() -> Self {
        Self {
            inner: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    /// Registers that a key belongs to the provided logical bitmap/tag.
    pub fn add(&self, tag: impl Into<String>, key: Vec<u8>, pointer: VersionPointer) {
        let tag = tag.into();
        let mut guard = self.inner.write();
        let entry = guard.entry(tag).or_default();
        match entry.get_mut(&key) {
            Some(existing) if existing.sequence >= pointer.sequence => return,
            Some(existing) => *existing = pointer,
            None => {
                entry.insert(key, pointer);
            }
        }
    }

    /// Returns the set of keys that belong to all provided tags and are visible in the snapshot.
    pub fn intersect_keys(&self, tags: &[String], snapshot: SequenceNumber) -> Vec<Vec<u8>> {
        if tags.is_empty() {
            return Vec::new();
        }

        let guard = self.inner.read();
        let mut iter = tags.iter();
        let first = match iter.next() {
            Some(tag) => guard.get(tag.as_str()).cloned().unwrap_or_default(),
            None => return Vec::new(),
        };

        let mut keys: HashSet<Vec<u8>> = first
            .into_iter()
            .filter(|(_, pointer)| pointer.is_visible_at(snapshot))
            .map(|(key, _)| key)
            .collect();

        for tag in iter {
            if let Some(mapping) = guard.get(tag.as_str()) {
                let tag_keys: HashSet<Vec<u8>> = mapping
                    .iter()
                    .filter(|(_, pointer)| pointer.is_visible_at(snapshot))
                    .map(|(key, _)| key.clone())
                    .collect();
                keys = keys
                    .intersection(&tag_keys)
                    .cloned()
                    .collect::<HashSet<_>>();
            } else {
                return Vec::new();
            }
        }

        keys.into_iter().collect()
    }
}