Skip to main content

yo_kv/
db.rs

1//! One database, cut into stripes.
2//!
3//! A [`Keyspace`] is one map and one arena and it is reached with `&mut`, which
4//! means one command at a time and so one thread at a time. That is the whole
5//! reason `yodb serve` runs on one core: not the socket layer, not the parser,
6//! the fact that the thing underneath every command can only be held by one
7//! caller.
8//!
9//! A database here is several keyspaces instead of one. A key belongs to
10//! exactly one of them, decided by its hash and by nothing else, so two
11//! commands on two different keys are two commands on two different objects
12//! and there is nothing for them to queue behind. Which stripe a key is on is a
13//! function of the key alone, so it does not move, and no index anywhere has to
14//! record it.
15//!
16//! One stripe is a database exactly as it was, and that is the default here.
17//!
18//! What more than one stripe cost was two things, and both of them are paid.
19//! A command that names several keys is no longer handed one keyspace and
20//! resolves each key against the database instead, and everything that walks a
21//! whole database walks all of the stripes: the expiry cycle, eviction,
22//! compaction, `SCAN`, `KEYS`, `RANDOMKEY`, the settings and the snapshot. A
23//! database is held by more than one thread now, one stripe at a time each.
24
25use yo_common::Small;
26use yo_common::lock::{Held, Lock};
27use yo_index::Cursor as KeyCursor;
28
29use crate::value::Kind;
30use crate::{Clock, Keyspace};
31
32/// The most stripes one database can be cut into.
33///
34/// Two fields decide this and they agree. Eight bits of hash are free above the
35/// directory and they are what chooses the stripe, and eight bits of a `SCAN`
36/// cursor are free above the bucket and they are what remembers which stripe a
37/// walk had got to. It is far more than a machine has cores and the point of
38/// the ceiling is not to be reached, it is to keep both of those choices inside
39/// a field nothing else is reading.
40pub const MAX_STRIPES: usize = 1 << yo_index::STRIPE_BITS;
41
42/// Which end of the hash the stripe number is cut from.
43///
44/// The index inside a keyspace takes the top of the hash for its directory,
45/// counting down from bit 56, and the bottom six bits for the bucket inside a
46/// segment. Both ends are spoken for, and a stripe number cut from either one
47/// would move together with the thing it is supposed to be independent of:
48/// every key on a stripe would land in the same corner of that stripe's index.
49/// The eight bits above the directory are the ones nothing else reads.
50const STRIPE_SHIFT: u32 = 56;
51
52/// One database.
53///
54/// Holds the keys a client sees under one `SELECT`, spread over one or more
55/// keyspaces. A caller that knows which key it wants asks [`Db::at`] and gets
56/// the one keyspace that key can be in. A caller that wants the whole database
57/// walks [`Db::stripes_mut`], and the answers it adds up are the same answers a
58/// single keyspace would have given.
59pub struct Db {
60    /// The stripes, always a power of two of them and always at least one.
61    ///
62    /// Each one behind a lock, because a database is going to be reached by
63    /// more than one thread and a stripe is the piece one command holds. A
64    /// caller that has this database by exclusive reference does not go near
65    /// the locks: the borrow checker has already proved that nobody else is
66    /// looking, so `at` and every whole database walk go through `get_mut` and
67    /// pay nothing. The locks are for the callers that have it shared.
68    stripes: Vec<Lock<Keyspace>>,
69    /// `stripes.len() - 1`, kept here so the hot path is a shift and an and
70    /// rather than a division.
71    mask: u64,
72    /// What every stripe's clock was last set to.
73    ///
74    /// A copy rather than a lookup, so that asking what the time is does not
75    /// mean taking a stripe. Every stripe carries the same reading and they are
76    /// all moved together, so this is that reading and not a fourth opinion.
77    clock: Clock,
78    /// The buffers for work that is not any one stripe's, behind a lock of
79    /// their own. [`Db::spare`] has the order they are taken in and why there
80    /// is one set of them rather than one per thread.
81    spare: Lock<Spare>,
82}
83
84/// Somewhere to put bytes and rows that came out of one stripe and are wanted
85/// while another stripe is being held.
86///
87/// The sources of a `BITOP`, the element a cross stripe `LMOVE` is carrying,
88/// the tables a set operation fills in. Every stripe has buffers of its own for
89/// its own work, and these are the ones for work that is nobody's.
90#[derive(Default)]
91pub(crate) struct Spare {
92    /// The bytes.
93    pub(crate) bytes: Vec<u8>,
94    /// Where each of the things in `bytes` ends, for the callers that put more
95    /// than one thing in it.
96    pub(crate) rows: Vec<usize>,
97    /// The tables a set operation across stripes fills in.
98    ///
99    /// A keyspace keeps a pair of these for the set operations that happen
100    /// inside it, for the reason [`crate::setops::Scratch`] gives: building the
101    /// table per call was most of what a `SUNION` over text sets did. An
102    /// operation whose keys are on several stripes is not any one stripe's, so
103    /// it gets its own.
104    pub(crate) setops: crate::setops::Scratch,
105}
106
107impl Db {
108    /// A database of `stripes` empty keyspaces on `clock`.
109    ///
110    /// The count is rounded up to a power of two and clamped to
111    /// [`MAX_STRIPES`], and zero means one. Rounding rather than refusing
112    /// because the number arrives from `--threads` and from
113    /// `available_parallelism`, and neither of those has any reason to be a
114    /// power of two, while a mask is the only stripe lookup worth having.
115    #[must_use]
116    pub fn with_clock(clock: Clock, stripes: usize) -> Db {
117        let n = stripes.clamp(1, MAX_STRIPES).next_power_of_two();
118        Db {
119            stripes: (0..n)
120                .map(|_| Lock::new(Keyspace::with_clock(clock.clone())))
121                .collect(),
122            mask: (n - 1) as u64,
123            clock,
124            spare: Lock::new(Spare {
125                bytes: Vec::new(),
126                rows: Vec::new(),
127                setops: crate::setops::Scratch::new(),
128            }),
129        }
130    }
131
132    /// A database of one keyspace on the system clock, which is a database
133    /// exactly as it was before there were stripes.
134    #[must_use]
135    pub fn new() -> Db {
136        Db::with_clock(Clock::system(), 1)
137    }
138
139    /// How many stripes this database is cut into.
140    #[must_use]
141    pub fn width(&self) -> usize {
142        self.stripes.len()
143    }
144
145    /// Which stripe `key` lives on.
146    ///
147    /// A function of the key and the width and nothing else, so the same key
148    /// always answers the same stripe and a caller can work out where a key is
149    /// without holding the database.
150    #[inline]
151    #[must_use]
152    pub fn stripe_of(&self, key: &[u8]) -> usize {
153        self.stripe_of_hash(Keyspace::hash_of(key))
154    }
155
156    /// The same, for a caller that already has the hash.
157    ///
158    /// The engine hashes the first key of every command before it runs it, to
159    /// prefetch the record, so on the command path the hash is in hand already
160    /// and hashing it again would be the second most expensive thing in a
161    /// `GET`.
162    ///
163    /// The hash must be [`Keyspace::hash_of`] of the key. Anything else picks
164    /// the wrong stripe, and the wrong stripe is a key that cannot be found
165    /// rather than an error, so this is not something to hand a number that
166    /// came from somewhere else.
167    #[inline]
168    #[must_use]
169    pub fn stripe_of_hash(&self, hash: u64) -> usize {
170        ((hash >> STRIPE_SHIFT) & self.mask) as usize
171    }
172
173    /// The stripe `key` is on.
174    ///
175    /// # Panics
176    ///
177    /// Never. The mask cannot select a stripe that is not there.
178    #[inline]
179    #[must_use]
180    pub fn at(&mut self, key: &[u8]) -> &mut Keyspace {
181        let i = self.stripe_of(key);
182        self.stripes[i].get_mut()
183    }
184
185    /// The stripe `key` is on, held.
186    ///
187    /// For a caller that has the database shared, which is every caller once
188    /// there is more than one thread. The stripe is released when the answer is
189    /// dropped, so a caller that wants it for the length of a command has to
190    /// keep the answer for the length of the command rather than write it into
191    /// the middle of a larger expression.
192    #[inline]
193    #[must_use]
194    pub fn hold(&self, key: &[u8]) -> Held<'_, Keyspace> {
195        let i = self.stripe_of(key);
196        self.stripes[i].lock()
197    }
198
199    /// The stripe a key with this hash is on.
200    ///
201    /// As [`Db::stripe_of_hash`] for what the hash has to be.
202    #[inline]
203    #[must_use]
204    pub fn at_hashed(&mut self, hash: u64) -> &mut Keyspace {
205        let i = self.stripe_of_hash(hash);
206        self.stripes[i].get_mut()
207    }
208
209    /// The stripe a key with this hash is on, held.
210    ///
211    /// As [`Db::stripe_of_hash`] for what the hash has to be.
212    #[inline]
213    #[must_use]
214    pub fn hold_hashed(&self, hash: u64) -> Held<'_, Keyspace> {
215        let i = self.stripe_of_hash(hash);
216        self.stripes[i].lock()
217    }
218
219    /// Warm the line a key with this hash is going to be read from, if the
220    /// stripe it is on is not busy.
221    ///
222    /// What the prefetch stage uses, and the one place a lock is not worth
223    /// waiting for. A prefetch is a hint about a command that has not started
224    /// yet, so a stripe that somebody else is holding is a stripe whose lines
225    /// are being pulled about anyway, and waiting for it would turn a hint into
226    /// a wait for another thread. It is skipped instead.
227    #[inline]
228    pub fn prefetch_hashed(&self, hash: u64) {
229        let i = self.stripe_of_hash(hash);
230        if let Some(stripe) = self.stripes[i].try_lock() {
231            stripe.prefetch(hash);
232        }
233    }
234
235    /// The one stripe every one of `keys` is on, or `None` when they are spread
236    /// over more than one.
237    ///
238    /// This is what a command that names several keys asks first. A database of
239    /// one stripe always answers `Some(0)`, so the old path stays the path, and
240    /// a wide database answers it often enough to be worth asking: a client that
241    /// hash tags its keys the way a cluster makes it does it so that its
242    /// multi key commands land in one place, and this is that place.
243    #[must_use]
244    pub fn one_stripe<'k>(&self, mut keys: impl Iterator<Item = &'k [u8]>) -> Option<usize> {
245        let first = self.stripe_of(keys.next()?);
246        keys.all(|key| self.stripe_of(key) == first)
247            .then_some(first)
248    }
249
250    /// The buffers a command that spans stripes builds its answer in.
251    ///
252    /// Held for the length of the command and taken before any stripe is. That
253    /// order is the rule and it is the only lock order this database has: every
254    /// caller that wants both wants the spare first and the stripes after, in
255    /// stripe order, so no two of them can be waiting for each other.
256    ///
257    /// One set of buffers per database and not per thread, so two threads
258    /// running a command that spans stripes on the same database take turns.
259    /// That is a real serialisation and it is deliberate: the commands that
260    /// come through here are the set algebra and the two key moves, which are
261    /// a rounding error in any cache workload, and the alternative is either
262    /// buffers per thread that nothing frees or an allocation on a command
263    /// path, and Y7 does not allow the second one.
264    pub(crate) fn spare(&self) -> Held<'_, Spare> {
265        self.spare.lock()
266    }
267
268    /// Stripe `i`.
269    ///
270    /// # Panics
271    ///
272    /// If `i` is not a stripe. Callers get their index from [`Db::stripe_of`]
273    /// or from a walk over [`Db::width`], so an index out of range here is a
274    /// bug in the caller.
275    #[inline]
276    #[must_use]
277    pub fn stripe_mut(&mut self, i: usize) -> &mut Keyspace {
278        self.stripes[i].get_mut()
279    }
280
281    /// Stripe `i`, held.
282    ///
283    /// # Panics
284    ///
285    /// As [`Db::stripe_mut`], and also if the calling thread is already holding
286    /// this stripe, in a debug build. Holding one twice is a wait for yourself
287    /// and the lock says so rather than stopping.
288    #[inline]
289    #[must_use]
290    pub fn hold_stripe(&self, i: usize) -> Held<'_, Keyspace> {
291        self.stripes[i].lock()
292    }
293
294    /// Every stripe named, each one once, held, in stripe order.
295    ///
296    /// The order is what makes this safe to call while another database is
297    /// being held elsewhere and what makes two commands that want the same pair
298    /// of stripes want them the same way round. The names are deduplicated
299    /// because two keys of a multi key command land on one stripe often enough,
300    /// and asking for a stripe twice is the mistake the lock panics about.
301    #[must_use]
302    pub fn hold_many(&self, homes: impl Iterator<Item = usize>) -> Holds<'_> {
303        let mut want: Small<u16, INLINE_HOLDS> = homes.map(|i| i as u16).collect();
304        want.sort_unstable();
305        let mut out = Holds::new();
306        // A stripe number is eight bits, so this can never be one of them, which
307        // is what makes it the mark for nothing taken yet.
308        let mut last = u16::MAX;
309        for &i in want.iter() {
310            if i == last {
311                continue;
312            }
313            last = i;
314            out.push(i, self.stripes[usize::from(i)].lock());
315        }
316        out
317    }
318
319    /// The same, for a command that has keys rather than stripe numbers.
320    ///
321    /// Which is most of them: a multi key command is handed the names off the
322    /// wire and works out where they live here. Two keys on one stripe hold it
323    /// once, so `MGET a a` and `MGET a b` where both land in the same place are
324    /// one hold and not two.
325    #[must_use]
326    pub fn hold_keys<'k>(&self, keys: impl Iterator<Item = &'k [u8]>) -> Holds<'_> {
327        self.hold_many(keys.map(|key| self.stripe_of(key)))
328    }
329
330    /// Every stripe, in order, mutably.
331    ///
332    /// Free, because an exclusive reference to the database is already an
333    /// exclusive reference to every stripe in it.
334    pub fn stripes_mut(&mut self) -> impl Iterator<Item = &mut Keyspace> {
335        self.stripes.iter_mut().map(Lock::get_mut)
336    }
337
338    /// What time every stripe here thinks it is.
339    ///
340    /// One reading and not one per stripe. The clock is set on all of them
341    /// together at the top of a turn of the loop, so a command that asks two
342    /// stripes what the time is has to get the same answer from both or two
343    /// keys written by the same command would expire at different moments. The
344    /// reading is kept here as well as in the stripes so that asking the time
345    /// does not mean taking one of them.
346    #[must_use]
347    pub fn now_ms(&self) -> u64 {
348        self.clock.now_ms()
349    }
350
351    /// How many keys are in the database.
352    ///
353    /// One stripe at a time and never two at once, so this is a sum of counts
354    /// that were each true when it was read rather than a count of the database
355    /// at one moment. `DBSIZE` on a server that is being written to was already
356    /// that answer.
357    #[must_use]
358    pub fn len(&self) -> usize {
359        (0..self.stripes.len())
360            .map(|i| self.stripes[i].lock().len())
361            .sum()
362    }
363
364    /// Whether there are none.
365    #[must_use]
366    pub fn is_empty(&self) -> bool {
367        (0..self.stripes.len()).all(|i| self.stripes[i].lock().is_empty())
368    }
369
370    /// How many of the keys have a deadline on them.
371    #[must_use]
372    pub fn expires(&self) -> usize {
373        (0..self.stripes.len())
374            .map(|i| self.stripes[i].lock().expires())
375            .sum()
376    }
377
378    /// Throw the whole database away, which is what `FLUSHDB` does.
379    ///
380    /// One stripe at a time, the same as every other walk here. A reader on
381    /// another thread can see a database that is half thrown away, which is the
382    /// same thing it can see of a `FLUSHDB` on any server that does not stop
383    /// the world for one.
384    pub fn clear(&self) {
385        for i in 0..self.stripes.len() {
386            self.hold_stripe(i).clear();
387        }
388    }
389
390    /// Move every clock in the database to `ms`.
391    ///
392    /// One store, because every stripe of a database and the database itself
393    /// hold handles onto one reading rather than copies of it. It used to be a
394    /// walk that wanted the database exclusively, which is a thing no thread
395    /// could do while another was serving.
396    pub fn set_clock_ms(&self, ms: u64) {
397        self.clock.set(ms);
398    }
399
400    /// Trade this database's contents with another's, which is `SWAPDB`.
401    ///
402    /// Stripe by stripe rather than by exchanging the two databases where they
403    /// sit, because a caller holding a server shared has references out to the
404    /// databases and those have to go on pointing at the database the client
405    /// selected. What moves is what is in the stripes, which is a handful of
406    /// words each whatever they are holding, so this is still O(1) in the
407    /// number of keys and still the two pointer sized writes per stripe that
408    /// make `SWAPDB` fast and dangerous at the same time.
409    ///
410    /// The pair is held in address order and not in the order the client named
411    /// them, so two clients swapping the same two databases in opposite
412    /// directions take turns rather than each holding what the other is waiting
413    /// for. Swapping a database with itself does nothing, which is the answer a
414    /// real server gives too.
415    ///
416    /// A reader on another thread can see one stripe swapped and the next one
417    /// not, the same as it can see a half finished [`Db::clear`].
418    pub fn swap_with(&self, other: &Db) {
419        if std::ptr::eq(self, other) {
420            return;
421        }
422        debug_assert_eq!(
423            self.stripes.len(),
424            other.stripes.len(),
425            "two databases of one server are cut the same way"
426        );
427        let (first, second) = if std::ptr::from_ref(self) < std::ptr::from_ref(other) {
428            (self, other)
429        } else {
430            (other, self)
431        };
432        for i in 0..first.stripes.len() {
433            let mut a = first.hold_stripe(i);
434            let mut b = second.hold_stripe(i);
435            std::mem::swap(&mut *a, &mut *b);
436        }
437    }
438
439    /// Turn the running memory total on or off in every stripe.
440    pub fn track_memory(&self, on: bool) {
441        for i in 0..self.stripes.len() {
442            self.hold_stripe(i).track_memory(on);
443        }
444    }
445
446    /// A batch of keys and where the next batch starts, over the whole
447    /// database.
448    ///
449    /// This is `SCAN`, and it is one stripe at a time. The cursor carries the
450    /// stripe it had got to as well as the place in that stripe, which is what
451    /// the spare field in [`yo_index::Cursor`] is for.
452    ///
453    /// The promise a single keyspace makes survives being made one stripe at a
454    /// time, and it survives it for one reason: a key never changes stripe. So
455    /// a key that is there for the whole walk is on a stripe this walk has not
456    /// reached yet or on the one it is in the middle of, and either way it is
457    /// still coming. Nothing a writer does while the walk is going can move a
458    /// key from a stripe that is still to come to a stripe that is already
459    /// done.
460    ///
461    /// `budget` is spent per stripe rather than per call, so a call that
462    /// finishes a stripe exactly on the budget stops there rather than starting
463    /// the next one. What it will do is walk past any number of empty stripes,
464    /// because a stripe with nothing in it is a walk of one segment and
465    /// stopping to hand the client a cursor for it would be the more expensive
466    /// of the two.
467    pub fn scan(
468        &self,
469        from: KeyCursor,
470        budget: usize,
471        ty: Option<Kind>,
472        mut out: impl FnMut(&[u8]),
473    ) -> KeyCursor {
474        // A cursor naming a stripe this database does not have, which a client
475        // can produce by holding one across a server that came back narrower.
476        // It reads as a walk that is over, which is what Redis gives for any
477        // cursor it cannot make sense of, and the client starts again.
478        let mut at = from.stripe();
479        if at >= self.stripes.len() {
480            return KeyCursor::START;
481        }
482        let mut cursor = from.without_stripe();
483        let mut seen = 0usize;
484        while at < self.stripes.len() {
485            let next = self.hold_stripe(at).scan(cursor, budget, ty, |key| {
486                seen += 1;
487                out(key);
488            });
489            if !next.is_end() {
490                return next.with_stripe(at);
491            }
492            at += 1;
493            cursor = KeyCursor::START;
494            if at < self.stripes.len() && seen >= budget {
495                return KeyCursor::START.with_stripe(at);
496            }
497        }
498        KeyCursor::START
499    }
500
501    /// Every key in the database, once each.
502    ///
503    /// This is `KEYS`, and it is every key of every stripe. The order is the
504    /// order the stripes are in and then whatever order each one walks in,
505    /// which is no order at all as far as a client is concerned, the same as it
506    /// was with one stripe.
507    pub fn keys(&self, mut out: impl FnMut(&[u8])) {
508        for i in 0..self.stripes.len() {
509            self.hold_stripe(i).keys(&mut out);
510        }
511    }
512
513    /// One key from anywhere in the database, or `None` if there are none.
514    ///
515    /// This is `RANDOMKEY`. The stripe is drawn first, weighted by how many
516    /// keys each one holds, so a database whose stripes came out uneven does
517    /// not answer the small ones as often as the big ones. Then that stripe
518    /// picks a key the way it always did.
519    ///
520    /// A stripe can still answer nothing, because its count includes keys whose
521    /// deadline has gone and which nothing has collected yet. The stripes after
522    /// it are asked in turn when that happens, so an answer of `None` here
523    /// means every stripe was asked and none of them had a live key.
524    ///
525    /// The key is handed to `f` while its stripe is still held rather than
526    /// answered, because the stripe it came out of is what it is borrowed from
527    /// and letting go of that stripe is the end of the borrow. The caller
528    /// writes it into a reply, which is not part of this database and is
529    /// therefore still there afterwards. `false` means no stripe had one.
530    pub fn random_key(&self, f: impl FnOnce(&[u8])) -> bool {
531        let live: usize = (0..self.stripes.len())
532            .map(|i| self.hold_stripe(i).len())
533            .sum();
534        if live == 0 {
535            return false;
536        }
537        let draw = (self.hold_stripe(0).random() % live as u64) as usize;
538        let mut running = 0;
539        let mut first = 0;
540        for i in 0..self.stripes.len() {
541            running += self.hold_stripe(i).len();
542            if draw < running {
543                first = i;
544                break;
545            }
546        }
547        let mut f = Some(f);
548        for step in 0..self.stripes.len() {
549            let i = (first as u64 + step as u64) & self.mask;
550            let mut stripe = self.hold_stripe(i as usize);
551            if let Some(key) = stripe.random_key() {
552                // The closure is taken out of the option rather than called in
553                // place, because it is `FnOnce` and the loop it is inside can
554                // go round again. It never does after this point, which the
555                // return says.
556                f.take().expect("the loop stops the first time it fires")(key);
557                return true;
558            }
559        }
560        false
561    }
562}
563
564impl Default for Db {
565    fn default() -> Db {
566        Db::new()
567    }
568}
569
570/// How many stripes one command can name before the list of them reaches the
571/// heap.
572///
573/// Eight, which is the same number the set operations use for the keys
574/// themselves and for the same reason: a command over more operands than that
575/// is rare enough that the cost of it is not what anyone is measuring, and a
576/// command path is not allowed to allocate. A stripe is named once however many
577/// of the keys are on it, so eight here covers more than eight keys.
578const INLINE_HOLDS: usize = 8;
579
580/// Several stripes of one database, held at once.
581///
582/// What a command whose keys are spread over the database gets from
583/// [`Db::hold_many`]. It is a list rather than a map because the number of
584/// stripes a command names is at most the number of keys it names, which is
585/// small, and walking a handful of pairs is cheaper than anything with a hash
586/// in it. The list is in stripe order, which is what [`Db::hold_many`] promises
587/// and what keeps two of these from waiting on each other.
588pub struct Holds<'a> {
589    /// The first few, where the answer nearly always fits.
590    room: [Option<(u16, Held<'a, Keyspace>)>; INLINE_HOLDS],
591    /// How many of `room` are in use.
592    n: usize,
593    /// The rest, for a command that named keys on more stripes than there is
594    /// room for above. This is the one path here that allocates and the reason
595    /// it is allowed to is that reaching it means a client sent a command over
596    /// nine or more stripes, which no benchmark and no real workload does.
597    spill: Vec<(u16, Held<'a, Keyspace>)>,
598}
599
600impl<'a> Holds<'a> {
601    /// Holding nothing.
602    fn new() -> Holds<'a> {
603        Holds {
604            room: [const { None }; INLINE_HOLDS],
605            n: 0,
606            spill: Vec::new(),
607        }
608    }
609
610    /// One more, which the caller has already taken and which comes after every
611    /// stripe added before it.
612    fn push(&mut self, home: u16, held: Held<'a, Keyspace>) {
613        if self.n < INLINE_HOLDS {
614            self.room[self.n] = Some((home, held));
615            self.n += 1;
616        } else {
617            self.spill.push((home, held));
618        }
619    }
620
621    /// Stripe `i`, which the caller asked for and is therefore holding.
622    ///
623    /// # Panics
624    ///
625    /// If `i` was not one of the stripes asked for, which is a caller that
626    /// worked out a stripe number twice and got two different answers.
627    #[must_use]
628    pub fn stripe(&self, i: usize) -> &Keyspace {
629        let home = i as u16;
630        for slot in self.room[..self.n].iter().flatten() {
631            if slot.0 == home {
632                return &slot.1;
633            }
634        }
635        let at = self
636            .spill
637            .binary_search_by_key(&home, |&(where_, _)| where_)
638            .expect("a stripe that was asked for");
639        &self.spill[at].1
640    }
641
642    /// The same, for writing.
643    ///
644    /// One stripe at a time even though every one of them is held, because a
645    /// command that writes into two of them at once would need the borrow
646    /// checker told they are different ones and nothing here does that. A
647    /// rename takes the record out of one and puts it in the other, and the
648    /// record owns what it holds in between.
649    ///
650    /// # Panics
651    ///
652    /// As [`Holds::stripe`].
653    #[must_use]
654    pub fn stripe_mut(&mut self, i: usize) -> &mut Keyspace {
655        let home = i as u16;
656        for slot in self.room[..self.n].iter_mut().flatten() {
657            if slot.0 == home {
658                return &mut slot.1;
659            }
660        }
661        let at = self
662            .spill
663            .binary_search_by_key(&home, |&(where_, _)| where_)
664            .expect("a stripe that was asked for");
665        &mut self.spill[at].1
666    }
667
668    /// How many stripes are being held.
669    #[must_use]
670    pub fn len(&self) -> usize {
671        self.n + self.spill.len()
672    }
673
674    /// Whether none are, which is a command that named no keys.
675    #[must_use]
676    pub fn is_empty(&self) -> bool {
677        self.len() == 0
678    }
679}
680
681#[cfg(test)]
682mod tests {
683    use std::collections::HashSet;
684
685    use yo_index::Cursor as KeyCursor;
686
687    use super::{Db, MAX_STRIPES};
688    use crate::{Clock, Keyspace, many};
689
690    fn filled(stripes: usize, keys: u32) -> Db {
691        let mut db = Db::with_clock(Clock::fixed(1_000_000), stripes);
692        for i in 0..keys {
693            let key = format!("k{i}").into_bytes();
694            db.at(&key).setnx(&key, b"v").expect("room for a record");
695        }
696        db
697    }
698
699    /// A stripe goes to whichever thread takes it, so the records in it have to
700    /// survive being written by one thread and read by another.
701    #[test]
702    fn two_threads_take_turns_over_one_stripe() {
703        let db = filled(1, 8);
704        std::thread::scope(|s| {
705            for at in 0..4u32 {
706                let db = &db;
707                s.spawn(move || {
708                    let key = format!("t{at}").into_bytes();
709                    db.hold(&key).setnx(&key, b"v").expect("room");
710                });
711            }
712        });
713        assert_eq!(db.hold_stripe(0).len(), 12);
714        // And what the threads wrote reads back, which is the part a bump
715        // pointer that had been left on another thread would get wrong.
716        for at in 0..4u32 {
717            let key = format!("t{at}").into_bytes();
718            assert!(db.hold_stripe(0).get(&key).expect("a string").is_some());
719        }
720    }
721
722    #[test]
723    fn a_width_is_always_a_power_of_two_and_never_zero() {
724        for asked in [0, 1, 2, 3, 5, 8, 9, 100] {
725            let db = Db::with_clock(Clock::system(), asked);
726            assert!(db.width().is_power_of_two());
727            assert!(db.width() >= asked.max(1));
728        }
729        assert_eq!(Db::with_clock(Clock::system(), 10_000).width(), MAX_STRIPES);
730    }
731
732    #[test]
733    fn one_stripe_takes_every_key() {
734        let db = Db::with_clock(Clock::system(), 1);
735        for i in 0..1000u32 {
736            assert_eq!(db.stripe_of(&i.to_le_bytes()), 0);
737        }
738    }
739
740    /// The question every multi key command asks before it does anything.
741    #[test]
742    fn a_list_of_keys_is_on_one_stripe_or_it_is_not() {
743        let names: [&[u8]; 3] = [b"a", b"b", b"c"];
744        let one = Db::with_clock(Clock::system(), 1);
745        assert_eq!(one.one_stripe(names.into_iter()), Some(0));
746        assert_eq!(one.one_stripe(std::iter::empty()), None);
747
748        // Sixteen stripes and three keys, which land together about one time in
749        // two hundred and fifty and are checked here to be sure they have not.
750        let many = Db::with_clock(Clock::system(), 16);
751        assert_eq!(many.one_stripe(names.into_iter()), None);
752        let home = many.stripe_of(b"a");
753        assert_eq!(many.one_stripe(std::iter::once(&b"a"[..])), Some(home));
754        assert_eq!(many.one_stripe([&b"a"[..], b"a"].into_iter()), Some(home));
755    }
756
757    #[test]
758    fn a_key_always_answers_the_same_stripe() {
759        let db = Db::with_clock(Clock::system(), 16);
760        for i in 0..1000u32 {
761            let key = i.to_le_bytes();
762            let first = db.stripe_of(&key);
763            assert_eq!(db.stripe_of(&key), first);
764            assert_eq!(db.stripe_of_hash(Keyspace::hash_of(&key)), first);
765        }
766    }
767
768    // Not a claim about the hash, a claim about which bits of it are read. A
769    // stripe number cut from bits the index also reads would still be stable
770    // and would still spread, and would still put every key on a stripe into
771    // one corner of that stripe's index. This is the cheapest check that the
772    // bits are being taken from somewhere: a thousand keys over sixteen
773    // stripes leaves none of them empty unless the number is nearly constant.
774    #[test]
775    fn the_stripe_number_moves_with_the_key() {
776        let db = Db::with_clock(Clock::system(), 16);
777        let mut seen = [0usize; 16];
778        for i in 0..1000u32 {
779            seen[db.stripe_of(&i.to_le_bytes())] += 1;
780        }
781        assert!(
782            seen.iter().all(|&n| n > 0),
783            "some stripe took no keys: {seen:?}"
784        );
785    }
786
787    #[test]
788    fn a_key_written_to_its_stripe_is_found_on_its_stripe() {
789        let mut db = Db::with_clock(Clock::system(), 8);
790        for i in 0..200u32 {
791            let key = i.to_le_bytes();
792            assert!(db.at(&key).setnx(&key, b"x").unwrap());
793        }
794        assert_eq!(db.len(), 200);
795        for i in 0..200u32 {
796            let key = i.to_le_bytes();
797            assert!(db.at(&key).exists(&key));
798        }
799        db.clear();
800        assert!(db.is_empty());
801    }
802
803    #[test]
804    fn a_scan_walks_every_stripe_and_answers_every_key_once() {
805        // Eight stripes whatever happens, because the claim is about stripes.
806        // How many keys are spread over them is not.
807        let keys = many(2_000u32);
808        let db = filled(8, keys);
809        let mut seen: Vec<Vec<u8>> = Vec::new();
810        let mut at = KeyCursor::START;
811        let mut calls = 0;
812        loop {
813            at = db.scan(at, 10, None, |key| seen.push(key.to_vec()));
814            calls += 1;
815            if at.is_end() {
816                break;
817            }
818            assert!(calls < 10_000, "a scan that will not finish");
819        }
820        let unique: HashSet<Vec<u8>> = seen.iter().cloned().collect();
821        assert_eq!(unique.len(), keys as usize);
822        assert_eq!(
823            seen.len(),
824            keys as usize,
825            "a quiet scan returned a key twice"
826        );
827
828        let mut walked = HashSet::new();
829        db.keys(|key| {
830            walked.insert(key.to_vec());
831        });
832        assert_eq!(unique, walked);
833    }
834
835    // Not about the keys, about the number in the middle of the cursor. Every
836    // batch after the first stripe has one in it, and a client that has held
837    // one from a database that had more stripes than this one gets an answer
838    // that says the walk is over rather than a panic.
839    #[test]
840    fn a_scan_carries_the_stripe_in_the_cursor() {
841        // Enough keys that every one of the eight stripes has some, which two
842        // hundred does as surely as two thousand. The assert on the stripe count
843        // below is what would catch it if it did not.
844        let db = filled(8, many(2_000u32));
845        let first = db.scan(KeyCursor::START, 10, None, |_| {});
846        assert!(!first.is_end());
847
848        let mut stripes = HashSet::new();
849        let mut at = KeyCursor::START;
850        loop {
851            at = db.scan(at, 10, None, |_| {});
852            if at.is_end() {
853                break;
854            }
855            stripes.insert(at.stripe());
856        }
857        assert_eq!(stripes.len(), 8, "some stripe was never the one in hand");
858
859        let beyond = KeyCursor::START.with_stripe(9);
860        let mut any = false;
861        assert!(db.scan(beyond, 10, None, |_| any = true).is_end());
862        assert!(!any);
863    }
864
865    #[test]
866    fn a_random_key_comes_from_whichever_stripe_still_has_one() {
867        let keys = many(5_000u32);
868        // The one key that survives the emptying below, somewhere in the middle
869        // so that the stripe it lands in is not the first or the last.
870        let last = keys / 2 + 42;
871        let last_key = format!("k{last}").into_bytes();
872        let mut db = filled(8, keys);
873        let mut all = HashSet::new();
874        db.keys(|key| {
875            all.insert(key.to_vec());
876        });
877        let mut picked = HashSet::new();
878        for _ in 0..200 {
879            let mut key = Vec::new();
880            assert!(
881                db.random_key(|k| key.extend_from_slice(k)),
882                "the database is not empty"
883            );
884            assert!(all.contains(&key), "a key that is not there");
885            picked.insert(key);
886        }
887        assert!(picked.len() > 10, "only {} distinct keys", picked.len());
888
889        // One key left in a database of eight stripes, so seven of the eight
890        // have nothing to answer with and the draw lands on one of those seven
891        // nearly every time.
892        for i in 0..keys {
893            if i != last {
894                let key = format!("k{i}").into_bytes();
895                db.at(&key).del(&key);
896            }
897        }
898        for _ in 0..20 {
899            let mut key = Vec::new();
900            assert!(db.random_key(|k| key.extend_from_slice(k)));
901            assert_eq!(key, last_key);
902        }
903        db.at(&last_key).del(&last_key);
904        assert!(!db.random_key(|_| unreachable!("there are no keys left")));
905    }
906
907    /// The key is handed out of the stripe it is on rather than copied, so a
908    /// draw asks the allocator for nothing at all.
909    #[test]
910    fn a_random_key_does_not_allocate() {
911        let db = filled(8, 500);
912        assert!(db.random_key(|_| {}), "the database is not empty");
913        let (_, allocs) = crate::tally::counted(|| {
914            for _ in 0..200 {
915                assert!(db.random_key(|_| {}), "the database is not empty");
916            }
917        });
918        assert_eq!(
919            allocs, 0,
920            "randomkey allocated {allocs} times in two hundred"
921        );
922    }
923
924    /// A command names its stripes in whatever order its keys arrived in and
925    /// names some of them twice. What comes back is each one once, and every
926    /// one of them is the stripe that was asked for.
927    #[test]
928    fn holding_several_stripes_takes_each_of_them_once() {
929        let mut db = filled(16, 400);
930        let counts: Vec<usize> = (0..db.width()).map(|i| db.stripe_mut(i).len()).collect();
931        let held = db.hold_many([9, 2, 9, 0, 2, 15].into_iter());
932        assert_eq!(held.len(), 4, "six names, four stripes");
933        assert!(!held.is_empty());
934        for i in [0, 2, 9, 15] {
935            assert_eq!(held.stripe(i).len(), counts[i], "stripe {i} came back");
936        }
937    }
938
939    /// Nothing named is nothing held, which is what a command with no keys
940    /// left after the missing ones were dropped hands back.
941    #[test]
942    fn holding_no_stripes_holds_nothing() {
943        let db = filled(4, 40);
944        let held = db.hold_many(std::iter::empty());
945        assert!(held.is_empty());
946        assert_eq!(held.len(), 0);
947    }
948
949    /// Y7 covers this the moment a database is wide, because a set operation
950    /// over keys on several stripes is a command path. Eight stripes fit
951    /// without the heap and the ninth is the one that is allowed to reach for
952    /// it.
953    #[test]
954    fn holding_up_to_eight_stripes_does_not_allocate() {
955        let db = filled(16, 400);
956        let (_, allocs) = crate::tally::counted(|| {
957            for _ in 0..50 {
958                let held = db.hold_many((0..8).rev());
959                assert_eq!(held.len(), 8);
960            }
961        });
962        assert_eq!(allocs, 0, "holding eight stripes allocated {allocs} times");
963    }
964
965    /// And more than eight still works, which is the part the spill is there
966    /// for.
967    #[test]
968    fn holding_more_stripes_than_there_is_room_for_still_holds_them_all() {
969        let mut db = filled(16, 400);
970        let counts: Vec<usize> = (0..db.width()).map(|i| db.stripe_mut(i).len()).collect();
971        let held = db.hold_many((0..16).rev());
972        assert_eq!(held.len(), 16);
973        for (i, &was) in counts.iter().enumerate() {
974            assert_eq!(held.stripe(i).len(), was, "stripe {i} came back");
975        }
976    }
977}