1use yo_common::Result;
31
32use crate::array::Array;
33use crate::hash::Hash;
34use crate::keyspace::Keyspace;
35use crate::list::List;
36use crate::set::Set;
37use crate::value::{self, Kind};
38use crate::zset::Zset;
39
40#[derive(Debug, Clone)]
46pub struct Record {
47 body: Body,
48 expire_at: Option<u64>,
51}
52
53impl Record {
54 #[must_use]
56 pub const fn kind(&self) -> Kind {
57 match self.body {
58 Body::String(_) => Kind::String,
59 Body::Set(_) => Kind::Set,
60 Body::Hash(_) => Kind::Hash,
61 Body::List(_) => Kind::List,
62 Body::Zset(_) => Kind::Zset,
63 Body::Array(_) => Kind::Array,
64 }
65 }
66
67 #[must_use]
69 pub const fn expire_at(&self) -> Option<u64> {
70 self.expire_at
71 }
72}
73
74#[derive(Debug, Clone)]
82enum Body {
83 String(Vec<u8>),
84 Set(Set),
85 Hash(Hash),
86 List(List),
87 Zset(Zset),
88 Array(Array),
89}
90
91#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93pub enum Moved {
94 Missing,
96 Taken,
98 Ok,
100}
101
102impl Keyspace {
103 pub fn export(&mut self, key: &[u8]) -> Option<Record> {
112 let addr = self.live_rec(key)?;
113 let rec = self.map.value_at(addr);
114 let expire_at = value::expire_at(rec);
115 let body = match value::kind(rec) {
119 Kind::String => Body::String(value::read(rec).to_vec()),
120 Kind::Set => Body::Set(
121 self.sets
122 .get(value::slot(rec))
123 .expect("the record points at its body")
124 .clone(),
125 ),
126 Kind::Hash => Body::Hash(
127 self.hashes
128 .get(value::slot(rec))
129 .expect("the record points at its body")
130 .clone(),
131 ),
132 Kind::List => Body::List(
133 self.lists
134 .get(value::slot(rec))
135 .expect("the record points at its body")
136 .clone(),
137 ),
138 Kind::Zset => Body::Zset(
139 self.zsets
140 .get(value::slot(rec))
141 .expect("the record points at its body")
142 .clone(),
143 ),
144 Kind::Array => Body::Array(
145 self.arrays
146 .get(value::slot(rec))
147 .expect("the record points at its body")
148 .clone(),
149 ),
150 Kind::Stream => unreachable!("nothing can store a stream yet"),
153 };
154 Some(Record { body, expire_at })
155 }
156
157 pub fn import(&mut self, key: &[u8], rec: Record) {
163 let at = rec.expire_at;
164 match rec.body {
165 Body::String(bytes) => self.store(key, &bytes, at),
168 Body::Set(set) => {
169 self.free_body(key);
170 let slot = self.sets.insert(set);
171 self.bodies += 1;
172 self.write_slot(key, Kind::Set, slot, at);
173 }
174 Body::Hash(hash) => {
175 self.free_body(key);
176 let slot = self.hashes.insert(hash);
177 self.bodies += 1;
178 self.write_slot(key, Kind::Hash, slot, at);
179 }
180 Body::List(list) => {
181 self.free_body(key);
182 let slot = self.lists.insert(list);
183 self.bodies += 1;
184 self.write_slot(key, Kind::List, slot, at);
185 }
186 Body::Zset(zset) => {
187 self.free_body(key);
188 let slot = self.zsets.insert(zset);
189 self.bodies += 1;
190 self.write_slot(key, Kind::Zset, slot, at);
191 }
192 Body::Array(array) => {
193 self.free_body(key);
194 let slot = self.arrays.insert(array);
195 self.bodies += 1;
196 self.write_slot(key, Kind::Array, slot, at);
197 }
198 }
199 }
200
201 pub fn rename(&mut self, src: &[u8], dst: &[u8], only_if_new: bool) -> Moved {
218 if self.live_rec(src).is_none() {
219 return Moved::Missing;
220 }
221 let same = src == dst;
222 if only_if_new && (same || self.live_rec(dst).is_some()) {
223 return Moved::Taken;
224 }
225 if same {
226 return Moved::Ok;
227 }
228 let addr = self.map.find(src).expect("it was live a line ago");
232 let bytes = self.map.value_at(addr).to_vec();
233 self.free_body(dst);
234 self.map.set_with(dst, bytes.len(), |out| {
235 out.copy_from_slice(&bytes);
236 });
237 self.map.del(src);
241 Moved::Ok
242 }
243
244 pub fn copy(&mut self, src: &[u8], dst: &[u8], replace: bool) -> Moved {
255 let Some(rec) = self.export(src) else {
256 return Moved::Missing;
257 };
258 if !replace && self.live_rec(dst).is_some() {
259 return Moved::Taken;
260 }
261 self.import(dst, rec);
262 Moved::Ok
263 }
264
265 pub fn touch<'k>(&mut self, keys: impl Iterator<Item = &'k [u8]>) -> usize {
272 keys.filter(|key| self.exists(key)).count()
273 }
274
275 fn write_slot(&mut self, key: &[u8], kind: Kind, slot: u32, at: Option<u64>) {
279 let len = value::slot_record_len(at.is_some());
280 self.map.set_with(key, len, |out| {
281 value::write_slot_record(out, kind, slot, at);
282 });
283 }
284}
285
286#[must_use]
292pub fn no_such_key() -> yo_common::Error {
293 yo_common::Error::new(yo_common::Code::Invalid, "no such key")
294}
295
296impl Moved {
301 pub fn found(self) -> Result<Moved> {
308 match self {
309 Moved::Missing => Err(no_such_key()),
310 other => Ok(other),
311 }
312 }
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318 use crate::Clock;
319 use crate::End;
320 use crate::zsets::ZAdd;
321
322 fn db() -> Keyspace {
323 Keyspace::with_clock(Clock::fixed(1_000_000))
324 }
325
326 fn members(d: &mut Keyspace, key: &[u8]) -> Vec<String> {
327 let mut out: Vec<String> = d
328 .smembers(key)
329 .expect("a set")
330 .expect("a key")
331 .map(|m| String::from_utf8(m.to_vec()).expect("utf8 in these tests"))
332 .collect();
333 out.sort();
334 out
335 }
336
337 fn put(d: &mut Keyspace, key: &[u8], val: &[u8]) {
338 d.set_plain(key, val).expect("room for a record");
339 }
340
341 fn read(d: &mut Keyspace, key: &[u8]) -> Vec<u8> {
342 d.get(key).expect("a string").expect("there").to_vec()
343 }
344
345 #[test]
346 fn a_rename_moves_the_value_and_leaves_nothing_behind() {
347 let mut d = db();
348 put(&mut d, b"a", b"v1");
349
350 assert_eq!(d.rename(b"a", b"b", false), Moved::Ok);
351 assert!(!d.exists(b"a"));
352 assert_eq!(read(&mut d, b"b"), b"v1");
353 }
354
355 #[test]
356 fn a_rename_with_no_source_is_the_one_error_in_this_file() {
357 let mut d = db();
358 assert_eq!(d.rename(b"a", b"b", false), Moved::Missing);
359 assert_eq!(d.rename(b"a", b"b", true), Moved::Missing);
360 assert_eq!(
361 d.copy(b"a", b"b", false),
362 Moved::Missing,
363 "copy just says 0"
364 );
365 }
366
367 #[test]
368 fn a_rename_carries_the_source_deadline_and_drops_the_destination_one() {
369 let mut d = db();
370 put(&mut d, b"a", b"v1");
371 d.set_expiry(b"a", Some(2_000_000));
372 put(&mut d, b"b", b"v2");
373 d.set_expiry(b"b", Some(1_500_000));
374
375 assert_eq!(d.rename(b"a", b"b", false), Moved::Ok);
376 assert_eq!(d.deadline_of(b"b"), crate::Ask::At(2_000_000));
377 }
378
379 #[test]
380 fn renaming_a_key_onto_itself_keeps_it_and_renamenx_refuses() {
381 let mut d = db();
382 put(&mut d, b"a", b"v1");
383 d.set_expiry(b"a", Some(2_000_000));
384
385 assert_eq!(d.rename(b"a", b"a", false), Moved::Ok);
386 assert_eq!(read(&mut d, b"a"), b"v1");
387 assert_eq!(d.deadline_of(b"a"), crate::Ask::At(2_000_000));
388 assert_eq!(d.rename(b"a", b"a", true), Moved::Taken);
389 }
390
391 #[test]
392 fn renamenx_writes_over_nothing() {
393 let mut d = db();
394 put(&mut d, b"a", b"v1");
395 put(&mut d, b"b", b"v2");
396
397 assert_eq!(d.rename(b"a", b"b", true), Moved::Taken);
398 assert_eq!(read(&mut d, b"a"), b"v1");
399 assert_eq!(read(&mut d, b"b"), b"v2");
400 assert_eq!(d.rename(b"a", b"c", true), Moved::Ok);
401 assert!(!d.exists(b"a"));
402 }
403
404 #[test]
405 fn renaming_a_set_moves_the_slot_and_not_the_members() {
406 let mut d = db();
407 d.sadd(b"s", [b"m1".as_ref(), b"m2".as_ref()].into_iter())
408 .expect("a set");
409 let before = d.memory_bytes();
410
411 assert_eq!(d.rename(b"s", b"t", false), Moved::Ok);
412 assert_eq!(members(&mut d, b"t"), ["m1", "m2"]);
413 assert_eq!(d.kind_of(b"t"), Some(Kind::Set));
414 assert!(!d.exists(b"s"));
415 assert!(
418 d.memory_bytes().abs_diff(before) < 64,
419 "the members were not copied"
420 );
421 }
422
423 #[test]
424 fn renaming_over_a_set_frees_the_set_that_was_there() {
425 let mut d = db();
426 d.sadd(b"s", [b"m1".as_ref()].into_iter()).expect("a set");
427 d.sadd(b"t", [b"m2".as_ref()].into_iter()).expect("a set");
428 assert_eq!(d.sets.len(), 2);
429
430 assert_eq!(d.rename(b"s", b"t", false), Moved::Ok);
431 assert_eq!(d.sets.len(), 1, "the destination's body went with it");
432 assert_eq!(members(&mut d, b"t"), ["m1"]);
433 }
434
435 #[test]
436 fn a_copy_is_a_second_value_and_not_a_second_name() {
437 let mut d = db();
438 d.sadd(b"s", [b"m1".as_ref(), b"m2".as_ref()].into_iter())
439 .expect("a set");
440
441 assert_eq!(d.copy(b"s", b"t", false), Moved::Ok);
442 d.sadd(b"t", [b"m3".as_ref()].into_iter()).expect("a set");
443 assert_eq!(
444 members(&mut d, b"s"),
445 ["m1", "m2"],
446 "the original is intact"
447 );
448 assert_eq!(members(&mut d, b"t"), ["m1", "m2", "m3"]);
449 }
450
451 #[test]
452 fn a_copy_refuses_a_destination_it_was_not_told_it_could_have() {
453 let mut d = db();
454 put(&mut d, b"a", b"v1");
455 put(&mut d, b"b", b"v2");
456
457 assert_eq!(d.copy(b"a", b"b", false), Moved::Taken);
458 assert_eq!(read(&mut d, b"b"), b"v2");
459 assert_eq!(d.copy(b"a", b"b", true), Moved::Ok);
460 assert_eq!(read(&mut d, b"b"), b"v1");
461 }
462
463 #[test]
464 fn a_copy_carries_the_deadline() {
465 let mut d = db();
466 put(&mut d, b"a", b"v1");
467 d.set_expiry(b"a", Some(2_000_000));
468
469 assert_eq!(d.copy(b"a", b"b", false), Moved::Ok);
470 assert_eq!(d.deadline_of(b"b"), crate::Ask::At(2_000_000));
471 assert_eq!(d.deadline_of(b"a"), crate::Ask::At(2_000_000));
472 }
473
474 #[test]
475 fn a_destination_that_has_already_gone_counts_as_free() {
476 let mut d = db();
477 put(&mut d, b"a", b"v1");
478 put(&mut d, b"b", b"v2");
479 d.set_expiry(b"b", Some(999_999));
480
481 assert_eq!(d.copy(b"a", b"b", false), Moved::Ok, "b was already gone");
482 assert_eq!(read(&mut d, b"b"), b"v1");
483 }
484
485 #[test]
486 fn a_source_that_has_already_gone_is_not_a_source() {
487 let mut d = db();
488 put(&mut d, b"a", b"v1");
489 d.set_expiry(b"a", Some(999_999));
490
491 assert_eq!(d.rename(b"a", b"b", false), Moved::Missing);
492 assert_eq!(d.copy(b"a", b"b", false), Moved::Missing);
493 }
494
495 #[test]
496 fn a_record_taken_out_of_a_database_outlives_it() {
497 let mut from = db();
498 from.sadd(b"s", [b"m1".as_ref(), b"m2".as_ref()].into_iter())
499 .expect("a set");
500 let rec = from.export(b"s").expect("a record");
501 assert_eq!(rec.kind(), Kind::Set);
502 from.clear();
503
504 let mut into = db();
505 into.import(b"s", rec);
506 assert_eq!(members(&mut into, b"s"), ["m1", "m2"]);
507 }
508
509 #[test]
510 fn importing_over_a_body_does_not_leave_it_in_the_slab() {
511 let mut d = db();
512 d.sadd(b"s", [b"m1".as_ref()].into_iter()).expect("a set");
513 d.sadd(b"t", [b"m2".as_ref()].into_iter()).expect("a set");
514 let rec = d.export(b"s").expect("a record");
515
516 d.import(b"t", rec);
517 assert_eq!(d.sets.len(), 2, "s and t, and not the one t used to hold");
518 assert_eq!(members(&mut d, b"t"), ["m1"]);
519 }
520
521 #[test]
522 fn importing_a_string_over_a_set_frees_the_set() {
523 let mut d = db();
524 put(&mut d, b"a", b"v1");
525 d.sadd(b"s", [b"m1".as_ref()].into_iter()).expect("a set");
526 assert_eq!(d.sets.len(), 1);
527
528 assert_eq!(d.copy(b"a", b"s", true), Moved::Ok);
529 assert_eq!(d.sets.len(), 0, "the set went when the string arrived");
530 assert_eq!(d.kind_of(b"s"), Some(Kind::String));
531 }
532
533 #[test]
545 fn a_list_can_be_copied_and_the_copy_is_its_own() {
546 let mut d = db();
547 d.push(b"l", End::Left, [b"a".as_ref(), b"b".as_ref()].into_iter())
548 .expect("a list");
549
550 assert_eq!(d.copy(b"l", b"m", false), Moved::Ok);
551 assert_eq!(d.kind_of(b"m"), Some(Kind::List));
552 assert_eq!(d.llen(b"m").expect("a list"), 2);
553
554 d.push(b"m", End::Left, [b"c".as_ref()].into_iter())
555 .expect("a list");
556 assert_eq!(d.llen(b"l").expect("a list"), 2, "the source did not grow");
557 assert_eq!(d.llen(b"m").expect("a list"), 3);
558 }
559
560 #[test]
562 fn a_zset_can_be_copied_and_the_copy_is_its_own() {
563 let mut d = db();
564 d.zadd(b"z", [(1.0, b"m1".as_ref())].into_iter(), ZAdd::default())
565 .expect("a zset");
566
567 assert_eq!(d.copy(b"z", b"y", false), Moved::Ok);
568 assert_eq!(d.kind_of(b"y"), Some(Kind::Zset));
569 assert_eq!(d.zscore(b"y", b"m1").expect("a zset"), Some(1.0));
570
571 d.zadd(b"y", [(2.0, b"m2".as_ref())].into_iter(), ZAdd::default())
572 .expect("a zset");
573 assert_eq!(d.zcard(b"z").expect("a zset"), 1, "the source did not grow");
574 assert_eq!(d.zcard(b"y").expect("a zset"), 2);
575 }
576
577 #[test]
584 fn copying_over_a_list_frees_the_list() {
585 let mut d = db();
586 put(&mut d, b"a", b"v1");
587 d.push(b"l", End::Left, [b"x".as_ref()].into_iter())
588 .expect("a list");
589
590 assert_eq!(d.copy(b"a", b"l", true), Moved::Ok);
591 assert_eq!(d.kind_of(b"l"), Some(Kind::String));
592 assert_eq!(read(&mut d, b"l"), b"v1");
593 }
594
595 #[test]
596 fn touch_counts_the_way_exists_counts() {
597 let mut d = db();
598 put(&mut d, b"a", b"v1");
599 put(&mut d, b"b", b"v2");
600
601 assert_eq!(d.touch([b"a".as_ref()].into_iter()), 1);
602 assert_eq!(d.touch([b"a".as_ref(), b"b".as_ref()].into_iter()), 2);
603 assert_eq!(d.touch([b"a".as_ref(), b"a".as_ref()].into_iter()), 2);
604 assert_eq!(d.touch([b"a".as_ref(), b"z".as_ref()].into_iter()), 1);
605 assert_eq!(d.touch([b"z".as_ref()].into_iter()), 0);
606 }
607}