use async_trait::async_trait;
use hitbox::{BackendLabel, CacheKey, CacheValue, Raw};
use hitbox_backend::Backend;
use hitbox_backend::format::{Format, JsonFormat};
use hitbox_backend::{
BackendResult, CacheKeyFormat, Compressor, DeleteStatus, PassthroughCompressor,
};
use moka::future::Cache;
#[derive(Clone)]
pub struct MokaBackend<S = JsonFormat, C = PassthroughCompressor>
where
S: Format,
C: Compressor,
{
pub(crate) cache: Cache<CacheKey, CacheValue<Raw>>,
pub(crate) key_format: CacheKeyFormat,
pub(crate) serializer: S,
pub(crate) compressor: C,
pub(crate) label: BackendLabel,
}
impl<S, C> MokaBackend<S, C>
where
S: Format,
C: Compressor,
{
pub fn cache(&self) -> &Cache<CacheKey, CacheValue<Raw>> {
&self.cache
}
pub fn entry_count(&self) -> u64 {
self.cache.entry_count()
}
pub fn weighted_size(&self) -> u64 {
self.cache.weighted_size()
}
pub fn record_metrics(&self) {
crate::metrics::record_capacity(
self.label.as_str(),
self.entry_count(),
self.weighted_size(),
);
}
}
impl MokaBackend<JsonFormat, PassthroughCompressor> {
pub fn builder() -> crate::builder::MokaBackendBuilder<
crate::builder::NoCapacity,
JsonFormat,
PassthroughCompressor,
> {
crate::builder::MokaBackendBuilder::new()
}
}
#[async_trait]
impl<S, C> Backend for MokaBackend<S, C>
where
S: Format + Send + Sync,
C: Compressor + Send + Sync,
{
async fn read(&self, key: &CacheKey) -> BackendResult<Option<CacheValue<Raw>>> {
self.cache.get(key).await.map(Ok).transpose()
}
async fn write(&self, key: &CacheKey, value: CacheValue<Raw>) -> BackendResult<()> {
self.cache.insert(key.clone(), value).await;
self.record_metrics();
Ok(())
}
async fn remove(&self, key: &CacheKey) -> BackendResult<DeleteStatus> {
let value = self.cache.remove(key).await;
self.record_metrics();
match value {
Some(_) => Ok(DeleteStatus::Deleted(1)),
None => Ok(DeleteStatus::Missing),
}
}
fn label(&self) -> BackendLabel {
self.label.clone()
}
fn value_format(&self) -> &dyn Format {
&self.serializer
}
fn key_format(&self) -> &CacheKeyFormat {
&self.key_format
}
fn compressor(&self) -> &dyn Compressor {
&self.compressor
}
}
impl<S, C> hitbox_backend::CacheBackend for MokaBackend<S, C>
where
S: Format + Send + Sync,
C: Compressor + Send + Sync,
{
}