fast-cache 0.1.0

Embedded-first thread-per-core in-memory cache with optional Redis-compatible server
Documentation
use std::sync::atomic::Ordering;

use parking_lot::{RwLockReadGuard, RwLockWriteGuard};

use super::helpers::bucket_index;
use super::*;

impl RedisObjectStore {
    pub(crate) fn new(shard_count: usize) -> Self {
        let shard_count = shard_count.max(1);
        let shards = (0..shard_count)
            .map(|_| RedisObjectShard {
                buckets: (0..OBJECT_BUCKETS)
                    .map(|_| RwLock::new(RedisObjectBucket::default()))
                    .collect(),
                object_count: AtomicIsize::new(0),
            })
            .collect();
        Self {
            shards,
            has_objects_hint: AtomicBool::new(false),
        }
    }

    #[inline(always)]
    pub(crate) fn has_objects(&self) -> bool {
        self.has_objects_hint.load(Ordering::Acquire)
    }

    #[inline(always)]
    pub(crate) fn object_count(&self) -> usize {
        let count = self
            .shards
            .iter()
            .map(|shard| shard.object_count.load(Ordering::Acquire))
            .sum::<isize>();
        let count = count.max(0) as usize;
        self.has_objects_hint.store(count != 0, Ordering::Release);
        count
    }

    #[inline(always)]
    pub(crate) fn read_bucket(
        &self,
        shard_id: usize,
        key_hash: u64,
    ) -> RwLockReadGuard<'_, RedisObjectBucket> {
        self.shards[shard_id].buckets[bucket_index(key_hash)].read()
    }

    #[inline(always)]
    pub(crate) fn write_bucket(
        &self,
        shard_id: usize,
        key_hash: u64,
    ) -> RwLockWriteGuard<'_, RedisObjectBucket> {
        self.shards[shard_id].buckets[bucket_index(key_hash)].write()
    }

    #[inline(always)]
    pub(crate) fn note_created(&self, shard_id: usize) {
        let previous = self.shards[shard_id]
            .object_count
            .fetch_add(1, Ordering::Relaxed);
        if previous <= 0 {
            self.has_objects_hint.store(true, Ordering::Release);
        }
    }

    #[inline(always)]
    pub(crate) fn note_deleted(&self, shard_id: usize) {
        self.shards[shard_id]
            .object_count
            .fetch_sub(1, Ordering::Relaxed);
    }

    pub(crate) fn keys_with_type(&self, now_ms: u64) -> Vec<(Bytes, &'static str)> {
        let mut keys = Vec::with_capacity(self.object_count());
        for shard in &self.shards {
            for bucket in &shard.buckets {
                bucket.read().keys_with_type(&mut keys, now_ms);
            }
        }
        keys
    }
}