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 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 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}