use super::http_cache::{CacheObject, HttpCacheStorage};
use super::{LOG_TARGET, Result};
use async_trait::async_trait;
use pingap_core::TinyUfo;
use strum::EnumString;
use tracing::debug;
type CacheKey = String;
pub struct TinyUfoCache {
cache: TinyUfo<CacheKey, CacheObject>,
}
#[derive(Debug, Clone, Copy, Default, EnumString)]
pub enum CacheMode {
#[default]
Normal,
Compact,
}
impl TinyUfoCache {
pub fn new(
mode: CacheMode,
total_weight_limit: usize,
estimated_size: usize,
) -> Self {
const SAMPLES_DIVISOR: usize = 32;
let samples = estimated_size / SAMPLES_DIVISOR;
match mode {
CacheMode::Compact => Self {
cache: TinyUfo::new_compact(total_weight_limit, samples),
},
CacheMode::Normal => Self {
cache: TinyUfo::new(total_weight_limit, samples),
},
}
}
}
#[async_trait]
impl HttpCacheStorage for TinyUfoCache {
async fn get(
&self,
key: &str,
namespace: &[u8],
) -> Result<Option<CacheObject>> {
debug!(
target: LOG_TARGET,
key, namespace, "getting cache entry from TinyUfo storage"
);
Ok(self.cache.get(&key.to_string()))
}
async fn put(
&self,
key: &str,
namespace: &[u8],
data: CacheObject,
) -> Result<()> {
let weight = data.get_weight();
debug!(
target: LOG_TARGET,
key,
namespace,
weight = weight,
"storing cache entry in TinyUfo storage"
);
self.cache.put(key.to_string(), data, weight);
Ok(())
}
async fn remove(
&self,
key: &str,
namespace: &[u8],
) -> Result<Option<CacheObject>> {
debug!(
target: LOG_TARGET,
key, namespace, "removing cache entry from TinyUfo storage"
);
Ok(self.cache.remove(&key.to_string()))
}
}
#[cfg(test)]
mod tests {
use super::*;
use bytes::Bytes;
use pretty_assertions::assert_eq;
#[tokio::test]
async fn test_tiny_ufo_cache() {
let cache = TinyUfoCache::new(CacheMode::Normal, 10, 10);
let key = "key";
let obj = CacheObject {
meta: (b"Hello".to_vec(), b"World".to_vec()),
body: Bytes::from_static(b"Hello World!"),
};
let result = cache.get(key, b"").await.unwrap();
assert_eq!(true, result.is_none());
cache.put(key, b"", obj.clone()).await.unwrap();
let result = cache.get(key, b"").await.unwrap().unwrap();
assert_eq!(obj, result);
cache.remove(key, b"").await.unwrap().unwrap();
let result = cache.get(key, b"").await.unwrap();
assert_eq!(true, result.is_none());
}
}