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}