Skip to content
Clone
fad06fd
116 lines 3.3 KB Rust
use std::sync::Arc;
use foyer::{BlockEngineConfig, DeviceBuilder, FsDeviceBuilder, HybridCache, HybridCacheBuilder};
use crate::cache::CacheConfig;
use crate::error::BabyError;
pub type CacheKey = Vec<u8>;
pub type CacheValue = Vec<u8>;
pub struct CacheStore {
inner: HybridCache<CacheKey, CacheValue>,
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<Arc<Self>, 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<CacheKey, CacheValue> = 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<foyer::Statistics> {
Arc::clone(self.inner.statistics())
}
pub async fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, 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<u8>, value: Vec<u8>) {
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<F, Fut>(&self, key: Vec<u8>, fetch: F) -> Result<Vec<u8>, BabyError>
where
F: FnOnce() -> Fut,
Fut: std::future::Future<Output = Result<Vec<u8>, 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())
}
}