pub mod db_loader;
#[cfg(feature = "l1-moka")]
pub mod l1;
#[cfg(feature = "l2-redis")]
pub mod l2;
#[cfg(all(feature = "l1-moka", feature = "l2-redis"))]
pub mod two_level;
#[cfg(feature = "redis-native")]
pub mod redis_native;
#[cfg(feature = "ttl-control")]
pub mod ttl_control;
#[cfg(feature = "tiered-cache")]
pub mod tiered_cache;
use crate::error::Result;
use async_trait::async_trait;
use std::any::Any;
use crate::serialization::Serializer;
use serde::{de::DeserializeOwned, Serialize};
use tracing::instrument;
#[async_trait]
pub trait CacheExt: CacheOps {
#[instrument(skip(self), level = "debug")]
async fn get<T: DeserializeOwned + Send>(&self, key: &str) -> Result<Option<T>> {
let bytes = self.get_bytes(key).await?;
match bytes {
Some(data) => {
let val = self.serializer().deserialize(&data)?;
Ok(Some(val))
}
None => Ok(None),
}
}
#[instrument(skip(self, value), level = "debug")]
async fn set<T: Serialize + Send + Sync>(
&self,
key: &str,
value: &T,
ttl: Option<u64>,
) -> Result<()> {
let bytes = self.serializer().serialize(value)?;
self.set_bytes(key, bytes, ttl).await
}
#[instrument(skip(self, value), level = "debug")]
async fn set_l1_only<T: Serialize + Send + Sync>(
&self,
key: &str,
value: &T,
ttl: Option<u64>,
) -> Result<()> {
let bytes = self.serializer().serialize(value)?;
self.set_l1_bytes(key, bytes, ttl).await
}
#[instrument(skip(self, value), level = "debug")]
async fn set_l2_only<T: Serialize + Send + Sync>(
&self,
key: &str,
value: &T,
ttl: Option<u64>,
) -> Result<()> {
let bytes = self.serializer().serialize(value)?;
self.set_l2_bytes(key, bytes, ttl).await
}
#[instrument(skip(self, fetch), level = "debug")]
async fn get_or_fetch<T, F, Fut>(&self, key: &str, ttl: Option<u64>, fetch: F) -> Result<T>
where
T: DeserializeOwned + Serialize + Send + Sync + Clone,
F: FnOnce() -> Fut + Send,
Fut: std::future::Future<Output = Result<T>> + Send,
{
if let Some(cached) = self.get::<T>(key).await? {
return Ok(cached);
}
let value = fetch().await?;
self.set(key, &value, ttl).await?;
Ok(value)
}
#[instrument(skip(self), level = "debug")]
async fn try_get<T: DeserializeOwned + Send>(&self, key: &str) -> Result<Option<T>> {
self.get(key).await
}
#[instrument(skip(self), level = "debug")]
async fn remove<T: DeserializeOwned + Send>(&self, key: &str) -> Result<Option<T>> {
let old_value = self.get::<T>(key).await?;
self.delete(key).await?;
Ok(old_value)
}
#[instrument(skip(self), level = "debug")]
async fn contains(&self, key: &str) -> Result<bool> {
Ok(self.get_bytes(key).await?.is_some())
}
}
impl<T: CacheOps + ?Sized> CacheExt for T {}
#[async_trait]
pub trait CacheOps: Send + Sync + Any {
async fn get_bytes(&self, key: &str) -> Result<Option<Vec<u8>>>;
async fn get_l1_bytes(&self, _key: &str) -> Result<Option<Vec<u8>>> {
Err(crate::error::CacheError::NotSupported(
"get_l1_bytes".to_string(),
))
}
async fn get_l2_bytes(&self, _key: &str) -> Result<Option<Vec<u8>>> {
Err(crate::error::CacheError::NotSupported(
"get_l2_bytes".to_string(),
))
}
async fn set_bytes(&self, key: &str, value: Vec<u8>, ttl: Option<u64>) -> Result<()>;
async fn set_l1_bytes(&self, _key: &str, _value: Vec<u8>, _ttl: Option<u64>) -> Result<()> {
Err(crate::error::CacheError::NotSupported(
"set_l1_bytes".to_string(),
))
}
async fn set_l2_bytes(&self, _key: &str, _value: Vec<u8>, _ttl: Option<u64>) -> Result<()> {
Err(crate::error::CacheError::NotSupported(
"set_l2_bytes".to_string(),
))
}
async fn lock(&self, _key: &str, _ttl: u64) -> Result<Option<String>> {
Ok(None)
}
async fn unlock(&self, _key: &str, _value: &str) -> Result<bool> {
Ok(false)
}
async fn delete(&self, key: &str) -> Result<()>;
fn serializer(&self) -> &crate::serialization::SerializerEnum;
fn as_any(&self) -> &dyn Any;
fn into_any_arc(self: std::sync::Arc<Self>) -> std::sync::Arc<dyn Any + Send + Sync>;
async fn clear_l1(&self) -> Result<()> {
Err(crate::error::CacheError::NotSupported(
"clear_l1".to_string(),
))
}
async fn clear_l2(&self) -> Result<()> {
Err(crate::error::CacheError::NotSupported(
"clear_l2".to_string(),
))
}
async fn clear_wal(&self) -> Result<()> {
Err(crate::error::CacheError::NotSupported(
"clear_wal".to_string(),
))
}
async fn shutdown(&self) -> Result<()> {
Ok(())
}
}