rust_cache_server/
store.rs1use std::sync::atomic::{AtomicU64, Ordering};
2use std::sync::Arc;
3use std::time::{Duration, Instant};
4
5use dashmap::DashMap;
6use tokio::time;
7
8#[derive(Clone, Debug)]
9pub struct Value {
10 pub data: Vec<u8>,
11 pub expires_at: Option<Instant>,
12}
13
14impl Value {
15 pub fn new(data: Vec<u8>, ttl: Option<Duration>) -> Self {
16 let expires_at = ttl.map(|d| Instant::now() + d);
17 Self { data, expires_at }
18 }
19
20 pub fn is_expired(&self) -> bool {
21 if let Some(exp) = self.expires_at {
22 Instant::now() >= exp
23 } else {
24 false
25 }
26 }
27}
28
29#[derive(Default)]
30pub struct Store {
31 inner: DashMap<String, Value>,
32 max_memory_bytes: Option<u64>,
33 used_bytes: AtomicU64,
34}
35
36impl Store {
37 pub fn new(max_memory_bytes: Option<u64>) -> Self {
38 Self {
39 inner: DashMap::new(),
40 max_memory_bytes,
41 used_bytes: AtomicU64::new(0),
42 }
43 }
44
45 fn value_size(value: &Value) -> u64 {
46 value.data.len() as u64
47 }
48
49 pub fn get(&self, key: &str) -> Option<Vec<u8>> {
50 if let Some(entry) = self.inner.get(key) {
51 if entry.is_expired() {
52 drop(entry);
53 if let Some((_, old)) = self.inner.remove(key) {
54 let size = Self::value_size(&old);
55 self.used_bytes
56 .fetch_sub(size, Ordering::Relaxed);
57 }
58 None
59 } else {
60 Some(entry.data.clone())
61 }
62 } else {
63 None
64 }
65 }
66
67 pub fn set(
68 &self,
69 key: String,
70 value: Vec<u8>,
71 ttl: Option<Duration>,
72 ) -> Result<(), ()> {
73 let new_value = Value::new(value, ttl);
74 let new_size = Self::value_size(&new_value);
75
76 let mut old_size = 0;
77 if let Some(old) = self.inner.get(&key) {
78 old_size = Self::value_size(&old);
79 }
80
81 let prev = self
83 .used_bytes
84 .fetch_add(new_size.saturating_sub(old_size), Ordering::Relaxed);
85 let after = prev + new_size.saturating_sub(old_size);
86
87 if let Some(limit) = self.max_memory_bytes {
88 if after > limit {
89 self.used_bytes
91 .fetch_sub(new_size.saturating_sub(old_size), Ordering::Relaxed);
92 return Err(());
93 }
94 }
95
96 self.inner.insert(key, new_value);
97 Ok(())
98 }
99
100 pub fn del(&self, keys: &[String]) -> usize {
101 let mut removed = 0;
102 for k in keys {
103 if let Some((_, v)) = self.inner.remove(k) {
104 let size = Self::value_size(&v);
105 self.used_bytes
106 .fetch_sub(size, Ordering::Relaxed);
107 removed += 1;
108 }
109 }
110 removed
111 }
112
113 pub fn expire(&self, key: &str, ttl: Duration) -> bool {
114 if let Some(mut entry) = self.inner.get_mut(key) {
115 if entry.is_expired() {
116 drop(entry);
117 if let Some((_, v)) = self.inner.remove(key) {
118 let size = Self::value_size(&v);
119 self.used_bytes
120 .fetch_sub(size, Ordering::Relaxed);
121 }
122 false
123 } else {
124 entry.expires_at = Some(Instant::now() + ttl);
125 true
126 }
127 } else {
128 false
129 }
130 }
131
132 pub fn ttl(&self, key: &str) -> Option<Duration> {
133 if let Some(entry) = self.inner.get(key) {
134 if let Some(exp) = entry.expires_at {
135 if Instant::now() >= exp {
136 drop(entry);
137 if let Some((_, v)) = self.inner.remove(key) {
138 let size = Self::value_size(&v);
139 self.used_bytes
140 .fetch_sub(size, Ordering::Relaxed);
141 }
142 None
143 } else {
144 Some(exp.saturating_duration_since(Instant::now()))
145 }
146 } else {
147 None
148 }
149 } else {
150 None
151 }
152 }
153
154 pub fn keys(&self) -> Vec<String> {
156 let mut result = Vec::new();
157 for entry in self.inner.iter() {
158 if entry.is_expired() {
159 continue;
160 }
161 result.push(entry.key().clone());
162 }
163 result
164 }
165
166 pub fn clear_all(&self) {
168 self.inner.clear();
169 self.used_bytes.store(0, Ordering::Relaxed);
170 }
171
172 pub fn incr_by(&self, key: &str, delta: i64, create_if_missing: bool) -> Option<i64> {
176 let current = if let Some(entry) = self.inner.get(key) {
178 if entry.is_expired() {
179 drop(entry);
180 if let Some((_, old)) = self.inner.remove(key) {
181 let size = Self::value_size(&old);
182 self.used_bytes.fetch_sub(size, Ordering::Relaxed);
183 }
184 None
185 } else {
186 match std::str::from_utf8(&entry.data) {
188 Ok(s) => s.trim().parse::<i64>().ok(),
189 Err(_) => None,
190 }
191 }
192 } else {
193 None
194 };
195
196 let new_value = if let Some(val) = current {
197 val.checked_add(delta)?
198 } else if create_if_missing {
199 delta
200 } else {
201 return None;
202 };
203
204 let new_data = new_value.to_string().into_bytes();
206 let new_value_obj = Value::new(new_data.clone(), None);
207 let new_size = Self::value_size(&new_value_obj);
208
209 let old_size = if let Some(old) = self.inner.get(key) {
210 Self::value_size(&old)
211 } else {
212 0
213 };
214
215 if let Some(limit) = self.max_memory_bytes {
217 let prev = self.used_bytes.load(Ordering::Relaxed);
218 let after = prev + new_size.saturating_sub(old_size);
219 if after > limit {
220 return None;
221 }
222 }
223
224 self.used_bytes
226 .fetch_add(new_size.saturating_sub(old_size), Ordering::Relaxed);
227
228 self.inner.insert(key.to_string(), new_value_obj);
229 Some(new_value)
230 }
231}
232
233pub fn spawn_cleanup(store: Arc<Store>, interval: Duration) {
234 tokio::spawn(async move {
235 let mut ticker = time::interval(interval);
236 loop {
237 ticker.tick().await;
238
239 let mut expired_keys = Vec::new();
241 for entry in store.inner.iter() {
242 if entry.is_expired() {
243 expired_keys.push(entry.key().clone());
244 }
245 }
246
247 for key in expired_keys {
248 if let Some((_, v)) = store.inner.remove(&key) {
249 let size = Store::value_size(&v);
250 store
251 .used_bytes
252 .fetch_sub(size, Ordering::Relaxed);
253 }
254 }
255 }
256 });
257}
258
259
260