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