#![allow(non_snake_case)]
use std::sync::Arc;
use crate::cache::{RiCache, RiCacheStats};
use crate::core::RiResult;
pub struct RiHybridCache {
memory_cache: Arc<crate::cache::backends::RiMemoryCache>,
redis_cache: Arc<crate::cache::backends::RiRedisCache>,
}
impl RiHybridCache {
pub async fn new(redis_url: &str) -> crate::core::RiResult<Self> {
let memory_cache = Arc::new(crate::cache::backends::RiMemoryCache::new());
let redis_cache = Arc::new(crate::cache::backends::RiRedisCache::new(redis_url).await?);
Ok(Self {
memory_cache,
redis_cache,
})
}
}
#[async_trait::async_trait]
impl RiCache for RiHybridCache {
async fn get(&self, key: &str) -> RiResult<Option<String>> {
if let Ok(Some(value)) = self.memory_cache.get(key).await {
return Ok(Some(value));
}
if let Ok(Some(value)) = self.redis_cache.get(key).await {
let _ = self.memory_cache.set(key, &value, Some(3600)).await;
return Ok(Some(value));
}
Ok(None)
}
async fn set(&self, key: &str, value: &str, ttl_seconds: Option<u64>) -> crate::core::RiResult<()> {
self.memory_cache.set(key, value, ttl_seconds).await?;
self.redis_cache.set(key, value, ttl_seconds).await?;
Ok(())
}
async fn delete(&self, key: &str) -> crate::core::RiResult<bool> {
let memory_deleted = self.memory_cache.delete(key).await?;
let redis_deleted = self.redis_cache.delete(key).await?;
Ok(memory_deleted || redis_deleted)
}
async fn exists(&self, key: &str) -> bool {
self.memory_cache.exists(key).await || self.redis_cache.exists(key).await
}
async fn keys(&self) -> crate::core::RiResult<Vec<String>> {
let memory_keys = self.memory_cache.keys().await?;
let redis_keys = self.redis_cache.keys().await?;
let mut all_keys = memory_keys;
for key in redis_keys {
if !all_keys.contains(&key) {
all_keys.push(key);
}
}
Ok(all_keys)
}
async fn clear(&self) -> crate::core::RiResult<()> {
self.memory_cache.clear().await?;
self.redis_cache.clear().await?;
Ok(())
}
async fn stats(&self) -> RiCacheStats {
let memory_stats = self.memory_cache.stats().await;
let redis_stats = self.redis_cache.stats().await;
RiCacheStats {
hits: memory_stats.hits + redis_stats.hits,
misses: memory_stats.misses + redis_stats.misses,
entries: memory_stats.entries + redis_stats.entries,
memory_usage_bytes: memory_stats.memory_usage_bytes + redis_stats.memory_usage_bytes,
avg_hit_rate: (memory_stats.avg_hit_rate + redis_stats.avg_hit_rate) / 2.0,
hit_count: memory_stats.hit_count + redis_stats.hit_count,
miss_count: memory_stats.miss_count + redis_stats.miss_count,
eviction_count: memory_stats.eviction_count + redis_stats.eviction_count,
}
}
async fn cleanup_expired(&self) -> crate::core::RiResult<usize> {
let memory_cleaned = self.memory_cache.cleanup_expired().await?;
let redis_cleaned = self.redis_cache.cleanup_expired().await?;
Ok(memory_cleaned + redis_cleaned)
}
}