use std::sync::Arc; use foyer::{BlockEngineConfig, DeviceBuilder, FsDeviceBuilder, HybridCache, HybridCacheBuilder}; use crate::cache::CacheConfig; use crate::error::BabyError; pub type CacheKey = Vec; pub type CacheValue = Vec; pub struct CacheStore { inner: HybridCache, cfg: CacheConfig, } impl std::fmt::Debug for CacheStore { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("CacheStore") .field("name", &self.cfg.name) .field("disk_dir", &self.cfg.disk_dir) .finish() } } impl CacheStore { pub async fn open(cfg: CacheConfig) -> Result, BabyError> { std::fs::create_dir_all(&cfg.disk_dir).map_err(|source| BabyError::Io { path: cfg.disk_dir.clone(), source, })?; let device = FsDeviceBuilder::new(&cfg.disk_dir) .with_capacity(cfg.disk_capacity_bytes) .build() .map_err(|source| BabyError::Cache { op: "device_build", source, })?; let inner: HybridCache = HybridCacheBuilder::new() .with_name(cfg.name.clone()) .memory(cfg.memory_capacity_bytes) .storage() .with_engine_config(BlockEngineConfig::new(device)) .build() .await .map_err(|source| BabyError::Cache { op: "build", source, })?; Ok(Arc::new(Self { inner, cfg })) } pub async fn close(&self) -> Result<(), BabyError> { self.inner.close().await.map_err(|source| BabyError::Cache { op: "close", source, }) } /// Drop all cached entries. Used to invalidate the whole store after an /// operation that may change or prune many objects/refs at once (e.g. /// `git fetch`, `git gc --prune=now`, `git fast-import`). pub async fn clear(&self) -> Result<(), BabyError> { self.inner.clear().await.map_err(|source| BabyError::Cache { op: "clear", source, }) } pub fn config(&self) -> &CacheConfig { &self.cfg } pub fn statistics(&self) -> Arc { Arc::clone(self.inner.statistics()) } pub async fn get(&self, key: &[u8]) -> Result>, BabyError> { let entry = self .inner .get(key) .await .map_err(|source| BabyError::Cache { op: "get", source })?; Ok(entry.map(|e| e.value().clone())) } pub fn insert(&self, key: Vec, value: Vec) { self.inner.insert(key, value); } pub fn contains(&self, key: &[u8]) -> bool { self.inner.contains(key) } pub fn remove(&self, key: &[u8]) { self.inner.remove(key); } pub async fn get_or_fetch(&self, key: Vec, fetch: F) -> Result, BabyError> where F: FnOnce() -> Fut, Fut: std::future::Future, BabyError>> + Send + 'static, { let entry = self .inner .get_or_fetch(&key, fetch) .await .map_err(|source| BabyError::Cache { op: "get_or_fetch", source, })?; Ok(entry.value().clone()) } }