moka_cache/
lib.rs

1#![allow(non_upper_case_globals)]
2use anyhow::{anyhow, Result};
3use bincode::config;
4pub use bincode::{Decode, Encode};
5pub use moka::notification::RemovalCause;
6use moka::{sync::Cache, Equivalent, Expiry};
7#[allow(unused_imports)]
8use serde::{de::DeserializeOwned, Deserialize, Serialize};
9use std::{
10    hash::Hash,
11    sync::Arc,
12    sync::OnceLock,
13    time::{Duration, Instant},
14};
15
16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17pub enum Expiration {
18    Never,
19    Second(u64),
20    Minute(u64),
21    Hour(u64),
22}
23
24impl Expiration {
25    pub fn as_duration(&self) -> Option<Duration> {
26        match self {
27            Expiration::Never => None,
28            Expiration::Second(v) => Some(Duration::from_secs(*v)),
29            Expiration::Minute(v) => Some(Duration::from_secs(*v * 60)),
30            Expiration::Hour(v) => Some(Duration::from_secs(*v * 60 * 60)),
31        }
32    }
33}
34
35pub struct CacheExpiry;
36
37pub type CacheData = (Expiration, Vec<u8>);
38
39type AppCache = Cache<String, (Expiration, Vec<u8>)>;
40
41impl Expiry<String, (Expiration, Vec<u8>)> for CacheExpiry {
42    #[allow(unused_variables)]
43    fn expire_after_create(
44        &self,
45        key: &String,
46        value: &(Expiration, Vec<u8>),
47        current_time: Instant,
48    ) -> Option<Duration> {
49        value.0.as_duration()
50    }
51}
52
53static CacheHand: OnceLock<AppCache> = OnceLock::new();
54
55//初始化缓存
56pub fn setup(
57    callback: Option<fn(Arc<String>, CacheData, RemovalCause)>,
58    max_cap: u64,
59) -> Result<()> {
60    let mut c = Cache::builder()
61        .max_capacity(max_cap)
62        .expire_after(CacheExpiry {});
63
64    if let Some(callback) = callback {
65        c = c.eviction_listener(callback);
66    }
67    let c = c.build();
68    CacheHand
69        .set(c)
70        .map_err(|e| anyhow!("setup cache error:{:?}", e))?;
71    Ok(())
72}
73
74pub fn insert<K, V>(key: K, value: V, exp: Expiration) -> Result<()>
75where
76    K: Into<String>,
77    V: Serialize + Encode + Sync + Send,
78{
79    let cache = CacheHand.get().ok_or_else(|| anyhow!("cache is null"))?;
80    let k = key.into();
81    let b = bincode::encode_to_vec(&value, config::standard().with_little_endian())?;
82    cache.insert(k, (exp, b));
83    Ok(())
84}
85
86pub fn get<K, V>(key: &K) -> Option<(Expiration, V)>
87where
88    K: Equivalent<String> + Hash + ?Sized,
89    V: DeserializeOwned + Decode<()> + Sync + Send,
90{
91    if let Some(h) = CacheHand.get() {
92        let v = h.get(key)?;
93        let c = config::standard();
94        let b = bincode::decode_from_slice::<V, _>(v.1.as_ref(), c);
95        if let Ok((value, _)) = b {
96            return Some((v.0, value));
97        }
98        if let Err(e) = b {
99            log::error!("cache deserialize error: {}", e.to_string());
100        }
101        return None;
102    }
103
104    None
105}
106
107pub fn get_exp<K>(key: &K) -> Option<Expiration>
108where
109    K: Equivalent<String> + Hash + ?Sized,
110{
111    let value = CacheHand.get().map(|h| h.get(key)).unwrap_or(None);
112    if let Some(v) = value {
113        return Some(v.0);
114    }
115    None
116}
117
118pub fn remove<K>(key: &K)
119where
120    K: Equivalent<String> + Hash + ?Sized,
121{
122    CacheHand.get().map(|h| {
123        h.invalidate(key);
124    });
125}
126
127pub fn contains_key<K>(key: &K) -> bool
128where
129    K: Equivalent<String> + Hash + ?Sized,
130{
131    CacheHand
132        .get()
133        .map(|h| h.contains_key(key))
134        .unwrap_or(false)
135}
136
137//每隔10检查缓存是否过期
138pub fn check_exp_interval() {
139    if let Some(cache) = CacheHand.get() {
140        cache.run_pending_tasks();
141    }
142}
143
144// 刷新key ttl
145pub fn refresh<K>(key: &K) -> Result<()>
146where
147    K: Equivalent<String> + Hash + std::fmt::Display + ?Sized,
148{
149    let value = get(key);
150
151    let Some(value) = value else {
152        return Err(anyhow!("key: {} not found", key));
153    };
154
155    if value.0 == Expiration::Never {
156        return Ok(());
157    }
158
159    remove(key);
160
161    if let Some(c) = CacheHand.get() {
162        c.insert(key.to_string(), value);
163    }
164
165    Ok(())
166}
167
168#[cfg(test)]
169#[allow(dead_code)]
170mod test {
171
172    use super::*;
173    use std::thread::sleep;
174
175    fn cache_key_expired(_key: Arc<String>, _: CacheData, _case: RemovalCause) {}
176    fn init() {
177        setup(Some(cache_key_expired), 512).unwrap();
178    }
179
180    #[test]
181    fn test_encode_decode() {
182        let value: i32 = 1000;
183        let config = config::standard().with_little_endian();
184        let b = bincode::encode_to_vec(&value, config).unwrap();
185        println!("b-->{:?}", b);
186        let (value, _) = bincode::decode_from_slice::<i32, _>(b.as_ref(), config).unwrap();
187        println!("value-->{}", value);
188    }
189
190    #[test]
191    fn test_cache_u16() {
192        init();
193        remove("test_cache_get_u1622");
194        insert("test_cache_get_u1622", 1000, Expiration::Never).unwrap();
195        let v = get::<_, u32>("test_cache_get_u1622");
196        println!("test_cache_get_u1622-->{:?}", v);
197    }
198
199    #[test]
200    fn test_cache_byte() {
201        init();
202        let b = b"hello world".to_vec();
203        insert("test_cache_get_byte", b, Expiration::Never).unwrap();
204        let v = get::<_, Vec<u8>>("test_cache_get_byte");
205        println!("test_cache_get_byte-->{:?}", v);
206    }
207
208    #[test]
209    fn test_cache_struct() {
210        #[derive(Encode, Decode, Debug, Clone, Serialize, Deserialize)]
211        struct Config {
212            pub path: String,
213            pub cache_capacity: u32,
214            pub len: usize,
215        }
216        init();
217        let b = Config {
218            path: "test".to_string(),
219            cache_capacity: 1024,
220            len: 1024,
221        };
222        insert("test_cache_struct", b, Expiration::Never).unwrap();
223        let v = get::<_, Config>("test_cache_struct");
224        println!("test_cache_struct-->{:?}", v);
225    }
226
227    #[test]
228    fn test_cache_get() {
229        init();
230
231        //
232        insert("test_cache_get", "hello world", Expiration::Never).unwrap();
233        let v = get::<_, String>("test_cache_get");
234        println!("test_cache_get--->: {:?}", v);
235
236        //
237        insert("test_cache_get_bool", true, Expiration::Never).unwrap();
238        let v = get::<_, bool>("test_cache_get_bool");
239        println!("test_cache_get_bool-->{:?}", v);
240
241        insert("test_cache_get_bool_false", false, Expiration::Never).unwrap();
242        let v = get::<_, bool>("test_cache_get_bool_false");
243        println!("test_cache_get_bool_false-->{:?}", v);
244
245        //
246        insert("test_cache_get_i32", 1000, Expiration::Never).unwrap();
247        let v = get::<_, i32>("test_cache_get_i32");
248        println!("test_cache_get_i32-->{:?}", v);
249
250        //
251        insert(
252            "test_cache_get_byte",
253            b"hello world".to_vec(),
254            Expiration::Never,
255        )
256        .unwrap();
257        let v = get::<_, Vec<u8>>("test_cache_get_byte");
258        println!("test_cache_get_byte-->{:?}", v);
259    }
260
261    //
262    fn test_src_mcache() {
263        let expiry = CacheExpiry;
264
265        let eviction_listener = |key, value, cause| {
266            println!("过期 key-----> {key}. value--> {value:?}. Cause: {cause:?}");
267        };
268
269        let cache = Cache::builder()
270            .max_capacity(100)
271            .expire_after(expiry)
272            .eviction_listener(eviction_listener)
273            .build();
274
275        cache.insert("0".to_string(), (Expiration::Second(5), b"a".to_vec()));
276        cache.insert("1".to_string(), (Expiration::Second(6), b"b".to_vec()));
277        cache.insert("2".to_string(), (Expiration::Never, b"c".to_vec()));
278        cache.insert("3".to_string(), (Expiration::Never, b"3333".to_vec()));
279        //update
280        cache.insert(
281            "0".to_string(),
282            (Expiration::Second(10), b"abbbbaa".to_vec()),
283        );
284
285        println!("Entry count: {}", cache.entry_count());
286
287        let Some(v) = cache.get("0") else {
288            println!("cache.get(&0): none");
289            return;
290        };
291        println!("cache.get(&0): {:?}", v);
292
293        println!("0 {}", cache.contains_key("0"));
294        println!("1 {}", cache.contains_key("1"));
295        println!("2 {}", cache.contains_key("2"));
296        println!("3 {}", cache.contains_key("3"));
297
298        let re = cache.remove("3");
299        println!("remove:{:?}", re);
300
301        println!("\n Sleeping for 6 seconds...\n");
302        sleep(Duration::from_secs(6));
303
304        println!("Entry count: {}", cache.entry_count());
305        println!("0 {}", cache.contains_key("0"));
306        println!("1 {}", cache.contains_key("1"));
307        println!("2 {}", cache.contains_key("2"));
308        println!("3 {}", cache.contains_key("3"));
309
310        let Some(v) = cache.get("2") else {
311            return;
312        };
313        println!("cache.get(2): {:?}", v);
314        sleep(Duration::from_secs(6));
315    }
316
317    fn test_cache_evication() {
318        let _ = check_exp_interval();
319        insert("check_evication", "过期了value", Expiration::Second(5)).unwrap();
320        sleep(Duration::from_secs(3));
321        println!("sleep 3s");
322
323        let (_, v) = get::<_, String>("check_evication").unwrap();
324        println!("get_string:{:?}", v);
325        println!("sleep 3s");
326        sleep(Duration::from_secs(3));
327        println!("contains_key:{:?}", contains_key("check_evication"));
328        sleep(Duration::from_secs(3));
329        //println!("get_string:{:?}", get_string("check_evication"));
330    }
331
332    //
333    fn test_cache_delete() {
334        let key = "key_u64";
335        // insert_u64("key_u64", 555, Expiration::Second(6));
336
337        println!("sleep 3s");
338        sleep(Duration::from_secs(3));
339        println!("get_exp:{:?}", get_exp(key));
340        //   println!("get_u64:{:?}", get_u64(&key));
341
342        println!("update:");
343        remove(key);
344        sleep(Duration::from_secs(1));
345
346        // insert_u64(key.to_string(), 666, Expiration::Second(12));
347        // println!("get_exp:{:?}", get_exp(&key));
348        // println!("get_u64:{:?}", get_u64(&key));
349
350        // println!("sleep 3s");
351        // sleep(Duration::from_secs(3));
352        println!("get_exp:{:?}", get_exp(key));
353        // println!("get_u64:{:?}", get_u64(&key));
354    }
355
356    //
357    fn test_cache_refresh() {
358        let key = "key_u64";
359        //insert_u64("key_u64", 555, Expiration::Second(6));
360
361        println!("sleep 3s");
362        sleep(Duration::from_secs(3));
363        let Some(exp_at) = get_exp(key) else {
364            return;
365        };
366        println!("get_exp:{:?}", exp_at);
367        //   println!("get_u64:{:?}", get_u64(&key));
368
369        println!("del:");
370        remove(key);
371
372        // insert_u64(key, 666, exp_at);
373        println!("get_exp:{:?}", get_exp(key));
374        // println!("get_u64:{:?}", get_u64(&key));
375
376        println!("sleep 3s");
377        sleep(Duration::from_secs(2));
378        println!("get_exp:{:?}", get_exp(key));
379        //println!("get_u64:{:?}", get_u64(&key));
380
381        println!("sleep 5s");
382        sleep(Duration::from_secs(2));
383        println!("get_exp:{:?}", get_exp(key));
384        //  println!("get_u64:{:?}", get_u64(&key));
385    }
386
387    //
388    fn test_cache_refresh2() {
389        let key = "key_u64";
390        //insert_u64(key, 555, Expiration::Second(4));
391
392        println!("sleep 2s");
393        sleep(Duration::from_secs(2));
394
395        println!("refresh: ");
396        refresh(key).expect("refresh error");
397
398        println!("sleep 5s");
399        sleep(Duration::from_secs(5));
400        println!("get_exp:{:?}", get_exp(key));
401        //  println!("get_u64:{:?}", get_u64(&key));
402    }
403}