Skip to main content

yo_kv/
strings.rs

1//! The string type and its commands.
2//!
3//! The commands are an `impl` block on [`Keyspace`] rather than methods on some
4//! per type object, because a key belongs to the database and not to a type.
5//! Everything in this file is about strings; everything that is about the
6//! database whatever it holds is in [`keyspace`](crate::keyspace).
7//!
8//! One method per Redis command, taking and returning ordinary Rust values.
9//! There is no command enum here and no dispatch: this is the layer the wire
10//! calls into and the layer the embedded API calls into, and Y23 says those two
11//! have to be the same code rather than two implementations of the same idea.
12//! Anything that is about parsing arguments or writing a reply lives above.
13//!
14//! Errors carry Redis's own message text, because it ends up on the wire
15//! verbatim, and a [`Code`] alongside it, because the embedded caller should be
16//! matching on a value rather than on a string (P5).
17
18use crate::cond::Compare;
19use crate::counter::{self, Counted, IncrEx, IncrExpire, Num};
20use crate::keyspace::{Keyspace, wrong_type};
21use crate::lcs;
22use crate::value::{self, Encoding, Kind, Str};
23use std::borrow::Cow;
24use yo_common::num::parse_f64;
25use yo_common::{Code, Error, Result};
26use yo_index::RawMap;
27
28/// What Redis says when a value should have been a number and was not.
29const NOT_AN_INT: &str = "value is not an integer or out of range";
30/// What Redis says when a value should have been a float and was not.
31const NOT_A_FLOAT: &str = "value is not a valid float";
32/// What Redis says when the result of a counter would leave the range.
33const WOULD_OVERFLOW: &str = "increment or decrement would overflow";
34/// What Redis says when a write would make a string too long.
35const TOO_LONG: &str = "string exceeds maximum allowed size (proto-max-bulk-len)";
36/// What we say when a key is longer than this band holds.
37const KEY_TOO_LONG: &str = "key exceeds maximum allowed size";
38/// What Redis says when an offset is negative or past the end of the world.
39const BAD_OFFSET: &str = "offset is out of range";
40
41/// The longest key this band stores.
42///
43/// Redis's limit is 512 MiB for a key as well as for a value. A key that long is
44/// not a key, it is a value in the wrong place, and holding the ceiling down
45/// here is what lets [`STRING_MAX`] be a constant rather than a function of the
46/// key in hand.
47pub const KEY_MAX: usize = 64 * 1024;
48
49/// The largest string this band stores.
50///
51/// Redis's limit is 512 MiB. Ours is a segment, because a string lives in the
52/// arena and the arena hands out at most one segment's worth in one piece. The
53/// band above this is the log region (`06` section 2) and lands with tiering in
54/// M5, at which point this constant goes up to Redis's. It is a divergence and
55/// it is listed as one rather than left for somebody to discover.
56pub const STRING_MAX: usize = RawMap::max_record() - RawMap::header_len() - KEY_MAX - 16;
57
58/// Whether a `SET` should go ahead given what is already there.
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
60pub enum Exists {
61    /// Store whatever is there. Plain `SET`.
62    #[default]
63    Always,
64    /// Only if the key is absent. `SET NX`, and `SETNX`.
65    IfMissing,
66    /// Only if the key is present. `SET XX`.
67    IfPresent,
68}
69
70/// What a write should do with the key's deadline.
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
72pub enum Expire {
73    /// Leave the key with no deadline. Plain `SET`, and `GETEX PERSIST`.
74    #[default]
75    Clear,
76    /// Leave whatever deadline was there. `SET KEEPTTL`, and plain `GETEX`.
77    Keep,
78    /// Expire at this absolute unix millisecond. `EX`, `PX`, `EXAT`, `PXAT`.
79    At(u64),
80}
81
82/// Everything `SET` can be asked to do beyond storing the value.
83#[derive(Debug, Clone, Copy, Default)]
84pub struct SetOptions<'a> {
85    /// `NX` or `XX`.
86    pub exists: Exists,
87    /// `EX`, `PX`, `EXAT`, `PXAT` or `KEEPTTL`.
88    pub expire: Expire,
89    /// `IFEQ`, `IFNE`, `IFDEQ` or `IFDNE`.
90    ///
91    /// Redis 8.4's compare and set. A missing key never compares equal, so
92    /// `IFEQ` on a key that is not there does not store, and `IFNE` on one
93    /// does.
94    pub compare: Option<Compare<'a>>,
95    /// `GET`: hand back what was there, whether or not the write happened.
96    pub get: bool,
97}
98
99impl<'a> SetOptions<'a> {
100    /// No options at all, which is plain `SET`.
101    pub const PLAIN: SetOptions<'static> = SetOptions {
102        exists: Exists::Always,
103        expire: Expire::Clear,
104        compare: None,
105        get: false,
106    };
107
108    /// This, but only if the key is missing.
109    #[must_use]
110    pub const fn if_missing(mut self) -> SetOptions<'a> {
111        self.exists = Exists::IfMissing;
112        self
113    }
114
115    /// This, but only if the key is present.
116    #[must_use]
117    pub const fn if_present(mut self) -> SetOptions<'a> {
118        self.exists = Exists::IfPresent;
119        self
120    }
121
122    /// This, with a deadline.
123    #[must_use]
124    pub const fn expiring(mut self, e: Expire) -> SetOptions<'a> {
125        self.expire = e;
126        self
127    }
128
129    /// This, but only if the current value is exactly `bytes`. `IFEQ`.
130    #[must_use]
131    pub const fn if_equal(mut self, bytes: &'a [u8]) -> SetOptions<'a> {
132        self.compare = Some(Compare::Equal(bytes));
133        self
134    }
135
136    /// This, but only if the current value is not exactly `bytes`. `IFNE`.
137    #[must_use]
138    pub const fn if_not_equal(mut self, bytes: &'a [u8]) -> SetOptions<'a> {
139        self.compare = Some(Compare::NotEqual(bytes));
140        self
141    }
142
143    /// This, but only against a value whose digest is `d`. `IFDEQ`.
144    #[must_use]
145    pub const fn if_digest(mut self, d: u64) -> SetOptions<'a> {
146        self.compare = Some(Compare::DigestEqual(d));
147        self
148    }
149
150    /// This, but only against a value whose digest is not `d`. `IFDNE`.
151    #[must_use]
152    pub const fn if_not_digest(mut self, d: u64) -> SetOptions<'a> {
153        self.compare = Some(Compare::DigestNotEqual(d));
154        self
155    }
156
157    /// This, returning the previous value.
158    #[must_use]
159    pub const fn returning(mut self) -> SetOptions<'a> {
160        self.get = true;
161        self
162    }
163}
164
165/// What a `SET` did.
166#[derive(Debug, Clone, PartialEq, Eq, Default)]
167pub struct SetOutcome {
168    /// Whether the value was written. `NX`, `XX` and `IFEQ` can all say no.
169    pub stored: bool,
170    /// The previous value, when `GET` was asked for and there was one.
171    ///
172    /// Owned, because the record it lived in has been written over by the time
173    /// this is handed back, and only ever filled in by [`Keyspace::set`]. A
174    /// caller that does not want the copy calls [`Keyspace::set_with`] and gets
175    /// the old value where it still lives, which is what the wire does.
176    pub previous: Option<Vec<u8>>,
177}
178
179/// The string commands.
180///
181/// These hang off the database rather than off a per type object, because a
182/// key belongs to the database: `GET` against a set has to be able to see that
183/// it is a set.
184impl Keyspace {
185    // ---------------------------------------------------------------- reading
186
187    /// `GET key`.
188    ///
189    /// One probe of the map for the whole command. It used to be three, because
190    /// the reap looked the key up to see whether it was dead, the type check
191    /// looked it up to see whether it was a string, and the read looked it up
192    /// again to read it, and all three walked a bucket for the same record.
193    /// `Keyspace::live_rec` hands back where that record is and the rest is
194    /// two arena reads at a known address.
195    pub fn get(&mut self, key: &[u8]) -> Result<Option<Str<'_>>> {
196        let Some(addr) = self.live_rec(key) else {
197            return Ok(None);
198        };
199        let rec = self.map.value_at(addr);
200        if value::kind(rec) != Kind::String {
201            return Err(wrong_type());
202        }
203        // One more bit of the byte the kind came out of, and on a database with
204        // no file behind it no record ever has it set. See
205        // [`Keyspace::warmed`].
206        if value::cold(rec).is_some() {
207            return self.warmed(key);
208        }
209        Ok(Some(value::read(self.map.value_at(addr))))
210    }
211
212    /// `MGET key [key ...]`.
213    ///
214    /// Every dead key is reaped first and the whole answer is then read from a
215    /// store nobody is going to mutate, which is what lets all of the returned
216    /// values borrow from it at once instead of being copied out one at a time.
217    pub fn mget<'a>(&'a mut self, keys: &[&[u8]]) -> Vec<Option<Str<'a>>> {
218        for k in keys {
219            // A demoted value is brought back into memory here rather than
220            // served from the buffer, because this form hands back every value
221            // at once and there is one buffer. The wire does not come through
222            // here, it calls [`Keyspace::mget_one`] per key, and that one asks
223            // the doorkeeper properly. An error is dropped: this returns a
224            // `Vec` with no room in it to say that one key would not read back,
225            // and the key then reads as nil, which is what a key holding the
226            // wrong type does two lines below.
227            let _ = self.thaw(k);
228            // `live_rec` rather than `reap`, which does the same reap and also
229            // stamps the eviction clock. The reading pass below cannot, because
230            // it holds a shared borrow of the whole database so that every value
231            // it returns can borrow from it at once. The wire does not come
232            // through here at all, it walks the keys itself and calls
233            // [`Keyspace::mget_one`], so without this the same command would
234            // stamp from one entry point and not from the other.
235            self.live_rec(k);
236        }
237        let me: &Keyspace = self;
238        keys.iter().map(|k| me.peek(k)).collect()
239    }
240
241    /// One key of an `MGET`, which is nil rather than an error for a key that
242    /// holds another type.
243    ///
244    /// [`Keyspace::mget`] collects the whole answer into a `Vec` for a caller
245    /// that wants it in one piece. The wire wants the keys one at a time and in
246    /// order, and a `Vec` there would be an allocation per call on a thread that
247    /// must not allocate, so the dispatcher walks the keys itself and calls this
248    /// for each. It is not `get`, because `MGET` does not answer `WRONGTYPE`:
249    /// Redis gives nil for the odd key out rather than failing the ninety nine
250    /// good ones alongside it.
251    pub fn mget_one(&mut self, key: &[u8]) -> Option<Str<'_>> {
252        let addr = self.live_rec(key)?;
253        let rec = self.map.value_at(addr);
254        if value::kind(rec) != Kind::String {
255            return None;
256        }
257        if value::cold(rec).is_some() {
258            // A key whose value will not read back is nil here rather than an
259            // error, the same as a key holding a set is. `MGET` has no way to
260            // report one bad key out of a hundred and Redis does not try.
261            return self.warmed(key).ok().flatten();
262        }
263        Some(value::read(self.map.value_at(addr)))
264    }
265
266    /// `STRLEN key`, which is zero for a key that is not there.
267    ///
268    /// Answered out of the record even when the value is on the file, because a
269    /// demoted record carries the length next to the address. Going to the
270    /// device for a number that is already in memory would be a device read
271    /// spent on nothing, and it would be one that a client could use to pull a
272    /// whole database back into memory a key at a time.
273    pub fn strlen(&mut self, key: &[u8]) -> Result<usize> {
274        let Some(addr) = self.live_rec(key) else {
275            return Ok(0);
276        };
277        let rec = self.map.value_at(addr);
278        if value::kind(rec) != Kind::String {
279            return Err(wrong_type());
280        }
281        if let Some(c) = value::cold(rec) {
282            return Ok(c.len as usize);
283        }
284        Ok(value::read(rec).len())
285    }
286
287    /// `EXISTS key`, for one key.
288    ///
289    /// Asking whether a key is there does not count as using it, which is
290    /// Redis's rule and not a nicety. A health check that runs `EXISTS` over a
291    /// list of keys every second would otherwise be enough on its own to make
292    /// all of them look like the hottest keys in the database.
293    pub fn exists(&mut self, key: &[u8]) -> bool {
294        self.live_rec_untouched(key).is_some()
295    }
296
297    /// How a string is stored, which is `OBJECT ENCODING` for a string key.
298    ///
299    /// `None` for a key that is not there and for a key holding another type,
300    /// because the two encoding bits in a record only mean anything when the
301    /// record is the value. A set keeps its representation in its body, so
302    /// [`Keyspace::set_encoding`] asks the body, and
303    /// [`Keyspace::encoding_name`] is the command that routes between them.
304    ///
305    /// Every `OBJECT` subcommand looks without touching, so this does too.
306    pub fn encoding(&mut self, key: &[u8]) -> Option<Encoding> {
307        let addr = self.live_rec_untouched(key)?;
308        let rec = self.map.value_at(addr);
309        if value::kind(rec) != Kind::String {
310            return None;
311        }
312        Some(value::Meta::from_byte(rec[0]).encoding())
313    }
314
315    /// The key's deadline as an absolute unix millisecond, if it has one.
316    ///
317    /// `EXPIRETIME` and `PEXPIRETIME`, which do not count as using the key. See
318    /// [`Keyspace::deadline_of`].
319    pub fn expire_at(&mut self, key: &[u8]) -> Option<u64> {
320        let addr = self.live_rec_untouched(key)?;
321        value::expire_at(self.map.value_at(addr))
322    }
323
324    /// `GETRANGE key start end`, and `SUBSTR`, which is the same command.
325    ///
326    /// Both ends are inclusive and both may be negative, counting back from the
327    /// end. Everything out of range clamps, and a start past the end gives the
328    /// empty string rather than an error, which is Redis's behaviour and not an
329    /// oversight in it.
330    ///
331    /// Borrowed for a string, owned for an integer, because an integer's digits
332    /// do not exist anywhere until somebody asks for them.
333    pub fn getrange(&mut self, key: &[u8], start: i64, end: i64) -> Result<Cow<'_, [u8]>> {
334        // A range of a demoted value still reads the whole value back, because
335        // a chunk is 64 KiB and the range is usually smaller than one. The
336        // chunked band can serve a range out of the chunks it covers, and
337        // wiring that in here is worth doing once there is a workload asking
338        // for windows into large cold values. See [`cold::Reader::range`].
339        let Some(v) = self.get(key)? else {
340            return Ok(Cow::Borrowed(&[]));
341        };
342        Ok(match v {
343            Str::Bytes(b) => match range_of(b.len(), start, end) {
344                Some((s, e)) => Cow::Borrowed(&b[s..e]),
345                None => Cow::Borrowed(&[]),
346            },
347            Str::Int(n) => {
348                let text = Str::Int(n).to_vec();
349                match range_of(text.len(), start, end) {
350                    Some((s, e)) => Cow::Owned(text[s..e].to_vec()),
351                    None => Cow::Owned(Vec::new()),
352                }
353            }
354        })
355    }
356
357    // ---------------------------------------------------------------- writing
358
359    /// `SET key value [NX|XX] [GET] [IFEQ v|IFNE v|IFDEQ d|IFDNE d]
360    /// [EX s|PX ms|EXAT s|PXAT ms|KEEPTTL]`.
361    ///
362    /// The order the conditions are tested in is Redis's: the key is looked at
363    /// once, `NX`, `XX` and the four `IF` forms all decide against that one
364    /// look, and `GET` reports what was there whether or not the write went
365    /// ahead.
366    ///
367    /// The old value comes back owned, which costs a copy of it. On the wire
368    /// that copy is pure waste, because the reply is written and the bytes are
369    /// never looked at again, so the wire calls [`Keyspace::set_with`] instead
370    /// and this is that with a `to_vec` on the end.
371    pub fn set(&mut self, key: &[u8], val: &[u8], opts: SetOptions<'_>) -> Result<SetOutcome> {
372        let mut previous = None;
373        let mut out = self.set_with(key, val, opts, |v| previous = Some(v.to_vec()))?;
374        out.previous = previous;
375        Ok(out)
376    }
377
378    /// `SET`, handing the old value to `previous` rather than copying it out.
379    ///
380    /// [`Keyspace::set`] with the allocation taken off it. `previous` is called
381    /// with the value as it lies in the record, before the write goes over it,
382    /// and only when `GET` was asked for and there was something there. Nothing
383    /// after that point can fail, so a caller that writes the value straight
384    /// into a reply is not going to have to take it back out again.
385    ///
386    /// [`SetOutcome::previous`] is always `None` here. The value went to the
387    /// closure, and putting it in both places would be the copy this exists to
388    /// avoid.
389    pub fn set_with<F>(
390        &mut self,
391        key: &[u8],
392        val: &[u8],
393        opts: SetOptions<'_>,
394        previous: F,
395    ) -> Result<SetOutcome>
396    where
397        F: FnOnce(Str<'_>),
398    {
399        check_len(key, val.len())?;
400        self.reap(key);
401        if opts.get || opts.compare.is_some() {
402            // Plain `SET` overwrites whatever was there, but the forms that read
403            // the old value first cannot: there is nothing to hand back and
404            // nothing to compare against. Redis answers WRONGTYPE for both.
405            self.string_only(key)?;
406            // And a value on the file has to come back before it can be handed
407            // over or compared against. Plain `SET` does not do this, and that
408            // is the point: overwriting a demoted key costs no device read.
409            self.thaw(key)?;
410        }
411
412        let present = self.map.get(key);
413        let mut out = SetOutcome::default();
414        if opts.get
415            && let Some(rec) = present
416        {
417            previous(value::read(rec));
418        }
419        let allowed = match opts.exists {
420            Exists::Always => true,
421            Exists::IfMissing => present.is_none(),
422            Exists::IfPresent => present.is_some(),
423        };
424        let matches = match opts.compare {
425            // A key that is not there is not equal to anything, including the
426            // empty string, and the `NE` forms read that the other way round.
427            Some(c) => c.holds(present.map(value::read)),
428            None => true,
429        };
430        if !allowed || !matches {
431            return Ok(out);
432        }
433
434        let deadline = match opts.expire {
435            Expire::Clear => None,
436            Expire::At(ms) => Some(ms),
437            Expire::Keep => present.and_then(value::expire_at),
438        };
439        self.store(key, val, deadline);
440        out.stored = true;
441        Ok(out)
442    }
443
444    /// `SET key value`, with nothing else asked for.
445    pub fn set_plain(&mut self, key: &[u8], val: &[u8]) -> Result<()> {
446        check_len(key, val.len())?;
447        self.store(key, val, None);
448        Ok(())
449    }
450
451    /// `SETNX key value`, which answers whether it stored.
452    pub fn setnx(&mut self, key: &[u8], val: &[u8]) -> Result<bool> {
453        Ok(self.set(key, val, SetOptions::PLAIN.if_missing())?.stored)
454    }
455
456    /// `SETEX key seconds value`.
457    ///
458    /// A zero or negative time to live is an error and not a delete, which is
459    /// what Redis does: `SETEX k 0 v` returns `ERR invalid expire time`.
460    pub fn setex(&mut self, key: &[u8], seconds: i64, val: &[u8]) -> Result<()> {
461        let ms = seconds
462            .checked_mul(1000)
463            .ok_or_else(|| invalid_expire("setex"))?;
464        self.set_expiring(key, ms, val, "setex")
465    }
466
467    /// `PSETEX key milliseconds value`.
468    pub fn psetex(&mut self, key: &[u8], millis: i64, val: &[u8]) -> Result<()> {
469        self.set_expiring(key, millis, val, "psetex")
470    }
471
472    /// The body both of those share.
473    ///
474    /// The command name is carried in rather than taken from whichever method
475    /// does the work, because the message is the caller's: a `SETEX` with a bad
476    /// time to live says `setex` even though the milliseconds are handled here,
477    /// and a client that matches on the text gets the command it sent.
478    fn set_expiring(&mut self, key: &[u8], millis: i64, val: &[u8], what: &str) -> Result<()> {
479        if millis <= 0 {
480            return Err(invalid_expire(what));
481        }
482        let at = self.deadline_in(millis, what)?;
483        self.set(key, val, SetOptions::PLAIN.expiring(Expire::At(at)))?;
484        Ok(())
485    }
486
487    /// `GETSET key value`, which is `SET key value GET` without the options.
488    pub fn getset(&mut self, key: &[u8], val: &[u8]) -> Result<Option<Vec<u8>>> {
489        Ok(self.set(key, val, SetOptions::PLAIN.returning())?.previous)
490    }
491
492    /// `GETDEL key`.
493    pub fn getdel(&mut self, key: &[u8]) -> Result<Option<Vec<u8>>> {
494        let mut had = None;
495        self.getdel_with(key, |v| had = Some(v.to_vec()))?;
496        Ok(had)
497    }
498
499    /// `GETDEL`, handing the value to `f` rather than copying it out.
500    ///
501    /// [`Keyspace::getdel`] with the allocation taken off it, the same pair
502    /// [`Keyspace::set`] and [`Keyspace::set_with`] are. `f` is called with the
503    /// value where it still lies, before the key goes, and the answer says
504    /// whether there was one.
505    pub fn getdel_with<F>(&mut self, key: &[u8], f: F) -> Result<bool>
506    where
507        F: FnOnce(Str<'_>),
508    {
509        self.reap(key);
510        self.string_only(key)?;
511        // Warmed and not thawed. The key is about to be deleted, so putting its
512        // value back in memory on the way past would be work done for a record
513        // that is not going to exist a line later.
514        self.warm(key)?;
515        let Some(v) = self.peek(key) else {
516            return Ok(false);
517        };
518        f(v);
519        self.drop_key(key);
520        Ok(true)
521    }
522
523    /// `GETEX key [EX s|PX ms|EXAT s|PXAT ms|PERSIST]`.
524    ///
525    /// [`Expire::Keep`] is plain `GETEX`, which reads without touching the
526    /// deadline, and [`Expire::Clear`] is `GETEX PERSIST`.
527    pub fn getex(&mut self, key: &[u8], expire: Expire) -> Result<Option<Str<'_>>> {
528        self.reap(key);
529        self.string_only(key)?;
530        // Thawed rather than warmed, because a deadline that changes rewrites
531        // the whole record: the value does not move but the header in front of
532        // it changes length, so the bytes have to be in hand either way. Plain
533        // `GETEX` with no expiry argument is the read that the doorkeeper
534        // should get a vote on, and it takes the branch below instead.
535        if expire == Expire::Keep {
536            self.warm(key)?;
537        } else {
538            self.thaw(key)?;
539        }
540        if expire != Expire::Keep {
541            let current = self.map.get(key).and_then(value::expire_at);
542            let wanted = match expire {
543                Expire::At(ms) => Some(ms),
544                _ => None,
545            };
546            if current != wanted && self.map.get(key).is_some() {
547                // The value does not change, only the header in front of it, so
548                // this reads the value out and writes the whole record back. A
549                // deadline that is added or removed changes the record's length,
550                // so there is nothing to overwrite in place.
551                //
552                // Through the database's scratch buffer rather than a fresh
553                // `Vec`, for the reason `RENAME` does the same thing: the
554                // borrow of the map has to end before the write can begin, and
555                // a value carried three lines is not worth a malloc and a free.
556                let rec = self.map.get(key).expect("checked just above");
557                let mut bytes = std::mem::take(&mut self.scratch);
558                bytes.clear();
559                value::read(rec).write_to(&mut bytes);
560                self.store(key, &bytes, wanted);
561                self.scratch = bytes;
562            }
563        }
564        Ok(self.peek(key))
565    }
566
567    /// `DEL key`, for one key. Answers whether it was there.
568    ///
569    /// Any type, and it takes the body with it. `DEL` is the one command that
570    /// genuinely does not care what it is deleting.
571    pub fn del(&mut self, key: &[u8]) -> bool {
572        self.reap(key);
573        self.drop_key(key)
574    }
575
576    /// `MSET key value [key value ...]`.
577    ///
578    /// Always succeeds, always overwrites, and always clears any deadline the
579    /// keys had, which is `SET` without options applied to each pair in turn.
580    ///
581    /// The pairs arrive as an iterator rather than a slice because the wire
582    /// layer has them as positions in the connection's read buffer, and a
583    /// slice would mean collecting them into a `Vec` first. `MSET` is on the
584    /// list of four commands M2 is measured on, and a shard thread that
585    /// allocates aborts, so an API that forces an allocation to call it is the
586    /// wrong API. The iterator is walked twice, which is why it has to be
587    /// `Clone`, and an iterator over borrowed slices is two words to copy.
588    pub fn mset<'k>(
589        &mut self,
590        pairs: impl Iterator<Item = (&'k [u8], &'k [u8])> + Clone,
591    ) -> Result<()> {
592        for (k, v) in pairs.clone() {
593            check_len(k, v.len())?;
594        }
595        for (k, v) in pairs {
596            self.store(k, v, None);
597        }
598        Ok(())
599    }
600
601    /// `MSETNX key value [key value ...]`, which stores all of them or none.
602    ///
603    /// The whole set of keys is checked before anything is written, so a
604    /// duplicate key inside one call does not defeat itself.
605    pub fn msetnx<'k>(
606        &mut self,
607        pairs: impl Iterator<Item = (&'k [u8], &'k [u8])> + Clone,
608    ) -> Result<bool> {
609        for (k, v) in pairs.clone() {
610            check_len(k, v.len())?;
611        }
612        for (k, _) in pairs.clone() {
613            self.reap(k);
614            if self.map.contains(k) {
615                return Ok(false);
616            }
617        }
618        for (k, v) in pairs {
619            self.store(k, v, None);
620        }
621        Ok(true)
622    }
623
624    /// `APPEND key value`, answering the new length.
625    ///
626    /// Appending to a key that is not there creates it, which makes `APPEND` on
627    /// an empty key the same as `SET`. Any deadline the key had is kept, which
628    /// is Redis's behaviour: `APPEND` is not a fresh `SET`.
629    pub fn append(&mut self, key: &[u8], tail: &[u8]) -> Result<usize> {
630        self.reap(key);
631        self.string_only(key)?;
632        self.thaw(key)?;
633        let Some(rec) = self.map.get(key) else {
634            check_len(key, tail.len())?;
635            self.store(key, tail, None);
636            return Ok(tail.len());
637        };
638        let deadline = value::expire_at(rec);
639        // The database's one scratch buffer, for the reason `LMOVE` uses it:
640        // building the new value needs the old bytes in hand while `store_raw`
641        // wants `&mut self`, and a `Vec` per call is a malloc and a free on the
642        // command a log writer sends in a loop. Taken out and put back on every
643        // path, so an early return leaves it as it was found.
644        let mut joined = std::mem::take(&mut self.scratch);
645        joined.clear();
646        value::read(rec).write_to(&mut joined);
647        if let Err(e) = check_len(key, joined.len() + tail.len()) {
648            self.scratch = joined;
649            return Err(e);
650        }
651        joined.extend_from_slice(tail);
652        let len = joined.len();
653        self.store_raw(key, &joined, deadline);
654        self.scratch = joined;
655        Ok(len)
656    }
657
658    /// `SETRANGE key offset value`, answering the new length.
659    ///
660    /// A write past the end pads with zero bytes, and a write of nothing to a
661    /// key that is not there creates nothing and answers zero. Both of those are
662    /// Redis's, and both are the kind of edge a client library's test suite
663    /// checks.
664    pub fn setrange(&mut self, key: &[u8], offset: usize, val: &[u8]) -> Result<usize> {
665        self.reap(key);
666        self.string_only(key)?;
667        // `SETRANGE key n ""` writes nothing and answers the length, which the
668        // record already knows, so that form does not touch the device. See
669        // [`Keyspace::strlen`], which is the same argument.
670        if val.is_empty() {
671            return Ok(self.strlen(key).unwrap_or(0));
672        }
673        self.thaw(key)?;
674        let end = offset
675            .checked_add(val.len())
676            .ok_or_else(|| Error::new(Code::Invalid, BAD_OFFSET))?;
677        check_len(key, end)?;
678
679        // The same scratch buffer [`Keyspace::append`] uses, for the same
680        // reason. `SETRANGE` in a loop is how a client keeps a fixed layout
681        // record in one key.
682        let mut bytes = std::mem::take(&mut self.scratch);
683        bytes.clear();
684        let deadline = match self.map.get(key) {
685            Some(rec) => {
686                value::read(rec).write_to(&mut bytes);
687                value::expire_at(rec)
688            }
689            None => None,
690        };
691        if bytes.len() < end {
692            bytes.resize(end, 0);
693        }
694        bytes[offset..end].copy_from_slice(val);
695        let len = bytes.len();
696        self.store_raw(key, &bytes, deadline);
697        self.scratch = bytes;
698        Ok(len)
699    }
700
701    // --------------------------------------------------------------- counters
702
703    /// `INCR key`.
704    #[inline]
705    pub fn incr(&mut self, key: &[u8]) -> Result<i64> {
706        self.incrby(key, 1)
707    }
708
709    /// `DECR key`.
710    #[inline]
711    pub fn decr(&mut self, key: &[u8]) -> Result<i64> {
712        self.decrby(key, 1)
713    }
714
715    /// `DECRBY key decrement`.
716    ///
717    /// Negating first would overflow on `i64::MIN`, which is why the decrement
718    /// is carried through as a subtraction rather than turned into an addition.
719    pub fn decrby(&mut self, key: &[u8], by: i64) -> Result<i64> {
720        self.count(key, by, true)
721    }
722
723    /// `INCRBY key increment`, and with an increment of one, `INCR`.
724    ///
725    /// This is the command the milestone's gate is about, so the path it takes
726    /// is worth stating. A key that is already int encoded is one probe, an add
727    /// and an eight byte store back into the record the probe landed on. No
728    /// arena allocation, no free, no second record, and no rehash. Every other
729    /// case falls through to a rewrite, which is what `INCR` on a string that
730    /// happens to look like a number costs.
731    #[inline]
732    pub fn incrby(&mut self, key: &[u8], by: i64) -> Result<i64> {
733        self.count(key, by, false)
734    }
735
736    fn count(&mut self, key: &[u8], by: i64, subtract: bool) -> Result<i64> {
737        check_len(key, 0)?;
738        // A demoted value is never int encoded, so a counter that is being
739        // counted on is never on the file and this costs one branch on a null
740        // field. It is here for the key that was a long string, got demoted,
741        // and is now being incremented, which answers an error rather than
742        // reading twelve bytes of address as a number.
743        self.thaw(key)?;
744        let hash = RawMap::hash_of(key);
745        let now = self.clock.now_ms();
746
747        // One probe, and the mutable borrow ends inside this block whichever way
748        // it goes, so the slow paths below are free to reallocate.
749        let mut current: Option<i64> = None;
750        let mut deadline: Option<u64> = None;
751        let mut dead = false;
752        if let Some(rec) = self.map.value_mut_hashed(hash, key) {
753            // The type check is inside the probe rather than in front of it,
754            // which is what the other writers do with `string_only`. The kind is
755            // three bits of the same byte the expiry flag is in, and that byte
756            // has already been loaded by the time this is asked, so here it is
757            // free. In front of the probe it measured at one and a half
758            // nanoseconds on a command that runs in eighteen, which is eight per
759            // cent of the number M2's gate is written against.
760            if value::kind(rec) != Kind::String {
761                return Err(wrong_type());
762            }
763            if value::is_expired(rec, now) {
764                dead = true;
765            } else {
766                deadline = value::expire_at(rec);
767                match value::read_int_in_place(rec) {
768                    Some((n, at)) => {
769                        let next = step(n, by, subtract)?;
770                        value::write_int_in_place(rec, at, next);
771                        return Ok(next);
772                    }
773                    None => {
774                        current = Some(
775                            value::read(rec)
776                                .as_int()
777                                .ok_or_else(|| Error::new(Code::Invalid, NOT_AN_INT))?,
778                        );
779                    }
780                }
781            }
782        }
783
784        if dead {
785            self.drop_key(key);
786            self.expired += 1;
787            deadline = None;
788        }
789        let next = step(current.unwrap_or(0), by, subtract)?;
790        self.store_int(key, next, deadline);
791        Ok(next)
792    }
793
794    /// `INCRBYFLOAT key increment`.
795    ///
796    /// The result is stored as a string, never as an integer, because Redis
797    /// stores it with its own formatting and `OBJECT ENCODING` reports `embstr`
798    /// afterwards even when the number came out whole.
799    pub fn incrbyfloat(&mut self, key: &[u8], by: f64) -> Result<f64> {
800        check_len(key, 0)?;
801        // An infinite increment is not refused up front. Redis parses it,
802        // performs the addition and reports the sum, so `INCRBYFLOAT k inf`
803        // says the increment would produce infinity rather than that the
804        // increment is not a float, and the check below is the one that says
805        // it.
806        self.reap(key);
807        self.string_only(key)?;
808        self.thaw(key)?;
809        let (current, deadline) = match self.map.get(key) {
810            Some(rec) => {
811                // Read out of the record rather than copied out of it. An int
812                // encoded value has no digits anywhere to borrow, so that arm
813                // converts instead of formatting and parsing, which is the same
814                // double either way: the decimal form of an `i64` rounds to the
815                // nearest double and so does the cast.
816                let n = match value::read(rec) {
817                    Str::Int(n) => n as f64,
818                    Str::Bytes(b) => {
819                        parse_f64(b).ok_or_else(|| Error::new(Code::Invalid, NOT_A_FLOAT))?
820                    }
821                };
822                (n, value::expire_at(rec))
823            }
824            None => (0.0, None),
825        };
826        let next = current + by;
827        if !next.is_finite() {
828            return Err(Error::new(
829                Code::Invalid,
830                "increment would produce NaN or Infinity",
831            ));
832        }
833        let mut buf = [0u8; yo_common::num::DOUBLE_MAX];
834        let text = yo_common::num::write_double(&mut buf, next);
835        self.store_text(key, text, deadline);
836        Ok(next)
837    }
838
839    // ------------------------------------------------------------------- 8.4+
840
841    /// `MSETEX numkeys key value [key value ...] [NX|XX]
842    /// [EX s|PX ms|EXAT s|PXAT ms|KEEPTTL]`.
843    ///
844    /// Redis 8.4. `MSET` with a condition and a shared deadline, and the
845    /// condition is over the whole set rather than per key: `NX` needs every
846    /// key to be missing and `XX` needs every one to be present, and a partial
847    /// match writes nothing and answers false. Without an expiration option the
848    /// deadline is cleared, the same way plain `SET` clears it, and
849    /// [`Expire::Keep`] is `KEEPTTL`, which leaves each key its own.
850    ///
851    /// A duplicate key inside one call is not an error and the last value wins.
852    pub fn msetex<'k>(
853        &mut self,
854        pairs: impl Iterator<Item = (&'k [u8], &'k [u8])> + Clone,
855        exists: Exists,
856        expire: Expire,
857    ) -> Result<bool> {
858        for (k, v) in pairs.clone() {
859            check_len(k, v.len())?;
860        }
861        for (k, _) in pairs.clone() {
862            self.reap(k);
863        }
864        let allowed = match exists {
865            Exists::Always => true,
866            Exists::IfMissing => pairs.clone().all(|(k, _)| !self.map.contains(k)),
867            Exists::IfPresent => pairs.clone().all(|(k, _)| self.map.contains(k)),
868        };
869        if !allowed {
870            return Ok(false);
871        }
872        for (k, v) in pairs {
873            let deadline = match expire {
874                Expire::Clear => None,
875                Expire::At(ms) => Some(ms),
876                Expire::Keep => self.map.get(k).and_then(value::expire_at),
877            };
878            self.store(k, v, deadline);
879        }
880        Ok(true)
881    }
882
883    /// `DELEX key [IFEQ v|IFNE v|IFDEQ d|IFDNE d]`.
884    ///
885    /// Redis 8.4's compare and delete, the other half of `SET ... IFEQ`. The
886    /// point of it is the read modify write nobody was doing correctly: a client
887    /// that reads a value, decides it is stale and deletes it can be beaten to
888    /// the key by another client between the read and the delete, and `WATCH`
889    /// plus `MULTI` costs a round trip to avoid it.
890    ///
891    /// `None` compares against nothing and deletes unconditionally, which is
892    /// plain `DEL` for one key. A key that is not there answers false whatever
893    /// the condition says, including the `NE` forms that a missing key
894    /// satisfies, because there is still nothing to delete.
895    pub fn delex(&mut self, key: &[u8], compare: Option<Compare<'_>>) -> bool {
896        self.reap(key);
897        // Only the comparing form reads the value, and only that form pays for
898        // a demoted one. `DELEX` with no compare deletes a cold key without
899        // touching the file at all. An error faulting is a comparison that
900        // cannot be made, which is a comparison that does not hold.
901        let matches = match compare {
902            Some(c) => {
903                if self.warm(key).is_err() {
904                    return false;
905                }
906                c.holds(self.peek(key))
907            }
908            None => true,
909        };
910        matches && self.drop_key(key)
911    }
912
913    /// `DIGEST key`, the XXH3 of the value.
914    ///
915    /// Redis 8.4, and the reason it exists is `IFDEQ`: a client that wants to
916    /// compare and swap against a large value sends eight bytes instead of the
917    /// value. `None` is a key that is not there, which is a nil reply.
918    pub fn digest(&mut self, key: &[u8]) -> Result<Option<u64>> {
919        self.reap(key);
920        self.string_only(key)?;
921        // The digest is over the value, so a demoted one has to be read back.
922        // Warmed and not thawed: a client polling a digest to see whether a
923        // large value has changed is exactly the read the doorkeeper is for.
924        self.warm(key)?;
925        Ok(self.peek(key).map(|v| v.digest()))
926    }
927
928    /// `INCREX key [BYINT n|BYFLOAT f] [SATURATE] [LBOUND l] [UBOUND u]
929    /// [EX s|PX ms|EXAT s|PXAT ms|PERSIST] [ENX]`.
930    ///
931    /// Redis 8.8, and the first Redis primitive that implements a workload
932    /// rather than a data structure. What it replaces is `INCR` followed by
933    /// `EXPIRE`, which is two round trips, or a Lua script, which is one round
934    /// trip and a script cache.
935    ///
936    /// The rate limiter is `INCREX key EX window ENX`: the counter goes up, and
937    /// the window is started only when the key had no deadline, so a burst
938    /// inside one window expires together at the deadline the first call set
939    /// rather than each call pushing it out. The quota counter is `UBOUND`
940    /// without `SATURATE`, which refuses rather than clamping and reports zero
941    /// applied. The stock level is `LBOUND 0 SATURATE`, which takes what it can.
942    ///
943    /// A refused increment writes nothing at all: it does not create the key and
944    /// it does not touch the deadline of a key that was there.
945    pub fn increx(&mut self, key: &[u8], opts: IncrEx) -> Result<Counted> {
946        check_len(key, 0)?;
947        self.reap(key);
948        self.string_only(key)?;
949        self.thaw(key)?;
950
951        let (current, had_deadline) = match self.map.get(key) {
952            Some(rec) => {
953                let v = value::read(rec);
954                let now = if opts.by.is_int() {
955                    Num::Int(
956                        v.as_int()
957                            .ok_or_else(|| Error::new(Code::Invalid, NOT_AN_INT))?,
958                    )
959                } else {
960                    let text = v.to_vec();
961                    Num::Float(
962                        parse_f64(&text).ok_or_else(|| Error::new(Code::Invalid, NOT_A_FLOAT))?,
963                    )
964                };
965                (now, value::expire_at(rec))
966            }
967            None => (
968                if opts.by.is_int() {
969                    Num::Int(0)
970                } else {
971                    Num::Float(0.0)
972                },
973                None,
974            ),
975        };
976
977        let out = counter::apply(current, &opts)?;
978        if !out.stored {
979            return Ok(out);
980        }
981
982        let deadline = match opts.expire {
983            IncrExpire::Keep => had_deadline,
984            IncrExpire::Persist => None,
985            IncrExpire::At(ms) => Some(ms),
986            IncrExpire::AtIfNone(ms) => had_deadline.or(Some(ms)),
987        };
988        match out.value {
989            Num::Int(n) => self.store_int(key, n, deadline),
990            Num::Float(f) => {
991                // Stored as text and never as an integer, for the same reason
992                // `INCRBYFLOAT` is: Redis reports `embstr` afterwards even when
993                // the number came out whole.
994                let mut buf = [0u8; yo_common::num::DOUBLE_MAX];
995                let text = yo_common::num::write_double(&mut buf, f);
996                self.store_text(key, text, deadline);
997            }
998        }
999        Ok(out)
1000    }
1001
1002    /// One string value, copied out, or an empty one for a key that is not
1003    /// there.
1004    ///
1005    /// What `LCS` needs, and the only read here that hands back an owned value.
1006    /// It is its own method rather than a step inside [`Keyspace::lcs`] because
1007    /// the two keys `LCS` names can be on two stripes of the same database, and
1008    /// then there is no single keyspace that can be asked for both.
1009    ///
1010    /// # Errors
1011    ///
1012    /// `WRONGTYPE` if the key holds something that is not a string.
1013    pub fn string_copy(&mut self, key: &[u8]) -> Result<Vec<u8>> {
1014        self.reap(key);
1015        self.string_only(key)?;
1016        self.warm(key)?;
1017        Ok(self.peek(key).map(|v| v.to_vec()).unwrap_or_default())
1018    }
1019
1020    /// `LCS key1 key2`, the longest common subsequence itself.
1021    ///
1022    /// A key that is not there is the empty string, which is Redis's reading and
1023    /// not an error.
1024    pub fn lcs(&mut self, a: &[u8], b: &[u8]) -> Result<Vec<u8>> {
1025        let (x, y) = self.both(a, b)?;
1026        lcs::string(&x, &y)
1027    }
1028
1029    /// `LCS key1 key2 LEN`.
1030    pub fn lcs_len(&mut self, a: &[u8], b: &[u8]) -> Result<usize> {
1031        let (x, y) = self.both(a, b)?;
1032        lcs::len(&x, &y)
1033    }
1034
1035    /// `LCS key1 key2 IDX [MINMATCHLEN n]`.
1036    ///
1037    /// `WITHMATCHLEN` is not a parameter here because every run comes back with
1038    /// its length attached. Whether that length reaches the client is the reply
1039    /// writer's decision and not the store's.
1040    pub fn lcs_idx(&mut self, a: &[u8], b: &[u8], minmatchlen: u32) -> Result<lcs::Idx> {
1041        let (x, y) = self.both(a, b)?;
1042        lcs::idx(&x, &y, minmatchlen)
1043    }
1044
1045    /// Both values as bytes, for the one command that needs two keys at once.
1046    ///
1047    /// Copied rather than borrowed, which is the only place in this file that
1048    /// copies a value it did not have to. `LCS` builds a table the size of the
1049    /// product of the two lengths, so a pair of copies is not what makes it
1050    /// expensive, and borrowing both at once through a `&mut self` reap is a
1051    /// fight with the borrow checker for no measurable gain.
1052    fn both(&mut self, a: &[u8], b: &[u8]) -> Result<(Vec<u8>, Vec<u8>)> {
1053        // One key at a time, because there is one buffer and this needs two
1054        // values. Each is copied out before the next is faulted, which is the
1055        // one place in this file that copies a value it did not have to and it
1056        // was already copying before any of this.
1057        Ok((self.string_copy(a)?, self.string_copy(b)?))
1058    }
1059
1060    // ---------------------------------------------------------------- private
1061
1062    /// The string under `key` without reaping first.
1063    ///
1064    /// Every public read reaps before calling this, so a caller that skips the
1065    /// reap would be reading a value the clock says is gone.
1066    ///
1067    /// A key holding something else answers `None` and not the first few bytes
1068    /// of a slab number read as a string. That is the right answer for `MGET`,
1069    /// which Redis documents as giving nil for a key of the wrong type rather
1070    /// than failing the whole command, and it is not the right answer for `GET`,
1071    /// which is why the readers that owe a `WRONGTYPE` ask
1072    /// [`Keyspace::string_only`] first.
1073    ///
1074    /// A key whose value is on the file has to have been through
1075    /// [`Keyspace::warm`] or [`Keyspace::thaw`] before this is called, because
1076    /// this reads a served value out of the database's one buffer and nothing
1077    /// in the buffer says whose value it is. A debug build asserts it. On a
1078    /// database with no file behind it there are no cold records and this is
1079    /// exactly what it always was.
1080    #[inline]
1081    pub(crate) fn peek(&self, key: &[u8]) -> Option<Str<'_>> {
1082        let rec = self.map.get(key)?;
1083        if value::kind(rec) != Kind::String {
1084            return None;
1085        }
1086        Some(self.value_of(key, rec))
1087    }
1088
1089    /// Fail with `WRONGTYPE` if `key` holds something that is not a string.
1090    ///
1091    /// A missing key passes, because every string command treats a missing key
1092    /// as an empty one and none of them care what type it is not.
1093    ///
1094    /// The early return is the point. A database with no sets, no hashes and no
1095    /// lists in it cannot be holding the wrong type under any key, so the check
1096    /// is one branch on a counter this struct already has in cache, and no
1097    /// lookup at all. Once one set exists every string command pays a lookup it
1098    /// did not pay before, which is the cost of being able to say no.
1099    ///
1100    /// [`Keyspace::count`] does not use this and reads the kind out of the
1101    /// record its own probe returned instead. Both are correct and the reason
1102    /// for the difference is measured rather than stylistic: `INCR` runs in
1103    /// eighteen nanoseconds and the branch here cost it one and a half of them,
1104    /// where inside the probe the byte is already loaded and it costs nothing.
1105    /// Every other writer is long enough that it does not show, so they take the
1106    /// version that reads as one line.
1107    #[inline]
1108    pub(crate) fn string_only(&self, key: &[u8]) -> Result<()> {
1109        if self.bodies == 0 {
1110            return Ok(());
1111        }
1112        match self.map.get(key) {
1113            Some(rec) if value::kind(rec) != Kind::String => Err(wrong_type()),
1114            _ => Ok(()),
1115        }
1116    }
1117
1118    /// Store `val` under `key`, choosing the encoding from the bytes.
1119    pub(crate) fn store(&mut self, key: &[u8], val: &[u8], deadline: Option<u64>) {
1120        let enc = Encoding::of(val);
1121        let len = value::record_len(enc, val.len(), deadline.is_some());
1122        self.free_body(key);
1123        self.write_rec(key, len, |out| {
1124            value::write_record(out, enc, val, deadline);
1125        });
1126    }
1127
1128    /// Store `val` under `key` as text, choosing `embstr` or `raw` by length
1129    /// but never int encoding it.
1130    ///
1131    /// This is what the float counters do. `INCRBYFLOAT k 1` on `5` leaves `6`,
1132    /// and a real server reports `embstr` for it and not `int`, because the
1133    /// result went through Redis's own formatter and straight into a string
1134    /// object without being offered to `tryObjectEncoding`.
1135    fn store_text(&mut self, key: &[u8], val: &[u8], deadline: Option<u64>) {
1136        let enc = if val.len() <= value::EMBSTR_MAX {
1137            Encoding::Embstr
1138        } else {
1139            Encoding::Raw
1140        };
1141        let len = value::record_len(enc, val.len(), deadline.is_some());
1142        self.free_body(key);
1143        self.write_rec(key, len, |out| {
1144            value::write_record(out, enc, val, deadline);
1145        });
1146    }
1147
1148    /// Store `val` under `key` as a `raw` string whatever its length.
1149    ///
1150    /// `APPEND` and `SETRANGE` both leave `raw` behind in Redis even for a four
1151    /// byte result, because they build the value with `sdscatlen` and the
1152    /// object never goes back through the encoder. `OBJECT ENCODING` is tested
1153    /// on exactly that.
1154    pub(crate) fn store_raw(&mut self, key: &[u8], val: &[u8], deadline: Option<u64>) {
1155        let len = value::record_len(Encoding::Raw, val.len(), deadline.is_some());
1156        self.free_body(key);
1157        self.write_rec(key, len, |out| {
1158            value::write_record(out, Encoding::Raw, val, deadline);
1159        });
1160    }
1161
1162    /// Store an integer the caller already has, without formatting it first.
1163    fn store_int(&mut self, key: &[u8], n: i64, deadline: Option<u64>) {
1164        let len = value::record_len(Encoding::Int, 0, deadline.is_some());
1165        self.free_body(key);
1166        self.write_rec(key, len, |out| {
1167            value::write_int_record(out, n, deadline);
1168        });
1169    }
1170
1171    /// `millis` from now, as an absolute unix millisecond.
1172    fn deadline_in(&self, millis: i64, what: &str) -> Result<u64> {
1173        u64::try_from(millis)
1174            .ok()
1175            .and_then(|ms| self.clock.now_ms().checked_add(ms))
1176            .ok_or_else(|| invalid_expire(what))
1177    }
1178}
1179
1180/// Add or subtract, refusing to wrap.
1181#[inline]
1182fn step(n: i64, by: i64, subtract: bool) -> Result<i64> {
1183    let r = if subtract {
1184        n.checked_sub(by)
1185    } else {
1186        n.checked_add(by)
1187    };
1188    r.ok_or_else(|| Error::new(Code::Invalid, WOULD_OVERFLOW))
1189}
1190
1191/// Refuse a key or a value this band cannot hold.
1192///
1193/// Not string only. The key limit is the keyspace's and applies to every type,
1194/// and a set member is held the same way a string is, so [`crate::sets`] checks
1195/// against this rather than growing a second copy of the same two numbers.
1196///
1197/// Public because the commands that write several keys at once check every pair
1198/// before they write any, and once those keys are spread over several stripes
1199/// the check cannot be inside the write: it would pass on the first stripe,
1200/// write there, and then fail on the second, leaving half of an `MSET` done.
1201///
1202/// # Errors
1203///
1204/// If the key is longer than [`KEY_MAX`] or the value longer than
1205/// [`STRING_MAX`].
1206#[inline]
1207pub fn check_len(key: &[u8], len: usize) -> Result<()> {
1208    if key.len() > KEY_MAX {
1209        return Err(Error::new(Code::Full, KEY_TOO_LONG));
1210    }
1211    if len > STRING_MAX {
1212        return Err(Error::new(Code::Full, TOO_LONG));
1213    }
1214    Ok(())
1215}
1216
1217fn invalid_expire(what: &str) -> Error {
1218    Error::fmt(
1219        Code::Invalid,
1220        format_args!("invalid expire time in '{what}' command"),
1221    )
1222}
1223
1224/// Turn Redis's inclusive, possibly negative range into a half open one.
1225///
1226/// Returns `None` when the range selects nothing, which the caller answers with
1227/// the empty string.
1228fn range_of(len: usize, start: i64, end: i64) -> Option<(usize, usize)> {
1229    if len == 0 {
1230        return None;
1231    }
1232    let n = len as i64;
1233    let clamp = |i: i64| -> i64 { if i < 0 { (n + i).max(0) } else { i.min(n) } };
1234    let s = clamp(start);
1235    // The end is inclusive, so one past it is where the slice stops.
1236    let e = if end < 0 {
1237        (n + end + 1).max(0)
1238    } else {
1239        (end + 1).min(n)
1240    };
1241    if s >= e {
1242        None
1243    } else {
1244        Some((s as usize, e as usize))
1245    }
1246}
1247
1248#[cfg(test)]
1249mod tests {
1250    use super::*;
1251    use crate::clock::Clock;
1252    use crate::value::EMBSTR_MAX;
1253
1254    /// A store on a fixed clock, so expiry is a function of what the test does
1255    /// and not of how long the test takes to run.
1256    fn store() -> Keyspace {
1257        Keyspace::with_clock(Clock::fixed(1_000))
1258    }
1259
1260    fn got(s: &mut Keyspace, key: &[u8]) -> Option<Vec<u8>> {
1261        s.get(key)
1262            .expect("a string in these tests")
1263            .map(|v| v.to_vec())
1264    }
1265
1266    #[test]
1267    fn set_and_get_round_trip() {
1268        let mut s = store();
1269        assert_eq!(got(&mut s, b"k"), None);
1270        s.set_plain(b"k", b"hello").unwrap();
1271        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"hello"[..]));
1272        assert_eq!(s.strlen(b"k").expect("a string"), 5);
1273        assert_eq!(s.len(), 1);
1274        s.set_plain(b"k", b"bye").unwrap();
1275        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"bye"[..]));
1276        assert_eq!(s.len(), 1, "overwriting made a second key");
1277    }
1278
1279    #[test]
1280    fn a_value_comes_back_exactly_as_it_went_in() {
1281        let mut s = store();
1282        for text in [&b""[..], b"0", b"007", b"-0", b"+1", b"9223372036854775808"] {
1283            s.set_plain(b"k", text).unwrap();
1284            assert_eq!(got(&mut s, b"k").as_deref(), Some(text), "{text:?}");
1285        }
1286    }
1287
1288    #[test]
1289    fn object_encoding_matches_redis() {
1290        let mut s = store();
1291        s.set_plain(b"n", b"42").unwrap();
1292        assert_eq!(s.encoding(b"n"), Some(Encoding::Int));
1293        s.set_plain(b"z", b"007").unwrap();
1294        assert_eq!(s.encoding(b"z"), Some(Encoding::Embstr));
1295        s.set_plain(b"e", &[b'x'; EMBSTR_MAX]).unwrap();
1296        assert_eq!(s.encoding(b"e"), Some(Encoding::Embstr));
1297        s.set_plain(b"r", &[b'x'; EMBSTR_MAX + 1]).unwrap();
1298        assert_eq!(s.encoding(b"r"), Some(Encoding::Raw));
1299        assert_eq!(s.encoding(b"missing"), None);
1300        // What APPEND leaves behind is raw even though it reads as a number.
1301        s.set_plain(b"a", b"1").unwrap();
1302        s.append(b"a", b"2").unwrap();
1303        assert_eq!(s.encoding(b"a"), Some(Encoding::Raw));
1304    }
1305
1306    #[test]
1307    fn nx_and_xx_decide_against_what_is_there() {
1308        let mut s = store();
1309        assert!(
1310            !s.set(b"k", b"v", SetOptions::PLAIN.if_present())
1311                .unwrap()
1312                .stored
1313        );
1314        assert_eq!(got(&mut s, b"k"), None);
1315        assert!(
1316            s.set(b"k", b"v", SetOptions::PLAIN.if_missing())
1317                .unwrap()
1318                .stored
1319        );
1320        assert!(
1321            !s.set(b"k", b"w", SetOptions::PLAIN.if_missing())
1322                .unwrap()
1323                .stored
1324        );
1325        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"v"[..]));
1326        assert!(
1327            s.set(b"k", b"w", SetOptions::PLAIN.if_present())
1328                .unwrap()
1329                .stored
1330        );
1331        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"w"[..]));
1332        assert!(s.setnx(b"fresh", b"1").unwrap());
1333        assert!(!s.setnx(b"fresh", b"2").unwrap());
1334    }
1335
1336    #[test]
1337    fn ifeq_compares_against_the_string_the_client_would_have_read() {
1338        let mut s = store();
1339        // A key that is not there is not equal to anything.
1340        assert!(
1341            !s.set(b"k", b"v", SetOptions::PLAIN.if_equal(b""))
1342                .unwrap()
1343                .stored
1344        );
1345        s.set_plain(b"k", b"42").unwrap();
1346        assert!(
1347            !s.set(b"k", b"v", SetOptions::PLAIN.if_equal(b"43"))
1348                .unwrap()
1349                .stored
1350        );
1351        // Int encoded, so the comparison is against the digits and not the bytes
1352        // in the record, and "042" is not "42".
1353        assert!(
1354            !s.set(b"k", b"v", SetOptions::PLAIN.if_equal(b"042"))
1355                .unwrap()
1356                .stored
1357        );
1358        assert!(
1359            s.set(b"k", b"v", SetOptions::PLAIN.if_equal(b"42"))
1360                .unwrap()
1361                .stored
1362        );
1363        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"v"[..]));
1364    }
1365
1366    #[test]
1367    fn get_reports_the_old_value_whether_or_not_the_write_happened() {
1368        let mut s = store();
1369        assert_eq!(
1370            s.set(b"k", b"a", SetOptions::PLAIN.returning())
1371                .unwrap()
1372                .previous,
1373            None
1374        );
1375        let out = s.set(b"k", b"b", SetOptions::PLAIN.returning()).unwrap();
1376        assert!(out.stored);
1377        assert_eq!(out.previous.as_deref(), Some(&b"a"[..]));
1378        // Refused by NX, and still reports what is there.
1379        let out = s
1380            .set(b"k", b"c", SetOptions::PLAIN.if_missing().returning())
1381            .unwrap();
1382        assert!(!out.stored);
1383        assert_eq!(out.previous.as_deref(), Some(&b"b"[..]));
1384        assert_eq!(s.getset(b"k", b"d").unwrap().as_deref(), Some(&b"b"[..]));
1385    }
1386
1387    #[test]
1388    fn a_key_is_gone_the_millisecond_its_deadline_arrives() {
1389        let mut s = store();
1390        s.set(b"k", b"v", SetOptions::PLAIN.expiring(Expire::At(1_500)))
1391            .unwrap();
1392        assert_eq!(s.expire_at(b"k"), Some(1_500));
1393        s.clock().set(1_499);
1394        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"v"[..]));
1395        s.clock().set(1_500);
1396        assert_eq!(got(&mut s, b"k"), None);
1397        assert_eq!(s.len(), 0, "the dead key was not reclaimed");
1398        assert_eq!(s.expired_keys(), 1);
1399    }
1400
1401    #[test]
1402    fn keepttl_keeps_the_deadline_and_a_plain_set_clears_it() {
1403        let mut s = store();
1404        s.set(b"k", b"v", SetOptions::PLAIN.expiring(Expire::At(9_000)))
1405            .unwrap();
1406        s.set(b"k", b"w", SetOptions::PLAIN.expiring(Expire::Keep))
1407            .unwrap();
1408        assert_eq!(s.expire_at(b"k"), Some(9_000));
1409        s.set_plain(b"k", b"x").unwrap();
1410        assert_eq!(s.expire_at(b"k"), None);
1411    }
1412
1413    #[test]
1414    fn setex_refuses_a_time_to_live_that_is_not_one() {
1415        let mut s = store();
1416        // The command in the message is the one that was called, lower cased,
1417        // even though `SETEX` hands the milliseconds to the same body `PSETEX`
1418        // uses.
1419        assert_eq!(
1420            s.setex(b"k", 0, b"v").unwrap_err().message(),
1421            "invalid expire time in 'setex' command"
1422        );
1423        assert_eq!(
1424            s.psetex(b"k", 0, b"v").unwrap_err().message(),
1425            "invalid expire time in 'psetex' command"
1426        );
1427        assert!(s.setex(b"k", -1, b"v").is_err());
1428        assert_eq!(got(&mut s, b"k"), None);
1429        s.setex(b"k", 10, b"v").unwrap();
1430        assert_eq!(s.expire_at(b"k"), Some(11_000));
1431        s.psetex(b"p", 250, b"v").unwrap();
1432        assert_eq!(s.expire_at(b"p"), Some(1_250));
1433    }
1434
1435    #[test]
1436    fn getex_reads_and_retimes_in_one_go() {
1437        let mut s = store();
1438        s.set(b"k", b"v", SetOptions::PLAIN.expiring(Expire::At(5_000)))
1439            .unwrap();
1440        // Plain GETEX leaves the deadline alone.
1441        assert_eq!(
1442            s.getex(b"k", Expire::Keep)
1443                .expect("a string")
1444                .map(|v| v.to_vec())
1445                .as_deref(),
1446            Some(&b"v"[..])
1447        );
1448        assert_eq!(s.expire_at(b"k"), Some(5_000));
1449        // PERSIST clears it.
1450        assert!(s.getex(b"k", Expire::Clear).expect("a string").is_some());
1451        assert_eq!(s.expire_at(b"k"), None);
1452        // And a new deadline replaces it.
1453        assert!(
1454            s.getex(b"k", Expire::At(7_000))
1455                .expect("a string")
1456                .is_some()
1457        );
1458        assert_eq!(s.expire_at(b"k"), Some(7_000));
1459        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"v"[..]));
1460        assert!(
1461            s.getex(b"missing", Expire::At(7_000))
1462                .expect("a string")
1463                .is_none()
1464        );
1465    }
1466
1467    #[test]
1468    fn getdel_hands_the_value_over_and_keeps_nothing() {
1469        let mut s = store();
1470        s.set_plain(b"k", b"v").unwrap();
1471        assert_eq!(
1472            s.getdel(b"k").expect("a string").as_deref(),
1473            Some(&b"v"[..])
1474        );
1475        assert_eq!(s.getdel(b"k").expect("a string"), None);
1476        assert_eq!(s.len(), 0);
1477        s.set_plain(b"k", b"v").unwrap();
1478        assert!(s.del(b"k"));
1479        assert!(!s.del(b"k"));
1480    }
1481
1482    #[test]
1483    fn mset_writes_every_pair_and_msetnx_writes_none_of_them() {
1484        let mut s = store();
1485        s.mset([(&b"a"[..], &b"1"[..]), (&b"b"[..], &b"2"[..])].into_iter())
1486            .unwrap();
1487        let vals = s.mget(&[&b"a"[..], &b"b"[..], &b"missing"[..]]);
1488        let vals: Vec<_> = vals.iter().map(|v| v.map(|v| v.to_vec())).collect();
1489        assert_eq!(vals[0].as_deref(), Some(&b"1"[..]));
1490        assert_eq!(vals[1].as_deref(), Some(&b"2"[..]));
1491        assert_eq!(vals[2], None);
1492
1493        assert!(
1494            !s.msetnx([(&b"b"[..], &b"9"[..]), (&b"c"[..], &b"3"[..])].into_iter())
1495                .unwrap()
1496        );
1497        assert_eq!(got(&mut s, b"c"), None, "msetnx wrote part of the set");
1498        assert_eq!(got(&mut s, b"b").as_deref(), Some(&b"2"[..]));
1499        assert!(
1500            s.msetnx([(&b"c"[..], &b"3"[..]), (&b"d"[..], &b"4"[..])].into_iter())
1501                .unwrap()
1502        );
1503        assert_eq!(got(&mut s, b"d").as_deref(), Some(&b"4"[..]));
1504    }
1505
1506    #[test]
1507    fn mget_reaps_before_it_reads() {
1508        let mut s = store();
1509        s.set(b"a", b"1", SetOptions::PLAIN.expiring(Expire::At(1_100)))
1510            .unwrap();
1511        s.set_plain(b"b", b"2").unwrap();
1512        s.clock().set(1_100);
1513        let vals = s.mget(&[&b"a"[..], &b"b"[..]]);
1514        assert!(vals[0].is_none(), "a dead key came back from mget");
1515        assert!(vals[1].is_some());
1516        assert_eq!(s.len(), 1);
1517    }
1518
1519    #[test]
1520    fn append_creates_extends_and_keeps_the_deadline() {
1521        let mut s = store();
1522        assert_eq!(s.append(b"k", b"one").unwrap(), 3);
1523        assert_eq!(s.append(b"k", b" two").unwrap(), 7);
1524        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"one two"[..]));
1525        s.set(b"t", b"a", SetOptions::PLAIN.expiring(Expire::At(4_000)))
1526            .unwrap();
1527        s.append(b"t", b"b").unwrap();
1528        assert_eq!(s.expire_at(b"t"), Some(4_000));
1529        assert_eq!(got(&mut s, b"t").as_deref(), Some(&b"ab"[..]));
1530    }
1531
1532    /// `APPEND` in a loop is how a client writes a log into one key, so the
1533    /// copy of the old value it has to make must not be a fresh `Vec` every
1534    /// time. The value keeps growing here, so the scratch buffer and the index
1535    /// are both still allowed to grow, which is why this counts a ceiling rather
1536    /// than zero. Before the scratch buffer it was a hundred and change.
1537    #[test]
1538    fn append_reuses_its_buffer_instead_of_allocating_per_call() {
1539        let mut s = store();
1540        s.append(b"k", b"start").expect("room");
1541        let (_, allocs) = crate::tally::counted(|| {
1542            for _ in 0..100 {
1543                s.append(b"k", b"0123456789").expect("room");
1544            }
1545        });
1546        assert!(
1547            allocs < 20,
1548            "append allocated {allocs} times in a hundred, so it is still copying into a new Vec"
1549        );
1550        assert_eq!(got(&mut s, b"k").map(|v| v.len()), Some(1005));
1551    }
1552
1553    /// The same claim for `SETRANGE`, which is easier to state because the value
1554    /// does not grow: writing over the same five bytes of the same key a hundred
1555    /// times has nothing left to allocate for.
1556    #[test]
1557    fn setrange_stops_allocating_once_its_buffer_is_grown() {
1558        let mut s = store();
1559        s.set_plain(b"k", b"Hello World").expect("room");
1560        s.setrange(b"k", 6, b"Redis").expect("room");
1561        let (_, allocs) = crate::tally::counted(|| {
1562            for _ in 0..100 {
1563                s.setrange(b"k", 6, b"Redis").expect("room");
1564            }
1565        });
1566        assert_eq!(allocs, 0, "setrange allocated {allocs} times in a hundred");
1567        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"Hello Redis"[..]));
1568    }
1569
1570    /// `EXPIRE` on a string rewrites the record, which means holding the value
1571    /// while it does. A cache that sets a deadline on every write sends as many
1572    /// of these as it does `SET`.
1573    #[test]
1574    fn expiry_on_a_string_stops_allocating_once_its_buffer_is_grown() {
1575        let mut s = store();
1576        s.set_plain(b"k", b"a value of some length").expect("room");
1577        // Far enough out that the key is still there at the end. A deadline in
1578        // the past is reaped, and a reaped key is a different test.
1579        const FUTURE: u64 = 4_000_000_000_000;
1580        s.set_expiry(b"k", Some(FUTURE));
1581        let (_, allocs) = crate::tally::counted(|| {
1582            for i in 0..100 {
1583                // A different deadline each time, because the same one is a no
1584                // op that never reaches the rewrite.
1585                s.set_expiry(b"k", Some(FUTURE + i));
1586            }
1587        });
1588        assert_eq!(
1589            allocs, 0,
1590            "set_expiry allocated {allocs} times in a hundred"
1591        );
1592        assert_eq!(
1593            got(&mut s, b"k").as_deref(),
1594            Some(&b"a value of some length"[..])
1595        );
1596    }
1597
1598    #[test]
1599    fn setrange_pads_with_zero_bytes() {
1600        let mut s = store();
1601        assert_eq!(s.setrange(b"k", 0, b"").unwrap(), 0);
1602        assert_eq!(got(&mut s, b"k"), None, "an empty write created a key");
1603        assert_eq!(s.setrange(b"k", 3, b"xy").unwrap(), 5);
1604        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"\0\0\0xy"[..]));
1605        s.set_plain(b"h", b"Hello World").unwrap();
1606        assert_eq!(s.setrange(b"h", 6, b"Redis").unwrap(), 11);
1607        assert_eq!(got(&mut s, b"h").as_deref(), Some(&b"Hello Redis"[..]));
1608    }
1609
1610    #[test]
1611    fn getrange_counts_from_both_ends_and_clamps() {
1612        let mut s = store();
1613        s.set_plain(b"k", b"This is a string").unwrap();
1614        assert_eq!(&*s.getrange(b"k", 0, 3).expect("a string"), b"This");
1615        assert_eq!(&*s.getrange(b"k", -3, -1).expect("a string"), b"ing");
1616        assert_eq!(
1617            &*s.getrange(b"k", 0, -1).expect("a string"),
1618            b"This is a string"
1619        );
1620        assert_eq!(&*s.getrange(b"k", 10, 100).expect("a string"), b"string");
1621        // A start past the end, and a range that runs backwards, are both empty.
1622        assert_eq!(&*s.getrange(b"k", 100, 200).expect("a string"), b"");
1623        assert_eq!(&*s.getrange(b"k", 5, 2).expect("a string"), b"");
1624        assert_eq!(&*s.getrange(b"missing", 0, -1).expect("a string"), b"");
1625        // An int encoded value ranges over its digits.
1626        s.set_plain(b"n", b"12345").unwrap();
1627        assert_eq!(&*s.getrange(b"n", 1, 3).expect("a string"), b"234");
1628        assert_eq!(&*s.getrange(b"n", 9, 9).expect("a string"), b"");
1629    }
1630
1631    #[test]
1632    fn incr_counts_and_refuses_what_is_not_a_number() {
1633        let mut s = store();
1634        assert_eq!(s.incr(b"k").unwrap(), 1);
1635        assert_eq!(s.incr(b"k").unwrap(), 2);
1636        assert_eq!(s.incrby(b"k", 40).unwrap(), 42);
1637        assert_eq!(s.decr(b"k").unwrap(), 41);
1638        assert_eq!(s.decrby(b"k", 41).unwrap(), 0);
1639        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"0"[..]));
1640        assert_eq!(s.encoding(b"k"), Some(Encoding::Int));
1641
1642        s.set_plain(b"t", b"hello").unwrap();
1643        let e = s.incr(b"t").unwrap_err();
1644        assert_eq!(e.code(), Code::Invalid);
1645        assert_eq!(e.message(), NOT_AN_INT);
1646        // The refused increment left the value alone.
1647        assert_eq!(got(&mut s, b"t").as_deref(), Some(&b"hello"[..]));
1648    }
1649
1650    #[test]
1651    fn incr_works_on_a_number_that_is_stored_as_text() {
1652        let mut s = store();
1653        // Appending onto an existing key leaves a raw string, which INCR still
1654        // counts. Appending onto a key that is not there does not, because
1655        // Redis runs the new value through tryObjectEncoding on create.
1656        s.append(b"k", b"1").unwrap();
1657        assert_eq!(s.encoding(b"k"), Some(Encoding::Int));
1658        s.append(b"k", b"0").unwrap();
1659        assert_eq!(s.encoding(b"k"), Some(Encoding::Raw));
1660        assert_eq!(s.incr(b"k").unwrap(), 11);
1661        assert_eq!(
1662            s.encoding(b"k"),
1663            Some(Encoding::Int),
1664            "INCR did not re-encode"
1665        );
1666        // A leading zero is not a number to string2ll, so it is not one here.
1667        s.set_plain(b"z", b"007").unwrap();
1668        assert!(s.incr(b"z").is_err());
1669    }
1670
1671    #[test]
1672    fn a_counter_refuses_to_wrap() {
1673        let mut s = store();
1674        s.set_plain(b"k", b"9223372036854775807").unwrap();
1675        let e = s.incr(b"k").unwrap_err();
1676        assert_eq!(e.code(), Code::Invalid);
1677        assert_eq!(e.message(), WOULD_OVERFLOW);
1678        assert_eq!(
1679            got(&mut s, b"k").as_deref(),
1680            Some(&b"9223372036854775807"[..])
1681        );
1682        s.set_plain(b"m", b"-9223372036854775808").unwrap();
1683        assert!(s.decr(b"m").is_err());
1684        // Subtracting i64::MIN is the case negating first would get wrong.
1685        s.set_plain(b"d", b"0").unwrap();
1686        assert!(s.decrby(b"d", i64::MIN).is_err());
1687    }
1688
1689    #[test]
1690    fn incr_keeps_the_deadline_and_reaps_a_dead_key_first() {
1691        let mut s = store();
1692        s.set(b"k", b"5", SetOptions::PLAIN.expiring(Expire::At(2_000)))
1693            .unwrap();
1694        assert_eq!(s.incr(b"k").unwrap(), 6);
1695        assert_eq!(s.expire_at(b"k"), Some(2_000), "the deadline was dropped");
1696        // Past the deadline, the counter starts again from zero and the key has
1697        // no deadline any more.
1698        s.clock().set(2_000);
1699        assert_eq!(s.incr(b"k").unwrap(), 1);
1700        assert_eq!(s.expire_at(b"k"), None);
1701        assert_eq!(s.expired_keys(), 1);
1702    }
1703
1704    /// The gate is about this path, so it gets its own test: incrementing an int
1705    /// encoded value must not touch the arena at all.
1706    #[test]
1707    fn incr_on_an_int_does_not_allocate() {
1708        let mut s = store();
1709        s.set_plain(b"k", b"1").unwrap();
1710        let before = s.map().arena().live_bytes();
1711        for want in 2..1_000 {
1712            assert_eq!(s.incr(b"k").unwrap(), want);
1713        }
1714        assert_eq!(
1715            s.map().arena().live_bytes(),
1716            before,
1717            "INCR moved the record"
1718        );
1719        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"999"[..]));
1720    }
1721
1722    #[test]
1723    fn incrbyfloat_formats_the_way_redis_does() {
1724        let mut s = store();
1725        assert_eq!(s.incrbyfloat(b"k", 10.5).unwrap(), 10.5);
1726        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"10.5"[..]));
1727        assert_eq!(s.incrbyfloat(b"k", 0.1).unwrap(), 10.6);
1728        // A whole result is still stored as a string, never as an integer.
1729        s.set_plain(b"n", b"5").unwrap();
1730        assert_eq!(s.incrbyfloat(b"n", 1.0).unwrap(), 6.0);
1731        assert_eq!(got(&mut s, b"n").as_deref(), Some(&b"6"[..]));
1732        assert_eq!(s.encoding(b"n"), Some(Encoding::Embstr));
1733
1734        s.set_plain(b"t", b"hello").unwrap();
1735        let e = s.incrbyfloat(b"t", 1.0).unwrap_err();
1736        assert_eq!(e.message(), NOT_A_FLOAT);
1737        // An increment that cannot land anywhere is reported as the sum it
1738        // would have produced, which is the sentence a real server sends and
1739        // not the one about the argument.
1740        assert_eq!(
1741            s.incrbyfloat(b"k", f64::INFINITY).unwrap_err().message(),
1742            "increment would produce NaN or Infinity"
1743        );
1744        assert_eq!(
1745            s.incrbyfloat(b"k", f64::NAN).unwrap_err().message(),
1746            "increment would produce NaN or Infinity"
1747        );
1748        // And the key it could not increment is left as it was.
1749        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"10.6"[..]));
1750    }
1751
1752    /// An int encoded value takes the other arm of the read in `incrbyfloat`,
1753    /// which converts rather than formatting the digits and parsing them back.
1754    /// Both arms have to reach the same double or the same command answers two
1755    /// different things depending on how the value happened to be stored.
1756    #[test]
1757    fn incrbyfloat_reads_an_int_encoded_value_the_same_as_its_digits() {
1758        for n in [0i64, 6, -6, 1 << 40, -(1 << 40), i64::MAX, i64::MIN] {
1759            let mut s = store();
1760            s.set_plain(b"i", n.to_string().as_bytes()).unwrap();
1761            // `APPEND` of nothing leaves the same bytes in a record that is no
1762            // longer int encoded, which is the only way to get the two arms
1763            // looking at one value.
1764            s.set_plain(b"t", n.to_string().as_bytes()).unwrap();
1765            s.append(b"t", b"").unwrap();
1766            assert_eq!(s.encoding(b"i"), Some(Encoding::Int));
1767            assert_ne!(s.encoding(b"t"), Some(Encoding::Int));
1768            assert_eq!(
1769                s.incrbyfloat(b"i", 0.5).unwrap(),
1770                s.incrbyfloat(b"t", 0.5).unwrap(),
1771                "the two encodings of {n} do not increment alike"
1772            );
1773        }
1774    }
1775
1776    /// `INCRBYFLOAT` used to copy the value out of the record so it could parse
1777    /// it, and then throw the copy away.
1778    #[test]
1779    fn incrbyfloat_does_not_allocate() {
1780        let mut s = store();
1781        for _ in 0..4 {
1782            s.incrbyfloat(b"f", 1.5).unwrap();
1783        }
1784        let (_, allocs) = crate::tally::counted(|| {
1785            for _ in 0..50 {
1786                s.incrbyfloat(b"f", 1.5).unwrap();
1787            }
1788        });
1789        assert_eq!(allocs, 0, "incrbyfloat allocated {allocs} times in fifty");
1790    }
1791
1792    /// `SET ... GET` used to hand the old value back as a `Vec` that the wire
1793    /// writes once and drops.
1794    #[test]
1795    fn set_with_does_not_allocate_to_report_the_old_value() {
1796        let mut s = store();
1797        let opts = SetOptions::PLAIN.returning();
1798        let mut seen = Vec::with_capacity(64);
1799        for _ in 0..4 {
1800            s.set_with(b"k", b"a-value", opts, |v| v.write_to(&mut seen))
1801                .unwrap();
1802        }
1803        let (_, allocs) = crate::tally::counted(|| {
1804            for _ in 0..50 {
1805                seen.clear();
1806                s.set_with(b"k", b"a-value", opts, |v| v.write_to(&mut seen))
1807                    .unwrap();
1808            }
1809        });
1810        assert_eq!(allocs, 0, "set with GET allocated {allocs} times in fifty");
1811        assert_eq!(seen, b"a-value");
1812        // And the owning version still answers what it always did.
1813        let done = s.set(b"k", b"next", opts).unwrap();
1814        assert_eq!(done.previous.as_deref(), Some(&b"a-value"[..]));
1815        assert!(done.stored);
1816    }
1817
1818    #[test]
1819    fn a_value_that_is_too_long_is_an_error_and_not_a_panic() {
1820        let mut s = store();
1821        let huge = vec![b'x'; STRING_MAX + 1];
1822        let e = s.set_plain(b"k", &huge).unwrap_err();
1823        assert_eq!(e.code(), Code::Full);
1824        assert_eq!(e.message(), TOO_LONG);
1825        assert!(s.append(b"k", &huge).is_err());
1826        assert!(s.setrange(b"k", STRING_MAX, b"x").is_err());
1827        let long_key = vec![b'k'; KEY_MAX + 1];
1828        assert_eq!(s.set_plain(&long_key, b"v").unwrap_err().code(), Code::Full);
1829        assert_eq!(s.len(), 0);
1830    }
1831
1832    #[test]
1833    fn exists_and_strlen_agree_with_get() {
1834        let mut s = store();
1835        assert!(!s.exists(b"k"));
1836        assert_eq!(s.strlen(b"k").expect("a string"), 0);
1837        s.set(
1838            b"k",
1839            b"12345",
1840            SetOptions::PLAIN.expiring(Expire::At(2_000)),
1841        )
1842        .unwrap();
1843        assert!(s.exists(b"k"));
1844        assert_eq!(s.strlen(b"k").expect("a string"), 5);
1845        s.clock().set(2_000);
1846        assert!(!s.exists(b"k"));
1847        assert_eq!(s.strlen(b"k").expect("a string"), 0);
1848    }
1849
1850    #[test]
1851    fn msetex_writes_all_of_them_or_none() {
1852        let mut s = store();
1853        let pairs = [(&b"a"[..], &b"1"[..]), (&b"b"[..], &b"2"[..])];
1854        assert!(
1855            s.msetex(pairs.iter().copied(), Exists::Always, Expire::At(3_000))
1856                .unwrap()
1857        );
1858        assert_eq!(s.expire_at(b"a"), Some(3_000));
1859        assert_eq!(s.expire_at(b"b"), Some(3_000));
1860
1861        // The condition is over the whole set. One key present is enough to
1862        // stop NX, and one key missing is enough to stop XX, and neither
1863        // writes anything on the way to finding out.
1864        assert!(
1865            !s.msetex(pairs.iter().copied(), Exists::IfMissing, Expire::Clear)
1866                .unwrap()
1867        );
1868        assert_eq!(s.expire_at(b"a"), Some(3_000), "a failed NX still wrote");
1869        s.del(b"b");
1870        assert!(
1871            !s.msetex(pairs.iter().copied(), Exists::IfPresent, Expire::Clear)
1872                .unwrap()
1873        );
1874        assert!(!s.exists(b"b"), "a failed XX still wrote");
1875        assert!(
1876            s.msetex(pairs.iter().copied(), Exists::IfMissing, Expire::Clear)
1877                .is_ok()
1878        );
1879
1880        // KEEPTTL leaves each key whatever it had, which here is one with a
1881        // deadline and one without.
1882        s.set(b"a", b"1", SetOptions::PLAIN.expiring(Expire::At(9_000)))
1883            .unwrap();
1884        assert!(
1885            s.msetex(pairs.iter().copied(), Exists::Always, Expire::Keep)
1886                .unwrap()
1887        );
1888        assert_eq!(s.expire_at(b"a"), Some(9_000));
1889        assert_eq!(s.expire_at(b"b"), None);
1890        // With no expiration option at all it clears, the way plain SET does.
1891        assert!(
1892            s.msetex(pairs.iter().copied(), Exists::Always, Expire::Clear)
1893                .unwrap()
1894        );
1895        assert_eq!(s.expire_at(b"a"), None);
1896    }
1897
1898    #[test]
1899    fn msetex_lets_the_last_of_a_duplicated_key_win() {
1900        let mut s = store();
1901        let pairs = [(&b"k"[..], &b"1"[..]), (&b"k"[..], &b"2"[..])];
1902        assert!(
1903            s.msetex(pairs.iter().copied(), Exists::Always, Expire::Clear)
1904                .unwrap()
1905        );
1906        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"2"[..]));
1907    }
1908
1909    #[test]
1910    fn delex_deletes_only_what_it_was_told_to() {
1911        let mut s = store();
1912        s.set_plain(b"k", b"v").unwrap();
1913        assert!(!s.delex(b"k", Some(Compare::Equal(b"other"))));
1914        assert!(s.exists(b"k"), "a failed compare deleted the key");
1915        assert!(s.delex(b"k", Some(Compare::Equal(b"v"))));
1916        assert!(!s.exists(b"k"));
1917        // A key that is not there has nothing to delete, including under the
1918        // conditions a missing key satisfies.
1919        assert!(!s.delex(b"k", Some(Compare::Equal(b"v"))));
1920        assert!(!s.delex(b"k", Some(Compare::NotEqual(b"v"))));
1921        assert!(!s.delex(b"k", None));
1922        s.set_plain(b"k", b"v").unwrap();
1923        assert!(s.delex(b"k", None));
1924        // Int encoded, so the compare is against the digits.
1925        s.set_plain(b"n", b"42").unwrap();
1926        assert!(!s.delex(b"n", Some(Compare::Equal(b"042"))));
1927        assert!(s.delex(b"n", Some(Compare::Equal(b"42"))));
1928    }
1929
1930    #[test]
1931    fn the_four_conditions_agree_with_a_real_server() {
1932        let mut s = store();
1933        // SET IFNE on a key that is not there stores, because a key that is
1934        // not there is not equal to anything.
1935        assert!(
1936            s.set(b"m", b"v", SetOptions::PLAIN.if_not_equal(b"other"))
1937                .unwrap()
1938                .stored
1939        );
1940        // The digest forms are the value forms with the value hashed.
1941        let d = s.digest(b"m").expect("a string").expect("just written");
1942        assert_eq!(d, yo_common::xxh3::hash64(b"v"));
1943        assert!(
1944            !s.set(b"m", b"x", SetOptions::PLAIN.if_not_digest(d))
1945                .unwrap()
1946                .stored
1947        );
1948        assert!(
1949            s.set(b"m", b"x", SetOptions::PLAIN.if_digest(d))
1950                .unwrap()
1951                .stored
1952        );
1953        assert_eq!(got(&mut s, b"m").as_deref(), Some(&b"x"[..]));
1954        assert_eq!(s.digest(b"gone").expect("a string"), None);
1955        let d = s.digest(b"m").expect("a string").expect("still there");
1956        assert!(s.delex(b"m", Some(Compare::DigestEqual(d))));
1957    }
1958
1959    #[test]
1960    fn increx_counts_and_leaves_the_deadline_alone() {
1961        let mut s = store();
1962        let c = s.increx(b"k", IncrEx::PLAIN).unwrap();
1963        assert_eq!(
1964            (c.value, c.applied, c.stored),
1965            (Num::Int(1), Num::Int(1), true)
1966        );
1967        assert_eq!(s.expire_at(b"k"), None, "a plain INCREX set a deadline");
1968        assert_eq!(s.encoding(b"k"), Some(Encoding::Int));
1969
1970        // An expiration option sets one, and a later plain call keeps it.
1971        s.increx(b"k", IncrEx::PLAIN.expiring(IncrExpire::At(2_000)))
1972            .unwrap();
1973        assert_eq!(s.expire_at(b"k"), Some(2_000));
1974        s.increx(b"k", IncrEx::PLAIN).unwrap();
1975        assert_eq!(s.expire_at(b"k"), Some(2_000));
1976        // PERSIST drops it.
1977        s.increx(b"k", IncrEx::PLAIN.expiring(IncrExpire::Persist))
1978            .unwrap();
1979        assert_eq!(s.expire_at(b"k"), None);
1980    }
1981
1982    #[test]
1983    fn increx_with_enx_is_the_rate_limiter() {
1984        let mut s = store();
1985        // The window starts on the call that found no deadline, and every call
1986        // inside it leaves the deadline where the first one put it.
1987        let c = s
1988            .increx(b"k", IncrEx::PLAIN.expiring(IncrExpire::AtIfNone(1_500)))
1989            .unwrap();
1990        assert_eq!(c.value, Num::Int(1));
1991        assert_eq!(s.expire_at(b"k"), Some(1_500));
1992        s.clock().set(1_200);
1993        let c = s
1994            .increx(b"k", IncrEx::PLAIN.expiring(IncrExpire::AtIfNone(1_700)))
1995            .unwrap();
1996        assert_eq!(c.value, Num::Int(2));
1997        assert_eq!(s.expire_at(b"k"), Some(1_500), "the window was pushed out");
1998        // Past the deadline the counter and the window both start again.
1999        s.clock().set(1_500);
2000        let c = s
2001            .increx(b"k", IncrEx::PLAIN.expiring(IncrExpire::AtIfNone(2_000)))
2002            .unwrap();
2003        assert_eq!(c.value, Num::Int(1));
2004        assert_eq!(s.expire_at(b"k"), Some(2_000));
2005        assert_eq!(s.expired_keys(), 1);
2006    }
2007
2008    #[test]
2009    fn a_refused_increx_writes_nothing_at_all() {
2010        let mut s = store();
2011        let quota = IncrEx::PLAIN
2012            .by(Num::Int(10))
2013            .between(None, Some(Num::Int(5)));
2014        let c = s.increx(b"k", quota).unwrap();
2015        assert_eq!(
2016            (c.value, c.applied, c.stored),
2017            (Num::Int(0), Num::Int(0), false)
2018        );
2019        assert!(!s.exists(b"k"), "a refused increment created the key");
2020
2021        // The same increment with SATURATE lands on the bound and does create
2022        // it, which is the difference a client tells by the second number.
2023        let c = s.increx(b"k", quota.saturating()).unwrap();
2024        assert_eq!((c.value, c.applied), (Num::Int(5), Num::Int(5)));
2025        assert!(s.exists(b"k"));
2026
2027        // A refusal on a key that was already there leaves its deadline alone.
2028        s.set(b"q", b"1", SetOptions::PLAIN.expiring(Expire::At(4_000)))
2029            .unwrap();
2030        let c = s
2031            .increx(b"q", quota.expiring(IncrExpire::At(9_000)))
2032            .unwrap();
2033        assert!(!c.stored);
2034        assert_eq!(s.expire_at(b"q"), Some(4_000));
2035        assert_eq!(got(&mut s, b"q").as_deref(), Some(&b"1"[..]));
2036    }
2037
2038    #[test]
2039    fn increx_by_float_stores_text_the_way_incrbyfloat_does() {
2040        let mut s = store();
2041        let c = s.increx(b"f", IncrEx::PLAIN.by(Num::Float(1.5))).unwrap();
2042        assert_eq!((c.value, c.applied), (Num::Float(1.5), Num::Float(1.5)));
2043        assert_eq!(got(&mut s, b"f").as_deref(), Some(&b"1.5"[..]));
2044        // An int encoded key counted in floats stops being int encoded, which
2045        // is what a real server reports afterwards.
2046        s.set_plain(b"n", b"5").unwrap();
2047        assert_eq!(s.encoding(b"n"), Some(Encoding::Int));
2048        s.increx(b"n", IncrEx::PLAIN.by(Num::Float(0.5))).unwrap();
2049        assert_eq!(s.encoding(b"n"), Some(Encoding::Embstr));
2050        assert_eq!(got(&mut s, b"n").as_deref(), Some(&b"5.5"[..]));
2051    }
2052
2053    #[test]
2054    fn increx_refuses_a_value_that_is_not_a_number() {
2055        let mut s = store();
2056        s.set_plain(b"t", b"hello").unwrap();
2057        assert!(s.increx(b"t", IncrEx::PLAIN).is_err());
2058        assert!(s.increx(b"t", IncrEx::PLAIN.by(Num::Float(1.0))).is_err());
2059    }
2060
2061    #[test]
2062    fn lcs_reads_two_keys_and_treats_a_missing_one_as_empty() {
2063        let mut s = store();
2064        s.set_plain(b"a", b"ohmytext").unwrap();
2065        s.set_plain(b"b", b"mynewtext").unwrap();
2066        assert_eq!(s.lcs(b"a", b"b").unwrap(), b"mytext");
2067        assert_eq!(s.lcs_len(b"a", b"b").unwrap(), 6);
2068        assert_eq!(s.lcs_idx(b"a", b"b", 4).unwrap().matches.len(), 1);
2069        assert_eq!(s.lcs(b"a", b"missing").unwrap(), b"");
2070        assert_eq!(s.lcs_len(b"missing", b"gone").unwrap(), 0);
2071        // An int encoded value is compared as its digits.
2072        s.set_plain(b"n", b"12345").unwrap();
2073        s.set_plain(b"m", b"13579").unwrap();
2074        assert_eq!(s.lcs(b"n", b"m").unwrap(), b"135");
2075    }
2076
2077    #[test]
2078    fn lcs_does_not_see_a_key_that_has_expired() {
2079        let mut s = store();
2080        s.set(
2081            b"a",
2082            b"hello",
2083            SetOptions::PLAIN.expiring(Expire::At(1_100)),
2084        )
2085        .unwrap();
2086        s.set_plain(b"b", b"hello").unwrap();
2087        assert_eq!(s.lcs(b"a", b"b").unwrap(), b"hello");
2088        s.clock().set(1_100);
2089        assert_eq!(s.lcs(b"a", b"b").unwrap(), b"");
2090    }
2091
2092    #[test]
2093    fn the_store_reports_what_it_is_holding() {
2094        let mut s = Keyspace::new();
2095        assert!(s.is_empty());
2096        assert!(s.memory_bytes() > 0, "an empty index still has buckets");
2097        s.set_plain(b"k", b"v").unwrap();
2098        assert!(!s.is_empty());
2099        assert_eq!(s.len(), 1);
2100        // The clock is the system one, so it is somewhere after 2020.
2101        assert!(s.clock().now_ms() > 1_577_836_800_000);
2102        s.prefetch(Keyspace::hash_of(b"k"));
2103        assert_eq!(got(&mut s, b"k").as_deref(), Some(&b"v"[..]));
2104    }
2105
2106    #[test]
2107    fn clearing_hands_the_memory_back_and_not_only_the_keys() {
2108        let mut s = store();
2109        let empty = s.memory_bytes();
2110        let big = vec![b'x'; 4_096];
2111        for i in 0..2_000u32 {
2112            s.set_plain(format!("k{i}").as_bytes(), &big).unwrap();
2113        }
2114        assert_eq!(s.len(), 2_000);
2115        assert!(s.memory_bytes() > empty * 4, "the store should have grown");
2116
2117        // One key expires, so the counter has something in it to check.
2118        s.setex(b"gone", 1, b"v").unwrap();
2119        s.clock().set(3_000);
2120        assert!(got(&mut s, b"gone").is_none());
2121        assert_eq!(s.expired_keys(), 1);
2122
2123        s.clear();
2124        assert!(s.is_empty());
2125        assert_eq!(s.len(), 0);
2126        assert_eq!(got(&mut s, b"k0"), None);
2127        // Back to what a fresh store costs, rather than an arena still the size
2128        // of what used to be in it.
2129        assert_eq!(s.memory_bytes(), empty);
2130        // The expiry counter is not reset, because Redis does not reset it
2131        // either. Emptying a database is not expiring anything.
2132        assert_eq!(s.expired_keys(), 1);
2133
2134        // And it still works afterwards.
2135        s.set_plain(b"after", b"v").unwrap();
2136        assert_eq!(got(&mut s, b"after").as_deref(), Some(&b"v"[..]));
2137    }
2138}