hehe_store/local/
memory_cache.rs

1use crate::error::Result;
2use crate::traits::CacheStore;
3use async_trait::async_trait;
4use moka::future::Cache;
5use parking_lot::RwLock;
6use std::collections::HashMap;
7use std::sync::atomic::{AtomicI64, Ordering};
8use std::sync::Arc;
9use std::time::Duration;
10
11pub struct MemoryCache {
12    cache: Cache<String, Vec<u8>>,
13    counters: Arc<RwLock<HashMap<String, AtomicI64>>>,
14}
15
16impl MemoryCache {
17    pub fn new(max_capacity: u64) -> Self {
18        Self {
19            cache: Cache::builder()
20                .max_capacity(max_capacity)
21                .time_to_idle(Duration::from_secs(3600))
22                .build(),
23            counters: Arc::new(RwLock::new(HashMap::new())),
24        }
25    }
26
27    pub fn with_ttl(max_capacity: u64, default_ttl: Duration) -> Self {
28        Self {
29            cache: Cache::builder()
30                .max_capacity(max_capacity)
31                .time_to_live(default_ttl)
32                .build(),
33            counters: Arc::new(RwLock::new(HashMap::new())),
34        }
35    }
36}
37
38impl Default for MemoryCache {
39    fn default() -> Self {
40        Self::new(10000)
41    }
42}
43
44#[async_trait]
45impl CacheStore for MemoryCache {
46    async fn get(&self, key: &str) -> Result<Option<Vec<u8>>> {
47        Ok(self.cache.get(key).await)
48    }
49
50    async fn set(&self, key: &str, value: &[u8], _ttl: Option<Duration>) -> Result<()> {
51        self.cache.insert(key.to_string(), value.to_vec()).await;
52        Ok(())
53    }
54
55    async fn delete(&self, key: &str) -> Result<bool> {
56        let existed = self.cache.contains_key(key);
57        self.cache.remove(key).await;
58        Ok(existed)
59    }
60
61    async fn exists(&self, key: &str) -> Result<bool> {
62        Ok(self.cache.contains_key(key))
63    }
64
65    async fn mget(&self, keys: &[&str]) -> Result<Vec<Option<Vec<u8>>>> {
66        let mut results = Vec::with_capacity(keys.len());
67        for key in keys {
68            results.push(self.cache.get(*key).await);
69        }
70        Ok(results)
71    }
72
73    async fn mset(&self, entries: &[(&str, &[u8])], _ttl: Option<Duration>) -> Result<()> {
74        for (key, value) in entries {
75            self.cache.insert((*key).to_string(), value.to_vec()).await;
76        }
77        Ok(())
78    }
79
80    async fn incr(&self, key: &str, delta: i64) -> Result<i64> {
81        let counters = self.counters.read();
82        if let Some(counter) = counters.get(key) {
83            return Ok(counter.fetch_add(delta, Ordering::SeqCst) + delta);
84        }
85        drop(counters);
86
87        let mut counters = self.counters.write();
88        let counter = counters
89            .entry(key.to_string())
90            .or_insert_with(|| AtomicI64::new(0));
91        Ok(counter.fetch_add(delta, Ordering::SeqCst) + delta)
92    }
93
94    async fn expire(&self, _key: &str, _ttl: Duration) -> Result<bool> {
95        Ok(true)
96    }
97
98    async fn ttl(&self, _key: &str) -> Result<Option<Duration>> {
99        Ok(None)
100    }
101
102    async fn keys(&self, pattern: &str) -> Result<Vec<String>> {
103        let pattern = pattern.replace('*', "");
104        let mut result = Vec::new();
105
106        self.cache.run_pending_tasks().await;
107
108        for (key, _) in self.cache.iter() {
109            if pattern.is_empty() || key.contains(&pattern) {
110                result.push(key.to_string());
111            }
112        }
113
114        Ok(result)
115    }
116
117    async fn clear(&self) -> Result<()> {
118        self.cache.invalidate_all();
119        self.cache.run_pending_tasks().await;
120        self.counters.write().clear();
121        Ok(())
122    }
123
124    async fn len(&self) -> Result<usize> {
125        self.cache.run_pending_tasks().await;
126        Ok(self.cache.entry_count() as usize)
127    }
128
129    fn backend_name(&self) -> &'static str {
130        "memory"
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use super::*;
137
138    #[tokio::test]
139    async fn test_memory_cache_basic() {
140        let cache = MemoryCache::new(100);
141
142        cache.set("key1", b"value1", None).await.unwrap();
143        cache.set("key2", b"value2", None).await.unwrap();
144
145        let v1 = cache.get("key1").await.unwrap();
146        assert_eq!(v1, Some(b"value1".to_vec()));
147
148        let v2 = cache.get("key2").await.unwrap();
149        assert_eq!(v2, Some(b"value2".to_vec()));
150
151        let missing = cache.get("nonexistent").await.unwrap();
152        assert!(missing.is_none());
153    }
154
155    #[tokio::test]
156    async fn test_memory_cache_exists_delete() {
157        let cache = MemoryCache::new(100);
158
159        assert!(!cache.exists("key").await.unwrap());
160
161        cache.set("key", b"value", None).await.unwrap();
162        assert!(cache.exists("key").await.unwrap());
163
164        let deleted = cache.delete("key").await.unwrap();
165        assert!(deleted);
166        assert!(!cache.exists("key").await.unwrap());
167
168        let deleted_again = cache.delete("key").await.unwrap();
169        assert!(!deleted_again);
170    }
171
172    #[tokio::test]
173    async fn test_memory_cache_mget_mset() {
174        let cache = MemoryCache::new(100);
175
176        cache
177            .mset(&[("a", b"1"), ("b", b"2"), ("c", b"3")], None)
178            .await
179            .unwrap();
180
181        let results = cache.mget(&["a", "b", "nonexistent", "c"]).await.unwrap();
182        assert_eq!(results.len(), 4);
183        assert_eq!(results[0], Some(b"1".to_vec()));
184        assert_eq!(results[1], Some(b"2".to_vec()));
185        assert_eq!(results[2], None);
186        assert_eq!(results[3], Some(b"3".to_vec()));
187    }
188
189    #[tokio::test]
190    async fn test_memory_cache_incr() {
191        let cache = MemoryCache::new(100);
192
193        let v1 = cache.incr("counter", 1).await.unwrap();
194        assert_eq!(v1, 1);
195
196        let v2 = cache.incr("counter", 5).await.unwrap();
197        assert_eq!(v2, 6);
198
199        let v3 = cache.decr("counter", 2).await.unwrap();
200        assert_eq!(v3, 4);
201    }
202
203    #[tokio::test]
204    async fn test_memory_cache_clear() {
205        let cache = MemoryCache::new(100);
206
207        cache.set("a", b"1", None).await.unwrap();
208        cache.set("b", b"2", None).await.unwrap();
209
210        let len_before = cache.len().await.unwrap();
211        assert!(len_before > 0);
212
213        cache.clear().await.unwrap();
214
215        let len_after = cache.len().await.unwrap();
216        assert_eq!(len_after, 0);
217    }
218
219    #[tokio::test]
220    async fn test_memory_cache_string_helpers() {
221        let cache = MemoryCache::new(100);
222
223        cache.set_string("msg", "hello world", None).await.unwrap();
224
225        let value = cache.get_string("msg").await.unwrap();
226        assert_eq!(value, Some("hello world".to_string()));
227    }
228}