yo_kv/keyspace.rs
1//! One database, and the parts of it that are not about any particular type.
2//!
3//! This is the `dict` a Redis `SELECT` picks between, and one of these is what a
4//! shard owns. It was called `Strings` while strings were the only thing in it,
5//! which was accurate for M2 and stopped being accurate the moment a set needed
6//! somewhere to live.
7//!
8//! The commands hang off this as separate `impl` blocks, one file per type, so
9//! that `SET` lives in [`strings`](crate::strings) next to the other twenty five
10//! string commands rather than in a file that is the whole of Redis. They are
11//! methods on the keyspace and not on some per type object because a key belongs
12//! to the database and not to a type: `DEL` does not care what it is deleting,
13//! and `SADD` against a string has to be able to see that it is a string.
14//!
15//! # Not Sync
16//!
17//! Like everything that hangs off a shard. One of these belongs to one thread and
18//! is reached by sending that thread a command, which is Y1, and it is why
19//! nothing here takes a lock or an atomic.
20
21use std::sync::atomic::{AtomicU64, Ordering};
22
23use yo_common::{Addr, Code, Error, Result, Rng, bytes_eq};
24use yo_index::RawMap;
25
26use crate::Clock;
27use crate::access::{Access, Lfu, Policy};
28use crate::array::Array;
29use crate::cold::Blocks;
30use crate::evict;
31use crate::foreign::Foreign;
32use crate::hash::{self, Hash};
33use crate::list::{self, List};
34use crate::set::{self, Set};
35use crate::slab::{Bytes, Slab};
36use crate::stream::{self, Stream};
37use crate::tier::{self, Faulted, Relief, Tier};
38use crate::ttl::{self, Applied, Ask, Cond};
39use crate::value::{self, Kind, Str};
40use crate::zset::{self, Zset};
41
42/// Every collection already answered this question, and this is the answer said
43/// once more in a shape the slab can ask for without knowing what it is holding.
44///
45/// Here rather than in the five type files because it is one fact about the
46/// keyspace and not five facts about five types, and because a reader looking
47/// for how the memory total is kept should find it next to the slabs it counts.
48macro_rules! bytes {
49 ($($t:ty),*) => { $(impl Bytes for $t {
50 #[inline]
51 fn memory_bytes(&self) -> usize {
52 <$t>::memory_bytes(self)
53 }
54 })* };
55}
56bytes!(Set, Hash, List, Zset, Array, Stream);
57
58/// A foreign body counts what it says it counts, plus the box around it.
59///
60/// Not through the macro, because the macro calls an inherent method of the
61/// same name and this one is a trait method reached through a vtable. The
62/// pointer itself is two words on top of whatever the engine reports, which is
63/// the price of the escape and is worth naming rather than losing.
64impl Bytes for Box<dyn Foreign> {
65 #[inline]
66 fn memory_bytes(&self) -> usize {
67 self.as_ref().memory_bytes() + std::mem::size_of::<Box<dyn Foreign>>()
68 }
69}
70
71/// One database: every key, whatever type it holds.
72pub struct Keyspace {
73 pub(crate) map: RawMap,
74 pub(crate) clock: Clock,
75 /// Keys that were found dead on the way to answering something else.
76 pub(crate) expired: u64,
77 /// Keys thrown away to make room, which is a different number entirely.
78 ///
79 /// Redis keeps `expired_keys` and `evicted_keys` apart in `INFO` and the
80 /// distinction is the one people watch: expiry is the client getting what it
81 /// asked for, and eviction is the server deciding it cannot keep a promise
82 /// nobody asked it to break.
83 pub(crate) evicted: u64,
84 /// Every set in this database, addressed by the number in its record.
85 pub(crate) sets: Slab<Set>,
86 /// Every hash in this database, addressed the same way.
87 ///
88 /// A slab per type rather than one slab of an enum, so that a record's four
89 /// bytes index a `Hash` directly and reaching one is a load and not a load
90 /// followed by a discriminant check. The type tag in the record already
91 /// says which slab to look in, so the discriminant would be a second copy
92 /// of a fact the record has.
93 pub(crate) hashes: Slab<Hash>,
94 /// Every list in this database, addressed the same way.
95 pub(crate) lists: Slab<List>,
96 /// Every sorted set in this database, addressed the same way.
97 pub(crate) zsets: Slab<Zset>,
98 /// Every sparse array in this database, addressed the same way.
99 pub(crate) arrays: Slab<Array>,
100 /// Every stream in this database, addressed the same way.
101 pub(crate) streams: Slab<Stream>,
102 /// Every foreign body in this database, addressed the same way.
103 ///
104 /// A box per slot rather than a value, because the thing in it is not sized
105 /// here and could not be. That is one indirection more than the other
106 /// slabs pay, and it buys the graph, document and vector engines a place in
107 /// the keyspace without this crate depending on any of them. See
108 /// [`crate::foreign`].
109 ///
110 /// Empty on a server that has never held one, which is every server today,
111 /// and an empty slab is three words.
112 pub(crate) foreign: Slab<Box<dyn Foreign>>,
113 /// How many keys hold a body that is in a slab right now.
114 ///
115 /// Not how many hold something that is not a string, which is what it used to
116 /// be and what it still is on a database with no file behind it. A collection
117 /// that has been demoted has no slab slot, so it does not count here, and
118 /// that is what every reader of this number wants: [`Keyspace::free_body`]
119 /// has nothing to free for one, and a sweep has nothing to move.
120 ///
121
122 /// This exists so that a database of nothing but strings, which is every
123 /// benchmark today and most of what `SET` sees, can skip the body check in
124 /// [`Keyspace::free_body`] on one predictable branch against a field that is
125 /// already hot, rather than paying a second lookup per write forever.
126 pub(crate) bodies: usize,
127 /// Where a set changes representation.
128 pub(crate) limits: set::Limits,
129 /// Where a hash changes representation.
130 pub(crate) hash_limits: hash::Limits,
131 /// Where a list changes representation.
132 pub(crate) list_limits: list::Limits,
133 /// Where a sorted set changes representation.
134 pub(crate) zset_limits: zset::Limits,
135 /// Where a stream starts a new node, which is two `CONFIG` values.
136 pub(crate) stream_limits: stream::Limits,
137 /// What this database would evict, and therefore what a read writes back.
138 ///
139 /// One server wide setting in Redis, carried per database here for the same
140 /// reason the size ladder is: a `Keyspace` is reached without a server and
141 /// has to be able to answer on its own. `CONFIG SET maxmemory-policy` writes
142 /// it to all of them.
143 pub(crate) policy: Policy,
144 /// The two numbers the LFU counter moves by, which are `CONFIG` values.
145 pub(crate) lfu: Lfu,
146 /// How many keys a round of eviction sampling looks at.
147 ///
148 /// `maxmemory-samples`, carried per database for the same reason the policy
149 /// is. See [`evict::SAMPLES`] for why the default is five.
150 pub(crate) samples: usize,
151 /// The good candidates from earlier rounds of eviction sampling.
152 ///
153 /// See [`evict::Pool`]. Empty and costing nothing until the first eviction,
154 /// which on most databases is never.
155 pub(crate) pool: evict::Pool,
156 /// Where `SPOP` and `SRANDMEMBER` draw from.
157 pub(crate) rng: Rng,
158 /// Where a demoted value goes and comes back from, if this database has one.
159 ///
160 /// `None` on a database with no file behind it, which is every embedded
161 /// caller that never opened one and every test that does not care, and on
162 /// such a database no record is ever cold and every check against this is a
163 /// null test on a field in the same cache line as the map.
164 ///
165 /// Boxed rather than a type parameter on `Keyspace`. The parameter would
166 /// have to be named by `yo-resp`, by the typed API and by every caller of
167 /// either, all to spell a type that only the code opening the file knows,
168 /// and it would be a parameter on the hot path to describe the cold one. See
169 /// [`Blocks`].
170 pub(crate) tier: Option<Tier<Box<dyn Blocks>>>,
171 /// The last value read off the file, for the read that is being answered.
172 ///
173 /// A demoted value that is served rather than promoted has to live
174 /// somewhere for the length of one command, because the record it came from
175 /// holds an address and the caller was promised bytes. One buffer, cleared
176 /// and refilled, on the same argument as [`Keyspace::scratch`]: a fault is
177 /// already a device read and a malloc on top of it is free by comparison,
178 /// but it is also unnecessary.
179 ///
180 /// It holds the value of the last key that was faulted and nothing says
181 /// which key that was, which is why nothing reads it without having faulted
182 /// in the same call. Everything that does goes through
183 /// [`Keyspace::warm`].
184 pub(crate) cold: Vec<u8>,
185 /// Whose value is in [`Keyspace::cold`].
186 ///
187 /// Only ever read by a debug assertion, and it is there because the failure
188 /// it catches is silent: a read that forgets to warm and then finds a cold
189 /// record would hand back whatever the last fault put in the buffer, which
190 /// is a real value belonging to a different key. A test would see plausible
191 /// bytes and pass. The copy costs a key's worth of memcpy on a path that
192 /// has just read a device, which is nothing next to what it is guarding.
193 pub(crate) cold_key: Vec<u8>,
194 /// A collection body on its way to the file or on its way back.
195 ///
196 /// Not [`Keyspace::cold`], which holds the value of the last string that was
197 /// faulted and is read after the fact by [`Keyspace::value_of`]. This buffer
198 /// is written and consumed inside one call and nothing looks at it
199 /// afterwards, so sharing the other one would mean a `SADD` on a demoted set
200 /// quietly replacing the bytes a `GET` in the same pipeline was about to hand
201 /// back. One `Vec` each, cleared and refilled, is three words of a struct
202 /// that already has a hundred.
203 pub(crate) frozen: Vec<u8>,
204 /// The last collection key that was resolved, for the command behind it.
205 memo: Memo,
206 /// One buffer for the commands that have to hold an element while the
207 /// structure it came out of is being written.
208 ///
209 /// [`Keyspace::lmove`] is the reason this is here: it takes an element out
210 /// of one list and puts it into another, so there is a moment where the
211 /// bytes belong to nothing, and the borrow it would need to avoid that is a
212 /// borrow of two lists at once when the two lists may be the same one. A
213 /// `Vec` per call is the obvious way to cover that moment and it is a malloc
214 /// and a free on a command that a queue sends millions of. This is the same
215 /// `Vec` every time, cleared rather than freed, so the steady state is no
216 /// allocator call at all.
217 ///
218 /// [`Keyspace::append`], [`Keyspace::setrange`] and the string arm of
219 /// [`Keyspace::set_expiry`] use it for the same shape of problem: each of
220 /// them has to hold the old value while it writes the new record, and each
221 /// of them was doing that with a fresh `Vec` of the whole value. They cannot
222 /// overlap, because each one puts the buffer back before it returns and one
223 /// command runs at a time.
224 ///
225 /// It lives on the database and not on the caller because the callers are
226 /// wire handlers that are handed a `&mut Keyspace` and nothing else.
227 ///
228 /// It starts at [`SCRATCH`] bytes rather than empty. An empty one grows on
229 /// the first command that uses it, and that growth is a real allocation on a
230 /// command path even though it happens once. Buying it here, where nobody is
231 /// waiting, makes the rule Y7 enforces true without an exception written for
232 /// it. A value larger than that still grows it, and that one is allocation
233 /// proportional to what the caller sent rather than overhead per command.
234 pub(crate) scratch: Vec<u8>,
235
236 /// The same idea for indices rather than bytes.
237 ///
238 /// `ZRANDMEMBER` with a positive count under the size of the set does a
239 /// partial Fisher-Yates, and that needs the permutation somewhere while it
240 /// draws from it. One buffer, cleared and refilled, rather than one `Vec`
241 /// per call, because sampling is a thing callers do in a loop.
242 ///
243 /// It does not start at a capacity, unlike [`Keyspace::scratch`]. There is
244 /// no size to guess: the buffer has to be as long as the set, so the first
245 /// call on a set larger than anything seen before grows it whatever it was
246 /// given to start with. That growth is proportional to the data rather than
247 /// per command.
248 pub(crate) rows: Vec<usize>,
249
250 /// The tables set algebra fills in, kept rather than built per call.
251 ///
252 /// Same idea again, one level up: a union walks everything into a hash
253 /// table and lets the table be the duplicate check, and building that table
254 /// was the largest single allocation left on any command path. See
255 /// [`setops::Scratch`], which is where the two tables and the argument for
256 /// them live.
257 ///
258 /// It is one table per database and not one per command, so a database that
259 /// has answered a union over a million members holds a million member table
260 /// until it answers a smaller one. That is the trade and it is the right way
261 /// round: the same database had to build that table anyway, and the version
262 /// that threw it away afterwards built it again on the next call.
263 pub(crate) setops: crate::setops::Scratch,
264
265 /// What the last geo search found, kept for the same reason.
266 ///
267 /// A search cannot answer in the order it walks: the nine hash boxes come
268 /// out in hash order and the reply is in distance order, so every candidate
269 /// has to be in hand before the first one can be written. See
270 /// [`crate::geos::Scratch`], which is the two buffers and the argument for
271 /// keeping them here.
272 pub(crate) geo: crate::geos::Scratch,
273}
274
275/// How big [`Keyspace::scratch`] starts.
276///
277/// A kibibyte, which covers a value of any ordinary size and costs one
278/// allocation per database. The number is not tuned and does not need to be: too
279/// small only means the buffer grows once more on some later command, and too
280/// large only means a kibibyte nobody used.
281const SCRATCH: usize = 1024;
282
283/// How many segments one call to [`Keyspace::victim`] will draw from.
284///
285/// A round is a whole segment, and a segment is sixty four buckets of seven
286/// entries each before its overflow chains are counted, so one round almost
287/// always answers. The retries are for the case where a round came back with
288/// nothing usable, which happens when the segment it drew was empty or when a
289/// `volatile` policy filtered out everything in it.
290///
291/// Four rather than more, because a round that comes back with nothing is
292/// telling you something a fifth round will not change. That used to be the
293/// wrong shape for the `volatile` policies, which could draw four rounds of
294/// keys with no deadline on a database that had almost none, on a path where a
295/// client is waiting. Those policies now draw from the second index of just the
296/// keys that carry a deadline, the way Redis draws from `db->expires`, so every
297/// key a round looks at is a key it is allowed to take.
298const ROUNDS: usize = 4;
299
300/// Where the last collection key resolved to, if it still resolves there.
301///
302/// Y13 says a batch of `SADD` on one key should be one table growth check, and
303/// the same argument applies a step earlier: it should be one resolve. A
304/// resolve is a hash, a bucket walk and a record read, and on a hot key every
305/// command in the batch was paying for all three to be told the same answer the
306/// command in front of it got.
307///
308/// One entry and not a cache, because one entry is the shape of the problem.
309/// Single key `SADD` is the case with no spread to exploit, so the only reuse
310/// there is to find is the command immediately before, and a bigger structure
311/// would cost a lookup to avoid a lookup.
312///
313/// It holds a slot rather than reaching the body through an address, because a
314/// slot is an index into the slab for its type and stays right for as long as
315/// the key is there. That is also why nothing here memoizes a string: a string
316/// lives in the record itself and moves when the record does.
317///
318/// It does carry the record's address alongside, and that is safe for a narrower
319/// reason than the slot is. An address is only good until the next write, and
320/// this whole memo is thrown away by the next write, so inside the window where
321/// the memo answers at all the address is exactly as valid as the slot. What it
322/// buys is the eviction stamp: a memo hit skips the probe, and without an address
323/// the stamp would have to put the probe back and there would be no memo left.
324///
325/// What it is worth is measured rather than argued about, by the pair of rows
326/// `engine/sadd` and `engine/sadd-alternating` in `yo-resp`'s `engine` bench.
327/// The second one alternates between two keys, which defeats this on every
328/// command and leaves both keys as warm in the cache as the one key was, so the
329/// difference between the rows is close to this and nothing else. On an Apple M4
330/// it is about nineteen nanoseconds a command, which is 1.25x at pipeline 64.
331struct Memo {
332 /// What the map's write counter said when this was taken.
333 writes: u64,
334 /// Whether there is anything here. Separate from the length because the
335 /// empty key is a key, and `SADD "" m` is a command Redis accepts.
336 live: bool,
337 /// The type the key held, so a hit can still answer `WRONGTYPE`.
338 kind: Kind,
339 /// Where the body is in the slab for `kind`.
340 slot: u32,
341 /// Where the record is, for the stamp a hit still owes.
342 addr: Addr,
343 /// How much of `key` is the key.
344 len: u8,
345 key: [u8; Memo::MAX],
346}
347
348impl Memo {
349 /// The longest key worth remembering.
350 ///
351 /// Thirty two bytes is half a cache line and covers every hot key anyone
352 /// writes down, including the `myset:{tag}` the generators send. A longer
353 /// key is not memoized rather than heap allocated, because the whole point
354 /// of this is to not touch memory it does not have to.
355 const MAX: usize = 32;
356
357 const fn empty() -> Memo {
358 Memo {
359 writes: 0,
360 live: false,
361 kind: Kind::String,
362 slot: 0,
363 addr: Addr::NONE,
364 len: 0,
365 key: [0; Memo::MAX],
366 }
367 }
368
369 /// What `key` resolved to last time, if that answer still stands.
370 ///
371 /// `writes` is the map's counter now. Any write at all since this was taken
372 /// and the answer is thrown away, which is stricter than it has to be and is
373 /// the version that cannot be wrong.
374 #[inline]
375 fn get(&self, writes: u64, key: &[u8]) -> Option<(Kind, u32, Addr)> {
376 if !self.live || self.writes != writes || key.len() != self.len as usize {
377 return None;
378 }
379 // `bytes_eq` and not `==`, which is a call into the platform's `memcmp`
380 // for a key of a length the compiler cannot see. This is the one
381 // comparison the hot key path always does, and on a profile of `SADD`
382 // it was most of what the lookup cost.
383 bytes_eq(&self.key[..key.len()], key).then_some((self.kind, self.slot, self.addr))
384 }
385
386 /// Remember that `key` is at `slot`, in the record at `addr`.
387 #[inline]
388 fn put(&mut self, writes: u64, key: &[u8], kind: Kind, slot: u32, addr: Addr) {
389 if key.len() > Memo::MAX {
390 self.live = false;
391 return;
392 }
393 self.writes = writes;
394 self.live = true;
395 self.kind = kind;
396 self.slot = slot;
397 self.addr = addr;
398 self.len = key.len() as u8;
399 self.key[..key.len()].copy_from_slice(key);
400 }
401}
402
403/// How many databases this process has made.
404///
405/// Mixed into a new database's seed so that the eight shards a server starts in
406/// the same millisecond do not all draw the same members in the same order. It
407/// is the only atomic in this file and it is touched once per database rather
408/// than once per command, so it is not on any path Y1 cares about.
409static MADE: AtomicU64 = AtomicU64::new(0);
410
411impl Keyspace {
412 /// An empty database on the system clock.
413 #[must_use]
414 pub fn new() -> Keyspace {
415 Keyspace::with_clock(Clock::system())
416 }
417
418 /// An empty database on a clock of the caller's choosing.
419 #[must_use]
420 pub fn with_clock(clock: Clock) -> Keyspace {
421 let made = MADE.fetch_add(1, Ordering::Relaxed);
422 Keyspace {
423 map: RawMap::new(),
424 clock,
425 expired: 0,
426 evicted: 0,
427 sets: Slab::new(),
428 hashes: Slab::new(),
429 lists: Slab::new(),
430 zsets: Slab::new(),
431 arrays: Slab::new(),
432 streams: Slab::new(),
433 foreign: Slab::new(),
434 bodies: 0,
435 limits: set::Limits::DEFAULT,
436 hash_limits: hash::Limits::DEFAULT,
437 list_limits: list::Limits::default(),
438 zset_limits: zset::Limits::DEFAULT,
439 stream_limits: stream::Limits::default(),
440 policy: Policy::default(),
441 lfu: Lfu::DEFAULT,
442 samples: evict::SAMPLES,
443 pool: evict::Pool::new(),
444 rng: Rng::new(clock.now_ms() ^ made.wrapping_mul(0x9e37_79b9_7f4a_7c15)),
445 tier: None,
446 cold: Vec::new(),
447 cold_key: Vec::new(),
448 frozen: Vec::new(),
449 memo: Memo::empty(),
450 scratch: Vec::with_capacity(SCRATCH),
451 rows: Vec::new(),
452 setops: crate::setops::Scratch::new(),
453 geo: crate::geos::Scratch::default(),
454 }
455 }
456
457 /// Pin what `SPOP` and `SRANDMEMBER` draw.
458 ///
459 /// A database seeds itself from the clock and a counter, which is what a
460 /// server wants and what a test cannot assert against. Every test in this
461 /// crate that cares which member comes back calls this first, the same way
462 /// every expiry test drives a fixed clock, and for the same reason: the one
463 /// input that makes a result unrepeatable is better handed in than reached
464 /// for.
465 ///
466 /// It is public because reproducing a bug report is the same problem. A
467 /// seed printed in a crash report is worth having somewhere to put.
468 #[inline]
469 pub const fn seed(&mut self, seed: u64) {
470 self.rng = Rng::new(seed);
471 }
472
473 /// What this database would evict, which is `CONFIG GET maxmemory-policy`.
474 #[inline]
475 #[must_use]
476 pub const fn policy(&self) -> Policy {
477 self.policy
478 }
479
480 /// Change what this database would evict.
481 ///
482 /// Every key already stored keeps whatever is in its access field, which is
483 /// why Redis warns on `OBJECT FREQ` that switching at runtime takes time to
484 /// adjust. Under the new policy those bits mean something else, and the only
485 /// honest thing to do about it is to let them be corrected by use. A key
486 /// nobody has touched since the switch reads as freshly used rather than as
487 /// stale, which is the safe direction: the other one evicts the working set
488 /// on the first pass after an operator changes a setting.
489 ///
490 /// The candidate pool does go, because a score only means anything against
491 /// another score under the same rule and every number in there was worked
492 /// out under the old one.
493 #[inline]
494 pub fn set_policy(&mut self, policy: Policy) {
495 if policy != self.policy {
496 self.pool.clear();
497 }
498 self.policy = policy;
499 }
500
501 /// The two numbers the LFU counter moves by, which are two `CONFIG` values.
502 #[inline]
503 #[must_use]
504 pub const fn lfu(&self) -> Lfu {
505 self.lfu
506 }
507
508 /// Change how fast the LFU counter climbs and decays.
509 #[inline]
510 pub const fn set_lfu(&mut self, lfu: Lfu) {
511 self.lfu = lfu;
512 }
513
514 /// Seconds since `key` was last used, which is `OBJECT IDLETIME`.
515 ///
516 /// `None` for a key that is not there. A key that has never been stamped
517 /// reads as zero rather than as ancient, which is what
518 /// [`Access::is_unset`] is for.
519 ///
520 /// This does not count as a use. Redis looks the key up with its no touch
521 /// flag here, and it has to: a diagnostic that resets the number it reports
522 /// would answer zero every time it was asked.
523 pub fn idle_secs(&mut self, key: &[u8]) -> Option<u64> {
524 let addr = self.live_rec_untouched(key)?;
525 let now = self.clock.now_ms();
526 Some(self.access_at(addr).idle_secs(now))
527 }
528
529 /// How often `key` is used, which is `OBJECT FREQ`.
530 ///
531 /// The eight bit counter, decayed to now, on the same terms as
532 /// [`Keyspace::idle_secs`]: `None` for a key that is not there, and asking
533 /// is not using.
534 ///
535 /// The caller is the one that has to check the policy first. This reports
536 /// what the bits say, and under a policy that is not LFU they say something
537 /// else, which is a refusal on the wire rather than a number.
538 pub fn freq(&mut self, key: &[u8]) -> Option<u8> {
539 let addr = self.live_rec_untouched(key)?;
540 let (now, lfu) = (self.clock.now_ms(), self.lfu);
541 Some(self.access_at(addr).freq(now, lfu))
542 }
543
544 /// Write a record under `key`, with the access field the policy wants on it.
545 ///
546 /// Every record this crate writes goes through here, which is the point of
547 /// it. A record is written fresh whenever a key is created and whenever a
548 /// string's value changes, and a fresh record starts with the blank field
549 /// [`value::write_record`] leaves behind. Blank reads as freshly used, which
550 /// is right at the moment of writing and wrong a minute later, so something
551 /// has to stamp it and this is the only place that knows the clock.
552 ///
553 /// Redis stamps at the same moment, in `createObject`, and for the same
554 /// reason.
555 pub(crate) fn write_rec(
556 &mut self,
557 key: &[u8],
558 len: usize,
559 fill: impl FnOnce(&mut [u8]),
560 ) -> Option<usize> {
561 let a = self.access_for_write(key);
562 // The one bit in the record that says the key has a deadline, handed
563 // straight back to the map. What the map does with it is keep a second
564 // index of just those records, so the expire cycle and the volatile
565 // eviction policies have somewhere to sample from that is not the whole
566 // keyspace. Nothing here counts anything: the map's own count of marked
567 // records is the number, and a number kept in two places is a number
568 // that eventually disagrees with itself.
569 self.map.set_with(
570 key,
571 len,
572 |_| {},
573 |out| {
574 fill(out);
575 value::set_access(out, a);
576 value::has_expiry(out)
577 },
578 )
579 }
580
581 /// Take `key` out of the map, keeping the deadline count right.
582 ///
583 /// The other half of [`Keyspace::write_rec`], and every path that removes a
584 /// record goes through one of the two. That is `DEL`, lazy expiry, eviction
585 /// and the source key of a `RENAME`, and the last one is why this is not
586 /// simply folded into [`Keyspace::drop_key`]: a rename hands the body to the
587 /// destination and must not free it, so it deletes the source record without
588 /// dropping the key, and it still has to be counted.
589 #[inline]
590 pub(crate) fn del_rec(&mut self, key: &[u8]) -> bool {
591 self.map.del(key)
592 }
593
594 /// What the access field of a record about to be written should say.
595 ///
596 /// Under the eight policies that read the field as a clock this is the time,
597 /// with no probe and no thought: writing a key is using it, and under the LRM
598 /// pair writing it is the only thing that counts as using it.
599 ///
600 /// Under LFU it is the counter that is already there, carried across the
601 /// rewrite unchanged. Unchanged rather than incremented, because the lookup
602 /// that resolved the key for this write already counted the access, and
603 /// counting it twice would rank a key that is written more highly than a key
604 /// that is read the same number of times. A key that is not there yet starts
605 /// at [`crate::access::LFU_INIT`], which is where Redis starts a new object.
606 ///
607 /// The probe is the reason this is written as two cases rather than one. It
608 /// is paid only under an LFU policy, so the default policy and every other
609 /// one write a record for exactly what it cost before.
610 fn access_for_write(&mut self, key: &[u8]) -> Access {
611 let now = self.clock.now_ms();
612 if !self.policy.is_lfu() {
613 return Access::lru(now);
614 }
615 match self.map.get(key).and_then(value::access) {
616 Some(a) if !a.is_unset() => a,
617 _ => Access::lfu(now),
618 }
619 }
620
621 /// The access field of the record at `addr`, or the unset one for a record
622 /// written before the field existed.
623 #[inline]
624 fn access_at(&self, addr: Addr) -> Access {
625 value::access(self.map.value_at(addr)).unwrap_or_default()
626 }
627
628 /// Write the access field back to the record at `addr`.
629 ///
630 /// The whole reason the field exists, and it runs on nearly every command,
631 /// so what it does is a load, an arithmetic step and a three byte store into
632 /// a cache line the caller has just read. It does not count as a write to the
633 /// map, because nothing moves and counting it would throw the [`Memo`] away
634 /// once per command. See [`RawMap::value_at_mut`].
635 ///
636 /// The LFU arm reads before it writes, because the counter it produces is a
637 /// function of the counter that is there. The clock arm does not, because the
638 /// time is the time whatever the record used to say.
639 #[inline]
640 fn stamp(&mut self, addr: Addr) {
641 let now = self.clock.now_ms();
642 if self.policy.is_lfu() {
643 let (lfu, current) = (self.lfu, self.access_at(addr));
644 let next = current.touched(now, lfu, &mut self.rng);
645 value::set_access(self.map.value_at_mut(addr), next);
646 } else {
647 value::set_access(self.map.value_at_mut(addr), Access::lru(now));
648 }
649 }
650
651 /// Where a set changes representation, which is three `CONFIG` values.
652 #[inline]
653 pub const fn limits(&self) -> &set::Limits {
654 &self.limits
655 }
656
657 /// Change where a set changes representation.
658 ///
659 /// Moving these does not rewrite the sets that already exist, which is what
660 /// Redis does too: `CONFIG SET set-max-listpack-entries 0` leaves every
661 /// listpack alone and only decides what the next `SADD` builds.
662 #[inline]
663 pub const fn set_limits(&mut self, limits: set::Limits) {
664 self.limits = limits;
665 }
666
667 /// Where a hash changes representation, which is two `CONFIG` values.
668 #[inline]
669 pub const fn hash_limits(&self) -> &hash::Limits {
670 &self.hash_limits
671 }
672
673 /// Change where a hash changes representation.
674 ///
675 /// Same rule as the set: moving these leaves every hash that already exists
676 /// exactly as it is, and only decides what the next `HSET` builds.
677 #[inline]
678 pub const fn set_hash_limits(&mut self, limits: hash::Limits) {
679 self.hash_limits = limits;
680 }
681
682 /// Where a list changes representation, which is one `CONFIG` value.
683 #[inline]
684 pub const fn list_limits(&self) -> &list::Limits {
685 &self.list_limits
686 }
687
688 /// Change where a list changes representation.
689 ///
690 /// Same rule again: this decides what the next `LPUSH` builds and leaves
691 /// every list that already exists alone. `list-max-listpack-size` is one
692 /// number rather than two, and [`list::Limits::of`] is what turns it into
693 /// the pair this holds.
694 #[inline]
695 pub const fn set_list_limits(&mut self, limits: list::Limits) {
696 self.list_limits = limits;
697 }
698
699 /// Where a stream starts a new node, which is two `CONFIG` values.
700 #[inline]
701 pub const fn stream_limits(&self) -> &stream::Limits {
702 &self.stream_limits
703 }
704
705 /// Change where a stream starts a new node.
706 ///
707 /// Same rule as the other four: this decides what the next `XADD` builds
708 /// and leaves every node that is already full exactly as it is, which is
709 /// also what Redis does, since a node is never resized after it is written.
710 #[inline]
711 pub const fn set_stream_limits(&mut self, limits: stream::Limits) {
712 self.stream_limits = limits;
713 }
714
715 /// Where a sorted set changes representation, which is two `CONFIG` values.
716 #[inline]
717 pub const fn zset_limits(&self) -> &zset::Limits {
718 &self.zset_limits
719 }
720
721 /// Change where a sorted set changes representation.
722 ///
723 /// Same rule as the other three: this decides what the next `ZADD` builds
724 /// and leaves every sorted set that already exists exactly as it is.
725 #[inline]
726 pub const fn set_zset_limits(&mut self, limits: zset::Limits) {
727 self.zset_limits = limits;
728 }
729
730 /// The clock expiry compares against.
731 #[inline]
732 pub const fn clock(&self) -> &Clock {
733 &self.clock
734 }
735
736 /// The clock, to refresh once per turn of the loop.
737 #[inline]
738 pub const fn clock_mut(&mut self) -> &mut Clock {
739 &mut self.clock
740 }
741
742 /// The map underneath, for statistics and for compaction.
743 #[inline]
744 pub const fn map(&self) -> &RawMap {
745 &self.map
746 }
747
748 /// How many keys are stored, including any that are dead and not yet
749 /// noticed. This is Redis's `DBSIZE`, which counts the same way.
750 #[inline]
751 pub fn len(&self) -> usize {
752 self.map.len()
753 }
754
755 /// Whether anything is stored.
756 #[inline]
757 pub fn is_empty(&self) -> bool {
758 self.map.is_empty()
759 }
760
761 /// What `key` holds, or `None` if there is nothing under it.
762 ///
763 /// This is `TYPE`. A key past its deadline is reaped first, so a dead key
764 /// answers `None` and not the type it used to be.
765 ///
766 /// One lookup, because the tag and the deadline are both in the record the
767 /// lookup returned. Reading the kind out before the reap rather than after
768 /// is what keeps it to one.
769 ///
770 /// It does not go through the lookup that stamps, and so it leaves the
771 /// eviction clock where it was, which is right and is worth saying rather than
772 /// leaving to be inferred from the shape of the code. `TYPE` is one of the
773 /// commands Redis looks up with its no touch flag, along with the `OBJECT`
774 /// subcommands underneath this, which read through `reap` for the same
775 /// reason.
776 pub fn kind_of(&mut self, key: &[u8]) -> Option<Kind> {
777 let now = self.clock.now_ms();
778 let (kind, dead) = self
779 .map
780 .get(key)
781 .map(|rec| (value::kind(rec), value::is_expired(rec, now)))?;
782 if dead {
783 self.drop_key(key);
784 self.expired += 1;
785 return None;
786 }
787 Some(kind)
788 }
789
790 /// How a set is represented, or `None` if `key` is not a set.
791 ///
792 /// This follows the slot and asks the body rather than reading the record,
793 /// because the record only holds a number. Putting a copy of the
794 /// representation in the record's two spare encoding bits would mean
795 /// rewriting the record every time a set was promoted, for the sake of a
796 /// command nobody calls in a loop, and would leave two places able to
797 /// disagree about the same fact.
798 /// A demoted set is brought back to answer, which is the one thing this
799 /// costs that the others do not. The word is a property of the body and the
800 /// body is on the device, so there is nothing else to read it off. It is one
801 /// device read for a command nobody sends in a loop, and the alternative is a
802 /// copy of the word in the record's two spare encoding bits with two places
803 /// then able to disagree about it.
804 pub fn set_encoding(&mut self, key: &[u8]) -> Option<set::Encoding> {
805 self.reap(key);
806 let rec = self.map.get(key)?;
807 if value::kind(rec) != Kind::Set {
808 return None;
809 }
810 let cold = value::Meta::from_byte(rec[0]).is_cold();
811 let at = if cold {
812 // The record is given up here, because promotion writes a new one.
813 self.promote_body(key).ok()??
814 } else {
815 value::slot(rec)
816 };
817 Some(self.sets.get(at)?.encoding())
818 }
819
820 /// How a hash is represented, or `None` if `key` is not a hash.
821 ///
822 /// The same shape as [`Keyspace::set_encoding`] and for the same reason: the
823 /// record holds a slot number and the body is the thing that knows which of
824 /// the two it currently is. A demoted hash is brought back to answer, which
825 /// is the same trade the set makes.
826 pub fn hash_encoding(&mut self, key: &[u8]) -> Option<hash::Encoding> {
827 self.reap(key);
828 let rec = self.map.get(key)?;
829 if value::kind(rec) != Kind::Hash {
830 return None;
831 }
832 let cold = value::Meta::from_byte(rec[0]).is_cold();
833 let at = if cold {
834 self.promote_body(key).ok()??
835 } else {
836 value::slot(rec)
837 };
838 Some(self.hashes.get(at)?.encoding())
839 }
840
841 /// How a list is represented, or `None` if `key` is not a list.
842 ///
843 /// The same shape as [`Keyspace::set_encoding`], and the same argument for
844 /// asking the body rather than reading a copy out of the record. A demoted
845 /// list is brought back to answer, as the set and the hash are.
846 pub fn list_encoding(&mut self, key: &[u8]) -> Option<list::Encoding> {
847 self.reap(key);
848 let rec = self.map.get(key)?;
849 if value::kind(rec) != Kind::List {
850 return None;
851 }
852 let cold = value::Meta::from_byte(rec[0]).is_cold();
853 let at = if cold {
854 self.promote_body(key).ok()??
855 } else {
856 value::slot(rec)
857 };
858 Some(self.lists.get(at)?.encoding())
859 }
860
861 /// How a sorted set is represented, or `None` if `key` is not one.
862 pub fn zset_encoding(&mut self, key: &[u8]) -> Option<zset::Encoding> {
863 self.reap(key);
864 let rec = self.map.get(key)?;
865 if value::kind(rec) != Kind::Zset {
866 return None;
867 }
868 let cold = value::Meta::from_byte(rec[0]).is_cold();
869 let at = if cold {
870 self.promote_body(key).ok()??
871 } else {
872 value::slot(rec)
873 };
874 Some(self.zsets.get(at)?.encoding())
875 }
876
877 /// Put a foreign body under `key`, over whatever was there.
878 ///
879 /// The keyspace takes the box and frees it when the key goes, which is the
880 /// whole reason a graph lives in here rather than in a table beside it. See
881 /// [`crate::foreign`] for why that mattered enough to spend the last tag
882 /// pattern on.
883 ///
884 /// Overwriting is allowed and is what a caller that has just decided to
885 /// replace a key wants. A caller that did not mean to overwrite asks
886 /// [`Keyspace::kind_of`] first, which is what the commands above do so they
887 /// can answer WRONGTYPE rather than quietly throw a hash away.
888 pub fn put_foreign(&mut self, key: &[u8], body: Box<dyn Foreign>) -> u32 {
889 self.free_body(key);
890 let at = self.foreign.insert(body);
891 let len = value::slot_record_len(false);
892 self.write_rec(key, len, |out| {
893 value::write_slot_record(out, Kind::Foreign, at, None);
894 });
895 self.bodies += 1;
896 at
897 }
898
899 /// The foreign body under `key`.
900 ///
901 /// `None` for a key that is not there or has expired, an error for a key
902 /// holding something this crate does understand, which is the same three
903 /// way answer every other type's entry point gives.
904 ///
905 /// The caller turns the `&dyn Foreign` back into its own type with
906 /// [`downcast_ref`], and a `None` from that is a key holding a different
907 /// foreign body, which is also WRONGTYPE and is the caller's to report
908 /// because only it knows which one it wanted.
909 ///
910 /// [`downcast_ref`]: crate::Foreign
911 pub fn foreign(&mut self, key: &[u8]) -> Result<Option<&dyn Foreign>> {
912 let Some(at) = self.live_slot(key, Kind::Foreign)? else {
913 return Ok(None);
914 };
915 Ok(Some(
916 self.foreign
917 .get(at)
918 .expect("the record points at its body")
919 .as_ref(),
920 ))
921 }
922
923 /// The same, with a mutable borrow.
924 pub fn foreign_mut(&mut self, key: &[u8]) -> Result<Option<&mut dyn Foreign>> {
925 let Some(at) = self.live_slot(key, Kind::Foreign)? else {
926 return Ok(None);
927 };
928 Ok(Some(
929 self.foreign
930 .get_mut(at)
931 .expect("the record points at its body")
932 .as_mut(),
933 ))
934 }
935
936 /// Drop `key` if the foreign body under it has gone empty.
937 ///
938 /// Redis deletes a key when its collection empties, and a client can see
939 /// the difference, so every command that removes something calls this
940 /// afterwards rather than each of them deciding what empty means.
941 pub fn reap_foreign(&mut self, key: &[u8]) {
942 let gone = matches!(self.foreign(key), Ok(Some(b)) if b.is_empty());
943 if gone {
944 self.drop_key(key);
945 }
946 }
947
948 /// The foreign body under `key`, without the reap or the type check.
949 ///
950 /// For the arms that already have a live record in hand and only want the
951 /// body, where going through [`Keyspace::foreign`] would mean reaping a key
952 /// that was read a line ago.
953 fn foreign_at(&mut self, key: &[u8]) -> Option<&dyn Foreign> {
954 let rec = self.map.get(key)?;
955 let at = value::slot(rec);
956 Some(self.foreign.get(at)?.as_ref())
957 }
958
959 /// What `TYPE` should say about `key`.
960 ///
961 /// [`Kind::name`] for everything this crate knows, and the body's own word
962 /// for a foreign one, because a client asking about a graph is told `graph`
963 /// and not `foreign`. `None` for a key that is not there, which is the
964 /// `none` Redis answers with.
965 pub fn type_name(&mut self, key: &[u8]) -> Option<&'static str> {
966 match self.kind_of(key)? {
967 Kind::Foreign => self.foreign_at(key).map(Foreign::type_name),
968 kind => Some(kind.name()),
969 }
970 }
971
972 /// `OBJECT ENCODING key`, as the word Redis puts on the wire.
973 ///
974 /// One place that knows every type's answer, so that adding the hash means
975 /// adding an arm here and not finding the four callers that each worked it
976 /// out for themselves.
977 pub fn encoding_name(&mut self, key: &[u8]) -> Option<&'static str> {
978 match self.kind_of(key)? {
979 Kind::String => self.encoding(key).map(value::Encoding::name),
980 Kind::Set => self.set_encoding(key).map(set::Encoding::name),
981 Kind::Hash => self.hash_encoding(key).map(hash::Encoding::name),
982 Kind::List => self.list_encoding(key).map(list::Encoding::name),
983 Kind::Zset => self.zset_encoding(key).map(zset::Encoding::name),
984 // The one type with one encoding, so there is nothing to ask.
985 Kind::Array => Some("sliced-array"),
986 // The same, and Redis's word for it rather than a description of
987 // the node layout.
988 Kind::Stream => Some("stream"),
989 // The body knows and this does not, which is the whole point of it.
990 Kind::Foreign => self.foreign_at(key).map(Foreign::encoding),
991 }
992 }
993
994 /// Put a deadline on `key`, or take one off. Answers whether it was there.
995 ///
996 /// Any type. A deadline lives in the record and changes its length, so this
997 /// writes the record again rather than patching it, and for a set that is
998 /// five bytes or thirteen and never the members. The body is left exactly
999 /// where it is, which is why this writes through the map instead of taking
1000 /// the free the body path an overwrite takes.
1001 ///
1002 /// This is the raw write. [`Keyspace::expire`] and [`Keyspace::persist`] are
1003 /// what `EXPIRE` and its family call, and they come through here once they
1004 /// have worked out whether the deadline is allowed to move.
1005 pub fn set_expiry(&mut self, key: &[u8], at: Option<u64>) -> bool {
1006 self.reap(key);
1007 let Some(rec) = self.map.get(key) else {
1008 return false;
1009 };
1010 if value::expire_at(rec) == at {
1011 return true;
1012 }
1013 // A deadline does not move a value that is on the file, it changes the
1014 // eight bytes in front of the address. So this writes a new pointer
1015 // rather than reading the value back to write it out again, and `EXPIRE`
1016 // on a demoted key costs no device read at all. That is the same promise
1017 // `TTL` and `STRLEN` keep and it is why the header stayed in memory.
1018 //
1019 // Ahead of the type split rather than inside the string arm, because a
1020 // demoted set is a pointer in exactly the same way and writing a slot
1021 // record over one would leave a record pointing at a slab slot that
1022 // belongs to something else.
1023 if let Some(c) = value::cold(rec) {
1024 let m = value::Meta::from_byte(rec[0]);
1025 let (kind, enc) = (m.kind(), m.encoding());
1026 let was = value::access(rec).unwrap_or_default();
1027 self.map.set_with(
1028 key,
1029 value::cold_record_len(at.is_some()),
1030 |_| {},
1031 |out| {
1032 value::write_cold_record(out, kind, enc, c.at, c.len, at);
1033 value::set_access(out, was);
1034 value::has_expiry(out)
1035 },
1036 );
1037 return true;
1038 }
1039 // Read what has to survive out of the record before writing over it.
1040 match value::kind(rec) {
1041 Kind::String => {
1042 // Through the scratch buffer rather than a fresh `Vec`, since
1043 // `EXPIRE` on a string is a command a cache sends as often as
1044 // the `SET` before it.
1045 let mut bytes = std::mem::take(&mut self.scratch);
1046 bytes.clear();
1047 value::read(rec).write_to(&mut bytes);
1048 self.store(key, &bytes, at);
1049 self.scratch = bytes;
1050 }
1051 // Every body type writes the same record: a tag and a slot number.
1052 // The body is not touched and does not need to be, which is the
1053 // whole point of keeping it out of the record.
1054 kind @ (Kind::Set
1055 | Kind::Hash
1056 | Kind::List
1057 | Kind::Zset
1058 | Kind::Array
1059 | Kind::Stream
1060 | Kind::Foreign) => {
1061 let slot = value::slot(rec);
1062 let len = value::slot_record_len(at.is_some());
1063 self.write_rec(key, len, |out| {
1064 value::write_slot_record(out, kind, slot, at);
1065 });
1066 }
1067 }
1068 true
1069 }
1070
1071 /// The key's deadline, as the three way answer `TTL` and `PTTL` are built on.
1072 ///
1073 /// [`Ask::Missing`] for a key that is not there, [`Ask::NoDeadline`] for one
1074 /// that is and has no deadline, and the absolute millisecond otherwise. A key
1075 /// past its deadline is reaped on the way through, so it answers `Missing`
1076 /// and not the moment that has gone.
1077 ///
1078 /// Asking when a key dies is not using it, so this does not stamp the
1079 /// eviction clock. Redis reads the key with its no touch flag here for the
1080 /// same reason, and it matters more than it looks: a client polling `TTL` on
1081 /// a key would otherwise keep that key at the top of the working set for as
1082 /// long as it kept asking whether it was about to go.
1083 pub fn deadline_of(&mut self, key: &[u8]) -> Ask {
1084 let Some(addr) = self.live_rec_untouched(key) else {
1085 return Ask::Missing;
1086 };
1087 match value::expire_at(self.map.value_at(addr)) {
1088 Some(at) => Ask::At(at),
1089 None => Ask::NoDeadline,
1090 }
1091 }
1092
1093 /// Move `key`'s deadline to `at`, if `cond` lets it.
1094 ///
1095 /// This is `EXPIRE`, `PEXPIRE`, `EXPIREAT` and `PEXPIREAT`, which differ only
1096 /// in the unit and the origin of the number. All four turn it into one
1097 /// absolute millisecond before they get here, so the condition rules live in
1098 /// one place and the four commands cannot drift apart.
1099 ///
1100 /// A deadline that has already passed deletes the key rather than being
1101 /// stored, and the answer says so. `EXPIRE` cannot report the difference
1102 /// because it replies 1 either way, but the caller is not always `EXPIRE`,
1103 /// and a delete is a different thing from a deadline.
1104 ///
1105 /// The condition is checked before the past check, which is the order Redis
1106 /// uses and is the one that matters: `EXPIRE key 0 XX` on a key with no
1107 /// deadline answers 0 and leaves the key alone, rather than deleting it.
1108 pub fn expire(&mut self, key: &[u8], at: u64, cond: Cond) -> Applied {
1109 let prev = match self.deadline_of(key) {
1110 Ask::Missing => return Applied::Missing,
1111 Ask::NoDeadline => None,
1112 Ask::At(at) => Some(at),
1113 };
1114 let done = ttl::decide(prev, at, cond, self.clock.now_ms());
1115 match done {
1116 Applied::Ok => {
1117 self.set_expiry(key, Some(at));
1118 }
1119 // The structure that answered `Deleted` for a field only holds
1120 // deadlines, so its caller has to remove the field. Here the caller
1121 // is us and the key is ours, so it goes now.
1122 Applied::Deleted => {
1123 self.drop_key(key);
1124 }
1125 Applied::Missing | Applied::NotMet => {}
1126 }
1127 done
1128 }
1129
1130 /// Take `key`'s deadline off. Answers whether there was one to take.
1131 ///
1132 /// This is `PERSIST`, and the reply is the same 0 for a key that is not there
1133 /// and a key that was never going to expire, which is Redis's answer and not
1134 /// a shortcut here.
1135 pub fn persist(&mut self, key: &[u8]) -> bool {
1136 if !matches!(self.deadline_of(key), Ask::At(_)) {
1137 return false;
1138 }
1139 self.set_expiry(key, None);
1140 true
1141 }
1142
1143 /// Give back whatever `key` holds outside its record, if it holds anything.
1144 ///
1145 /// Every path that deletes a key or writes over one has to come through
1146 /// here, because a set that loses its record without losing its slab slot is
1147 /// a leak that nothing ever notices: the memory is reachable, the slot is
1148 /// never reused, and `DBSIZE` looks right. Six delete sites and four string
1149 /// writers each remembering to do it themselves is five chances to forget,
1150 /// and one of them would be forgotten. So this is the funnel, and when the
1151 /// hash type lands the only place that changes is the match below.
1152 ///
1153 /// The record is left alone. This frees the body and the caller either
1154 /// deletes the record or writes a new one over it.
1155 pub(crate) fn free_body(&mut self, key: &[u8]) {
1156 if self.bodies == 0 {
1157 return;
1158 }
1159 let Some(rec) = self.map.get(key) else {
1160 return;
1161 };
1162 // A body that has been moved to the file has no slab slot to give back,
1163 // and the four bytes where the slot number would be are the front of an
1164 // address. Reading them as a slot and freeing it would hand back a slot
1165 // belonging to a different key. The chunks on the file are left where
1166 // they are, which is what the log's compaction collects. See
1167 // [`crate::tier`].
1168 if value::Meta::from_byte(rec[0]).is_cold() {
1169 return;
1170 }
1171 match value::kind(rec) {
1172 Kind::String => {}
1173 Kind::Set => {
1174 let at = value::slot(rec);
1175 self.sets.remove(at);
1176 self.bodies -= 1;
1177 }
1178 Kind::Hash => {
1179 let at = value::slot(rec);
1180 self.hashes.remove(at);
1181 self.bodies -= 1;
1182 }
1183 Kind::List => {
1184 let at = value::slot(rec);
1185 self.lists.remove(at);
1186 self.bodies -= 1;
1187 }
1188 Kind::Zset => {
1189 let at = value::slot(rec);
1190 self.zsets.remove(at);
1191 self.bodies -= 1;
1192 }
1193 Kind::Array => {
1194 let at = value::slot(rec);
1195 self.arrays.remove(at);
1196 self.bodies -= 1;
1197 }
1198 Kind::Stream => {
1199 let at = value::slot(rec);
1200 self.streams.remove(at);
1201 self.bodies -= 1;
1202 }
1203 Kind::Foreign => {
1204 let at = value::slot(rec);
1205 self.foreign.remove(at);
1206 self.bodies -= 1;
1207 }
1208 }
1209 }
1210
1211 /// Delete `key` and whatever it held. Answers whether it was there.
1212 #[inline]
1213 pub(crate) fn drop_key(&mut self, key: &[u8]) -> bool {
1214 self.free_body(key);
1215 self.del_rec(key)
1216 }
1217
1218 /// Drop `key` if its deadline has passed.
1219 ///
1220 /// This is lazy expiry and it is half of the story. The other half is
1221 /// [`Keyspace::expire_cycle`], which the maintenance slice runs and which is
1222 /// what stops a key nobody ever reads again from holding its memory forever
1223 /// (`14` section 1).
1224 ///
1225 /// Every public read calls this first, whatever type it is reading, which
1226 /// is why it is here and not in the file for any one type.
1227 #[inline]
1228 pub(crate) fn reap(&mut self, key: &[u8]) {
1229 let now = self.clock.now_ms();
1230 let dead = self.map.get(key).is_some_and(|r| value::is_expired(r, now));
1231 if dead {
1232 self.drop_key(key);
1233 self.expired += 1;
1234 }
1235 }
1236
1237 /// Give this database somewhere to keep values that are not in memory.
1238 ///
1239 /// Until this is called nothing is ever demoted, no record is ever cold and
1240 /// every command takes exactly the path it took before, which is why a
1241 /// database that never opens a file pays nothing for this existing.
1242 ///
1243 /// The store is whatever the caller wants it to be. In a server it is the
1244 /// shard's log. In a test it is a vector. This crate does not depend on
1245 /// either and does not want to: [`Blocks`] is an append that hands
1246 /// back an address and a read that takes one, and that is the whole of the
1247 /// contract between the memory engine and whatever is under it.
1248 pub fn attach(&mut self, blocks: Box<dyn Blocks>) {
1249 self.tier = Some(Tier::new(blocks));
1250 }
1251
1252 /// The tier, if one was attached, for its counters.
1253 #[must_use]
1254 pub const fn tier(&self) -> Option<&Tier<Box<dyn Blocks>>> {
1255 self.tier.as_ref()
1256 }
1257
1258 /// The tier, mutably, for a caller driving a sweep.
1259 pub const fn tier_mut(&mut self) -> Option<&mut Tier<Box<dyn Blocks>>> {
1260 self.tier.as_mut()
1261 }
1262
1263 /// Move one key's value out to the file.
1264 ///
1265 /// Answers whether it went. A key that is not there, one that is int
1266 /// encoded, one holding a type that does not move yet and one whose value is
1267 /// shorter than the pointer that would replace it all answer false, and so
1268 /// does every key on a database with nothing attached.
1269 ///
1270 /// This is the single key form, which is what a test and a `DEBUG`
1271 /// subcommand want. What a server under memory pressure wants is
1272 /// [`Keyspace::relieve`].
1273 ///
1274 /// One entry point for both kinds of value, because a caller naming a key
1275 /// should not have to know whether its body is in the record or in a slab.
1276 /// The two paths underneath are different all the way down: a string goes
1277 /// through the tier, and a collection goes through `demote_body` beside
1278 /// this, which frees a slab slot and grows a record.
1279 ///
1280 /// # Errors
1281 ///
1282 /// Whatever the store says when it will not take the bytes.
1283 pub fn demote(&mut self, key: &[u8]) -> Result<bool> {
1284 if self.tier.is_none() {
1285 return Ok(false);
1286 }
1287 let Some(addr) = self.map.find(key) else {
1288 return Ok(false);
1289 };
1290 if value::kind(self.map.value_at(addr)).is_body() {
1291 return self.demote_body(key);
1292 }
1293 let tier = self.tier.as_mut().expect("checked at the top");
1294 tier.demote(&mut self.map, key)
1295 }
1296
1297 /// How many bytes the attached store is holding, or `None` if there is not
1298 /// one.
1299 ///
1300 /// `None` and `Some(0)` are different answers and the difference is the one
1301 /// `maxstore` turns on. A database with nothing attached cannot migrate and
1302 /// has to evict, and a database with an empty file attached can migrate the
1303 /// moment it needs to.
1304 #[must_use]
1305 pub fn store_bytes(&self) -> Option<u64> {
1306 self.tier.as_ref().map(Tier::store_bytes)
1307 }
1308
1309 /// Move values out to the file until at least `shed` bytes of memory have
1310 /// gone.
1311 ///
1312 /// Answers with a [`Relief`], which is how many keys went and how much
1313 /// memory that gave back. This is `maxmemory` under the inversion `14`
1314 /// describes: the limit that used to throw keys away now moves them, and
1315 /// what a client stored is still there afterwards.
1316 ///
1317 /// Bytes to shed rather than a target to reach, because the caller with the
1318 /// limit is a server holding sixteen databases against one number and what
1319 /// it knows is how far over it is, not what any one database should be
1320 /// holding. `usize::MAX` means everything that can go, which is what a sweep
1321 /// wants.
1322 ///
1323 /// Victims are chosen by the same policy `maxmemory-policy` names, so a
1324 /// database set to `allkeys-lru` demotes the coldest keys and one set to
1325 /// `volatile-ttl` demotes the ones closest to expiring. See
1326 /// [`Tier::relieve`] for what a sweep does and where it stops.
1327 ///
1328 /// # Why `noeviction` still moves values
1329 ///
1330 /// Because it says do not lose data, and moving a value to the file does not
1331 /// lose any. The policy is two things at once in Redis, whether to give
1332 /// memory back at all and which keys to take it from, and only the second of
1333 /// those means anything here. So the default policy picks victims the way
1334 /// `allkeys-lru` does and the promise it was set for is kept: every key a
1335 /// client stored is still readable afterwards.
1336 ///
1337 /// The alternative is a server that was given a file, was given a limit, and
1338 /// answers writes with OOM until somebody finds the third setting that turns
1339 /// the file on. That is a trap and not a default.
1340 ///
1341 /// # Two passes, because the two kinds of value are counted in different
1342 /// places
1343 ///
1344 /// Strings go first, through [`Tier::relieve`], which measures itself against
1345 /// the arena because a string is its record and moving one makes the arena
1346 /// smaller. Collections cannot be swept that way. A collection's body is in a
1347 /// slab the arena knows nothing about, and moving one makes the arena
1348 /// **bigger**, because a twenty byte pointer replaces an eight byte slot
1349 /// number. A loop that watched the arena would demote every collection in the
1350 /// database, watch its number go up the whole time, and never stop.
1351 ///
1352 /// So the second pass is here rather than in the tier, and it measures itself
1353 /// against [`Keyspace::memory_bytes`], which is the arena and the slabs
1354 /// together. That is the only number that goes down when a body moves, and it
1355 /// is the number the server's limit is compared against anyway.
1356 ///
1357 /// # Errors
1358 ///
1359 /// Whatever the store says when it will not take the bytes.
1360 pub fn relieve(&mut self, shed: usize) -> Result<Relief> {
1361 if self.tier.is_none() {
1362 return Ok(Relief::default());
1363 }
1364 let now = self.clock.now_ms();
1365 let policy = match self.policy {
1366 Policy::NoEviction => Policy::AllKeysLru,
1367 chosen => chosen,
1368 };
1369 let lfu = self.lfu;
1370 let start = self.memory_bytes();
1371 let target = start.saturating_sub(shed);
1372 let budget = self.map.memory_bytes().saturating_sub(shed);
1373 let tier = self.tier.as_mut().expect("checked just above");
1374 let mut relief = tier.relieve(&mut self.map, budget, policy, now, lfu)?;
1375 // A sweep compacts the arena, which moves records, and the memo holds a
1376 // record's address. It is normally thrown away by the map's write
1377 // counter moving, and a sweep that demoted nothing and compacted anyway
1378 // is the one case where that counter does not move.
1379 self.memo = Memo::empty();
1380 if self.bodies > 0 && self.memory_bytes() > target {
1381 relief.moved += self.shed_bodies(target, policy, now, lfu)?;
1382 }
1383 relief.freed = start.saturating_sub(self.memory_bytes());
1384 Ok(relief)
1385 }
1386
1387 /// Sample the keyspace for collection bodies and move them out until
1388 /// [`Keyspace::memory_bytes`] is under `target`.
1389 ///
1390 /// The same shape as [`Tier::relieve`]'s loop, with the same stop rule and
1391 /// for the same reason: a round that finds nothing is a collision rather than
1392 /// a conclusion, so it takes [`tier::BARREN`] of them in a row to give up.
1393 /// What is different is the number being watched, which is explained on
1394 /// [`Keyspace::relieve`], and that there is no compaction step in here. The
1395 /// arena grows on this path rather than shrinking, so there is nothing for a
1396 /// compaction to hand back that the string pass has not already taken.
1397 fn shed_bodies(
1398 &mut self,
1399 target: usize,
1400 policy: Policy,
1401 now_ms: u64,
1402 lfu: Lfu,
1403 ) -> Result<usize> {
1404 let mut moved = 0;
1405 let mut barren = 0;
1406 // The pool comes out of the keyspace for the length of the sweep, because
1407 // it hands back a borrow of itself and demoting one victim needs the
1408 // whole keyspace. `kb` is the same borrow copied somewhere it can live
1409 // across that call, and it is one allocation for the sweep rather than
1410 // one per victim.
1411 let mut pool = core::mem::take(&mut self.pool);
1412 let mut kb: Vec<u8> = Vec::new();
1413 while self.memory_bytes() > target {
1414 pool.clear();
1415 let r = self.rng.next_u64();
1416 let pool = &mut pool;
1417 let mut seen = 0usize;
1418 let mut found = 0usize;
1419 // The body check is on the record and not on the slab, so the sample
1420 // closure does not need a second borrow of the keyspace. A record
1421 // that turns out to hold a body too small to be worth moving is
1422 // refused by `demote_body`, which has the slab in hand by then.
1423 self.map.sample(r, |k, v, _| {
1424 seen += 1;
1425 let m = value::Meta::from_byte(v[0]);
1426 if !m.is_cold() && moves(m.kind()) {
1427 pool.offer(k, evict::score(v, policy, now_ms, lfu));
1428 found += 1;
1429 }
1430 found < evict::CANDIDATES && seen < tier::WALK
1431 });
1432
1433 let mut round = 0;
1434 while let Some(k) = pool.take() {
1435 kb.clear();
1436 kb.extend_from_slice(k);
1437 if self.demote_body(&kb)? {
1438 round += 1;
1439 }
1440 }
1441 if round == 0 {
1442 barren += 1;
1443 if barren == tier::BARREN {
1444 break;
1445 }
1446 continue;
1447 }
1448 barren = 0;
1449 moved += round;
1450 }
1451 self.pool = pool;
1452 // Every demotion rewrote a record, so nothing the memo holds is worth
1453 // keeping and one of the slot numbers in it is now a freed slab slot.
1454 self.memo = Memo::empty();
1455 Ok(moved)
1456 }
1457
1458 /// Move `key`'s collection body out to the file.
1459 ///
1460 /// `Ok(false)` for a key that is not there, that holds a type this does not
1461 /// move yet, that is already on the file, or whose body is smaller than the
1462 /// pointer that would replace it. None of those is an error, for the same
1463 /// reason none of them is in [`crate::tier::demote`](Tier::demote): a sweep
1464 /// asks about a lot of keys and most of the answers are no.
1465 ///
1466 /// # What is different from a string
1467 ///
1468 /// A string's value is its record, so the tier can read it, write it out and
1469 /// rewrite the record without anyone else being involved. A collection's body
1470 /// is in a slab and its record holds a four byte number, so three things have
1471 /// to happen here and only here: the body is turned into bytes that mean
1472 /// something on a device, the slab slot is freed, and the record grows from
1473 /// eight bytes to twenty because an address and a length are longer than a
1474 /// slot number.
1475 ///
1476 /// That last part is why the memory a sweep frees does not show up in the
1477 /// arena. Demoting a collection makes the arena bigger and the slab smaller,
1478 /// and it is the sum that goes down. See [`Keyspace::relieve`].
1479 ///
1480 /// # Errors
1481 ///
1482 /// Whatever the store says when it cannot take the bytes.
1483 pub(crate) fn demote_body(&mut self, key: &[u8]) -> Result<bool> {
1484 if self.tier.is_none() {
1485 return Ok(false);
1486 }
1487 let Some(addr) = self.map.find(key) else {
1488 return Ok(false);
1489 };
1490 let rec = self.map.value_at(addr);
1491 let m = value::Meta::from_byte(rec[0]);
1492 if m.is_cold() || !moves(m.kind()) {
1493 return Ok(false);
1494 }
1495 let kind = m.kind();
1496 let expire_at = value::expire_at(rec);
1497 // Carried across and not restamped, as in `Tier::demote`. A key that was
1498 // moved out was not used, and a demotion that looked like a use would
1499 // make the next sweep pick the wrong victim.
1500 let was = value::access(rec).unwrap_or_default();
1501 let slot = value::slot(rec);
1502 // The same arithmetic the string side uses and not a tunable: a body
1503 // that costs less to keep than the pointer to it would is left where it
1504 // is. It is even more favourable here, because what a table costs in
1505 // memory is well above what its members weigh on a device.
1506 let grows_by = value::cold_record_len(expire_at.is_some())
1507 - value::slot_record_len(expire_at.is_some());
1508
1509 let mut buf = core::mem::take(&mut self.frozen);
1510 buf.clear();
1511 let worth = self.freeze_body(kind, slot, grows_by, &mut buf);
1512 let stashed = if worth {
1513 let tier = self.tier.as_mut().expect("checked at the top");
1514 Some(tier.stash(&buf))
1515 } else {
1516 None
1517 };
1518 self.frozen = buf;
1519 let Some(wrote) = stashed else {
1520 return Ok(false);
1521 };
1522 let chain = wrote?;
1523
1524 self.free_slot(kind, slot);
1525 self.bodies -= 1;
1526 let len = chain.len as u32;
1527 let wrote = self.map.set_with(
1528 key,
1529 value::cold_record_len(expire_at.is_some()),
1530 |_| {},
1531 |out| {
1532 // The encoding bits mean nothing on a collection record, which
1533 // is what `Meta::slot` already writes and says. `OBJECT
1534 // ENCODING` on a demoted body brings it back and asks the body,
1535 // which is one device read for a command nobody sends in a
1536 // loop, and is one place holding the fact rather than two.
1537 value::write_cold_record(out, kind, value::Encoding::Int, chain.at, len, expire_at);
1538 value::set_access(out, was);
1539 value::has_expiry(out)
1540 },
1541 );
1542 debug_assert!(wrote.is_some(), "the key was found a moment ago");
1543 // Not cleared by hand. Writing the record moves the map's write counter
1544 // and that is what the memo checks, so the slot number it is holding for
1545 // this key is already unreachable.
1546 Ok(true)
1547 }
1548
1549 /// Turn the body in `slot` into bytes, or say it is not worth moving.
1550 ///
1551 /// The one place that knows which slab a kind indexes on the way out, and
1552 /// the size check is in here because it needs the body in hand and the body
1553 /// is the thing this is holding. `false` leaves `buf` in whatever state it
1554 /// was, which the caller does not read.
1555 fn freeze_body(&self, kind: Kind, slot: u32, grows_by: usize, buf: &mut Vec<u8>) -> bool {
1556 match kind {
1557 Kind::Set => match self.sets.get(slot) {
1558 Some(body) if body.memory_bytes() > grows_by => {
1559 body.freeze(buf);
1560 true
1561 }
1562 Some(_) => false,
1563 None => {
1564 debug_assert!(false, "a set record with no set behind it");
1565 false
1566 }
1567 },
1568 Kind::Hash => match self.hashes.get(slot) {
1569 Some(body) if body.memory_bytes() > grows_by => {
1570 body.freeze(buf);
1571 true
1572 }
1573 Some(_) => false,
1574 None => {
1575 debug_assert!(false, "a hash record with no hash behind it");
1576 false
1577 }
1578 },
1579 Kind::List => match self.lists.get(slot) {
1580 Some(body) if body.memory_bytes() > grows_by => {
1581 body.freeze(buf);
1582 true
1583 }
1584 Some(_) => false,
1585 None => {
1586 debug_assert!(false, "a list record with no list behind it");
1587 false
1588 }
1589 },
1590 Kind::Zset => match self.zsets.get(slot) {
1591 Some(body) if body.memory_bytes() > grows_by => {
1592 body.freeze(buf);
1593 true
1594 }
1595 Some(_) => false,
1596 None => {
1597 debug_assert!(false, "a sorted set record with no sorted set behind it");
1598 false
1599 }
1600 },
1601 Kind::Array => match self.arrays.get(slot) {
1602 Some(body) if body.memory_bytes() > grows_by => {
1603 body.freeze(buf);
1604 true
1605 }
1606 Some(_) => false,
1607 None => {
1608 debug_assert!(false, "an array record with no array behind it");
1609 false
1610 }
1611 },
1612 Kind::Stream => match self.streams.get(slot) {
1613 Some(body) if body.memory_bytes() > grows_by => {
1614 body.freeze(buf);
1615 true
1616 }
1617 Some(_) => false,
1618 None => {
1619 debug_assert!(false, "a stream record with no stream behind it");
1620 false
1621 }
1622 },
1623 _ => {
1624 debug_assert!(false, "a kind `moves` said yes to and this does not know");
1625 false
1626 }
1627 }
1628 }
1629
1630 /// Give a slab slot back once its body has been written out.
1631 ///
1632 /// The twin of [`Keyspace::freeze_body`], kept beside it so that adding a
1633 /// type means touching two arms next to each other rather than hunting for
1634 /// the second one.
1635 fn free_slot(&mut self, kind: Kind, slot: u32) {
1636 match kind {
1637 Kind::Set => {
1638 self.sets.remove(slot);
1639 }
1640 Kind::Hash => {
1641 self.hashes.remove(slot);
1642 }
1643 Kind::List => {
1644 self.lists.remove(slot);
1645 }
1646 Kind::Zset => {
1647 self.zsets.remove(slot);
1648 }
1649 Kind::Array => {
1650 self.arrays.remove(slot);
1651 }
1652 Kind::Stream => {
1653 self.streams.remove(slot);
1654 }
1655 _ => debug_assert!(false, "freeing a slot in a slab that was never found"),
1656 }
1657 }
1658
1659 /// Send a cold record that holds a body back to [`Keyspace::promote_body`],
1660 /// and say whether that is what happened.
1661 ///
1662 /// The guard in front of both fault entry points, and it is here rather than
1663 /// in the tier because the tier cannot do this job. [`Tier::fault`] puts a
1664 /// value back by writing a string record, so handing it a demoted set would
1665 /// turn the set into a string holding the bytes a set freezes to. The kind is
1666 /// in the record and only this side has a slab to put a body in.
1667 ///
1668 /// One probe of the map on a path that is about to read a device, on a
1669 /// database that has a file at all. Every other database is refused by the
1670 /// caller before it gets here.
1671 ///
1672 /// # Errors
1673 ///
1674 /// Whatever the store says when the chain will not read back.
1675 fn body_came_back(&mut self, key: &[u8]) -> Result<bool> {
1676 let Some(addr) = self.map.find(key) else {
1677 return Ok(false);
1678 };
1679 let m = value::Meta::from_byte(self.map.value_at(addr)[0]);
1680 if !m.is_cold() || !m.kind().is_body() {
1681 return Ok(false);
1682 }
1683 self.promote_body(key)?;
1684 Ok(true)
1685 }
1686
1687 /// Bring `key`'s collection body back into a slab and answer its new slot.
1688 ///
1689 /// The record has to be rewritten either way, because a resident collection
1690 /// is a slot number and there is no way to hold one without being in the
1691 /// slab, so the doorkeeper does not get a vote. See [`Tier::fetch`].
1692 ///
1693 /// # Errors
1694 ///
1695 /// Whatever the store says when the chain will not read back, and
1696 /// [`Code::Corrupt`] when it reads back as something that is not a body.
1697 fn promote_body(&mut self, key: &[u8]) -> Result<Option<u32>> {
1698 let Some(addr) = self.map.find(key) else {
1699 return Ok(None);
1700 };
1701 let rec = self.map.value_at(addr);
1702 let Some(c) = value::cold(rec) else {
1703 return Ok(None);
1704 };
1705 let kind = value::kind(rec);
1706 let expire_at = value::expire_at(rec);
1707 let was = value::access(rec).unwrap_or_default();
1708 let Some(tier) = self.tier.as_mut() else {
1709 debug_assert!(false, "a cold record on a database with no file");
1710 return Ok(None);
1711 };
1712
1713 let mut buf = core::mem::take(&mut self.frozen);
1714 let read = tier.fetch(
1715 crate::cold::Chain {
1716 at: c.at,
1717 len: u64::from(c.len),
1718 },
1719 &mut buf,
1720 );
1721 self.frozen = buf;
1722 read?;
1723
1724 let slot = match kind {
1725 Kind::Set => {
1726 let set = Set::thaw(&self.frozen).map_err(|e| {
1727 Error::new(Code::Corrupt, "a demoted set did not read back")
1728 .with_detail(e.to_string())
1729 })?;
1730 self.sets.insert(set)
1731 }
1732 Kind::Hash => {
1733 let hash = Hash::thaw(&self.frozen).map_err(|e| {
1734 Error::new(Code::Corrupt, "a demoted hash did not read back")
1735 .with_detail(e.to_string())
1736 })?;
1737 self.hashes.insert(hash)
1738 }
1739 Kind::List => {
1740 let list = List::thaw(&self.frozen).map_err(|e| {
1741 Error::new(Code::Corrupt, "a demoted list did not read back")
1742 .with_detail(e.to_string())
1743 })?;
1744 self.lists.insert(list)
1745 }
1746 Kind::Zset => {
1747 let zset = Zset::thaw(&self.frozen).map_err(|e| {
1748 Error::new(Code::Corrupt, "a demoted sorted set did not read back")
1749 .with_detail(e.to_string())
1750 })?;
1751 self.zsets.insert(zset)
1752 }
1753 Kind::Array => {
1754 let array = Array::thaw(&self.frozen).map_err(|e| {
1755 Error::new(Code::Corrupt, "a demoted array did not read back")
1756 .with_detail(e.to_string())
1757 })?;
1758 self.arrays.insert(array)
1759 }
1760 Kind::Stream => {
1761 let stream = Stream::thaw(&self.frozen).map_err(|e| {
1762 Error::new(Code::Corrupt, "a demoted stream did not read back")
1763 .with_detail(e.to_string())
1764 })?;
1765 self.streams.insert(stream)
1766 }
1767 // Nothing else is written cold with a body yet, so arriving here
1768 // means a record that says one thing and a demoter that did another.
1769 _ => {
1770 return Err(Error::new(
1771 Code::Corrupt,
1772 "a demoted body of a type that is not moved out",
1773 )
1774 .with_detail(kind.name().to_string()));
1775 }
1776 };
1777 self.bodies += 1;
1778 let wrote = self.map.set_with(
1779 key,
1780 value::slot_record_len(expire_at.is_some()),
1781 |_| {},
1782 |out| {
1783 value::write_slot_record(out, kind, slot, expire_at);
1784 value::set_access(out, was);
1785 value::has_expiry(out)
1786 },
1787 );
1788 debug_assert!(wrote.is_some(), "the key was found a moment ago");
1789 Ok(Some(slot))
1790 }
1791
1792 /// Read `key`'s value off the file into [`Keyspace::cold`], if that is where
1793 /// it is.
1794 ///
1795 /// The doorkeeper decides whether the value also goes back into memory, so
1796 /// after this the record under `key` is either resident or still cold with
1797 /// its bytes in the buffer, and [`Keyspace::value_of`] is what tells the two
1798 /// apart. The address the caller was holding is not valid afterwards on the
1799 /// promoting path, because promotion rewrites the record.
1800 ///
1801 /// # Errors
1802 ///
1803 /// Whatever the store says when the chain will not read back.
1804 pub(crate) fn warm(&mut self, key: &[u8]) -> Result<Faulted> {
1805 if self.tier.is_none() {
1806 return Ok(Faulted::Warm);
1807 }
1808 if self.body_came_back(key)? {
1809 return Ok(Faulted::Promoted);
1810 }
1811 let tier = self.tier.as_mut().expect("checked at the top");
1812 let mut buf = core::mem::take(&mut self.cold);
1813 let r = tier.fault(&mut self.map, key, &mut buf);
1814 self.cold = buf;
1815 if r == Ok(Faulted::Served) {
1816 self.cold_key.clear();
1817 self.cold_key.extend_from_slice(key);
1818 }
1819 r
1820 }
1821
1822 /// Put `key`'s value back in memory if it was not there, for a command that
1823 /// is about to write it.
1824 ///
1825 /// See [`Tier::thaw`] for why the doorkeeper does not get a vote here. The
1826 /// short of it is that a read modify write leaves a resident record either
1827 /// way, so there is nothing for an answer to change.
1828 ///
1829 /// A caller can carry on exactly as it did before after this returns, with
1830 /// no cold case left to handle, which is why it is one line at the top of
1831 /// `APPEND` and `INCR` rather than a second path through them.
1832 ///
1833 /// # Errors
1834 ///
1835 /// Whatever the store says when the chain will not read back.
1836 pub(crate) fn thaw(&mut self, key: &[u8]) -> Result<()> {
1837 if self.tier.is_none() {
1838 return Ok(());
1839 }
1840 if self.body_came_back(key)? {
1841 return Ok(());
1842 }
1843 let tier = self.tier.as_mut().expect("checked at the top");
1844 let mut buf = core::mem::take(&mut self.cold);
1845 let r = tier.thaw(&mut self.map, key, &mut buf);
1846 self.cold = buf;
1847 r.map(|_| ())
1848 }
1849
1850 /// The value in a record that may have been left on the file.
1851 ///
1852 /// Only correct straight after a [`Keyspace::warm`] of the same key, since
1853 /// the buffer holds one value at a time. A debug build says so rather than
1854 /// handing back a value that belongs to somebody else.
1855 pub(crate) fn value_of<'a>(&'a self, key: &[u8], rec: &'a [u8]) -> Str<'a> {
1856 if value::cold(rec).is_some() {
1857 debug_assert!(
1858 bytes_eq(&self.cold_key, key),
1859 "a read found a value on the file without faulting it in first"
1860 );
1861 Str::Bytes(&self.cold)
1862 } else {
1863 value::read(rec)
1864 }
1865 }
1866
1867 /// [`Keyspace::warm`] and then the value, for the readers that do nothing
1868 /// else with the record.
1869 ///
1870 /// `None` when the key went away, which it cannot do here but which the
1871 /// second lookup has to allow for anyway: the first lookup's address does
1872 /// not survive a promotion, so this has to find the key again rather than
1873 /// trust a number from before.
1874 ///
1875 /// # Errors
1876 ///
1877 /// Whatever the store says when the chain will not read back.
1878 pub(crate) fn warmed(&mut self, key: &[u8]) -> Result<Option<Str<'_>>> {
1879 self.warm(key)?;
1880 let Some(addr) = self.map.find(key) else {
1881 return Ok(None);
1882 };
1883 Ok(Some(self.value_of(key, self.map.value_at(addr))))
1884 }
1885
1886 /// Where `key`'s record is, having thrown the key away first if it is dead.
1887 ///
1888 /// The same fold as [`Keyspace::live_slot`] for a caller that wants the
1889 /// record itself rather than a slot number, which is every string command.
1890 /// `GET` used to be a reap, then a type check, then a read, and each of the
1891 /// three hashed the key and walked a bucket for the same record. It is one
1892 /// walk now and two arena reads, and an arena read at a known address is a
1893 /// load.
1894 ///
1895 /// The address dies at the next write, which is why this is `pub(crate)`
1896 /// and why every caller reads it and drops it inside one command.
1897 ///
1898 /// Finding a key counts as using it, so this stamps the access field on the
1899 /// way past under every policy that wants it stamped, which is eight of the
1900 /// ten. A command that has to look at a key without using it calls
1901 /// [`Keyspace::live_rec_untouched`] instead, and the list of those is short
1902 /// and is Redis's list rather than ours.
1903 pub(crate) fn live_rec(&mut self, key: &[u8]) -> Option<Addr> {
1904 let addr = self.live_rec_untouched(key)?;
1905 if self.policy.stamps_on_read() {
1906 self.stamp(addr);
1907 }
1908 Some(addr)
1909 }
1910
1911 /// [`Keyspace::live_rec`] for a command that is asking about a key rather
1912 /// than using it.
1913 ///
1914 /// `TYPE`, `EXISTS`, the `TTL` family and every `OBJECT` subcommand look
1915 /// without touching, which is Redis's `LOOKUP_NOTOUCH` and is not an
1916 /// optimisation. `OBJECT IDLETIME` that counted as a use would report zero
1917 /// every time, and `EXISTS` in a health check loop would keep a dead key at
1918 /// the top of the working set forever.
1919 ///
1920 /// Untouched means the access field only. A key past its deadline is still
1921 /// reaped here, because a command asking whether a key exists has to be told
1922 /// that it does not.
1923 pub(crate) fn live_rec_untouched(&mut self, key: &[u8]) -> Option<Addr> {
1924 let now = self.clock.now_ms();
1925 let addr = self.map.find(key)?;
1926 if value::is_expired(self.map.value_at(addr), now) {
1927 self.drop_key(key);
1928 self.expired += 1;
1929 return None;
1930 }
1931 Some(addr)
1932 }
1933
1934 /// The slot under `key`, having thrown the key away first if it is dead.
1935 ///
1936 /// `None` for a key that is not there or that was and is now reaped, and
1937 /// `WRONGTYPE` for a key holding something other than `want`.
1938 ///
1939 /// One probe of the map, where a [`Keyspace::reap`] followed by a `get`
1940 /// costs two. That pair is how every collection command used to start, so a
1941 /// pipeline of sixty four `SADD` on one key hashed and probed for that key a
1942 /// hundred and twenty eight times to do sixty four inserts. The reap has to
1943 /// read the record and the command has to read the same record, and there
1944 /// was never a reason for those to be two visits.
1945 ///
1946 /// It answers a number rather than the record it just read because of the
1947 /// borrow checker and not because a number is nicer. A method that hands
1948 /// back a borrow of the map on one path and takes a mutable borrow to reap
1949 /// on the other is the case the borrow checker still refuses without
1950 /// Polonius. A slot is four bytes and copies out, so the borrow ends here
1951 /// and the caller reaches its body through the slab.
1952 ///
1953 /// And no probe at all when the command in front of it asked for the same
1954 /// key and nothing has been written since, which is the [`Memo`] and is what
1955 /// Y13 asks for on single key `SADD`.
1956 pub(crate) fn live_slot(&mut self, key: &[u8], want: Kind) -> Result<Option<u32>> {
1957 // A memo hit skips the record, so the stamp has to happen on the way out
1958 // of it as well. It is the same address every time, which is what makes
1959 // this cheap: no probe, just the store. Getting this wrong is the trap
1960 // worth naming, because the key that hits the memo most often is the
1961 // hottest key in the database, and it is the one that would have looked
1962 // steadily more idle the harder it was used.
1963 if let Some((kind, slot, addr)) = self.memo.get(self.map.writes(), key) {
1964 if kind != want {
1965 return Err(wrong_type());
1966 }
1967 if self.policy.stamps_on_read() {
1968 self.stamp(addr);
1969 }
1970 return Ok(Some(slot));
1971 }
1972 // `find` and then `value_at` rather than `get`, which is the same two
1973 // steps, so that the address is still in hand for the stamp below. `get`
1974 // would mean probing a second time for a record already read.
1975 let now = self.clock.now_ms();
1976 let Some(addr) = self.map.find(key) else {
1977 return Ok(None);
1978 };
1979 let rec = self.map.value_at(addr);
1980 if value::is_expired(rec, now) {
1981 self.drop_key(key);
1982 self.expired += 1;
1983 return Ok(None);
1984 }
1985 if value::kind(rec) != want {
1986 return Err(wrong_type());
1987 }
1988 // One test of a bit in a byte that is already in a register, on the
1989 // funnel every collection command comes through. A database with no file
1990 // behind it never sets it and pays that test and nothing else.
1991 if value::Meta::from_byte(rec[0]).is_cold() {
1992 return self.promote_body(key);
1993 }
1994 let slot = value::slot(rec);
1995 // A key with a deadline is not memoized. The memo is invalidated by
1996 // writes and a deadline passes without one, so remembering a dated key
1997 // would be remembering it past the moment it should have been reaped.
1998 // Both of these are read off the record before the stamp, which needs it
1999 // mutably and is the end of this borrow.
2000 let dated = value::expire_at(rec).is_some();
2001 if self.policy.stamps_on_read() {
2002 self.stamp(addr);
2003 }
2004 if !dated {
2005 self.memo.put(self.map.writes(), key, want, slot, addr);
2006 }
2007 Ok(Some(slot))
2008 }
2009
2010 /// Where `key` is, when either of two types will do.
2011 ///
2012 /// Every input to a sorted set operation may be a sorted set or a plain set,
2013 /// which is Redis's rule and means the type check there is a membership test
2014 /// rather than an equality. The kind comes back with the slot because the
2015 /// caller has to know which slab the number indexes.
2016 pub(crate) fn live_slot_either(
2017 &mut self,
2018 key: &[u8],
2019 a: Kind,
2020 b: Kind,
2021 ) -> Result<Option<(Kind, u32)>> {
2022 if let Some((kind, slot, addr)) = self.memo.get(self.map.writes(), key) {
2023 if kind != a && kind != b {
2024 return Err(wrong_type());
2025 }
2026 if self.policy.stamps_on_read() {
2027 self.stamp(addr);
2028 }
2029 return Ok(Some((kind, slot)));
2030 }
2031 let now = self.clock.now_ms();
2032 let Some(addr) = self.map.find(key) else {
2033 return Ok(None);
2034 };
2035 let rec = self.map.value_at(addr);
2036 if value::is_expired(rec, now) {
2037 self.drop_key(key);
2038 self.expired += 1;
2039 return Ok(None);
2040 }
2041 let kind = value::kind(rec);
2042 if kind != a && kind != b {
2043 return Err(wrong_type());
2044 }
2045 // As in `live_slot`, and the kind was read before the record was given
2046 // up because promotion rewrites it.
2047 if value::Meta::from_byte(rec[0]).is_cold() {
2048 return Ok(self.promote_body(key)?.map(|slot| (kind, slot)));
2049 }
2050 let slot = value::slot(rec);
2051 let dated = value::expire_at(rec).is_some();
2052 if self.policy.stamps_on_read() {
2053 self.stamp(addr);
2054 }
2055 if !dated {
2056 self.memo.put(self.map.writes(), key, kind, slot, addr);
2057 }
2058 Ok(Some((kind, slot)))
2059 }
2060
2061 /// Throw every key away. This is `FLUSHDB` on one database.
2062 ///
2063 /// The expiry counter is not reset, because Redis does not reset it either:
2064 /// `expired_keys` in `INFO stats` counts what this process has expired since
2065 /// it started, and emptying a database is not expiring anything. The count of
2066 /// keys that carry a deadline is a different number and it does go to zero,
2067 /// because it is a fact about what is in the database right now and there is
2068 /// nothing in it.
2069 pub fn clear(&mut self) {
2070 self.map.clear();
2071 self.sets.clear();
2072 self.hashes.clear();
2073 self.lists.clear();
2074 self.zsets.clear();
2075 self.arrays.clear();
2076 self.streams.clear();
2077 self.foreign.clear();
2078 self.pool.clear();
2079 self.bodies = 0;
2080 }
2081
2082 /// Keys reclaimed by running into them after their deadline.
2083 ///
2084 /// Redis calls this `expired_keys` in `INFO stats` and counts both lazy and
2085 /// active expiry into it, and so does this. [`Keyspace::expire_cycle`] is
2086 /// the active half and it counts into the same number, which is what makes
2087 /// this the total a dashboard can compare against a write rate rather than
2088 /// the share of it that happened to be reclaimed by a read.
2089 #[inline]
2090 pub const fn expired_keys(&self) -> u64 {
2091 self.expired
2092 }
2093
2094 /// Keys thrown away to make room.
2095 ///
2096 /// Redis calls this `evicted_keys` in `INFO stats`. It stays at zero under
2097 /// `noeviction`, which is the whole point of that policy, and a monitoring
2098 /// dashboard that sees it move on a server configured that way is looking at
2099 /// a bug rather than at load.
2100 #[inline]
2101 pub const fn evicted_keys(&self) -> u64 {
2102 self.evicted
2103 }
2104
2105 /// How many live keys carry a deadline.
2106 ///
2107 /// This is what `INFO keyspace` reports as `expires=`, and it is the live
2108 /// count rather than a running total: a key that gets a `TTL` and then has it
2109 /// taken away with `PERSIST` is in it and then is not.
2110 ///
2111 /// The map keeps it, because the map keeps the second index these keys are
2112 /// in. Nothing in this file counts it, which is deliberate: a count kept
2113 /// alongside the thing it counts is a count that eventually disagrees with
2114 /// it, and the one place that can be wrong should be the one place that owns
2115 /// the entries.
2116 #[inline]
2117 pub fn expires(&self) -> usize {
2118 self.map.tagged_len()
2119 }
2120
2121 /// How many keys a round of eviction sampling looks at.
2122 #[inline]
2123 pub const fn samples(&self) -> usize {
2124 self.samples
2125 }
2126
2127 /// Set how many keys a round of eviction sampling looks at.
2128 ///
2129 /// Zero is not refused here, because the caller doing the refusing is
2130 /// `CONFIG SET` and it has a message to produce. A zero that reaches here
2131 /// samples one bucket and takes the best of it, because the loop runs its
2132 /// body before it checks, which is a better answer than dividing by nothing.
2133 #[inline]
2134 pub const fn set_samples(&mut self, samples: usize) {
2135 self.samples = samples;
2136 }
2137
2138 /// Throw away one key, chosen by the policy. Answers whether one went.
2139 ///
2140 /// This is one step and not a loop on purpose. The caller is the thing that
2141 /// knows how much room it needs back, and a loop in here would either take
2142 /// too much or have to be told the same number twice. It also means the
2143 /// caller can put a bound on how long it spends evicting before it answers
2144 /// the client, which matters because the client is waiting on a write that
2145 /// this is making room for.
2146 ///
2147 /// It answers false without doing anything under `noeviction`, and also when
2148 /// a `volatile` policy is set on a database where nothing has a deadline.
2149 /// Those are the same answer to the caller and they mean the same thing: this
2150 /// server cannot give memory back and is about to have to refuse a write.
2151 pub fn evict_one(&mut self) -> bool {
2152 let Some(addr) = self.victim() else {
2153 return false;
2154 };
2155 // The key has to outlive the borrow that found it, because deleting is a
2156 // write and the address came out of a read. One copy into the scratch
2157 // buffer rather than a `Vec` per eviction, for the reason written on
2158 // [`Keyspace::scratch`]: this runs in a loop when it runs at all.
2159 let mut buf = core::mem::take(&mut self.scratch);
2160 buf.clear();
2161 buf.extend_from_slice(self.map.entry_at(addr).0);
2162 let gone = self.drop_key(&buf);
2163 self.scratch = buf;
2164 if gone {
2165 self.evicted += 1;
2166 }
2167 gone
2168 }
2169
2170 /// Where the key this policy would throw away lives, if there is one.
2171 ///
2172 /// The sampling loop. It draws buckets until it has looked at `samples` keys
2173 /// the policy would consider, scores each one, and hands back the best. See
2174 /// [`evict`] for what the score means and [`yo_index::RawMap::sample`] for
2175 /// why a bucket is the unit.
2176 ///
2177 /// The round cap is the part that is not obvious. A database with a hundred
2178 /// keys in a directory sized for a million is mostly empty buckets, and a
2179 /// `volatile` policy on a database where nothing has a deadline has no
2180 /// eligible keys at all however many buckets it looks in. Without the cap the
2181 /// second case is an infinite loop, and it is not a rare configuration, it is
2182 /// the classic eviction surprise. With it, the worst case is a fixed number
2183 /// of cache misses and a false, which is exactly what the caller needs to
2184 /// hear.
2185 ///
2186 /// A key past its deadline is skipped rather than taken. It is dead memory
2187 /// and evicting it would look like a win, but it would be counted as an
2188 /// eviction when it is an expiry, and those two numbers are watched
2189 /// separately for a reason. Lazy expiry takes it the next time anything asks
2190 /// for it, and the active cycle takes it before that.
2191 ///
2192 /// What comes back is not only the worst of this round. Everything sampled
2193 /// goes into [`evict::Pool`], which holds the sixteen best across rounds, so
2194 /// the answer is the worst key seen since the pool was last emptied. The
2195 /// price is that a candidate is a key rather than an address and so has to
2196 /// be looked up and rechecked here, because it can have been deleted or have
2197 /// expired or have lost its deadline since the round that spotted it.
2198 fn victim(&mut self) -> Option<Addr> {
2199 if matches!(self.policy, Policy::NoEviction) || self.map.is_empty() {
2200 self.pool.clear();
2201 return None;
2202 }
2203 // The classic eviction surprise, answered before it costs anything. A
2204 // `volatile` policy on a database where no key has a deadline has no
2205 // eligible key anywhere, and the loop below can only find that out by
2206 // drawing four rounds of buckets and being told so by every key in them,
2207 // on a path where a client is waiting for the write this is making room
2208 // for. The count knows.
2209 if self.policy.volatile_only() && self.expires() == 0 {
2210 self.pool.clear();
2211 return None;
2212 }
2213 let now = self.clock.now_ms();
2214 let (policy, lfu, want) = (self.policy, self.lfu, self.samples);
2215 if policy.is_random() {
2216 return self.draw(now, want);
2217 }
2218 // Which index to draw from. The `volatile` policies can only take a key
2219 // that has a deadline, and the map keeps a second index of exactly
2220 // those, so drawing from the whole keyspace and then throwing most of it
2221 // away is work with a cheaper alternative sitting right there. The
2222 // `allkeys` policies draw from everything, because everything is
2223 // eligible.
2224 let volatile = policy.volatile_only();
2225 let mut seen = 0usize;
2226 for _ in 0..ROUNDS {
2227 let r = self.rng.next_u64();
2228 let pool = &mut self.pool;
2229 // By reference, so the same closure can go to either sampler. A
2230 // `&mut F` is an `FnMut` when `F` is, which is what makes the two
2231 // calls below one closure rather than two copies of it.
2232 let mut offer = |key: &[u8], rec: &[u8], _addr: Addr| {
2233 if !value::is_expired(rec, now) && evict::eligible(rec, policy) {
2234 seen += 1;
2235 pool.offer(key, evict::score(rec, policy, now, lfu));
2236 }
2237 seen < want
2238 };
2239 if volatile {
2240 self.map.sample_tagged(r, &mut offer);
2241 } else {
2242 self.map.sample(r, &mut offer);
2243 }
2244 if seen >= want {
2245 break;
2246 }
2247 }
2248 while let Some(key) = self.pool.take() {
2249 let Some(addr) = self.map.find(key) else {
2250 continue;
2251 };
2252 let rec = self.map.value_at(addr);
2253 if value::is_expired(rec, now) || !evict::eligible(rec, policy) {
2254 continue;
2255 }
2256 return Some(addr);
2257 }
2258 None
2259 }
2260
2261 /// A fair draw among the eligible keys, which is what the random pair want.
2262 ///
2263 /// No pool, because there is no ordering for one to approximate: under
2264 /// `allkeys-random` and `volatile-random` every eligible key is as good a
2265 /// victim as every other, and remembering sixteen of them across rounds
2266 /// would only mean the same sixteen going first. The sampling is what does
2267 /// the choosing, so the address it lands on is used straight away and the
2268 /// key never has to be copied at all.
2269 fn draw(&mut self, now: u64, want: usize) -> Option<Addr> {
2270 let policy = self.policy;
2271 let volatile = policy.volatile_only();
2272 let mut best = evict::Best::EMPTY;
2273 let mut seen = 0usize;
2274 for _ in 0..ROUNDS {
2275 let r = self.rng.next_u64();
2276 let mut offer = |_key: &[u8], rec: &[u8], addr: Addr| {
2277 if !value::is_expired(rec, now) && evict::eligible(rec, policy) {
2278 seen += 1;
2279 best.offer(addr, evict::ANY);
2280 }
2281 seen < want
2282 };
2283 if volatile {
2284 self.map.sample_tagged(r, &mut offer);
2285 } else {
2286 self.map.sample(r, &mut offer);
2287 }
2288 if seen >= want {
2289 break;
2290 }
2291 }
2292 (!best.is_empty()).then_some(best.addr)
2293 }
2294
2295 /// Bytes held by the index, the arena and every body hanging off them.
2296 ///
2297 /// Asks every collection, so this is O(the number of collections) and is for
2298 /// the places that want the number exactly and are asked for it rarely:
2299 /// `INFO memory`, `MEMORY USAGE` and the tests.
2300 /// [`Keyspace::settled_memory_bytes`] is the one a memory limit uses.
2301 #[inline]
2302 pub fn memory_bytes(&self) -> usize {
2303 self.slab_bytes()
2304 + self.sets.value_bytes()
2305 + self.hashes.value_bytes()
2306 + self.lists.value_bytes()
2307 + self.zsets.value_bytes()
2308 + self.arrays.value_bytes()
2309 + self.streams.value_bytes()
2310 + self.foreign.value_bytes()
2311 }
2312
2313 /// The same number, asked only of the collections that could have moved.
2314 ///
2315 /// See [`Slab::track_bytes`] for how that is known. With tracking on this
2316 /// costs what the batch touched instead of what the database holds, which is
2317 /// what lets a server with a `maxmemory` ask once a batch. With tracking off
2318 /// it is [`Keyspace::memory_bytes`] and the two cannot disagree, because
2319 /// they are the same sum over the same values either way.
2320 #[inline]
2321 pub fn settled_memory_bytes(&mut self) -> usize {
2322 self.slab_bytes()
2323 + self.sets.settled_bytes()
2324 + self.hashes.settled_bytes()
2325 + self.lists.settled_bytes()
2326 + self.zsets.settled_bytes()
2327 + self.arrays.settled_bytes()
2328 + self.streams.settled_bytes()
2329 + self.foreign.settled_bytes()
2330 }
2331
2332 /// Start or stop keeping the running total in every slab.
2333 ///
2334 /// One call for all seven, because a limit is a property of the server and
2335 /// not of a type, and a database tracking its sets but not its hashes would
2336 /// answer a number that is neither of the two things it could mean.
2337 pub fn track_memory(&mut self, on: bool) {
2338 self.sets.track_bytes(on);
2339 self.hashes.track_bytes(on);
2340 self.lists.track_bytes(on);
2341 self.zsets.track_bytes(on);
2342 self.arrays.track_bytes(on);
2343 self.streams.track_bytes(on);
2344 self.foreign.track_bytes(on);
2345 }
2346
2347 /// The index, the arena and the slot arrays, none of which need asking
2348 /// twice, plus the tier when there is one.
2349 ///
2350 /// The tier is in here because a doorkeeper and a directory buffer are real
2351 /// memory and a limit that did not count them would be a limit on part of
2352 /// the server. It is also the honest way round: the thing that gives memory
2353 /// back costs some to keep, and both numbers belong in the same total.
2354 #[inline]
2355 fn slab_bytes(&self) -> usize {
2356 self.tier.as_ref().map_or(0, Tier::memory_bytes)
2357 + self.map.memory_bytes()
2358 + self.sets.slot_bytes()
2359 + self.hashes.slot_bytes()
2360 + self.lists.slot_bytes()
2361 + self.zsets.slot_bytes()
2362 + self.arrays.slot_bytes()
2363 + self.streams.slot_bytes()
2364 + self.foreign.slot_bytes()
2365 }
2366
2367 /// Give back one segment's worth of space if one has gone mostly dead.
2368 ///
2369 /// Overwriting a key does not reuse its bytes, it writes the new record at
2370 /// the bump pointer and counts the old one as dead, so a workload that sets
2371 /// the same keys over and over holds far more than it is storing until
2372 /// something compacts. This is that something, and it does at most one
2373 /// segment per call so that the loop can afford to ask every turn.
2374 #[inline]
2375 pub fn compact_step(&mut self) -> Option<usize> {
2376 self.map.compact_step()
2377 }
2378
2379 /// The same, for a store that is over a memory limit and has to give pages
2380 /// back rather than wait for a segment to be worth collecting.
2381 ///
2382 /// See [`RawMap::compact_hard`] for why the choice of segment changes and
2383 /// why it only changes under pressure.
2384 #[inline]
2385 pub fn compact_hard(&mut self) -> Option<usize> {
2386 self.map.compact_hard()
2387 }
2388
2389 /// Ask the cache for the bucket this key will land in.
2390 ///
2391 /// The first of the loop's two walks (`04` section 3) calls this.
2392 #[inline]
2393 pub fn prefetch(&self, hash: u64) {
2394 self.map.prefetch(hash);
2395 }
2396
2397 /// The hash this database files `key` under.
2398 #[inline]
2399 #[must_use]
2400 pub fn hash_of(key: &[u8]) -> u64 {
2401 RawMap::hash_of(key)
2402 }
2403}
2404
2405/// Whether a body of this kind can leave memory yet.
2406///
2407/// One list rather than a check in each of the three places that need it, so a
2408/// type that gains a `freeze` cannot be demotable in the sweep and unreadable on
2409/// the way back. A kind that is not in here stays in memory, which costs a
2410/// demotion that did not happen and is never a wrong answer.
2411const fn moves(kind: Kind) -> bool {
2412 matches!(
2413 kind,
2414 Kind::Set | Kind::Hash | Kind::List | Kind::Zset | Kind::Array | Kind::Stream
2415 )
2416}
2417
2418/// What Redis says when a command is sent at a key holding another type.
2419///
2420/// The text is Redis's, word for word, because it goes on the wire verbatim and
2421/// clients match on it. The `WRONGTYPE` at the front is not part of the message:
2422/// the protocol layer puts it there from the [`Code`], which is what lets an
2423/// embedded caller match on a value instead of on a string (P5).
2424pub fn wrong_type() -> Error {
2425 Error::new(
2426 Code::WrongType,
2427 "Operation against a key holding the wrong kind of value",
2428 )
2429}
2430
2431impl Default for Keyspace {
2432 fn default() -> Keyspace {
2433 Keyspace::new()
2434 }
2435}
2436
2437#[cfg(test)]
2438mod tests {
2439 use super::*;
2440
2441 fn db() -> Keyspace {
2442 Keyspace::with_clock(Clock::fixed(1_000))
2443 }
2444
2445 #[test]
2446 fn type_answers_string_for_a_string_and_nothing_for_a_missing_key() {
2447 let mut d = db();
2448 d.set_plain(b"k", b"v").expect("room");
2449 assert_eq!(d.kind_of(b"k"), Some(Kind::String));
2450 assert_eq!(d.kind_of(b"nope"), None);
2451 }
2452
2453 #[test]
2454 fn type_does_not_report_a_key_whose_deadline_has_gone() {
2455 let mut d = db();
2456 d.psetex(b"k", 100, b"v").expect("room");
2457 assert_eq!(d.kind_of(b"k"), Some(Kind::String));
2458
2459 d.clock_mut().advance(100);
2460 assert_eq!(
2461 d.kind_of(b"k"),
2462 None,
2463 "the deadline was 1100 and it is 1100"
2464 );
2465 assert_eq!(d.len(), 0, "and asking reaped it rather than leaving it");
2466 assert_eq!(d.expired_keys(), 1);
2467 }
2468
2469 /// The default policy evicts nothing and still keeps the clock, which is
2470 /// Redis's behaviour and is the configuration nearly every server runs.
2471 #[test]
2472 fn the_clock_runs_under_the_default_policy() {
2473 let mut d = db();
2474 assert_eq!(d.policy(), Policy::NoEviction);
2475 d.set_plain(b"k", b"v").expect("room");
2476 assert_eq!(d.idle_secs(b"k"), Some(0));
2477
2478 d.clock_mut().advance(60_000);
2479 assert_eq!(d.idle_secs(b"k"), Some(60), "a minute of nobody asking");
2480
2481 d.get(b"k").expect("a string").expect("still there");
2482 assert_eq!(d.idle_secs(b"k"), Some(0), "and reading it is using it");
2483 }
2484
2485 /// The commands that ask about a key rather than use it. Getting this wrong
2486 /// makes `OBJECT IDLETIME` answer zero every time it is called, because
2487 /// calling it would be the most recent use.
2488 #[test]
2489 fn asking_about_a_key_is_not_using_it() {
2490 let mut d = db();
2491 d.set_plain(b"k", b"v").expect("room");
2492 d.clock_mut().advance(30_000);
2493
2494 assert!(d.exists(b"k"));
2495 assert_eq!(d.kind_of(b"k"), Some(Kind::String));
2496 assert_eq!(d.encoding_name(b"k"), Some("embstr"));
2497 assert_eq!(d.deadline_of(b"k"), Ask::NoDeadline);
2498 assert_eq!(d.expire_at(b"k"), None);
2499 assert_eq!(d.idle_secs(b"k"), Some(30));
2500
2501 assert_eq!(
2502 d.idle_secs(b"k"),
2503 Some(30),
2504 "and asking twice is still not using it"
2505 );
2506 }
2507
2508 /// Least recently modified is the one policy where a read must leave the
2509 /// clock where it is, because the clock is the only thing it measures.
2510 #[test]
2511 fn a_read_moves_the_clock_under_lru_and_leaves_it_under_lrm() {
2512 for (policy, idle_after_read) in [(Policy::AllKeysLru, 0), (Policy::AllKeysLrm, 45)] {
2513 let mut d = db();
2514 d.set_policy(policy);
2515 d.set_plain(b"k", b"v").expect("room");
2516 d.clock_mut().advance(45_000);
2517
2518 d.get(b"k").expect("a string").expect("still there");
2519 assert_eq!(
2520 d.idle_secs(b"k"),
2521 Some(idle_after_read),
2522 "{}",
2523 policy.name()
2524 );
2525
2526 // Both of them move it on a write, which is the whole of what LRM
2527 // is measuring and is a side effect of the resolve under LRU.
2528 d.set_plain(b"k", b"w").expect("room");
2529 assert_eq!(
2530 d.idle_secs(b"k"),
2531 Some(0),
2532 "{} after a write",
2533 policy.name()
2534 );
2535 }
2536 }
2537
2538 /// The trap the memo sets. A hit skips the record entirely, so a stamp that
2539 /// only happened on a miss would leave the hottest key in the database
2540 /// looking steadily more idle the harder it was used.
2541 #[test]
2542 fn the_hot_key_path_still_stamps() {
2543 let mut d = db();
2544 d.set_policy(Policy::AllKeysLru);
2545 d.sadd(b"s", [&b"a"[..]].into_iter()).expect("room");
2546
2547 // Warm the memo, then run the key hard with nothing written in between,
2548 // which is the case the memo exists for.
2549 d.scard(b"s").expect("a set");
2550 d.clock_mut().advance(120_000);
2551 for _ in 0..64 {
2552 d.scard(b"s").expect("a set");
2553 }
2554 assert_eq!(d.idle_secs(b"s"), Some(0), "the memo swallowed the stamp");
2555 }
2556
2557 /// Under LFU the same bits are a counter, and it climbs with use rather than
2558 /// resetting to now.
2559 #[test]
2560 fn the_counter_climbs_under_an_lfu_policy() {
2561 let mut d = db();
2562 d.set_policy(Policy::AllKeysLfu);
2563 d.seed(7);
2564 d.set_plain(b"k", b"v").expect("room");
2565 let start = d.freq(b"k").expect("there");
2566
2567 for _ in 0..200 {
2568 d.get(b"k").expect("a string").expect("still there");
2569 }
2570 let hot = d.freq(b"k").expect("there");
2571 assert!(hot > start, "{hot} did not climb from {start}");
2572
2573 // And a key nobody reads decays rather than holding its place forever.
2574 d.set_plain(b"cold", b"v").expect("room");
2575 d.clock_mut().advance(60_000 * 10);
2576 assert!(d.freq(b"cold").expect("there") < start);
2577 }
2578
2579 /// Nothing goes under `noeviction`, which is the only promise that policy
2580 /// makes and the reason it is the default.
2581 #[test]
2582 fn noeviction_evicts_nothing() {
2583 let mut d = db();
2584 for i in 0..200u32 {
2585 d.set_plain(format!("k{i}").as_bytes(), b"v").expect("room");
2586 }
2587 assert!(!d.evict_one());
2588 assert_eq!(d.len(), 200);
2589 assert_eq!(d.evicted_keys(), 0);
2590 }
2591
2592 /// A volatile policy on a database where nothing has a deadline is the
2593 /// classic surprise: it looks configured and it cannot free a byte.
2594 #[test]
2595 fn a_volatile_policy_with_no_deadlines_anywhere_cannot_evict() {
2596 let mut d = db();
2597 d.set_policy(Policy::VolatileLru);
2598 for i in 0..200u32 {
2599 d.set_plain(format!("k{i}").as_bytes(), b"v").expect("room");
2600 }
2601 assert!(!d.evict_one(), "it found a key it had no business taking");
2602 assert_eq!(d.len(), 200);
2603
2604 // Give one key a deadline and it becomes the only thing that can go,
2605 // however many rounds of sampling that takes.
2606 let deadline = d.clock().now_ms() + 100_000;
2607 d.set_expiry(b"k7", Some(deadline));
2608 assert!(d.evict_one());
2609 assert!(!d.exists(b"k7"));
2610 assert_eq!(d.evicted_keys(), 1);
2611 }
2612
2613 /// The count against a walk, over everything that can move it. If these two
2614 /// ever disagree the count is worse than useless, because `INFO` would be
2615 /// reporting a number that looks like a measurement.
2616 #[test]
2617 fn the_deadline_count_says_what_a_walk_of_the_keyspace_says() {
2618 let mut d = db();
2619 let now = d.clock().now_ms();
2620 let check = |d: &mut Keyspace, note: &str| {
2621 let mut names = Vec::new();
2622 d.keys(|k| names.push(k.to_vec()));
2623 let walked = names
2624 .iter()
2625 .filter(|k| matches!(d.deadline_of(k), Ask::At(_)))
2626 .count();
2627 assert_eq!(d.expires(), walked, "{note}");
2628 };
2629
2630 for i in 0..40u32 {
2631 d.set_plain(format!("s{i}").as_bytes(), b"v").expect("room");
2632 d.sadd(format!("c{i}").as_bytes(), [b"m".as_slice()].into_iter())
2633 .expect("room");
2634 }
2635 check(&mut d, "nothing has a deadline yet");
2636 assert_eq!(d.expires(), 0);
2637
2638 // On, on again with a different deadline, and off.
2639 for i in (0..40u32).step_by(2) {
2640 d.set_expiry(format!("s{i}").as_bytes(), Some(now + 500_000));
2641 d.set_expiry(format!("c{i}").as_bytes(), Some(now + 500_000));
2642 }
2643 check(&mut d, "half of each type has one");
2644 assert_eq!(d.expires(), 40);
2645 for i in (0..40u32).step_by(4) {
2646 d.set_expiry(format!("s{i}").as_bytes(), Some(now + 900_000));
2647 }
2648 check(&mut d, "moving a deadline is not gaining one");
2649 assert_eq!(d.expires(), 40);
2650 for i in (0..40u32).step_by(4) {
2651 d.set_expiry(format!("c{i}").as_bytes(), None);
2652 }
2653 check(&mut d, "and PERSIST gives them back");
2654 assert_eq!(d.expires(), 30);
2655
2656 // Written over, which is the path where the record loses its deadline
2657 // without anybody saying so.
2658 d.set_plain(b"s2", b"fresh").expect("room");
2659 check(&mut d, "a plain SET drops the deadline it wrote over");
2660
2661 // Renamed, deleted, expired and evicted.
2662 d.rename(b"s6", b"s6new", false);
2663 check(&mut d, "a rename moved one rather than losing it");
2664 d.drop_key(b"s6new");
2665 d.drop_key(b"c2");
2666 check(&mut d, "two deleted");
2667 d.psetex(b"gone", 50, b"v").expect("room");
2668 check(&mut d, "and one more with a short deadline");
2669 d.clock_mut().advance(60);
2670 assert_eq!(d.kind_of(b"gone"), None, "which the read reaped");
2671 check(&mut d, "so the count lost it too");
2672 d.set_policy(Policy::VolatileRandom);
2673 assert!(d.evict_one());
2674 check(&mut d, "eviction under a volatile policy takes one of them");
2675
2676 d.clear();
2677 assert_eq!(d.expires(), 0, "and FLUSHDB takes the lot");
2678 }
2679
2680 /// The point of the count on the eviction path. A volatile policy with
2681 /// nothing to evict answers on the comparison rather than on four rounds of
2682 /// buckets, and it has to still answer `false`.
2683 #[test]
2684 fn a_volatile_policy_asks_the_count_before_it_samples() {
2685 let mut d = db();
2686 d.set_policy(Policy::VolatileLfu);
2687 for i in 0..500u32 {
2688 d.set_plain(format!("k{i}").as_bytes(), b"v").expect("room");
2689 }
2690 assert_eq!(d.expires(), 0);
2691 assert!(!d.evict_one(), "nothing is eligible and nothing went");
2692 assert_eq!(d.len(), 500);
2693
2694 // And the fast path gets out of the way the moment one key qualifies.
2695 d.set_expiry(b"k123", Some(d.clock().now_ms() + 100_000));
2696 assert_eq!(d.expires(), 1);
2697 assert!(d.evict_one());
2698 assert!(!d.exists(b"k123"));
2699 assert_eq!(d.expires(), 0, "and the count went with it");
2700 }
2701
2702 /// A needle in a haystack, which is the case sampling the whole keyspace
2703 /// could not do.
2704 ///
2705 /// Fifty thousand keys and three of them with a deadline. Under a volatile
2706 /// policy those three are the only ones that may go, and four rounds of
2707 /// sixty four buckets drawn from the whole index would land on one of them
2708 /// about once in a hundred tries. Drawn from the index of just the keys that
2709 /// carry a deadline it is the only thing there is to land on.
2710 ///
2711 /// Three of them and not one, so that the test is about finding an eligible
2712 /// key rather than about a table with a single entry in it.
2713 #[test]
2714 fn a_volatile_policy_finds_the_one_key_in_a_database_that_is_not_volatile() {
2715 let mut d = db();
2716 d.set_policy(Policy::VolatileLru);
2717 for i in 0..50_000u32 {
2718 d.set_plain(format!("k{i}").as_bytes(), b"v").expect("room");
2719 }
2720 let deadline = d.clock().now_ms() + 100_000;
2721 for k in [b"k7".as_slice(), b"k30000", b"k49999"] {
2722 assert!(d.set_expiry(k, Some(deadline)));
2723 }
2724 assert_eq!(d.expires(), 3);
2725
2726 for round in 0..3 {
2727 assert!(d.evict_one(), "round {round} found nothing to take");
2728 }
2729 assert_eq!(d.expires(), 0, "all three went");
2730 assert_eq!(d.len(), 50_000 - 3, "and nothing else did");
2731 assert!(!d.evict_one(), "and now there is nothing eligible left");
2732 assert_eq!(d.len(), 50_000 - 3);
2733 }
2734
2735 /// The direction of the score, which is the thing worth pinning. A test that
2736 /// only checked something was evicted would pass just as happily on a cache
2737 /// that keeps the cold keys and throws away the hot ones.
2738 #[test]
2739 fn the_stale_key_goes_before_the_fresh_one() {
2740 let mut d = db();
2741 d.set_policy(Policy::AllKeysLru);
2742 // Two keys is a small enough database that a bucket holds both of them
2743 // and the pick is between them rather than between whatever turned up.
2744 d.set_plain(b"cold", b"v").expect("room");
2745 d.clock_mut().advance(600_000);
2746 d.set_plain(b"hot", b"v").expect("room");
2747
2748 assert!(d.evict_one());
2749 assert!(!d.exists(b"cold"), "it kept the stale one");
2750 assert!(d.exists(b"hot"), "it took the fresh one");
2751 }
2752
2753 /// Under `volatile-ttl` the ordering is by deadline and not by use, so the
2754 /// key about to expire anyway is the one that goes.
2755 #[test]
2756 fn the_soonest_deadline_goes_first() {
2757 let mut d = db();
2758 d.set_policy(Policy::VolatileTtl);
2759 let now = d.clock().now_ms();
2760 d.set_plain(b"soon", b"v").expect("room");
2761 d.set_plain(b"later", b"v").expect("room");
2762 d.set_expiry(b"soon", Some(now + 10_000));
2763 d.set_expiry(b"later", Some(now + 900_000));
2764
2765 assert!(d.evict_one());
2766 assert!(!d.exists(b"soon"));
2767 assert!(d.exists(b"later"));
2768 }
2769
2770 /// Under LFU the key nobody reads goes, even though it was written more
2771 /// recently than the one that survives. That is the difference between the
2772 /// two families and it is invisible to a test written against the clock.
2773 #[test]
2774 fn the_least_used_key_goes_under_lfu() {
2775 let mut d = db();
2776 d.set_policy(Policy::AllKeysLfu);
2777 d.seed(11);
2778 d.set_plain(b"popular", b"v").expect("room");
2779 for _ in 0..300 {
2780 d.get(b"popular").expect("a string").expect("still there");
2781 }
2782 // Written after the reads above, so under any clock policy this would be
2783 // the freshest key in the database and the last thing to go.
2784 d.set_plain(b"ignored", b"v").expect("room");
2785
2786 assert!(d.evict_one());
2787 assert!(!d.exists(b"ignored"));
2788 assert!(d.exists(b"popular"));
2789 }
2790
2791 /// Sampling has to keep working when almost every bucket it looks in is
2792 /// empty, which is what a database looks like after most of it is deleted.
2793 #[test]
2794 fn a_nearly_empty_database_still_gives_up_a_key() {
2795 let mut d = db();
2796 d.set_policy(Policy::AllKeysRandom);
2797 for i in 0..4000u32 {
2798 d.set_plain(format!("k{i}").as_bytes(), b"v").expect("room");
2799 }
2800 for i in 0..3999u32 {
2801 d.drop_key(format!("k{i}").as_bytes());
2802 }
2803 assert_eq!(d.len(), 1);
2804
2805 // One key in a directory sized for four thousand. It may take more than
2806 // one round to land on it, and it may take more than one call, but the
2807 // rounds are bounded and so is this loop.
2808 let mut went = false;
2809 for _ in 0..500 {
2810 if d.evict_one() {
2811 went = true;
2812 break;
2813 }
2814 }
2815 assert!(went, "sampling never found the one key that was left");
2816 assert_eq!(d.len(), 0);
2817 assert!(!d.evict_one(), "and an empty database has nothing to give");
2818 }
2819
2820 /// Eviction and expiry are counted apart, so a key that was already dead
2821 /// when sampling found it is not billed as an eviction.
2822 #[test]
2823 fn a_dead_key_is_not_evicted() {
2824 let mut d = db();
2825 d.set_policy(Policy::AllKeysLru);
2826 let now = d.clock().now_ms();
2827 d.set_plain(b"k", b"v").expect("room");
2828 d.set_expiry(b"k", Some(now + 1000));
2829 d.clock_mut().advance(5000);
2830
2831 assert!(!d.evict_one(), "it evicted a key that was already dead");
2832 assert_eq!(d.evicted_keys(), 0);
2833 }
2834
2835 /// The point of the pool. A round looks at five keys, takes one, and used to
2836 /// throw the other four away, so the second worst key in the database had to
2837 /// be found again from scratch every time.
2838 #[test]
2839 fn a_candidate_that_was_not_taken_is_still_in_the_running() {
2840 let mut d = db();
2841 d.set_policy(Policy::AllKeysLru);
2842 for i in 0..40u32 {
2843 d.set_plain(format!("k{i}").as_bytes(), b"v").expect("room");
2844 d.clock_mut().advance(1000);
2845 }
2846 assert!(d.pool.is_empty(), "nothing has sampled anything yet");
2847
2848 assert!(d.evict_one());
2849 assert!(
2850 !d.pool.is_empty(),
2851 "every key it looked at and did not take was thrown away"
2852 );
2853 }
2854
2855 /// A candidate is a key and not an address, so it can stop being a key
2856 /// between the round that spotted it and the round that wants it. Every one
2857 /// of them going at once is the worst case, and the answer has to be the
2858 /// live key rather than a shrug.
2859 #[test]
2860 fn a_candidate_that_went_away_is_stepped_over() {
2861 let mut d = db();
2862 d.set_policy(Policy::AllKeysLru);
2863 for i in 0..40u32 {
2864 d.set_plain(format!("k{i}").as_bytes(), b"v").expect("room");
2865 d.clock_mut().advance(1000);
2866 }
2867 assert!(d.evict_one());
2868 assert!(!d.pool.is_empty());
2869
2870 // By hand, so every candidate still held names a key that is not there.
2871 for i in 0..40u32 {
2872 d.drop_key(format!("k{i}").as_bytes());
2873 }
2874 assert_eq!(d.len(), 0);
2875 d.set_plain(b"fresh", b"v").expect("room");
2876
2877 assert!(d.evict_one(), "it gave up on a database with a key in it");
2878 assert!(!d.exists(b"fresh"));
2879 assert!(d.pool.is_empty(), "and the stale ones went with it");
2880 }
2881
2882 /// A score only means something against another score under the same rule,
2883 /// so a pool full of them is worth nothing the moment the rule changes.
2884 #[test]
2885 fn changing_the_policy_throws_the_candidates_away() {
2886 let mut d = db();
2887 d.set_policy(Policy::AllKeysLru);
2888 let now = d.clock().now_ms();
2889 for i in 0..40u32 {
2890 d.set_plain(format!("k{i}").as_bytes(), b"v").expect("room");
2891 d.set_expiry(
2892 format!("k{i}").as_bytes(),
2893 Some(now + 100_000 + u64::from(i)),
2894 );
2895 d.clock_mut().advance(1000);
2896 }
2897 assert!(d.evict_one());
2898 assert!(!d.pool.is_empty());
2899
2900 d.set_policy(Policy::VolatileTtl);
2901 assert!(d.pool.is_empty(), "idle seconds against a countdown");
2902
2903 // And the same policy set again is not a change and costs nothing.
2904 d.set_policy(Policy::VolatileTtl);
2905 assert!(d.evict_one());
2906 assert!(!d.pool.is_empty());
2907 d.set_policy(Policy::VolatileTtl);
2908 assert!(!d.pool.is_empty());
2909 }
2910
2911 /// A fair draw has no ordering for a pool to get closer to, so the random
2912 /// pair never copy a key at all.
2913 #[test]
2914 fn a_random_policy_keeps_no_candidates() {
2915 let mut d = db();
2916 d.set_policy(Policy::AllKeysRandom);
2917 for i in 0..40u32 {
2918 d.set_plain(format!("k{i}").as_bytes(), b"v").expect("room");
2919 }
2920
2921 assert!(d.evict_one());
2922 assert_eq!(d.len(), 39);
2923 assert!(d.pool.is_empty());
2924 assert_eq!(
2925 d.pool.memory_bytes(),
2926 0,
2927 "and it allocated nothing to do it"
2928 );
2929 }
2930
2931 /// A flush leaves the pool naming keys that are all gone, which the recheck
2932 /// would survive and would pay sixteen lookups for.
2933 #[test]
2934 fn a_flush_takes_the_candidates_with_it() {
2935 let mut d = db();
2936 d.set_policy(Policy::AllKeysLru);
2937 for i in 0..40u32 {
2938 d.set_plain(format!("k{i}").as_bytes(), b"v").expect("room");
2939 d.clock_mut().advance(1000);
2940 }
2941 assert!(d.evict_one());
2942 assert!(!d.pool.is_empty());
2943
2944 d.clear();
2945 assert!(d.pool.is_empty());
2946 }
2947}