Skip to main content

sz_orm_pool/
cache.rs

1//! Cache abstraction layer
2//!
3//! Provides multi-level caching with memory support
4
5use std::collections::HashMap;
6use std::sync::{Arc, RwLock};
7use std::time::{Duration, Instant};
8use sz_orm_model::CacheError;
9
10pub trait Cache: Send + Sync {
11    fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError>;
12    fn set(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<(), CacheError>;
13    fn delete(&self, key: &str) -> Result<(), CacheError>;
14    fn clear(&self) -> Result<(), CacheError>;
15    fn exists(&self, key: &str) -> Result<bool, CacheError>;
16    fn expire(&self, key: &str, ttl: Duration) -> Result<(), CacheError>;
17    fn ttl(&self, key: &str) -> Result<Option<Duration>, CacheError>;
18}
19
20#[derive(Clone)]
21pub struct MemoryCache {
22    data: Arc<RwLock<HashMap<String, CacheEntry>>>,
23    default_ttl: Option<Duration>,
24}
25
26struct CacheEntry {
27    value: Vec<u8>,
28    expires_at: Option<Instant>,
29}
30
31impl MemoryCache {
32    pub fn new() -> Self {
33        Self {
34            data: Arc::new(RwLock::new(HashMap::new())),
35            default_ttl: None,
36        }
37    }
38
39    pub fn with_ttl(ttl: Duration) -> Self {
40        Self {
41            data: Arc::new(RwLock::new(HashMap::new())),
42            default_ttl: Some(ttl),
43        }
44    }
45}
46
47impl Default for MemoryCache {
48    fn default() -> Self {
49        Self::new()
50    }
51}
52
53impl Cache for MemoryCache {
54    fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError> {
55        let data = self.data.read()?;
56        if let Some(entry) = data.get(key) {
57            if let Some(expires_at) = entry.expires_at {
58                if expires_at <= Instant::now() {
59                    return Ok(None);
60                }
61            }
62            Ok(Some(entry.value.clone()))
63        } else {
64            Ok(None)
65        }
66    }
67
68    fn set(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<(), CacheError> {
69        let expires_at = ttl.or(self.default_ttl).map(|d| Instant::now() + d);
70        let mut data = self.data.write()?;
71        data.insert(key.to_string(), CacheEntry { value, expires_at });
72        Ok(())
73    }
74
75    fn delete(&self, key: &str) -> Result<(), CacheError> {
76        let mut data = self.data.write()?;
77        data.remove(key);
78        Ok(())
79    }
80
81    fn clear(&self) -> Result<(), CacheError> {
82        let mut data = self.data.write()?;
83        data.clear();
84        Ok(())
85    }
86
87    fn exists(&self, key: &str) -> Result<bool, CacheError> {
88        let data = self.data.read()?;
89        if let Some(entry) = data.get(key) {
90            if let Some(expires_at) = entry.expires_at {
91                if expires_at <= Instant::now() {
92                    return Ok(false);
93                }
94            }
95            Ok(true)
96        } else {
97            Ok(false)
98        }
99    }
100
101    fn expire(&self, key: &str, ttl: Duration) -> Result<(), CacheError> {
102        let mut data = self.data.write()?;
103        if let Some(entry) = data.get_mut(key) {
104            entry.expires_at = Some(Instant::now() + ttl);
105            Ok(())
106        } else {
107            Err(CacheError::NotFound(key.to_string()))
108        }
109    }
110
111    fn ttl(&self, key: &str) -> Result<Option<Duration>, CacheError> {
112        let data = self.data.read()?;
113        if let Some(entry) = data.get(key) {
114            if let Some(expires_at) = entry.expires_at {
115                if expires_at <= Instant::now() {
116                    return Ok(None);
117                }
118                let remaining = expires_at.duration_since(Instant::now());
119                Ok(Some(remaining))
120            } else {
121                Ok(None)
122            }
123        } else {
124            Err(CacheError::NotFound(key.to_string()))
125        }
126    }
127}
128
129pub struct MultiLevelCache {
130    caches: Vec<Box<dyn Cache>>,
131}
132
133impl MultiLevelCache {
134    pub fn new() -> Self {
135        Self { caches: Vec::new() }
136    }
137
138    pub fn add_cache(mut self, cache: Box<dyn Cache>) -> Self {
139        self.caches.push(cache);
140        self
141    }
142}
143
144impl Default for MultiLevelCache {
145    fn default() -> Self {
146        Self::new()
147    }
148}
149
150impl Cache for MultiLevelCache {
151    fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError> {
152        for (i, cache) in self.caches.iter().enumerate() {
153            if let Ok(Some(value)) = cache.get(key) {
154                // 保留原始 TTL 信息:从命中的缓存层查询剩余 TTL,写回低层时使用
155                let ttl = cache.ttl(key).ok().flatten();
156                for j in 0..i {
157                    let _ = self.caches[j].set(key, value.clone(), ttl);
158                }
159                return Ok(Some(value));
160            }
161        }
162        Ok(None)
163    }
164
165    fn set(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<(), CacheError> {
166        for cache in &self.caches {
167            cache.set(key, value.clone(), ttl)?;
168        }
169        Ok(())
170    }
171
172    fn delete(&self, key: &str) -> Result<(), CacheError> {
173        for cache in &self.caches {
174            cache.delete(key)?;
175        }
176        Ok(())
177    }
178
179    fn clear(&self) -> Result<(), CacheError> {
180        for cache in &self.caches {
181            cache.clear()?;
182        }
183        Ok(())
184    }
185
186    fn exists(&self, key: &str) -> Result<bool, CacheError> {
187        for cache in &self.caches {
188            if cache.exists(key)? {
189                return Ok(true);
190            }
191        }
192        Ok(false)
193    }
194
195    fn expire(&self, key: &str, ttl: Duration) -> Result<(), CacheError> {
196        for cache in &self.caches {
197            cache.expire(key, ttl)?;
198        }
199        Ok(())
200    }
201
202    fn ttl(&self, key: &str) -> Result<Option<Duration>, CacheError> {
203        if let Some(cache) = self.caches.first() {
204            cache.ttl(key)
205        } else {
206            Err(CacheError::NotFound("No caches configured".to_string()))
207        }
208    }
209}
210
211#[derive(Debug, Clone, Default)]
212pub struct CacheStats {
213    pub hits: u64,
214    pub misses: u64,
215    pub sets: u64,
216    pub deletes: u64,
217}
218
219// ===================== Read-Through / Write-Through 辅助方法 =====================
220
221/// Read-through(同步版):缓存未命中时通过 `loader` 回源加载,写入缓存后返回
222///
223/// # 参数
224/// - `cache`:缓存实例
225/// - `key`:缓存键
226/// - `ttl`:写入缓存时的 TTL(`None` 表示永不过期)
227/// - `loader`:回源加载闭包,返回 `Ok(None)` 表示数据源也无此键
228///
229/// # 返回
230/// - `Ok(Some(v))`:命中缓存或回源加载成功
231/// - `Ok(None)`:缓存与数据源均无此键
232/// - `Err(_)`:缓存或加载过程出错
233pub fn read_through<F>(
234    cache: &dyn Cache,
235    key: &str,
236    ttl: Option<Duration>,
237    loader: F,
238) -> Result<Option<Vec<u8>>, CacheError>
239where
240    F: FnOnce() -> Result<Option<Vec<u8>>, CacheError>,
241{
242    // 1. 先查缓存
243    if let Some(v) = cache.get(key)? {
244        return Ok(Some(v));
245    }
246    // 2. 缓存未命中,回源加载
247    let value = loader()?;
248    // 3. 加载到值则写入缓存
249    if let Some(ref v) = value {
250        cache.set(key, v.clone(), ttl)?;
251    }
252    Ok(value)
253}
254
255/// Read-through(异步版):缓存未命中时通过异步 `loader` 回源加载,写入缓存后返回
256///
257/// 用于数据库等异步数据源的回源加载场景。
258pub async fn read_through_async<F, Fut>(
259    cache: &dyn Cache,
260    key: &str,
261    ttl: Option<Duration>,
262    loader: F,
263) -> Result<Option<Vec<u8>>, CacheError>
264where
265    F: FnOnce() -> Fut,
266    Fut: std::future::Future<Output = Result<Option<Vec<u8>>, CacheError>>,
267{
268    // 1. 先查缓存(同步操作)
269    if let Some(v) = cache.get(key)? {
270        return Ok(Some(v));
271    }
272    // 2. 缓存未命中,异步回源加载
273    let value = loader().await?;
274    // 3. 加载到值则写入缓存
275    if let Some(ref v) = value {
276        cache.set(key, v.clone(), ttl)?;
277    }
278    Ok(value)
279}
280
281/// Write-through(同步版):同时写入缓存和后端存储(通过 `writer` 回调)
282///
283/// 写入顺序:先写后端存储,再写缓存。若后端存储写入失败,不写缓存。
284///
285/// # 参数
286/// - `cache`:缓存实例
287/// - `key`:缓存键
288/// - `value`:值
289/// - `ttl`:缓存 TTL
290/// - `writer`:后端存储写入闭包,接收 `(key, value)`
291pub fn write_through<F>(
292    cache: &dyn Cache,
293    key: &str,
294    value: Vec<u8>,
295    ttl: Option<Duration>,
296    writer: F,
297) -> Result<(), CacheError>
298where
299    F: FnOnce(&str, &[u8]) -> Result<(), CacheError>,
300{
301    // 1. 先写后端存储
302    writer(key, &value)?;
303    // 2. 再写缓存
304    cache.set(key, value, ttl)?;
305    Ok(())
306}
307
308/// Write-through(异步版):同时写入缓存和异步后端存储
309///
310/// 写入顺序:先写后端存储,再写缓存。若后端存储写入失败,不写缓存。
311pub async fn write_through_async<F, Fut>(
312    cache: &dyn Cache,
313    key: &str,
314    value: Vec<u8>,
315    ttl: Option<Duration>,
316    writer: F,
317) -> Result<(), CacheError>
318where
319    F: FnOnce(&str, Vec<u8>) -> Fut,
320    Fut: std::future::Future<Output = Result<Vec<u8>, CacheError>>,
321{
322    // 1. 先写后端存储(writer 消费 value,返回写入后的值用于缓存)
323    let stored = writer(key, value).await?;
324    // 2. 再写缓存
325    cache.set(key, stored, ttl)?;
326    Ok(())
327}
328
329/// Write-around(写旁路):仅写后端存储,同时失效缓存中的旧值
330///
331/// 适用于写多读少场景,避免频繁写入导致缓存频繁失效。
332pub fn write_around<F>(cache: &dyn Cache, key: &str, writer: F) -> Result<(), CacheError>
333where
334    F: FnOnce(&str) -> Result<(), CacheError>,
335{
336    writer(key)?;
337    cache.delete(key)?;
338    Ok(())
339}
340
341// ===================== 负缓存支持 =====================
342
343/// 缓存查找结果
344///
345/// 区分"缓存未命中"(需要回源)与"明确不存在"(负缓存命中,不回源),
346/// 避免缓存穿透(大量请求查询不存在的 key 导致回源压力)。
347#[derive(Debug, Clone, PartialEq, Eq)]
348pub enum CacheLookup {
349    /// 找到值
350    Found(Vec<u8>),
351    /// 缓存未命中(正缓存无值,需回源查询)
352    Miss,
353    /// 明确不存在(负缓存命中,在 TTL 期内不回源)
354    NotFound,
355}
356
357/// 带负缓存的缓存包装器
358///
359/// 在正缓存(`inner`)之上叠加负缓存层:当 `get` 返回 `None` 时,将 key 记录到
360/// 负缓存,在 `negative_ttl` 期内再次查询直接返回 `NotFound`,避免缓存穿透。
361///
362/// 写入(`set`)或删除(`delete`)key 时自动清除对应的负缓存条目。
363pub struct NegativeCache<C: Cache> {
364    /// 内部正缓存
365    inner: C,
366    /// 负缓存:key → 过期时刻
367    negatives: RwLock<HashMap<String, Instant>>,
368    /// 负缓存 TTL
369    negative_ttl: Duration,
370}
371
372impl<C: Cache> NegativeCache<C> {
373    /// 创建负缓存包装器,默认负缓存 TTL 为 60 秒
374    pub fn new(inner: C) -> Self {
375        Self {
376            inner,
377            negatives: RwLock::new(HashMap::new()),
378            negative_ttl: Duration::from_secs(60),
379        }
380    }
381
382    /// 设置负缓存 TTL
383    pub fn with_negative_ttl(mut self, ttl: Duration) -> Self {
384        self.negative_ttl = ttl;
385        self
386    }
387
388    /// 获取值,区分"未命中"和"明确不存在"
389    ///
390    /// 查找顺序:负缓存 → 正缓存。
391    /// - 负缓存命中且未过期 → `NotFound`(不回源)
392    /// - 正缓存命中 → `Found`
393    /// - 正缓存未命中 → 记录到负缓存,返回 `Miss`
394    pub fn get_or_negative(&self, key: &str) -> Result<CacheLookup, CacheError> {
395        // 先查负缓存
396        let now = Instant::now();
397        {
398            let neg = self.negatives.read()?;
399            if let Some(expires_at) = neg.get(key) {
400                if *expires_at > now {
401                    return Ok(CacheLookup::NotFound);
402                }
403            }
404        }
405        // 再查正缓存
406        match self.inner.get(key)? {
407            Some(v) => Ok(CacheLookup::Found(v)),
408            None => {
409                // 记录到负缓存(覆盖已过期的旧条目)
410                let mut neg = self.negatives.write()?;
411                neg.insert(key.to_string(), now + self.negative_ttl);
412                Ok(CacheLookup::Miss)
413            }
414        }
415    }
416
417    /// 清理所有已过期的负缓存条目
418    pub fn purge_expired(&self) -> Result<usize, CacheError> {
419        let now = Instant::now();
420        let mut neg = self.negatives.write()?;
421        let before = neg.len();
422        neg.retain(|_, expires_at| *expires_at > now);
423        Ok(before - neg.len())
424    }
425}
426
427impl<C: Cache> Cache for NegativeCache<C> {
428    fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError> {
429        match self.get_or_negative(key)? {
430            CacheLookup::Found(v) => Ok(Some(v)),
431            CacheLookup::Miss | CacheLookup::NotFound => Ok(None),
432        }
433    }
434
435    fn set(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<(), CacheError> {
436        // 写入正缓存时清除负缓存(key 现在有值了)
437        {
438            let mut neg = self.negatives.write()?;
439            neg.remove(key);
440        }
441        self.inner.set(key, value, ttl)
442    }
443
444    fn delete(&self, key: &str) -> Result<(), CacheError> {
445        {
446            let mut neg = self.negatives.write()?;
447            neg.remove(key);
448        }
449        self.inner.delete(key)
450    }
451
452    fn clear(&self) -> Result<(), CacheError> {
453        {
454            let mut neg = self.negatives.write()?;
455            neg.clear();
456        }
457        self.inner.clear()
458    }
459
460    fn exists(&self, key: &str) -> Result<bool, CacheError> {
461        self.inner.exists(key)
462    }
463
464    fn expire(&self, key: &str, ttl: Duration) -> Result<(), CacheError> {
465        self.inner.expire(key, ttl)
466    }
467
468    fn ttl(&self, key: &str) -> Result<Option<Duration>, CacheError> {
469        self.inner.ttl(key)
470    }
471}
472
473#[cfg(test)]
474mod tests {
475    use super::*;
476
477    #[test]
478    fn test_memory_cache_set_get() {
479        let cache = MemoryCache::new();
480        cache.set("key1", b"value1".to_vec(), None).unwrap();
481        let val = cache.get("key1").unwrap();
482        assert_eq!(val, Some(b"value1".to_vec()));
483    }
484
485    #[test]
486    fn test_memory_cache_delete() {
487        let cache = MemoryCache::new();
488        cache.set("key1", b"value1".to_vec(), None).unwrap();
489        cache.delete("key1").unwrap();
490        let val = cache.get("key1").unwrap();
491        assert_eq!(val, None);
492    }
493
494    #[test]
495    fn test_memory_cache_exists() {
496        let cache = MemoryCache::new();
497        cache.set("key1", b"value1".to_vec(), None).unwrap();
498        let exists = cache.exists("key1").unwrap();
499        assert!(exists);
500        let exists2 = cache.exists("nonexistent").unwrap();
501        assert!(!exists2);
502    }
503
504    #[test]
505    fn test_memory_cache_clear() {
506        let cache = MemoryCache::new();
507        cache.set("key1", b"value1".to_vec(), None).unwrap();
508        cache.set("key2", b"value2".to_vec(), None).unwrap();
509        cache.clear().unwrap();
510        let val = cache.get("key1").unwrap();
511        assert_eq!(val, None);
512    }
513
514    #[test]
515    fn test_memory_cache_with_ttl() {
516        let cache = MemoryCache::with_ttl(Duration::from_secs(1));
517        cache.set("key1", b"value1".to_vec(), None).unwrap();
518        let val = cache.get("key1").unwrap();
519        assert!(val.is_some());
520    }
521
522    #[test]
523    fn test_cache_stats() {
524        let stats = CacheStats::default();
525        assert_eq!(stats.hits, 0);
526        assert_eq!(stats.misses, 0);
527    }
528
529    #[test]
530    fn test_multi_level_cache() {
531        let cache1 = MemoryCache::new();
532        let cache2 = MemoryCache::new();
533        let multi = MultiLevelCache::new()
534            .add_cache(Box::new(cache1))
535            .add_cache(Box::new(cache2));
536
537        multi.set("key1", b"value1".to_vec(), None).unwrap();
538        let val = multi.get("key1").unwrap();
539        assert_eq!(val, Some(b"value1".to_vec()));
540
541        multi.delete("key1").unwrap();
542        let val = multi.get("key1").unwrap();
543        assert_eq!(val, None);
544    }
545
546    // ----- NegativeCache -----
547    #[test]
548    fn test_negative_cache_found() {
549        let inner = MemoryCache::new();
550        inner.set("key1", b"value1".to_vec(), None).unwrap();
551        let cache = NegativeCache::new(inner);
552        let result = cache.get_or_negative("key1").unwrap();
553        assert_eq!(result, CacheLookup::Found(b"value1".to_vec()));
554    }
555
556    #[test]
557    fn test_negative_cache_miss_then_not_found() {
558        let inner = MemoryCache::new();
559        let cache = NegativeCache::new(inner);
560        // 第一次查询:正缓存未命中 → Miss,记录到负缓存
561        let result = cache.get_or_negative("missing").unwrap();
562        assert_eq!(result, CacheLookup::Miss);
563        // 第二次查询:负缓存命中 → NotFound(不回源)
564        let result = cache.get_or_negative("missing").unwrap();
565        assert_eq!(result, CacheLookup::NotFound);
566    }
567
568    #[test]
569    fn test_negative_cache_set_clears_negative() {
570        let inner = MemoryCache::new();
571        let cache = NegativeCache::new(inner);
572        // 查询不存在的 key → Miss,记录负缓存
573        cache.get_or_negative("key1").unwrap();
574        assert_eq!(
575            cache.get_or_negative("key1").unwrap(),
576            CacheLookup::NotFound
577        );
578        // 写入值后负缓存应清除 → Found
579        cache.set("key1", b"value1".to_vec(), None).unwrap();
580        assert_eq!(
581            cache.get_or_negative("key1").unwrap(),
582            CacheLookup::Found(b"value1".to_vec())
583        );
584    }
585
586    #[test]
587    fn test_negative_cache_delete_clears_negative() {
588        let inner = MemoryCache::new();
589        inner.set("key1", b"value1".to_vec(), None).unwrap();
590        let cache = NegativeCache::new(inner);
591        // 删除后重新查询 → Miss(删除时清除负缓存,允许回源)
592        cache.delete("key1").unwrap();
593        let result = cache.get_or_negative("key1").unwrap();
594        assert_eq!(result, CacheLookup::Miss);
595    }
596
597    #[test]
598    fn test_negative_cache_ttl_expiry() {
599        let inner = MemoryCache::new();
600        let cache = NegativeCache::new(inner).with_negative_ttl(Duration::from_millis(50));
601        // 查询 → Miss,记录负缓存
602        cache.get_or_negative("key1").unwrap();
603        assert_eq!(
604            cache.get_or_negative("key1").unwrap(),
605            CacheLookup::NotFound
606        );
607        // 等待 TTL 过期
608        std::thread::sleep(Duration::from_millis(60));
609        // 过期后应再次 Miss(回源)
610        let result = cache.get_or_negative("key1").unwrap();
611        assert_eq!(result, CacheLookup::Miss);
612    }
613
614    #[test]
615    fn test_negative_cache_clear() {
616        let inner = MemoryCache::new();
617        let cache = NegativeCache::new(inner);
618        cache.get_or_negative("key1").unwrap();
619        cache.get_or_negative("key2").unwrap();
620        cache.clear().unwrap();
621        // clear 后应全部回源 → Miss
622        assert_eq!(cache.get_or_negative("key1").unwrap(), CacheLookup::Miss);
623        assert_eq!(cache.get_or_negative("key2").unwrap(), CacheLookup::Miss);
624    }
625
626    #[test]
627    fn test_negative_cache_purge_expired() {
628        let inner = MemoryCache::new();
629        let cache = NegativeCache::new(inner).with_negative_ttl(Duration::from_millis(50));
630        cache.get_or_negative("key1").unwrap();
631        cache.get_or_negative("key2").unwrap();
632        std::thread::sleep(Duration::from_millis(60));
633        let purged = cache.purge_expired().unwrap();
634        assert_eq!(purged, 2);
635    }
636
637    #[test]
638    fn test_negative_cache_as_cache_trait() {
639        let inner = MemoryCache::new();
640        let cache = NegativeCache::new(inner);
641        // 通过 Cache trait 的 get 方法访问:未命中返回 None
642        let val = cache.get("missing").unwrap();
643        assert_eq!(val, None);
644        // 负缓存命中后仍返回 None(但内部不回源)
645        let val = cache.get("missing").unwrap();
646        assert_eq!(val, None);
647        // 写入后返回值
648        cache.set("key1", b"value1".to_vec(), None).unwrap();
649        let val = cache.get("key1").unwrap();
650        assert_eq!(val, Some(b"value1".to_vec()));
651    }
652}