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};
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 let db = filled(8, 2_000);
806 let mut seen: Vec<Vec<u8>> = Vec::new();
807 let mut at = KeyCursor::START;
808 let mut calls = 0;
809 loop {
810 at = db.scan(at, 10, None, |key| seen.push(key.to_vec()));
811 calls += 1;
812 if at.is_end() {
813 break;
814 }
815 assert!(calls < 10_000, "a scan that will not finish");
816 }
817 let unique: HashSet<Vec<u8>> = seen.iter().cloned().collect();
818 assert_eq!(unique.len(), 2_000);
819 assert_eq!(seen.len(), 2_000, "a quiet scan returned a key twice");
820
821 let mut walked = HashSet::new();
822 db.keys(|key| {
823 walked.insert(key.to_vec());
824 });
825 assert_eq!(unique, walked);
826 }
827
828 // Not about the keys, about the number in the middle of the cursor. Every
829 // batch after the first stripe has one in it, and a client that has held
830 // one from a database that had more stripes than this one gets an answer
831 // that says the walk is over rather than a panic.
832 #[test]
833 fn a_scan_carries_the_stripe_in_the_cursor() {
834 let db = filled(8, 2_000);
835 let first = db.scan(KeyCursor::START, 10, None, |_| {});
836 assert!(!first.is_end());
837
838 let mut stripes = HashSet::new();
839 let mut at = KeyCursor::START;
840 loop {
841 at = db.scan(at, 10, None, |_| {});
842 if at.is_end() {
843 break;
844 }
845 stripes.insert(at.stripe());
846 }
847 assert_eq!(stripes.len(), 8, "some stripe was never the one in hand");
848
849 let beyond = KeyCursor::START.with_stripe(9);
850 let mut any = false;
851 assert!(db.scan(beyond, 10, None, |_| any = true).is_end());
852 assert!(!any);
853 }
854
855 #[test]
856 fn a_random_key_comes_from_whichever_stripe_still_has_one() {
857 let mut db = filled(8, 5_000);
858 let mut all = HashSet::new();
859 db.keys(|key| {
860 all.insert(key.to_vec());
861 });
862 let mut picked = HashSet::new();
863 for _ in 0..200 {
864 let mut key = Vec::new();
865 assert!(
866 db.random_key(|k| key.extend_from_slice(k)),
867 "the database is not empty"
868 );
869 assert!(all.contains(&key), "a key that is not there");
870 picked.insert(key);
871 }
872 assert!(picked.len() > 10, "only {} distinct keys", picked.len());
873
874 // One key left in a database of eight stripes, so seven of the eight
875 // have nothing to answer with and the draw lands on one of those seven
876 // nearly every time.
877 for i in 0..5_000u32 {
878 if i != 4_242 {
879 let key = format!("k{i}").into_bytes();
880 db.at(&key).del(&key);
881 }
882 }
883 for _ in 0..20 {
884 let mut key = Vec::new();
885 assert!(db.random_key(|k| key.extend_from_slice(k)));
886 assert_eq!(key, b"k4242");
887 }
888 db.at(b"k4242").del(b"k4242");
889 assert!(!db.random_key(|_| unreachable!("there are no keys left")));
890 }
891
892 /// The key is handed out of the stripe it is on rather than copied, so a
893 /// draw asks the allocator for nothing at all.
894 #[test]
895 fn a_random_key_does_not_allocate() {
896 let db = filled(8, 500);
897 assert!(db.random_key(|_| {}), "the database is not empty");
898 let (_, allocs) = crate::tally::counted(|| {
899 for _ in 0..200 {
900 assert!(db.random_key(|_| {}), "the database is not empty");
901 }
902 });
903 assert_eq!(
904 allocs, 0,
905 "randomkey allocated {allocs} times in two hundred"
906 );
907 }
908
909 /// A command names its stripes in whatever order its keys arrived in and
910 /// names some of them twice. What comes back is each one once, and every
911 /// one of them is the stripe that was asked for.
912 #[test]
913 fn holding_several_stripes_takes_each_of_them_once() {
914 let mut db = filled(16, 400);
915 let counts: Vec<usize> = (0..db.width()).map(|i| db.stripe_mut(i).len()).collect();
916 let held = db.hold_many([9, 2, 9, 0, 2, 15].into_iter());
917 assert_eq!(held.len(), 4, "six names, four stripes");
918 assert!(!held.is_empty());
919 for i in [0, 2, 9, 15] {
920 assert_eq!(held.stripe(i).len(), counts[i], "stripe {i} came back");
921 }
922 }
923
924 /// Nothing named is nothing held, which is what a command with no keys
925 /// left after the missing ones were dropped hands back.
926 #[test]
927 fn holding_no_stripes_holds_nothing() {
928 let db = filled(4, 40);
929 let held = db.hold_many(std::iter::empty());
930 assert!(held.is_empty());
931 assert_eq!(held.len(), 0);
932 }
933
934 /// Y7 covers this the moment a database is wide, because a set operation
935 /// over keys on several stripes is a command path. Eight stripes fit
936 /// without the heap and the ninth is the one that is allowed to reach for
937 /// it.
938 #[test]
939 fn holding_up_to_eight_stripes_does_not_allocate() {
940 let db = filled(16, 400);
941 let (_, allocs) = crate::tally::counted(|| {
942 for _ in 0..50 {
943 let held = db.hold_many((0..8).rev());
944 assert_eq!(held.len(), 8);
945 }
946 });
947 assert_eq!(allocs, 0, "holding eight stripes allocated {allocs} times");
948 }
949
950 /// And more than eight still works, which is the part the spill is there
951 /// for.
952 #[test]
953 fn holding_more_stripes_than_there_is_room_for_still_holds_them_all() {
954 let mut db = filled(16, 400);
955 let counts: Vec<usize> = (0..db.width()).map(|i| db.stripe_mut(i).len()).collect();
956 let held = db.hold_many((0..16).rev());
957 assert_eq!(held.len(), 16);
958 for (i, &was) in counts.iter().enumerate() {
959 assert_eq!(held.stripe(i).len(), was, "stripe {i} came back");
960 }
961 }
962}