bable 0.1.0

Badger's high performance sst table implementation
Documentation
use super::*;
use crate::error::*;
use stretto::{Cache, CacheCallback, Coster, KeyBuilder, TransparentKeyBuilder, UpdateValidator};

pub struct CacheOptions {
    ignore_internal_cost: bool,
    cleanup_duration: std::time::Duration,
    max_cost: i64,
    num_counters: usize,
}

impl CacheOptions {
    #[inline]
    pub fn new(num_counters: usize, max_cost: i64) -> Self {
        Self {
            ignore_internal_cost: false,
            cleanup_duration: std::time::Duration::from_millis(500),
            max_cost,
            num_counters,
        }
    }

    #[inline]
    pub fn set_ignore_internal_cost(mut self, ignore_internal_cost: bool) -> Self {
        self.ignore_internal_cost = ignore_internal_cost;
        self
    }

    #[inline]
    pub fn set_cleanup_duration(mut self, cleanup_duration: std::time::Duration) -> Self {
        self.cleanup_duration = cleanup_duration;
        self
    }
}

#[doc(hidden)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct NoopIndex;

impl UpdateValidator for NoopIndex {
    type Value = RefCounter<TableIndex>;

    #[inline(always)]
    fn should_update(&self, _prev: &Self::Value, _curr: &Self::Value) -> bool {
        true
    }
}

impl Coster for NoopIndex {
    type Value = RefCounter<TableIndex>;

    #[inline(always)]
    fn cost(&self, _val: &Self::Value) -> i64 {
        0
    }
}

impl CacheCallback for NoopIndex {
    type Value = RefCounter<TableIndex>;

    #[inline(always)]
    fn on_exit(&self, _val: Option<Self::Value>) {}
}

#[derive(Clone)]
#[repr(transparent)]
#[allow(clippy::type_complexity)]
pub struct IndexCache(
    RefCounter<
        Cache<
            u64,
            RefCounter<TableIndex>,
            TransparentKeyBuilder<u64>,
            NoopIndex,
            NoopIndex,
            NoopIndex,
        >,
    >,
);

impl IndexCache {
    pub fn new(opts: CacheOptions) -> Result<Self> {
        Cache::builder(opts.num_counters, opts.max_cost)
            .set_ignore_internal_cost(opts.ignore_internal_cost)
            .set_cleanup_duration(opts.cleanup_duration)
            .set_callback(NoopIndex)
            .set_coster(NoopIndex)
            .set_update_validator(NoopIndex)
            .set_key_builder(TransparentKeyBuilder::default())
            .finalize()
            .map(|c| Self(RefCounter::new(c)))
            .map_err(From::from)
    }
}

impl core::ops::Deref for IndexCache {
    type Target = Cache<
        u64,
        RefCounter<TableIndex>,
        TransparentKeyBuilder<u64>,
        NoopIndex,
        NoopIndex,
        NoopIndex,
    >;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[doc(hidden)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct NoopBlock;

impl UpdateValidator for NoopBlock {
    type Value = RefCounter<Block>;

    #[inline(always)]
    fn should_update(&self, _prev: &Self::Value, _curr: &Self::Value) -> bool {
        true
    }
}

impl Coster for NoopBlock {
    type Value = RefCounter<Block>;

    #[inline(always)]
    fn cost(&self, _val: &Self::Value) -> i64 {
        0
    }
}

impl CacheCallback for NoopBlock {
    type Value = RefCounter<Block>;

    #[inline(always)]
    fn on_exit(&self, _val: Option<Self::Value>) {}
}

#[doc(hidden)]
pub struct BlockKeyBuilder {
    sea: core::hash::BuildHasherDefault<vpb::checksum::SeaHasher>,
    xx: vpb::checksum::Xxh64Builder,
}

impl core::fmt::Debug for BlockKeyBuilder {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.debug_struct("BlockKeyBuilder").finish()
    }
}

impl Default for BlockKeyBuilder {
    fn default() -> Self {
        use rand::{thread_rng, Rng};
        let mut rng = thread_rng();
        let seed = rng.gen::<u64>();
        Self {
            sea: Default::default(),
            xx: vpb::checksum::Xxh64Builder::new(seed),
        }
    }
}

impl KeyBuilder for BlockKeyBuilder {
    type Key = Bytes;

    #[inline]
    fn hash_index<Q>(&self, key: &Q) -> u64
    where
        Self::Key: core::borrow::Borrow<Q>,
        Q: core::hash::Hash + Eq + ?Sized,
    {
        use core::hash::{BuildHasher, Hasher};

        let mut s = self.sea.build_hasher();
        key.hash(&mut s);
        s.finish()
    }

    #[inline]
    fn hash_conflict<Q>(&self, key: &Q) -> u64
    where
        Self::Key: core::borrow::Borrow<Q>,
        Q: core::hash::Hash + Eq + ?Sized,
    {
        use core::hash::{BuildHasher, Hasher};
        let mut x = self.xx.build_hasher();
        key.hash(&mut x);
        x.finish()
    }
}

#[derive(Clone)]
pub struct BlockCache(
    RefCounter<Cache<Bytes, RefCounter<Block>, BlockKeyBuilder, NoopBlock, NoopBlock, NoopBlock>>,
);

impl BlockCache {
    pub fn new(opts: CacheOptions) -> Result<Self> {
        Cache::builder(opts.num_counters, opts.max_cost)
            .set_ignore_internal_cost(opts.ignore_internal_cost)
            .set_cleanup_duration(opts.cleanup_duration)
            .set_callback(NoopBlock)
            .set_coster(NoopBlock)
            .set_update_validator(NoopBlock)
            .set_key_builder(BlockKeyBuilder::default())
            .finalize()
            .map(|c| Self(RefCounter::new(c)))
            .map_err(From::from)
    }
}

impl core::ops::Deref for BlockCache {
    type Target = Cache<Bytes, RefCounter<Block>, BlockKeyBuilder, NoopBlock, NoopBlock, NoopBlock>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}