hehe_store/local/
memory_cache.rs1use 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}