inner_mem_cache/
lib.rs

1use std::collections::HashMap;
2use std::collections::LinkedList;
3use std::hash::Hash;
4use std::sync::Arc;
5
6mod timeoutset;
7
8pub use timeoutset::TimeoutSet;
9
10pub enum MemCacheMode {
11    None,
12    TryClearAtUpdate,
13}
14
15impl MemCacheMode {
16    pub fn is_try_clear(&self) -> bool {
17        match self {
18            MemCacheMode::TryClearAtUpdate => true,
19            _ => false,
20        }
21    }
22}
23
24impl Default for MemCacheMode {
25    fn default() -> Self {
26        Self::TryClearAtUpdate
27    }
28}
29
30#[derive(Default)]
31pub struct MemCache<K, T>
32where
33    K: Eq + Hash,
34{
35    map: HashMap<K, (u64, T)>,
36    time_set: TimeoutSet<K>,
37    last_clear_time: u64,
38    try_clear_interval: u64,
39    pub mode: MemCacheMode,
40    pub time_out_fn: Option<Arc<dyn Fn(K, T) + Send + Sync>>,
41}
42
43fn now_millis() -> u64 {
44    use std::time::SystemTime;
45    SystemTime::now()
46        .duration_since(SystemTime::UNIX_EPOCH)
47        .unwrap()
48        .as_millis() as u64
49}
50
51impl<K, T> MemCache<K, T>
52where
53    K: Eq + Hash + Clone,
54    T: Clone,
55{
56    pub fn new() -> Self {
57        Self::new_with_clear_interval(10000)
58    }
59    pub fn new_with_clear_interval(interval_millis: u64) -> Self {
60        Self {
61            map: Default::default(),
62            time_set: Default::default(),
63            last_clear_time: 0u64,
64            try_clear_interval: interval_millis,
65            mode: MemCacheMode::TryClearAtUpdate,
66            time_out_fn: None,
67        }
68    }
69
70    fn build_last_time(cache_sec: i32) -> u64 {
71        if cache_sec == -1i32 {
72            0
73        } else {
74            ((cache_sec * 1000) as u64) + now_millis()
75        }
76    }
77
78    fn try_clear(&mut self) {
79        if !self.mode.is_try_clear() {
80            return;
81        }
82        let current_time = now_millis();
83        if current_time - self.try_clear_interval > self.last_clear_time {
84            self.clear_time_out();
85        }
86    }
87
88    pub fn get_time_out_keys(&self) -> LinkedList<&K> {
89        let current_time = now_millis();
90        self.time_set.get_timeout_values(current_time)
91    }
92
93    pub fn clear_time_out(&mut self) {
94        let current_time = now_millis();
95        let list = self.time_set.timeout(current_time);
96        for item in list {
97            if let Some((t, _)) = self.map.get(&item) {
98                if *t > current_time {
99                    continue;
100                }
101                let (_, v) = self.map.remove(&item).unwrap();
102                if let Some(f) = &self.time_out_fn {
103                    f(item, v);
104                }
105            }
106        }
107        self.last_clear_time = current_time;
108    }
109
110    pub fn set(&mut self, key: K, val: T, cache_sec: i32) {
111        self.try_clear();
112        if cache_sec == 0i32 || cache_sec < -1i32 {
113            return;
114        }
115        let last_time = Self::build_last_time(cache_sec);
116        self.time_set.add(last_time, key.clone());
117        self.map.insert(key, (last_time, val));
118    }
119
120    pub fn update_time_out(&mut self, key: &K, cache_sec: i32) {
121        self.try_clear();
122        if cache_sec == 0i32 || cache_sec < -1i32 {
123            return;
124        }
125        match self.get(key) {
126            Ok(_) => {
127                let last_time = Self::build_last_time(cache_sec);
128                self.time_set.add(last_time, key.clone());
129            }
130            Err(_) => {}
131        };
132    }
133
134    pub fn get(&self, key: &K) -> Result<T, String> {
135        match self.map.get(key) {
136            Some((t, v)) => {
137                if *t == 0 {
138                    return Ok(v.clone());
139                } else if now_millis() > *t {
140                    return Err("Expried".to_owned());
141                }
142                Ok(v.clone())
143            }
144            None => Err("NOT FOUND".to_owned()),
145        }
146    }
147
148    /// return the key value time to live;
149    /// The unit of time returned is seconds
150    pub fn time_to_live(&self, key: &K) -> i32 {
151        match self.map.get(key) {
152            Some((t, _)) => {
153                let now = now_millis();
154                if *t > now {
155                    ((*t - now) / 1000) as i32
156                } else {
157                    -1
158                }
159            }
160            None => -1,
161        }
162    }
163
164    pub fn remove(&mut self, key: &K) -> Option<T> {
165        self.try_clear();
166        match self.map.remove(key) {
167            Some((_, v)) => Some(v),
168            _ => None,
169        }
170    }
171
172    pub fn len(&self) -> usize {
173        self.time_set.len()
174    }
175
176    pub fn item_size(&self) -> usize {
177        self.time_set.item_size()
178    }
179}
180
181#[cfg(test)]
182mod tests {
183    use super::*;
184    use std::time::Duration;
185
186    fn time_out_print(k: String, v: String) {
187        println!("============ time out,{}:{}", &k, &v);
188    }
189
190    #[test]
191    fn test01() {
192        let mut m = MemCache::new_with_clear_interval(100);
193        //m.time_out_fn = Some(Arc::new(time_out_print));
194        let ref_info = Arc::new(1);
195        m.time_out_fn = Some(Arc::new(move |k, v| {
196            println!("============ time out,{}:{}", &k, &v);
197            println!("ref_info ,{}", &ref_info)
198        }));
199        let name = "name".to_owned();
200        m.set("name".to_owned(), "abc".to_owned(), 1);
201        println!("1.{:?}", m.get(&name));
202        assert!(m.get(&name).is_ok());
203        std::thread::sleep(Duration::from_millis(1001));
204        println!("2:{:?}", m.get(&name));
205        assert!(m.get(&name).is_err());
206        m.set("name".to_owned(), "abc".to_owned(), 1);
207        println!("3:{:?}", m.get(&name));
208        assert!(m.get(&name).is_ok());
209        std::thread::sleep(Duration::from_millis(1001));
210        assert!(m.get(&name).is_err());
211        println!("4:{:?}", m.get(&name));
212        std::thread::sleep(Duration::from_millis(1001));
213        m.clear_time_out()
214    }
215}