1use std::io;
13use std::time::Duration;
14
15use kevy_store::StoreError;
16
17use crate::pubsub::Subscription;
18#[cfg(not(target_arch = "wasm32"))]
19use crate::replica_glue::ensure_writable;
20use crate::store::{Store, commit_write, store_err};
21
22#[cfg(target_arch = "wasm32")]
26fn ensure_writable(_s: &Store) -> io::Result<()> { Ok(()) }
27
28impl Store {
29 pub fn set(&self, key: &[u8], value: &[u8]) -> io::Result<bool> {
36 ensure_writable(self)?;
37 let mut g = self.wshard(key);
38 let ok = g.store.set(key, value.to_vec(), None, false, false);
39 commit_write(&mut g, &[b"SET", key, value])?;
40 Ok(ok)
41 }
42
43 pub fn set_with_ttl(&self, key: &[u8], value: &[u8], ttl: Duration) -> io::Result<bool> {
49 ensure_writable(self)?;
50 let mut g = self.wshard(key);
51 let ok = g.store.set(key, value.to_vec(), Some(ttl), false, false);
52 let ms = ttl.as_millis().min(u128::from(u64::MAX)) as u64;
53 let deadline = kevy_store::now_unix_ms().saturating_add(ms);
54 commit_write(&mut g, &[b"SET", key, value])?;
55 commit_write(&mut g, &[b"PEXPIREAT", key, deadline.to_string().as_bytes()])?;
56 Ok(ok)
57 }
58
59 pub fn get(&self, key: &[u8]) -> io::Result<Option<Vec<u8>>> {
67 if self.config().maxmemory == 0 {
68 let g = self.rshard(key);
69 return Ok(g.store.get_shared(key).map_err(store_err)?.map(|c| c.into_owned()));
70 }
71 let mut g = self.wshard(key);
72 Ok(g.store.get(key).map_err(store_err)?.map(|c| c.into_owned()))
73 }
74
75 pub fn del(&self, keys: &[&[u8]]) -> io::Result<usize> {
78 ensure_writable(self)?;
79 let mut total = 0;
80 for k in keys {
81 let owned = vec![k.to_vec()];
82 let mut g = self.wshard(k);
83 let n = g.store.del(&owned);
84 if n > 0 {
85 total += n;
86 commit_write(&mut g, &[b"DEL", k])?;
87 }
88 }
89 Ok(total)
90 }
91
92 pub fn exists(&self, keys: &[&[u8]]) -> io::Result<usize> {
95 let mut total = 0;
96 for k in keys {
97 total += self.wshard(k).store.exists(&[k.to_vec()]);
98 }
99 Ok(total)
100 }
101
102 pub fn incr(&self, key: &[u8]) -> io::Result<i64> {
104 self.incr_by(key, 1)
105 }
106
107 pub fn incr_by(&self, key: &[u8], delta: i64) -> io::Result<i64> {
109 ensure_writable(self)?;
110 let mut g = self.wshard(key);
111 let n = g.store.incr_by(key, delta).map_err(store_err)?;
112 commit_write(&mut g, &[b"INCRBY", key, delta.to_string().as_bytes()])?;
113 Ok(n)
114 }
115
116 pub fn expire(&self, key: &[u8], ttl: Duration) -> io::Result<bool> {
120 ensure_writable(self)?;
121 let mut g = self.wshard(key);
122 let touched = g.store.expire(key, ttl);
123 if touched {
124 let ms = ttl.as_millis().min(u128::from(u64::MAX)) as u64;
125 let deadline = kevy_store::now_unix_ms().saturating_add(ms);
126 commit_write(&mut g, &[b"PEXPIREAT", key, deadline.to_string().as_bytes()])?;
127 }
128 Ok(touched)
129 }
130
131 pub fn persist(&self, key: &[u8]) -> io::Result<bool> {
133 ensure_writable(self)?;
134 let mut g = self.wshard(key);
135 let touched = g.store.persist(key);
136 if touched {
137 commit_write(&mut g, &[b"PERSIST", key])?;
138 }
139 Ok(touched)
140 }
141
142 pub fn ttl_ms(&self, key: &[u8]) -> i64 {
144 self.wshard(key).store.pttl(key)
145 }
146
147 pub fn type_of(&self, key: &[u8]) -> &'static str {
149 self.wshard(key).store.type_of(key)
150 }
151
152 pub fn dbsize(&self) -> usize {
154 self.sum_shards(|i| i.store.dbsize())
155 }
156
157 pub fn flushall(&self) -> io::Result<()> {
168 ensure_writable(self)?;
169 let r = self.try_for_each_shard(|inner| {
170 inner.store.flushall();
171 commit_write(inner, &[b"FLUSHALL"])
172 });
173 #[cfg(not(target_arch = "wasm32"))]
175 self.feed_bump_on_flush();
176 r
177 }
178
179 #[deprecated(
183 since = "1.2.0",
184 note = "renamed to `flushall`: `flush` collides with Write::flush (sync-to-disk); this WIPES the store"
185 )]
186 pub fn flush(&self) -> io::Result<()> {
187 self.flushall()
188 }
189
190 pub fn key_bytes(&self, key: &[u8]) -> Option<u64> {
192 self.wshard(key).store.estimate_key_bytes(key)
193 }
194
195 pub fn used_memory(&self) -> u64 {
197 self.sum_shards_u64(|i| i.store.used_memory())
198 }
199
200 pub fn evictions_total(&self) -> u64 {
202 self.sum_shards_u64(|i| i.store.evictions_total())
203 }
204
205 pub fn expired_keys_total(&self) -> u64 {
207 self.sum_shards_u64(|i| i.store.expired_keys_total())
208 }
209
210 pub fn hset(&self, key: &[u8], pairs: &[(&[u8], &[u8])]) -> io::Result<usize> {
214 ensure_writable(self)?;
215 let mut g = self.wshard(key);
216 let owned: Vec<(Vec<u8>, Vec<u8>)> =
217 pairs.iter().map(|(f, v)| (f.to_vec(), v.to_vec())).collect();
218 let added = g.store.hset(key, &owned).map_err(store_err)?;
219 let mut parts: Vec<&[u8]> = Vec::with_capacity(2 + pairs.len() * 2);
220 parts.push(b"HSET");
221 parts.push(key);
222 for (f, v) in pairs {
223 parts.push(f);
224 parts.push(v);
225 }
226 commit_write(&mut g, &parts)?;
227 Ok(added)
228 }
229
230 pub fn hget(&self, key: &[u8], field: &[u8]) -> io::Result<Option<Vec<u8>>> {
232 let mut g = self.wshard(key);
233 Ok(g.store
234 .hget(key, field)
235 .map_err(store_err)?
236 .map(<[u8]>::to_vec))
237 }
238
239 pub fn hdel(&self, key: &[u8], fields: &[&[u8]]) -> io::Result<usize> {
241 ensure_writable(self)?;
242 let mut g = self.wshard(key);
243 let owned: Vec<Vec<u8>> = fields.iter().map(|f| f.to_vec()).collect();
244 let removed = g.store.hdel(key, &owned).map_err(store_err)?;
245 if removed > 0 {
246 let mut parts: Vec<&[u8]> = Vec::with_capacity(2 + fields.len());
247 parts.push(b"HDEL");
248 parts.push(key);
249 for f in fields {
250 parts.push(f);
251 }
252 commit_write(&mut g, &parts)?;
253 }
254 Ok(removed)
255 }
256
257 pub fn lpush(&self, key: &[u8], values: &[&[u8]]) -> io::Result<usize> {
261 push_helper(self, key, values, b"LPUSH", kevy_store::Store::lpush)
262 }
263
264 pub fn rpush(&self, key: &[u8], values: &[&[u8]]) -> io::Result<usize> {
266 push_helper(self, key, values, b"RPUSH", kevy_store::Store::rpush)
267 }
268
269 pub fn lpop(&self, key: &[u8], count: usize) -> io::Result<Vec<Vec<u8>>> {
271 pop_helper(self, key, count, false)
272 }
273
274 pub fn rpop(&self, key: &[u8], count: usize) -> io::Result<Vec<Vec<u8>>> {
276 pop_helper(self, key, count, true)
277 }
278
279 pub fn llen(&self, key: &[u8]) -> io::Result<usize> {
281 self.wshard(key).store.llen(key).map_err(store_err)
282 }
283
284 pub fn sadd(&self, key: &[u8], members: &[&[u8]]) -> io::Result<usize> {
288 push_helper(self, key, members, b"SADD", kevy_store::Store::sadd)
289 }
290
291 pub fn srem(&self, key: &[u8], members: &[&[u8]]) -> io::Result<usize> {
293 ensure_writable(self)?;
294 let mut g = self.wshard(key);
295 let owned: Vec<Vec<u8>> = members.iter().map(|m| m.to_vec()).collect();
296 let removed = g.store.srem(key, &owned).map_err(store_err)?;
297 if removed > 0 {
298 let mut parts: Vec<&[u8]> = Vec::with_capacity(2 + members.len());
299 parts.push(b"SREM");
300 parts.push(key);
301 for m in members {
302 parts.push(m);
303 }
304 commit_write(&mut g, &parts)?;
305 }
306 Ok(removed)
307 }
308
309 pub fn smembers(&self, key: &[u8]) -> io::Result<Vec<Vec<u8>>> {
311 self.wshard(key).store.smembers(key).map_err(store_err)
312 }
313
314 pub fn scard(&self, key: &[u8]) -> io::Result<usize> {
316 self.wshard(key).store.scard(key).map_err(store_err)
317 }
318
319 pub fn zadd(&self, key: &[u8], pairs: &[(f64, &[u8])]) -> io::Result<usize> {
323 ensure_writable(self)?;
324 let mut g = self.wshard(key);
325 let owned: Vec<(f64, Vec<u8>)> =
326 pairs.iter().map(|(s, m)| (*s, m.to_vec())).collect();
327 let added = g.store.zadd(key, &owned).map_err(store_err)?;
328 let mut score_strs: Vec<Vec<u8>> = Vec::with_capacity(pairs.len());
329 for (s, _) in pairs {
330 score_strs.push(format!("{s}").into_bytes());
331 }
332 let mut parts: Vec<&[u8]> = Vec::with_capacity(2 + pairs.len() * 2);
333 parts.push(b"ZADD");
334 parts.push(key);
335 for (i, (_, m)) in pairs.iter().enumerate() {
336 parts.push(&score_strs[i]);
337 parts.push(m);
338 }
339 commit_write(&mut g, &parts)?;
340 Ok(added)
341 }
342
343 pub fn zrem(&self, key: &[u8], members: &[&[u8]]) -> io::Result<usize> {
345 ensure_writable(self)?;
346 let mut g = self.wshard(key);
347 let owned: Vec<Vec<u8>> = members.iter().map(|m| m.to_vec()).collect();
348 let removed = g.store.zrem(key, &owned).map_err(store_err)?;
349 if removed > 0 {
350 let mut parts: Vec<&[u8]> = Vec::with_capacity(2 + members.len());
351 parts.push(b"ZREM");
352 parts.push(key);
353 for m in members {
354 parts.push(m);
355 }
356 commit_write(&mut g, &parts)?;
357 }
358 Ok(removed)
359 }
360
361 pub fn zscore(&self, key: &[u8], member: &[u8]) -> io::Result<Option<f64>> {
363 self.wshard(key).store.zscore(key, member).map_err(store_err)
364 }
365
366 pub fn zcard(&self, key: &[u8]) -> io::Result<usize> {
368 self.wshard(key).store.zcard(key).map_err(store_err)
369 }
370
371 pub fn publish(&self, channel: &[u8], payload: &[u8]) -> usize {
377 let plans = {
380 let g = self.lock();
382 g.bus.collect_delivery(channel, payload)
383 };
384 let mut count = 0;
385 for (frame, sender) in plans {
386 if sender.send(frame).is_ok() {
387 count += 1;
388 }
389 }
390 count
391 }
392
393 pub fn subscribe(&self, channels: &[&[u8]]) -> Subscription {
398 let mut sub = Subscription::new(self.inner_handle(), self.guard_handle());
399 if !channels.is_empty() {
400 sub.subscribe(channels);
401 }
402 sub
403 }
404
405 pub fn psubscribe(&self, patterns: &[&[u8]]) -> Subscription {
407 let mut sub = Subscription::new(self.inner_handle(), self.guard_handle());
408 if !patterns.is_empty() {
409 sub.psubscribe(patterns);
410 }
411 sub
412 }
413}
414
415fn push_helper<F>(
420 s: &Store,
421 key: &[u8],
422 values: &[&[u8]],
423 verb: &'static [u8],
424 op: F,
425) -> io::Result<usize>
426where
427 F: FnOnce(&mut kevy_store::Store, &[u8], &[Vec<u8>]) -> Result<usize, StoreError>,
428{
429 ensure_writable(s)?;
430 let mut g = s.wshard(key);
431 let owned: Vec<Vec<u8>> = values.iter().map(|v| v.to_vec()).collect();
432 let n = op(&mut g.store, key, &owned).map_err(store_err)?;
433 let mut parts: Vec<&[u8]> = Vec::with_capacity(2 + values.len());
434 parts.push(verb);
435 parts.push(key);
436 for v in values {
437 parts.push(v);
438 }
439 commit_write(&mut g, &parts)?;
440 Ok(n)
441}
442
443fn pop_helper(s: &Store, key: &[u8], count: usize, from_tail: bool) -> io::Result<Vec<Vec<u8>>> {
444 ensure_writable(s)?;
445 let mut g = s.wshard(key);
446 let popped = if from_tail {
447 g.store.rpop(key, count).map_err(store_err)?
448 } else {
449 g.store.lpop(key, count).map_err(store_err)?
450 };
451 if !popped.is_empty() {
452 let verb: &[u8] = if from_tail { b"RPOP" } else { b"LPOP" };
453 let count_str = popped.len().to_string();
454 let parts: [&[u8]; 3] = [verb, key, count_str.as_bytes()];
455 commit_write(&mut g, &parts)?;
456 }
457 Ok(popped)
458}