1use crate::{KevyError, KevyResult};
15use std::sync::RwLockWriteGuard;
16
17use crate::shard::shard_idx;
18use crate::store::{Inner, Store, commit_write, store_err};
19
20use crate::store::ensure_writable;
21
22type ShardUndoEntry = (usize, Vec<u8>, Option<(kevy_store::Value, Option<u64>)>);
25
26pub struct AtomicAllShards<'a> {
29 pub(crate) guards: Vec<RwLockWriteGuard<'a, Inner>>,
30 log: Vec<(usize, Vec<Vec<u8>>)>,
32 undo: Vec<ShardUndoEntry>,
38 touched: std::collections::HashSet<Vec<u8>>,
39 #[cfg(feature = "index")]
44 pub(crate) indexes: std::sync::Arc<crate::ops_index::IndexReg>,
45}
46
47impl<'a> AtomicAllShards<'a> {
48 pub(crate) fn idx(&self, key: &[u8]) -> usize {
49 shard_idx(key, self.guards.len())
50 }
51
52
53 fn snap(&mut self, key: &[u8]) {
55 if self.touched.contains(key) {
56 return;
57 }
58 let i = self.idx(key);
59 let prior = self.guards[i].store.clone_with_ttl(key);
60 self.touched.insert(key.to_vec());
61 self.undo.push((i, key.to_vec(), prior));
62 }
63
64 fn log_arg(&mut self, idx: usize, parts: &[&[u8]]) {
65 self.log
66 .push((idx, parts.iter().map(|p| p.to_vec()).collect()));
67 }
68
69 pub fn set(&mut self, key: &[u8], value: &[u8]) -> bool {
73 self.snap(key);
74 let i = self.idx(key);
75 let ok = self.guards[i]
76 .store
77 .set(key, value.to_vec(), None, false, false);
78 self.log_arg(i, &[b"SET", key, value]);
79 ok
80 }
81
82 pub fn get(&mut self, key: &[u8]) -> KevyResult<Option<Vec<u8>>> {
84 let i = self.idx(key);
85 self.guards[i]
86 .store
87 .get(key)
88 .map(|opt| opt.as_deref().map(<[u8]>::to_vec))
89 .map_err(store_err)
90 }
91
92 pub fn incr(&mut self, key: &[u8]) -> KevyResult<i64> {
94 self.snap(key);
95 let i = self.idx(key);
96 let n = self.guards[i].store.incr_by(key, 1).map_err(store_err)?;
97 self.log_arg(i, &[b"INCR", key]);
98 Ok(n)
99 }
100
101 pub fn incr_by(&mut self, key: &[u8], delta: i64) -> KevyResult<i64> {
103 self.snap(key);
104 let i = self.idx(key);
105 let n = self.guards[i].store.incr_by(key, delta).map_err(store_err)?;
106 let s = format!("{delta}");
107 self.log_arg(i, &[b"INCRBY", key, s.as_bytes()]);
108 Ok(n)
109 }
110
111 pub fn hset(&mut self, key: &[u8], pairs: &[(&[u8], &[u8])]) -> KevyResult<usize> {
116 self.snap(key);
117 let i = self.idx(key);
118 let n = self.guards[i]
119 .store
120 .hset(key, pairs)
121 .map_err(store_err)?;
122 let mut parts: Vec<&[u8]> = Vec::with_capacity(2 + pairs.len() * 2);
123 parts.push(b"HSET");
124 parts.push(key);
125 for (f, v) in pairs {
126 parts.push(f);
127 parts.push(v);
128 }
129 self.log_arg(i, &parts);
130 Ok(n)
131 }
132
133 pub fn hget(&mut self, key: &[u8], field: &[u8]) -> KevyResult<Option<Vec<u8>>> {
135 let i = self.idx(key);
136 Ok(self.guards[i]
137 .store
138 .hget(key, field)
139 .map_err(store_err)?
140 .map(<[u8]>::to_vec))
141 }
142
143 pub fn hincrby(&mut self, key: &[u8], field: &[u8], delta: i64) -> KevyResult<i64> {
145 self.snap(key);
146 let i = self.idx(key);
147 let n = self.guards[i]
148 .store
149 .hincrby(key, field, delta)
150 .map_err(store_err)?;
151 let s = format!("{delta}");
152 self.log_arg(i, &[b"HINCRBY", key, field, s.as_bytes()]);
153 Ok(n)
154 }
155
156 pub fn zadd(&mut self, key: &[u8], pairs: &[(f64, &[u8])]) -> KevyResult<usize> {
161 self.snap(key);
162 let i = self.idx(key);
163 let n = self.guards[i]
164 .store
165 .zadd(key, pairs)
166 .map_err(store_err)?;
167 let score_strs: Vec<Vec<u8>> = pairs
168 .iter()
169 .map(|(s, _)| format!("{s}").into_bytes())
170 .collect();
171 let mut parts: Vec<&[u8]> = Vec::with_capacity(2 + pairs.len() * 2);
172 parts.push(b"ZADD");
173 parts.push(key);
174 for (j, (_, m)) in pairs.iter().enumerate() {
175 parts.push(&score_strs[j]);
176 parts.push(m);
177 }
178 self.log_arg(i, &parts);
179 Ok(n)
180 }
181
182 pub fn zincrby(&mut self, key: &[u8], delta: f64, member: &[u8]) -> KevyResult<f64> {
184 self.snap(key);
185 let i = self.idx(key);
186 let n = self.guards[i]
187 .store
188 .zincrby(key, delta, member)
189 .map_err(store_err)?;
190 let s = format!("{delta}");
191 self.log_arg(i, &[b"ZINCRBY", key, s.as_bytes(), member]);
192 Ok(n)
193 }
194
195 pub fn zscore(&mut self, key: &[u8], member: &[u8]) -> KevyResult<Option<f64>> {
197 let i = self.idx(key);
198 self.guards[i].store.zscore(key, member).map_err(store_err)
199 }
200
201 pub fn del(&mut self, keys: &[&[u8]]) -> usize {
206 for k in keys {
207 self.snap(k);
208 }
209 let mut n = 0;
210 for k in keys {
211 let i = self.idx(k);
212 if self.guards[i].store.del(&[k]) > 0 {
213 n += 1;
214 self.log_arg(i, &[b"DEL", k]);
215 }
216 }
217 n
218 }
219
220 pub fn exists(&mut self, keys: &[&[u8]]) -> usize {
222 keys.iter()
223 .filter(|k| {
224 let i = self.idx(k);
225 self.guards[i].store.key_exists(k)
226 })
227 .count()
228 }
229
230 pub fn hdel(&mut self, key: &[u8], fields: &[&[u8]]) -> KevyResult<usize> {
234 self.snap(key);
235 let i = self.idx(key);
236 let removed = self.guards[i].store.hdel(key, fields).map_err(store_err)?;
237 if removed > 0 {
238 let mut argv: Vec<&[u8]> = Vec::with_capacity(2 + fields.len());
239 argv.push(b"HDEL");
240 argv.push(key);
241 argv.extend_from_slice(fields);
242 self.log_arg(i, &argv);
243 }
244 Ok(removed)
245 }
246
247 pub fn hgetall(&mut self, key: &[u8]) -> KevyResult<Vec<(Vec<u8>, Vec<u8>)>> {
249 let i = self.idx(key);
250 let flat = self.guards[i].store.hgetall(key).map_err(store_err)?;
251 let mut out = Vec::with_capacity(flat.len() / 2);
252 let mut it = flat.into_iter();
253 while let (Some(f), Some(v)) = (it.next(), it.next()) {
254 out.push((f, v));
255 }
256 Ok(out)
257 }
258
259 pub fn hmget(&mut self, key: &[u8], fields: &[&[u8]]) -> KevyResult<Vec<Option<Vec<u8>>>> {
261 let i = self.idx(key);
262 self.guards[i].store.hmget(key, fields).map_err(store_err)
263 }
264
265 pub fn hexists(&mut self, key: &[u8], field: &[u8]) -> KevyResult<bool> {
267 let i = self.idx(key);
268 self.guards[i].store.hexists(key, field).map_err(store_err)
269 }
270
271 pub fn sadd(&mut self, key: &[u8], members: &[&[u8]]) -> KevyResult<usize> {
275 self.snap(key);
276 let i = self.idx(key);
277 let added = self.guards[i].store.sadd(key, members).map_err(store_err)?;
278 if added > 0 {
279 let mut argv: Vec<&[u8]> = Vec::with_capacity(2 + members.len());
280 argv.push(b"SADD");
281 argv.push(key);
282 argv.extend_from_slice(members);
283 self.log_arg(i, &argv);
284 }
285 Ok(added)
286 }
287
288 pub fn srem(&mut self, key: &[u8], members: &[&[u8]]) -> KevyResult<usize> {
290 self.snap(key);
291 let i = self.idx(key);
292 let removed = self.guards[i].store.srem(key, members).map_err(store_err)?;
293 if removed > 0 {
294 let mut argv: Vec<&[u8]> = Vec::with_capacity(2 + members.len());
295 argv.push(b"SREM");
296 argv.push(key);
297 argv.extend_from_slice(members);
298 self.log_arg(i, &argv);
299 }
300 Ok(removed)
301 }
302
303 pub fn lpush(&mut self, key: &[u8], values: &[&[u8]]) -> KevyResult<usize> {
307 self.snap(key);
308 let i = self.idx(key);
309 let len = self.guards[i].store.lpush(key, values).map_err(store_err)?;
310 let mut argv: Vec<&[u8]> = Vec::with_capacity(2 + values.len());
311 argv.push(b"LPUSH");
312 argv.push(key);
313 argv.extend_from_slice(values);
314 self.log_arg(i, &argv);
315 Ok(len)
316 }
317
318 pub fn rpush(&mut self, key: &[u8], values: &[&[u8]]) -> KevyResult<usize> {
320 self.snap(key);
321 let i = self.idx(key);
322 let len = self.guards[i].store.rpush(key, values).map_err(store_err)?;
323 let mut argv: Vec<&[u8]> = Vec::with_capacity(2 + values.len());
324 argv.push(b"RPUSH");
325 argv.push(key);
326 argv.extend_from_slice(values);
327 self.log_arg(i, &argv);
328 Ok(len)
329 }
330
331 pub fn zrem(&mut self, key: &[u8], members: &[&[u8]]) -> KevyResult<usize> {
335 self.snap(key);
336 let i = self.idx(key);
337 let removed = self.guards[i].store.zrem(key, members).map_err(store_err)?;
338 if removed > 0 {
339 let mut argv: Vec<&[u8]> = Vec::with_capacity(2 + members.len());
340 argv.push(b"ZREM");
341 argv.push(key);
342 argv.extend_from_slice(members);
343 self.log_arg(i, &argv);
344 }
345 Ok(removed)
346 }
347
348 pub fn zcard(&mut self, key: &[u8]) -> KevyResult<usize> {
350 let i = self.idx(key);
351 self.guards[i].store.zcard(key).map_err(store_err)
352 }
353
354 pub fn zadd_flags(
357 &mut self,
358 key: &[u8],
359 pairs: &[(f64, &[u8])],
360 flags: kevy_store::ZaddFlags,
361 ) -> KevyResult<kevy_store::ZaddReport> {
362 if !flags.valid() {
363 return Err(KevyError::InvalidInput("invalid ZADD flag combo".into()));
364 }
365 let i = self.idx(key);
366 let rep = self.guards[i]
367 .store
368 .zadd_flags(key, pairs, flags)
369 .map_err(store_err)?;
370 if !rep.applied.is_empty() {
371 let score_strs: Vec<Vec<u8>> = rep
372 .applied
373 .iter()
374 .map(|(s, _)| format!("{s}").into_bytes())
375 .collect();
376 let mut parts: Vec<&[u8]> = Vec::with_capacity(2 + rep.applied.len() * 2);
377 parts.push(b"ZADD");
378 parts.push(key);
379 for (j, (_, m)) in rep.applied.iter().enumerate() {
380 parts.push(&score_strs[j]);
381 parts.push(m);
382 }
383 self.log_arg(i, &parts);
384 }
385 Ok(rep)
386 }
387}
388
389impl Store {
390 pub fn atomic_all_shards<R>(
399 &self,
400 body: impl FnOnce(&mut AtomicAllShards<'_>) -> KevyResult<R>,
401 ) -> KevyResult<R> {
402 ensure_writable(self)?;
403 let guards: Vec<RwLockWriteGuard<'_, Inner>> = self
406 .shards
407 .iter()
408 .map(|s| s.write().expect("lock poisoned"))
409 .collect();
410 let mut ctx = AtomicAllShards {
411 guards,
412 log: Vec::new(),
413 undo: Vec::new(),
414 touched: std::collections::HashSet::new(),
415 #[cfg(feature = "index")]
416 indexes: std::sync::Arc::clone(&self.indexes),
417 };
418 let outcome = body(&mut ctx);
419 let log = std::mem::take(&mut ctx.log);
420 let undo = std::mem::take(&mut ctx.undo);
421 let r = match outcome {
422 Ok(r) => r,
423 Err(e) => {
424 rollback_all(&mut ctx.guards, undo);
425 return Err(e);
426 }
427 };
428 commit_group_all(&mut ctx.guards, log)?;
429 Ok(r)
430 }
431}
432
433#[cfg_attr(not(test), allow(dead_code))]
437pub(crate) const ATOMIC_ALL_OPS: &[&str] = &[
438 "SET", "GET", "INCR", "INCRBY", "HSET", "HGET", "HINCRBY", "ZADD",
439 "ZINCRBY", "ZSCORE", "DEL", "EXISTS", "HDEL", "HGETALL", "HMGET",
440 "HEXISTS", "SADD", "SREM", "LPUSH", "RPUSH", "ZREM", "ZCARD",
441 "SMEMBERS", "SISMEMBER", "LRANGE", "LLEN", "SCARD", "ZRANGEBYSCORE",
442];
443
444fn rollback_all(guards: &mut [RwLockWriteGuard<'_, Inner>], undo: Vec<ShardUndoEntry>) {
447 for (idx, key, prior) in undo.into_iter().rev() {
448 let g = &mut guards[idx];
449 match prior {
450 Some((value, ttl_ms)) => g.store.put_with_ttl(key, value, ttl_ms),
451 None => {
452 let k: &[u8] = &key;
453 g.store.del(&[k]);
454 }
455 }
456 }
457}
458
459fn commit_group_all(
463 guards: &mut [RwLockWriteGuard<'_, Inner>],
464 log: Vec<(usize, Vec<Vec<u8>>)>,
465) -> KevyResult<()> {
466 #[cfg(feature = "persist")]
467 for g in guards.iter_mut() {
468 if let Some(aof) = g.aof.as_mut() {
469 aof.begin_group();
470 }
471 }
472 let mut commit = Ok(());
473 for (idx, parts) in log {
474 let g = &mut guards[idx];
475 let refs: Vec<&[u8]> = parts.iter().map(|v| v.as_slice()).collect();
476 commit = commit_write(g, &refs);
477 if commit.is_err() {
478 break;
479 }
480 }
481 #[cfg(feature = "persist")]
482 for g in guards.iter_mut() {
483 if let Some(aof) = g.aof.as_mut() {
484 let synced = aof.end_group().map_err(KevyError::from);
485 if commit.is_ok() {
486 commit = synced;
487 }
488 }
489 }
490 commit
491}