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