1use std::time::{Duration, Instant};
9
10use crate::value::{HashData, SetData, Value, ZSetData};
11use crate::{Entry, RenameOutcome, SmallBytes, Store, glob_match, pack_deadline, unpack_deadline};
12
13impl Store {
14 pub fn del(&mut self, keys: &[Vec<u8>]) -> usize {
17 let now = Instant::now();
18 let mut removed = 0;
19 for k in keys {
20 if self.reap(k, now) && self.remove_entry(k.as_slice()).is_some() {
21 removed += 1;
22 }
23 }
24 removed
25 }
26
27 pub fn exists(&mut self, keys: &[Vec<u8>]) -> usize {
28 keys.iter().filter(|k| self.live_entry(k).is_some()).count()
29 }
30
31 pub fn expire(&mut self, key: &[u8], ttl: Duration) -> bool {
32 let now = Instant::now();
33 if !self.reap(key, now) {
34 return false;
35 }
36 if let Some(e) = self.map.get_mut(key) {
37 e.expire_at_ns = pack_deadline(now + ttl);
38 true
39 } else {
40 false
41 }
42 }
43
44 pub fn expire_at_unix_ms(&mut self, key: &[u8], deadline_ms: u64) -> bool {
54 let now = Instant::now();
55 if !self.reap(key, now) || !self.map.contains_key(key) {
56 return false;
57 }
58 let wall_now = crate::now_unix_ms();
59 if deadline_ms <= wall_now {
60 self.remove_entry(key);
62 return true;
63 }
64 let remaining = Duration::from_millis(deadline_ms - wall_now);
65 if let Some(e) = self.map.get_mut(key) {
66 e.expire_at_ns = pack_deadline(now + remaining);
67 }
68 true
69 }
70
71 pub fn take_with_ttl(&mut self, key: &[u8]) -> Option<(Value, Option<u64>)> {
78 let now = Instant::now();
79 if !self.reap(key, now) {
80 return None;
81 }
82 let entry = self.remove_entry(key)?;
83 let ttl_ms = entry.expire_at_ns.map(|ns| {
84 unpack_deadline(ns).saturating_duration_since(now).as_millis() as u64
85 });
86 Some((entry.value, ttl_ms))
87 }
88
89 pub fn put_with_ttl(&mut self, key: Vec<u8>, value: Value, ttl_ms: Option<u64>) {
95 let expire_at = ttl_ms.map(|ms| Instant::now() + Duration::from_millis(ms));
96 let entry = Entry::new(value, expire_at);
97 self.remove_entry(&key);
100 self.insert_entry(SmallBytes::from_vec(key), entry);
101 }
102
103 pub fn key_exists(&mut self, key: &[u8]) -> bool {
107 let now = Instant::now();
108 self.reap(key, now) && self.map.contains_key(key)
109 }
110
111 pub fn rename(&mut self, src: &[u8], dst: &[u8], nx: bool) -> RenameOutcome {
119 let now = Instant::now();
120 if !self.reap(src, now) {
121 return RenameOutcome::NoSuchSrc;
122 }
123 if src == dst {
124 return if nx {
128 RenameOutcome::DstExists
129 } else {
130 RenameOutcome::Renamed
131 };
132 }
133 if nx {
134 let dst_live = self.reap(dst, now) && self.map.contains_key(dst);
137 if dst_live {
138 return RenameOutcome::DstExists;
139 }
140 }
141 let Some(entry) = self.remove_entry(src) else {
144 return RenameOutcome::NoSuchSrc;
145 };
146 self.remove_entry(dst);
150 self.insert_entry(SmallBytes::from_vec(dst.to_vec()), entry);
151 RenameOutcome::Renamed
152 }
153
154 pub fn persist(&mut self, key: &[u8]) -> bool {
155 let now = Instant::now();
156 if !self.reap(key, now) {
157 return false;
158 }
159 match self.map.get_mut(key) {
160 Some(e) if e.expire_at_ns.is_some() => {
161 e.expire_at_ns = None;
162 true
163 }
164 _ => false,
165 }
166 }
167
168 pub fn pttl(&mut self, key: &[u8]) -> i64 {
170 let now = Instant::now();
171 if !self.reap(key, now) {
172 return -2;
173 }
174 match self.map.get(key).and_then(|e| e.expire_at_ns) {
175 None => -1,
176 Some(ns) => unpack_deadline(ns)
177 .saturating_duration_since(now)
178 .as_millis() as i64,
179 }
180 }
181
182 pub fn type_of(&mut self, key: &[u8]) -> &'static str {
183 let now = Instant::now();
184 if !self.reap(key, now) {
185 return "none";
186 }
187 self.map.get(key).map_or("none", |e| e.value.type_name())
188 }
189
190 pub fn dbsize(&self) -> usize {
191 self.map.len()
192 }
193
194 pub fn flush(&mut self) {
195 self.map.clear();
196 self.used_memory = 0;
197 }
199
200 pub fn ttl_pending_count(&self) -> usize {
205 let now = Instant::now();
206 self.map
207 .values()
208 .filter(|e| e.expire_at_ns.is_some() && !e.is_expired_at(now))
209 .count()
210 }
211
212 pub fn snapshot_each<F: FnMut(&[u8], &Value, Option<u64>)>(&self, mut f: F) {
216 let now = Instant::now();
217 for (k, e) in &self.map {
218 if e.is_expired_at(now) {
219 continue;
220 }
221 let ttl = e
222 .expire_at_ns
223 .map(|ns| unpack_deadline(ns).saturating_duration_since(now).as_millis() as u64);
224 f(k.as_slice(), &e.value, ttl);
225 }
226 }
227
228 fn insert_loaded(&mut self, key: Vec<u8>, value: Value, ttl_ms: Option<u64>) {
229 let expire_at = ttl_ms.map(|ms| Instant::now() + Duration::from_millis(ms));
230 self.insert_entry(SmallBytes::from_vec(key), Entry::new(value, expire_at));
231 }
232
233 pub fn load_str(&mut self, key: Vec<u8>, value: Vec<u8>, ttl_ms: Option<u64>) {
234 self.insert_loaded(key, Value::Str(SmallBytes::from_vec(value)), ttl_ms);
235 }
236
237 pub fn load_hash(
238 &mut self,
239 key: Vec<u8>,
240 fields: Vec<(Vec<u8>, Vec<u8>)>,
241 ttl_ms: Option<u64>,
242 ) {
243 let hash_data: HashData = fields
245 .into_iter()
246 .map(|(f, v)| (SmallBytes::from_vec(f), v))
247 .collect();
248 self.insert_loaded(key, Value::Hash(Box::new(hash_data)), ttl_ms);
249 }
250
251 pub fn load_list(&mut self, key: Vec<u8>, items: Vec<Vec<u8>>, ttl_ms: Option<u64>) {
252 self.insert_loaded(key, Value::List(Box::new(items.into_iter().collect())), ttl_ms);
253 }
254
255 pub fn load_set(&mut self, key: Vec<u8>, members: Vec<Vec<u8>>, ttl_ms: Option<u64>) {
256 let set_data: SetData = members.into_iter().map(SmallBytes::from_vec).collect();
257 self.insert_loaded(key, Value::Set(Box::new(set_data)), ttl_ms);
258 }
259
260 pub fn collect_keys(&self, pattern: Option<&[u8]>, limit: Option<usize>) -> Vec<Vec<u8>> {
263 let now = Instant::now();
264 let mut out = Vec::new();
265 for (k, e) in &self.map {
266 if e.is_expired_at(now) {
267 continue;
268 }
269 if let Some(p) = pattern
270 && !glob_match(p, k.as_slice())
271 {
272 continue;
273 }
274 out.push(k.to_vec());
275 if limit.is_some_and(|lim| out.len() >= lim) {
276 break;
277 }
278 }
279 out
280 }
281
282 pub fn load_zset(&mut self, key: Vec<u8>, pairs: Vec<(Vec<u8>, f64)>, ttl_ms: Option<u64>) {
283 let mut z = ZSetData::default();
284 for (m, score) in pairs {
285 z.insert(&m, score);
286 }
287 self.insert_loaded(key, Value::ZSet(Box::new(z)), ttl_ms);
288 }
289
290 pub fn load_stream(
295 &mut self,
296 key: Vec<u8>,
297 entries: Vec<crate::stream::LoadedStreamEntry>,
298 last_id: (u64, u64),
299 max_deleted_id: (u64, u64),
300 entries_added: u64,
301 ttl_ms: Option<u64>,
302 ) {
303 let mut s = crate::stream::StreamData::default();
304 for (ms, seq, fv) in entries {
305 let id = crate::stream::StreamId { ms, seq };
306 let fv_small: Vec<(SmallBytes, SmallBytes)> = fv
307 .into_iter()
308 .map(|(f, v)| (SmallBytes::from_vec(f), SmallBytes::from_vec(v)))
309 .collect();
310 s.load_entry(id, fv_small);
311 }
312 s.set_loaded_state(
313 crate::stream::StreamId { ms: last_id.0, seq: last_id.1 },
314 crate::stream::StreamId { ms: max_deleted_id.0, seq: max_deleted_id.1 },
315 entries_added,
316 );
317 self.insert_loaded(key, Value::Stream(Box::new(s)), ttl_ms);
318 }
319}