Skip to main content

yo_resp/
engine.rs

1//! Connections, framing and buffers: the seam between the loop and the
2//! commands.
3//!
4//! `yo-reactor` knows how to run a batch and nothing about what a command is.
5//! `dispatch` knows how to run a command and nothing about where the bytes came
6//! from. This module is the piece in between, and it is the piece a server is
7//! missing until it exists: the read buffer a command's arguments point into,
8//! the framing that says where one command ends and the next begins, the reply
9//! buffer that holds an answer until the batch is done, and the state a
10//! connection keeps between the two.
11//!
12//! # Two halves
13//!
14//! [`Wire`] is a pair rather than a thing. The connection half is the front,
15//! and it is in a module of its own that cannot name a [`Server`]: the buffers,
16//! the decoder pool, the framing, the sessions and the queue of framed work.
17//! The other half is the server, which is the databases and the numbers `INFO`
18//! reports. The line matters because it is the line the threads run along: a
19//! front belongs to the thread that accepted its connections and is reached by
20//! nothing else, and the server is the handle every thread holds a copy of.
21//! Everything that needs both is a method on `Wire` and there are three of them,
22//! which are running a command, answering a client that blocked and forgetting a
23//! client that has gone.
24//!
25//! # What a piece of work is
26//!
27//! [`Cmd`] is three numbers: which connection, which decoder holds the
28//! arguments, and where in that connection's buffer they point. It is `Copy`
29//! and twenty four bytes, so it crosses an intake lane without touching the
30//! heap, and it carries no borrow, which is what lets the reactor hold sixty
31//! four of them while the engine owns the bytes they name.
32//!
33//! The decoders are pooled. Framing takes one out of the pool per command,
34//! `run` puts it back, and a connection with a half read command keeps hold of
35//! one so that a bulk arriving in ten reads is decoded once rather than ten
36//! times. In the steady state the pool is as large as the deepest batch and
37//! nothing here allocates at all.
38//!
39//! # One write per connection
40//!
41//! Replies accumulate in the connection's [`Out`](crate::reply::Out) and go out
42//! in [`Wire::flush`], which is one call to the sink per connection touched by
43//! the batch and never one per reply. That is the syscall shape `04` section 2
44//! asks for, and it is the one aki got wrong: its `HGETALL` profile spent 69.7
45//! percent of its time in write syscalls.
46//!
47//! # What is not here
48//!
49//! Sockets. [`Sink`] is where the bytes go and the io_uring reactor implements
50//! it later, which keeps this module testable without a network and keeps the
51//! ring out of the crate that parses the protocol.
52//!
53//! The hash the first walk computes warms the bucket and is then thrown away,
54//! because `yo-kv`'s commands take keys rather than hashes. The prefetch is the
55//! part that is worth a cache miss; hashing a short key twice is a few
56//! nanoseconds, and removing the second one means a hashed form of every
57//! command method, which is a change to make with a benchmark rather than on
58//! the way past.
59//!
60//! ```
61//! use yo_resp::engine::{Recorder, Wire, pump};
62//! use yo_reactor::Reactor;
63//!
64//! let mut r = Reactor::inline(Wire::new(Recorder::new()));
65//! let conn = r.engine_mut().accept();
66//!
67//! r.engine_mut().feed(conn, b"*3\r\n$3\r\nSET\r\n$1\r\nk\r\n$1\r\nv\r\n*2\r\n$3\r\nGET\r\n$1\r\nk\r\n");
68//! let mut batch = Vec::new();
69//! assert_eq!(pump(&mut r, &mut batch), 2);
70//!
71//! assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$1\r\nv\r\n");
72//! ```
73
74use std::sync::Arc;
75
76use yo_reactor::{BATCH_MAX, Engine, Reactor};
77
78use crate::dispatch::table;
79use crate::dispatch::{self, Flow, Parked, Server};
80use crate::front::{Front, Wrote};
81use crate::proto::Limits;
82use yo_kv::Keyspace;
83
84pub use crate::front::Cmd;
85
86/// Which connection. An index, reused after a connection closes.
87pub type ConnId = u32;
88
89/// Keys a housekeeping call is allowed to look at while hunting dead ones.
90///
91/// The same number the loop's maintenance slice gets, because it buys the same
92/// thing: the sweep walks twenty keys at a time, so this is a couple of hundred
93/// draws in the worst case and one comparison in the common one, where no key
94/// in the database carries a deadline at all.
95const SWEEP_LOOKS: usize = yo_reactor::MAINTENANCE_UNITS as usize;
96
97/// Where replies go.
98///
99/// One call per connection per batch, with however many replies are waiting.
100/// The network reactor implements this over io_uring, a test implements it over
101/// a `Vec`, and neither this module nor `dispatch` has to know which.
102pub trait Sink {
103    /// Take up to all of `bytes` for `conn`, and say how many were taken.
104    ///
105    /// Fewer than were offered means the socket is full: what is left stays in
106    /// the connection's reply buffer and is offered again on the next flush.
107    fn write(&mut self, conn: ConnId, bytes: &[u8]) -> usize;
108
109    /// The connection is finished with and its id is about to be reused.
110    fn closed(&mut self, conn: ConnId) {
111        let _ = conn;
112    }
113}
114
115/// A sink that keeps everything, for tests and for a driver with no socket.
116#[derive(Debug, Default)]
117pub struct Recorder {
118    sent: Vec<Vec<u8>>,
119    closed: Vec<ConnId>,
120}
121
122impl Recorder {
123    /// An empty one.
124    #[must_use]
125    pub fn new() -> Recorder {
126        Recorder::default()
127    }
128
129    /// Everything written to a connection so far.
130    #[must_use]
131    pub fn sent(&self, conn: ConnId) -> &[u8] {
132        self.sent.get(conn as usize).map_or(&[], Vec::as_slice)
133    }
134
135    /// Whether a connection was closed.
136    #[must_use]
137    pub fn was_closed(&self, conn: ConnId) -> bool {
138        self.closed.contains(&conn)
139    }
140
141    /// Forget what was written, keeping the room it was written into.
142    pub fn clear(&mut self) {
143        for c in &mut self.sent {
144            c.clear();
145        }
146        self.closed.clear();
147    }
148}
149
150impl Sink for Recorder {
151    fn write(&mut self, conn: ConnId, bytes: &[u8]) -> usize {
152        // A test sink, so the growth here is not on anybody's data path.
153        yo_alloc::allow(|| {
154            if self.sent.len() <= conn as usize {
155                self.sent.resize_with(conn as usize + 1, Vec::new);
156            }
157            self.sent[conn as usize].extend_from_slice(bytes);
158        });
159        bytes.len()
160    }
161
162    fn closed(&mut self, conn: ConnId) {
163        yo_alloc::allow(|| self.closed.push(conn));
164    }
165}
166
167/// The engine: connections on one side, the command layer on the other.
168///
169/// One per thread, and it is two halves rather than one thing. The front is the
170/// connections and everything they own, which never leaves the thread that
171/// accepted them. [`Server`] is the databases, and every thread has a handle on
172/// the same one. This type is where the two meet, and every method on it that is
173/// not a one line delegation is a method that genuinely needs both: running a
174/// command, answering a client that blocked, and forgetting a client that has
175/// gone.
176pub struct Wire<S> {
177    front: Front<S>,
178    server: Arc<Server>,
179    /// This thread's parked clients, copied out of the shared list.
180    ///
181    /// Here rather than in `serve_waiters` so that a server with blocked
182    /// clients on it does not allocate once a batch. It is empty between
183    /// batches and it is only ever this thread's, like everything else on this
184    /// side of the engine.
185    parked: Vec<Parked>,
186    /// Messages published for this thread's connections, copied out of the
187    /// mailbox.
188    ///
189    /// Here for the reason `parked` is here: a server with subscribers on it
190    /// should not allocate a vector once a batch to drain into. It is empty
191    /// between batches.
192    post: Vec<dispatch::Envelope>,
193}
194
195impl<S: Sink> Wire<S> {
196    /// An engine with an empty server.
197    #[must_use]
198    pub fn new(sink: S) -> Wire<S> {
199        Wire::with_server(Server::new(), sink)
200    }
201
202    /// An engine over a server the caller built, which is how a test gives it a
203    /// clock it can move by hand.
204    #[must_use]
205    pub fn with_server(server: Server, sink: S) -> Wire<S> {
206        Wire::over(Arc::new(server), sink)
207    }
208
209    /// An engine over a server that already exists, which is how the second
210    /// thread and every thread after it gets one.
211    ///
212    /// Each thread builds its own front and they never see each other's. What
213    /// they share is behind the handle, and the reason the handle is counted
214    /// rather than borrowed is that the threads outlive whichever call started
215    /// them by design: a scope that borrows would tie the server's lifetime to
216    /// a frame that is meant to return.
217    #[must_use]
218    pub fn over(server: Arc<Server>, sink: S) -> Wire<S> {
219        Wire {
220            front: Front::new(sink),
221            parked: Vec::new(),
222            post: Vec::new(),
223            server,
224        }
225    }
226
227    /// The databases and the numbers `INFO` reports.
228    #[must_use]
229    pub fn server(&self) -> &Server {
230        &self.server
231    }
232
233    /// Another handle on the same server, for building the next thread's
234    /// engine.
235    #[must_use]
236    pub fn shared(&self) -> Arc<Server> {
237        Arc::clone(&self.server)
238    }
239
240    /// The server, for the few settings that have to be made before it is
241    /// serving.
242    ///
243    /// That is the directory and the thread count, both of which are read
244    /// everywhere and written once at startup, so they are settings and not
245    /// state. This works while this engine holds the only handle, which is the
246    /// case from the moment the server is built until the threads are started,
247    /// and it is the caller's job to do its setting up in that window.
248    ///
249    /// # Panics
250    ///
251    /// If a second handle already exists, because there is no honest answer to
252    /// give: changing the directory under a thread that is already serving out
253    /// of it is the bug this would otherwise hide.
254    pub fn server_mut(&mut self) -> &mut Server {
255        Arc::get_mut(&mut self.server)
256            .expect("the server is set up before the threads that share it are started")
257    }
258
259    /// Where the replies went.
260    #[must_use]
261    pub const fn sink(&self) -> &S {
262        self.front.sink()
263    }
264
265    /// The same, mutably.
266    pub const fn sink_mut(&mut self) -> &mut S {
267        self.front.sink_mut()
268    }
269
270    /// Change the protocol limits, which is `proto-max-bulk-len` and friends.
271    pub fn set_limits(&mut self, limits: Limits) {
272        self.front.set_limits(limits);
273    }
274
275    /// Open a connection and give back its id.
276    pub fn accept(&mut self) -> ConnId {
277        self.server.counted().opened();
278        let at = self.front.open(self.server.next_client());
279        self.note_buffers();
280        at
281    }
282
283    /// Tell the server what the connection buffers are holding now.
284    ///
285    /// The front cannot reach the server, so it keeps the change and this is
286    /// where it is handed over: at the end of whichever call moved a buffer.
287    fn note_buffers(&mut self) {
288        let delta = self.front.buffer_delta();
289        if delta != 0 {
290            self.server.note_conn_bytes(delta);
291        }
292    }
293
294    /// The peer went away.
295    ///
296    /// Whatever is buffered for it is dropped rather than written, and the slot
297    /// comes back as soon as the commands already framed out of its buffer have
298    /// run, because those commands' arguments still point into it.
299    pub fn hangup(&mut self, conn: ConnId) {
300        if !self.front.live(conn) {
301            return;
302        }
303        self.front.mark_gone(conn);
304        // A parked client holds its own commands, and those commands are what
305        // `pending` counts, so leaving it parked here would leave the slot owed
306        // to a connection that is never going to be answered. They go back to
307        // the queue and run as the no-ops a gone connection's commands are.
308        if self.front.blocked(conn) {
309            self.front.unpark(conn);
310        }
311        if self.front.pending(conn) == 0 {
312            self.release(conn);
313        }
314        self.note_buffers();
315    }
316
317    /// Answer everybody this thread can answer, and let go of everybody whose
318    /// deadline has passed.
319    ///
320    /// The walk is over the waiter list rather than over the connections, so it
321    /// costs what blocking costs and not what the server costs. Every caller
322    /// checks that somebody is parked before calling, which is the load and the
323    /// branch a server with nobody blocked pays.
324    ///
325    /// Only this thread's waiters, because a reply goes into a buffer this
326    /// thread owns and another thread's waiter is another thread's to answer.
327    /// The list is copied out under the lock and then let go of, so the work of
328    /// answering does not hold up a thread trying to park a client.
329    fn serve_waiters(&mut self) {
330        let now = self.server.now_ms();
331        let mine = self.server.my_slot();
332        self.server.waiters().mine(mine, &mut self.parked);
333        for at in 0..self.parked.len() {
334            let p = self.parked[at];
335            // The slot is reused and the client id is not. `release` forgets
336            // waiters, so this should never fire; it is here because being
337            // wrong about it writes a reply into somebody else's socket rather
338            // than dropping one.
339            if !self.front.answers(p.conn, p.client) {
340                self.server.forget_waiters(p.client);
341                continue;
342            }
343            // The front cannot reach the databases and the server cannot reach
344            // the connections, so the two halves are taken apart here and the
345            // one buffer this waiter needs is handed over.
346            let served = {
347                let Wire { server, front, .. } = self;
348                server.serve_waiter(p.client, now, front.out(p.conn))
349            };
350            if served {
351                self.server.forget_waiters(p.client);
352                self.front.unpark(p.conn);
353                self.front.soil(p.conn);
354            }
355        }
356        self.parked.clear();
357    }
358
359    /// Write out everything published for this thread's connections.
360    ///
361    /// The mailbox is emptied under its lock and then let go of, so a thread
362    /// rendering a thousand messages is not holding up the publishers filling
363    /// its box. The client id on each envelope is checked against the slot
364    /// because a slot is reused and an id is not, which is the same guard the
365    /// waiter list uses and for the same reason: being wrong here writes into
366    /// somebody else's socket rather than dropping a message.
367    fn deliver(&mut self) {
368        // Taken and put back so the loop can reach the front, the way the dirty
369        // list is. The capacity comes back with it.
370        let mut post = core::mem::take(&mut self.post);
371        self.server.take_mail(&mut post);
372        for env in post.drain(..) {
373            let conn = env.conn();
374            if !self.front.answers(conn, env.client()) {
375                continue;
376            }
377            env.write(self.front.out(conn));
378            self.front.soil(conn);
379        }
380        self.post = post;
381    }
382
383    /// How many connections are open.
384    #[must_use]
385    pub fn clients(&self) -> usize {
386        self.front.clients()
387    }
388
389    /// Commands framed and waiting for the reactor.
390    #[must_use]
391    pub fn ready(&self) -> usize {
392        self.front.ready()
393    }
394
395    /// Connections with a reply that has not gone out yet.
396    ///
397    /// Non zero means a socket was full and what is left is being held for a
398    /// later flush, which a driver waiting on readability needs to know: there
399    /// is work here that no incoming byte will ever wake it up for.
400    #[must_use]
401    pub fn owed(&self) -> usize {
402        self.front.owed()
403    }
404
405    /// Clients of this thread's that are blocked on a key.
406    ///
407    /// The other thing a driver waiting on readability needs to know, and for
408    /// the same reason `owed` is: there is work here that no incoming byte will
409    /// wake it for. A blocked client is answered by a write another thread made
410    /// or by its own deadline passing, and neither of those is a byte arriving
411    /// on this thread's poller, so a driver that reads this keeps its wait short
412    /// while anybody is waiting on it.
413    #[must_use]
414    pub fn waiting(&self) -> usize {
415        self.server.parked_here()
416    }
417
418    /// Mail waiting for this thread, plus subscribers of its own that mail
419    /// could arrive for.
420    ///
421    /// The third thing a driver waiting on readability needs to know, and for
422    /// the reason the other two are: a published message is a write another
423    /// thread made and no byte arriving here will wake this thread for it. So a
424    /// thread that has a subscriber keeps its wait short, and one that has none
425    /// is not affected.
426    #[must_use]
427    pub fn posted(&self) -> usize {
428        self.server.posted()
429    }
430
431    /// Whether a client has asked the server to stop.
432    ///
433    /// The driver reads this once a turn, next to the flag a signal sets, and
434    /// leaves its loop when either is set. Asked after the batch rather than
435    /// during it, so the `SHUTDOWN` and everything that shared its batch is
436    /// finished and written out before anything closes.
437    #[must_use]
438    pub fn stopping(&self) -> bool {
439        self.server.stopping()
440    }
441
442    /// Decoders in the pool, which is the high water mark of one batch.
443    #[must_use]
444    pub fn decoders(&self) -> usize {
445        self.front.decoders()
446    }
447
448    /// What every connection's read and reply buffers are holding.
449    #[must_use]
450    pub fn buffer_bytes(&self) -> usize {
451        self.front.buffer_bytes()
452    }
453
454    /// Take bytes off a connection and frame whatever commands they complete.
455    ///
456    /// Anything left over stays in the connection's buffer, half a command
457    /// included, so the caller hands over whatever the socket gave it without
458    /// looking at it.
459    pub fn feed(&mut self, conn: ConnId, bytes: &[u8]) {
460        self.front.feed(conn, bytes);
461        self.note_buffers();
462    }
463
464    /// Hand the slot and its buffers back, and let the server go of the client.
465    fn release(&mut self, conn: ConnId) {
466        // Before the slot goes back, because the watches this connection took
467        // are rows on the server and the session that names them is about to be
468        // reused by whoever gets the slot next.
469        if let Some(session) = self.front.session_mut(conn) {
470            dispatch::forget_session(&self.server, session);
471        }
472        let Some(client) = self.front.close(conn) else {
473            return;
474        };
475        self.forget(client);
476    }
477
478    /// The server side of a connection ending.
479    ///
480    /// It happens in the same call the slot was freed in, and before anything
481    /// else can run, because the slot is handed out again by the next accept
482    /// and a waiter still holding this client id would then be a waiter
483    /// pointing at somebody else's connection.
484    fn forget(&mut self, client: u64) {
485        self.server.forget_waiters(client);
486        self.server.counted().closed();
487    }
488
489    /// Move up to `max` framed commands into `into`.
490    ///
491    /// The reactor wants a batch it owns, and the front keeps the buffers, so
492    /// what crosses between them is this: numbers, no borrows.
493    pub fn take_ready(&mut self, into: &mut Vec<Cmd>, max: usize) -> usize {
494        self.front.take_ready(into, max)
495    }
496
497    /// Take a clock reading for the whole batch.
498    ///
499    /// `04` section 5: once per turn, never per command, so every command in a
500    /// batch compares against the same millisecond and two keys written
501    /// together expire together.
502    pub fn tick(&mut self) {
503        self.server.refresh_clock();
504    }
505
506    /// Do one batch's worth of housekeeping.
507    ///
508    /// That is the dead keys and then one segment of arena compaction at most,
509    /// which between them are what stop a server that rewrites the same keys,
510    /// or writes them under a deadline and never reads them back, from holding
511    /// every version of everything it has ever been sent. It is separate from
512    /// [`Wire::tick`] because the clock has to move before a batch runs and this
513    /// does not: it can wait until the replies are out, and the driver decides
514    /// when that is.
515    ///
516    /// Per batch and not per turn of the loop. A turn can carry one command or
517    /// a thousand, so a per turn call means the rate at which garbage is
518    /// collected has nothing to do with the rate at which it is made, and on a
519    /// saturated server the second one wins. That was measured: with this on
520    /// the loop's turn the server settled at seven segments for six segments'
521    /// worth of keys, which is where an unloaded process running the same
522    /// writes settled at six.
523    pub fn maintain(&mut self) -> Option<usize> {
524        // Before the compaction and not after it, because the reading the next
525        // batch judges its limit against should be the one taken after the last
526        // batch's writes rather than the one taken after this call's collecting.
527        // Both are true, and the first is the one that is a batch old at worst.
528        // Nothing at all on a server with no `maxmemory`, which is the default.
529        self.server.refresh_memory();
530        // Two fields and a return on a server that has never taken a backup,
531        // which is nearly all of them. It is here rather than on a timer for the
532        // same reason the compaction is: one loop turns everything.
533        self.server.backup_expire();
534        // The keys whose deadline has passed with nobody there to read them
535        // back. A slice's worth at most and gated to once a millisecond inside,
536        // so a driver that calls this after every batch does not turn a busy
537        // server into a server that spends its time sampling.
538        self.server.expire_slice(SWEEP_LOOKS);
539        self.server.compact_step()
540    }
541}
542
543impl<S: Sink> Engine for Wire<S> {
544    type Work = Cmd;
545
546    fn key_hash(&self, cmd: &Cmd) -> Option<u64> {
547        // Before the argument list is built, because most of the commands that
548        // get this far and answer `None` answer it on the spec alone, and
549        // building an `Args` to then throw it away is the sort of thing that
550        // does not show up in a profile and does show up in a total.
551        let spec = table::at(cmd.spec)?;
552        if spec.first_key <= 0 {
553            return None;
554        }
555        let args = self.front.args(cmd);
556        // The first key only. A command with more than one, which is `MSET` and
557        // `MGET`, warms the first and takes the miss on the rest; warming all of
558        // them means a hash list per command and that is the batch's own job
559        // once multi key commands are worth measuring.
560        let key = args.opt(spec.first_key as usize)?;
561        Some(Keyspace::hash_of(key))
562    }
563
564    fn prefetch(&self, cmd: &Cmd, hash: u64) {
565        let db = self.front.db(cmd.conn());
566        // The hash picks the stripe as well as the record, so this warms the
567        // line the command is going to read and not a line on some other
568        // stripe. It is the same hash the command itself will route on, which
569        // is why the stripe is worked out from a hash rather than from a key.
570        self.server.striped_ref(db).prefetch_hashed(hash);
571    }
572
573    fn run(&mut self, cmd: Cmd, _hash: Option<u64>) -> yo_reactor::Flow {
574        let conn = cmd.conn();
575        // Framed with the batch that blocked, so it is a command the client sent
576        // before it knew it would be waiting. It keeps its decoder and it keeps
577        // its place in `pending`, which is what stops the buffer it points into
578        // being compacted while it waits.
579        if self.front.blocked(conn) {
580            self.front.park(conn, cmd);
581            return yo_reactor::Flow::Next;
582        }
583
584        // The one place both halves are held at once. The front hands over the
585        // arguments, the session and the reply buffer, the server hands over
586        // the databases, and the command layer sees the two as one call.
587        let flow = if self.front.start(&cmd) {
588            let Wire { front, server, .. } = self;
589            let (args, session, out) = front.parts(&cmd);
590            let spec = table::at(cmd.spec);
591            dispatch::resolved(server, session, spec, args, out)
592        } else {
593            // Nobody to answer, or nobody who should be. The decoder still has
594            // to come back and the slot still has to be released, which is why
595            // this is not an early return.
596            Flow::Continue
597        };
598
599        self.front.done(&cmd);
600        if self.front.gone(conn) {
601            if self.front.pending(conn) == 0 {
602                self.release(conn);
603            }
604        } else {
605            match flow {
606                Flow::Close => {
607                    self.front.quit(conn);
608                    self.front.soil(conn);
609                }
610                // Nothing was written, so there is nothing to flush and no
611                // reason to put this connection on the dirty list. The waiter
612                // carries the slot from here on, and it needs to know which one:
613                // the command layer only ever saw the client id.
614                Flow::Block => {
615                    self.front.block(conn);
616                    let client = self.front.client(conn);
617                    self.server.bind_waiter(client, conn);
618                }
619                Flow::Continue => self.front.soil(conn),
620            }
621        }
622
623        // After each command and not once per batch. A client blocked on two
624        // keys and woken by `RPUSH b` then `RPUSH a` in one pipeline has to
625        // answer with `b`, because that is the push that was in front of it, and
626        // it can only do that if it was served in between the two.
627        if self.server.parked_here() != 0 {
628            self.serve_waiters();
629        }
630        yo_reactor::Flow::Next
631    }
632
633    fn flush(&mut self) {
634        // The deadline sweep, and it is here because this is the one thing the
635        // driver calls on a turn that ran nothing at all. A client whose timeout
636        // passes while the server is idle is answered within the loop's idle
637        // wait, which the loop shortens to a millisecond on a thread that has
638        // somebody waiting. That is finer than the 10hz Redis checks its own
639        // blocked clients at.
640        //
641        // This thread's count and not the server's, because the sweep can only
642        // answer this thread's waiters, so on any other thread it is a lock
643        // taken to find nothing.
644        if self.server.parked_here() != 0 {
645            self.server.refresh_clock();
646            self.serve_waiters();
647        }
648
649        // Then the published messages, before the write out below and after
650        // everything this batch answered, which is the order a client that
651        // publishes to itself sees on a real server: the count first and the
652        // message second, checked on the wire against 8.10.1.
653        if self.server.mail_here() != 0 {
654            self.deliver();
655        }
656
657        // Taken and put back so the loop below can reach the rest of the
658        // engine. The capacity comes back with it, so this is not an
659        // allocation.
660        let mut dirty = self.front.take_dirty();
661        let mut at = 0;
662        while at < dirty.len() {
663            let conn = dirty[at];
664            match self.front.write_out(conn) {
665                // The socket was full. The connection stays on the list with
666                // what is left of its reply, and the next flush offers it
667                // again, which is the whole of the backpressure story here.
668                Wrote::Owed => at += 1,
669                Wrote::Done => {
670                    dirty.swap_remove(at);
671                }
672                Wrote::Ended(client) => {
673                    self.forget(client);
674                    dirty.swap_remove(at);
675                }
676            }
677        }
678        self.front.give_dirty(dirty);
679        self.note_buffers();
680    }
681
682    fn maintain(&mut self, budget: &mut yo_reactor::Budget) {
683        // The clock is the first thing the maintenance slice does, because
684        // everything else in it compares against a time.
685        if !budget.spend(1) {
686            return;
687        }
688        self.tick();
689        // Then the dead keys, which is what stops a cache that writes with a
690        // deadline and never reads back from holding every key it has ever
691        // written. One unit a key looked at, so the slice bounds the sweep the
692        // same way it bounds everything else in here, and a server where nothing
693        // has a deadline spends nothing at all.
694        let looks = budget.left() as usize;
695        let spent = self.server.expire_slice(looks);
696        budget.spend(u32::try_from(spent).unwrap_or(u32::MAX));
697    }
698}
699
700/// Run everything that is framed, in batches, and write the replies.
701///
702/// The inline driver: it is what a caller who is already on the shard thread
703/// uses in place of the loop, and it goes through the same two walks the loop
704/// goes through (`15` section 7). `batch` is the caller's, so a driver in a hot
705/// loop hands the same `Vec` back every time and never allocates.
706pub fn pump<S: Sink>(reactor: &mut Reactor<Wire<S>>, batch: &mut Vec<Cmd>) -> usize {
707    let mut ran = 0;
708    reactor.engine_mut().tick();
709    loop {
710        batch.clear();
711        if reactor.engine_mut().take_ready(batch, BATCH_MAX) == 0 {
712            break;
713        }
714        // The command path, and therefore the thing Y7 is about. The guard is
715        // what arms `yo-alloc`, and it covers dispatch and nothing else: framing
716        // before it and writing the replies after it are both allowed to reach
717        // for the heap, and only running the commands is not.
718        //
719        // It goes here rather than around the whole loop because `take_ready`
720        // and `flush` are on the other side of that line, and because a batch is
721        // the unit a caller can reason about. Under the default mode this is one
722        // relaxed load.
723        let armed = yo_alloc::guard();
724        ran += reactor.execute_all(batch.drain(..));
725        drop(armed);
726        reactor.engine_mut().flush();
727        // After the replies are out, so the batch that made the garbage is not
728        // the batch that waits for it to be collected.
729        reactor.engine_mut().maintain();
730    }
731    // Once for a turn that ran nothing at all, which is where a server that has
732    // gone quiet catches up on what the last busy turn left behind.
733    reactor.engine_mut().maintain();
734    // Then once more for a connection with something to say and nothing to run:
735    // a protocol error, or a socket that was full the last time round, or a
736    // subscriber the housekeeping above owes the news that a key it was told to
737    // watch reached its deadline. That last one is why the flush is after the
738    // call rather than before it: an idle server turns every twenty
739    // milliseconds, and news that waits for the next turn is news that arrives
740    // twenty milliseconds after the thing it is about.
741    reactor.engine_mut().flush();
742    ran
743}
744
745#[cfg(test)]
746mod tests {
747    use super::*;
748
749    /// The wire bytes for a command, built the way a client would.
750    fn wire(args: &[&[u8]]) -> Vec<u8> {
751        let mut b = format!("*{}\r\n", args.len()).into_bytes();
752        for a in args {
753            b.extend_from_slice(format!("${}\r\n", a.len()).as_bytes());
754            b.extend_from_slice(a);
755            b.extend_from_slice(b"\r\n");
756        }
757        b
758    }
759
760    fn engine() -> (Reactor<Wire<Recorder>>, ConnId, Vec<Cmd>) {
761        let mut r = Reactor::inline(Wire::new(Recorder::new()));
762        let conn = r.engine_mut().accept();
763        (r, conn, Vec::new())
764    }
765
766    /// Where the fixed clock a blocking test moves by hand starts.
767    const START_MS: u64 = 1_000_000;
768
769    /// The same, on a clock the test moves rather than the system's.
770    ///
771    /// A test about a timeout cannot wait for one: waiting a hundred
772    /// milliseconds is a test that fails on a loaded machine and waiting a
773    /// hundred seconds is not a test.
774    fn timed() -> (Reactor<Wire<Recorder>>, ConnId, Vec<Cmd>) {
775        let server = crate::dispatch::Server::with_clock(yo_kv::Clock::fixed(START_MS));
776        let mut r = Reactor::inline(Wire::with_server(server, Recorder::new()));
777        let conn = r.engine_mut().accept();
778        (r, conn, Vec::new())
779    }
780
781    #[test]
782    fn a_pipelined_batch_comes_back_in_order_and_in_one_write() {
783        let (mut r, conn, mut batch) = engine();
784        let mut stream = wire(&[b"SET", b"k", b"v"]);
785        stream.extend(wire(&[b"GET", b"k"]));
786        stream.extend(wire(&[b"INCR", b"n"]));
787
788        r.engine_mut().feed(conn, &stream);
789        assert_eq!(r.engine().ready(), 3);
790        assert_eq!(pump(&mut r, &mut batch), 3);
791
792        assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$1\r\nv\r\n:1\r\n");
793        assert_eq!(r.engine().ready(), 0);
794    }
795
796    /// The framing has to survive a command arriving in pieces, because that is
797    /// what a socket does.
798    #[test]
799    fn a_command_split_across_reads_resumes_rather_than_restarts() {
800        let (mut r, conn, mut batch) = engine();
801        let bytes = wire(&[b"SET", b"key", b"value"]);
802
803        for at in 1..bytes.len() {
804            r.engine_mut().feed(conn, &bytes[at - 1..at]);
805            assert_eq!(r.engine().ready(), 0, "not a command yet at {at}");
806        }
807        r.engine_mut().feed(conn, &bytes[bytes.len() - 1..]);
808        assert_eq!(r.engine().ready(), 1);
809        assert_eq!(pump(&mut r, &mut batch), 1);
810        assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
811
812        // And the value that arrived in single bytes is the value that was
813        // stored, which is the part a naive resume gets wrong.
814        r.engine_mut().feed(conn, &wire(&[b"GET", b"key"]));
815        pump(&mut r, &mut batch);
816        assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$5\r\nvalue\r\n");
817    }
818
819    #[test]
820    fn two_connections_are_two_sessions_over_one_server() {
821        let (mut r, a, mut batch) = engine();
822        let b = r.engine_mut().accept();
823
824        r.engine_mut().feed(a, &wire(&[b"SELECT", b"3"]));
825        r.engine_mut().feed(a, &wire(&[b"SET", b"k", b"a"]));
826        r.engine_mut().feed(b, &wire(&[b"SET", b"k", b"b"]));
827        r.engine_mut().feed(a, &wire(&[b"GET", b"k"]));
828        r.engine_mut().feed(b, &wire(&[b"GET", b"k"]));
829        pump(&mut r, &mut batch);
830
831        assert_eq!(r.engine().sink().sent(a), b"+OK\r\n+OK\r\n$1\r\na\r\n");
832        assert_eq!(r.engine().sink().sent(b), b"+OK\r\n$1\r\nb\r\n");
833        assert_eq!(r.engine().clients(), 2);
834    }
835
836    /// The point of the whole exercise: two engines, two threads, one server.
837    ///
838    /// The server is told it will have two threads before either starts, the
839    /// way `yodb serve` tells it. Without that it has one set of counters and
840    /// both threads land on it, which is the wrap round `Server::mine_at`
841    /// documents and which loses counts: a bump is a load and a store rather
842    /// than a fetch and add, because the fast path is one thread writing its
843    /// own set and paying for a locked instruction on every command to make a
844    /// shared set exact would be paying it on the path that is never shared.
845    /// Miri found this by running the two threads far enough apart to lose one,
846    /// which a real machine does rarely enough to have passed here for months.
847    #[test]
848    fn two_threads_write_into_one_server() {
849        const EACH: usize = 200;
850
851        let mut server = Server::new();
852        server.set_threads(2);
853        let first = Wire::with_server(server, Recorder::new());
854        let second = Wire::over(first.shared(), Recorder::new());
855        let server = first.shared();
856
857        std::thread::scope(|s| {
858            for (at, engine) in [first, second].into_iter().enumerate() {
859                s.spawn(move || {
860                    let mut r = Reactor::inline(engine);
861                    let mut batch = Vec::new();
862                    let conn = r.engine_mut().accept();
863                    for i in 0..EACH {
864                        let key = format!("t{at}:{i}");
865                        r.engine_mut()
866                            .feed(conn, &wire(&[b"SET", key.as_bytes(), b"v"]));
867                        pump(&mut r, &mut batch);
868                    }
869                });
870            }
871        });
872
873        // Every key both threads wrote is in the one database, which is the
874        // whole claim: the fronts were separate and the keyspace was not.
875        assert_eq!(server.striped_ref(0).len(), 2 * EACH);
876        // And both threads counted into the same total, each from its own set
877        // of counters, which is what the sum over the threads is for.
878        assert_eq!(server.totals().connections, 2);
879    }
880
881    /// A blocked client is answered into a buffer one thread owns, so it is
882    /// that thread's to answer and nobody else's to throw away.
883    #[test]
884    fn a_waiter_belongs_to_the_thread_that_parked_it() {
885        let mut server = Server::new();
886        server.set_threads(2);
887        let first = Wire::with_server(server, Recorder::new());
888        let second = Wire::over(first.shared(), Recorder::new());
889        let server = first.shared();
890
891        let parked = std::sync::Barrier::new(2);
892        let swept = std::sync::Barrier::new(2);
893
894        std::thread::scope(|s| {
895            let (parked, swept) = (&parked, &swept);
896            s.spawn(move || {
897                let mut r = Reactor::inline(first);
898                let mut batch = Vec::new();
899                let conn = r.engine_mut().accept();
900                r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"a", b"0"]));
901                pump(&mut r, &mut batch);
902                parked.wait();
903
904                // Turns with nothing on them, each of which walks a list whose
905                // one other entry belongs to the thread next door.
906                for _ in 0..50 {
907                    pump(&mut r, &mut batch);
908                }
909                swept.wait();
910                assert!(r.engine().sink().sent(conn).is_empty(), "nothing to say");
911            });
912            s.spawn(move || {
913                let mut r = Reactor::inline(second);
914                let mut batch = Vec::new();
915                let conn = r.engine_mut().accept();
916                r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"b", b"0"]));
917                pump(&mut r, &mut batch);
918                parked.wait();
919                swept.wait();
920
921                // The push comes in on a second connection, because the first
922                // one is not reading anything while it waits.
923                let pusher = r.engine_mut().accept();
924                r.engine_mut().feed(pusher, &wire(&[b"RPUSH", b"b", b"v"]));
925                pump(&mut r, &mut batch);
926                assert_eq!(
927                    r.engine().sink().sent(conn),
928                    b"*2\r\n$1\r\nb\r\n$1\r\nv\r\n",
929                    "served by the thread that parked it"
930                );
931            });
932        });
933
934        assert_eq!(server.parked(), 1, "and the other one is still waiting");
935    }
936
937    /// The count a thread branches on before it reaches for the shared list is
938    /// its own, because the list is one lock and a thread can only answer what
939    /// it parked itself. Branching on the server wide count instead would put
940    /// every thread through that lock after every command as soon as one client
941    /// blocked anywhere.
942    #[test]
943    fn a_thread_counts_the_clients_it_blocked_and_nobody_else_s() {
944        let mut server = Server::new();
945        server.set_threads(2);
946        let first = Wire::with_server(server, Recorder::new());
947        let second = Wire::over(first.shared(), Recorder::new());
948        let server = first.shared();
949
950        let parked = std::sync::Barrier::new(2);
951        let looked = std::sync::Barrier::new(2);
952
953        std::thread::scope(|s| {
954            let (parked, looked) = (&parked, &looked);
955            s.spawn(move || {
956                let mut r = Reactor::inline(first);
957                let mut batch = Vec::new();
958                let conn = r.engine_mut().accept();
959                r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"a", b"0"]));
960                pump(&mut r, &mut batch);
961                assert_eq!(r.engine().waiting(), 1, "the one this thread blocked");
962                parked.wait();
963                looked.wait();
964
965                // A second client of this thread's that never blocked, opened
966                // and closed. It is not on the list, so the count stays where
967                // it was rather than following the disconnect down.
968                let other = r.engine_mut().accept();
969                r.engine_mut().feed(other, &wire(&[b"PING"]));
970                pump(&mut r, &mut batch);
971                r.engine_mut().hangup(other);
972                pump(&mut r, &mut batch);
973                assert_eq!(r.engine().waiting(), 1, "still just the blocked one");
974            });
975            s.spawn(move || {
976                let mut r = Reactor::inline(second);
977                let mut batch = Vec::new();
978                parked.wait();
979
980                // A thread with nothing of its own blocked, on a server that
981                // has one client blocked on it.
982                pump(&mut r, &mut batch);
983                assert_eq!(r.engine().waiting(), 0, "none of them are this one's");
984                assert_eq!(r.engine().server().parked(), 1, "one on the server");
985                looked.wait();
986            });
987        });
988
989        assert_eq!(server.parked(), 1);
990    }
991
992    /// Two fronts hand out connection slots from zero, so the number that tells
993    /// two clients apart cannot come from a front.
994    #[test]
995    fn client_ids_are_the_server_s_to_hand_out() {
996        let first = Wire::new(Recorder::new());
997        let second = Wire::over(first.shared(), Recorder::new());
998        let mut a = Reactor::inline(first);
999        let mut b = Reactor::inline(second);
1000
1001        let (one, two) = (a.engine_mut().accept(), b.engine_mut().accept());
1002        assert_eq!(one, two, "the same slot on each front");
1003
1004        // HELLO answers with the connection id, which is the number CLIENT
1005        // KILL and CLIENT UNPAUSE take, so two fronts agreeing on it is two
1006        // clients that cannot be told apart. Protocol three so that the proto
1007        // field in the same reply is not one of the ids being looked for.
1008        let mut batch = Vec::new();
1009        a.engine_mut().feed(one, &wire(&[b"HELLO", b"3"]));
1010        b.engine_mut().feed(two, &wire(&[b"HELLO", b"3"]));
1011        pump(&mut a, &mut batch);
1012        pump(&mut b, &mut batch);
1013
1014        let first = String::from_utf8_lossy(a.engine().sink().sent(one)).into_owned();
1015        let second = String::from_utf8_lossy(b.engine().sink().sent(two)).into_owned();
1016        assert!(first.contains(":1\r\n"), "{first}");
1017        assert!(second.contains(":2\r\n"), "{second}");
1018    }
1019
1020    #[test]
1021    fn quit_is_answered_and_then_the_connection_goes() {
1022        let (mut r, conn, mut batch) = engine();
1023        r.engine_mut().feed(conn, &wire(&[b"PING"]));
1024        r.engine_mut().feed(conn, &wire(&[b"QUIT"]));
1025        pump(&mut r, &mut batch);
1026
1027        assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n+OK\r\n");
1028        assert!(r.engine().sink().was_closed(conn));
1029        assert_eq!(r.engine().clients(), 0);
1030
1031        // The slot comes back, buffers and all.
1032        let again = r.engine_mut().accept();
1033        assert_eq!(again, conn);
1034        assert_eq!(r.engine().clients(), 1);
1035    }
1036
1037    /// Redis's own unit/quit, which caught this: we answered the `QUIT` and
1038    /// then ran the `SET` behind it.
1039    #[test]
1040    fn what_a_client_pipelined_behind_quit_is_never_run() {
1041        let (mut r, conn, mut batch) = engine();
1042        let mut stream = wire(&[b"QUIT"]);
1043        stream.extend(wire(&[b"SET", b"foo", b"bar"]));
1044        r.engine_mut().feed(conn, &stream);
1045        // Both were framed, because framing happens before anything runs.
1046        assert_eq!(r.engine().ready(), 2);
1047        pump(&mut r, &mut batch);
1048
1049        // One reply and not two, and the connection is gone.
1050        assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
1051        assert!(r.engine().sink().was_closed(conn));
1052
1053        // And the write never happened, which is the part a client can see
1054        // after it reconnects. The recorder is cleared first because the next
1055        // connection lands back in the slot this one just left, and what was
1056        // written to the slot before is still sitting in it.
1057        r.engine_mut().sink_mut().clear();
1058        let next = r.engine_mut().accept();
1059        r.engine_mut().feed(next, &wire(&[b"GET", b"foo"]));
1060        pump(&mut r, &mut batch);
1061        assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1062    }
1063
1064    /// A connection that never said `HELLO` is answered in RESP2, whatever the
1065    /// last client in that slot was speaking.
1066    ///
1067    /// The protocol is kept in the reply buffer and the reply buffer outlives
1068    /// the connection, so this is the one piece of connection state that a
1069    /// recycled slot used to carry over. A client got a RESP3 null back from
1070    /// the first `GET` that missed and could not parse it, which is as bad as a
1071    /// compatibility bug gets: nothing the client did caused it and nothing it
1072    /// could send would have avoided it.
1073    #[test]
1074    fn a_slot_that_last_spoke_resp3_answers_the_next_client_in_resp2() {
1075        let (mut r, conn, mut batch) = engine();
1076        r.engine_mut().feed(conn, &wire(&[b"HELLO", b"3"]));
1077        r.engine_mut().feed(conn, &wire(&[b"GET", b"nothing"]));
1078        pump(&mut r, &mut batch);
1079        assert!(r.engine().sink().sent(conn).ends_with(b"_\r\n"));
1080        r.engine_mut().feed(conn, &wire(&[b"QUIT"]));
1081        pump(&mut r, &mut batch);
1082
1083        r.engine_mut().sink_mut().clear();
1084        let next = r.engine_mut().accept();
1085        assert_eq!(next, conn, "the same slot, which is what this is about");
1086        r.engine_mut().feed(next, &wire(&[b"GET", b"nothing"]));
1087        pump(&mut r, &mut batch);
1088        assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1089    }
1090
1091    /// The other way a connection ends, which does not throw anything away.
1092    #[test]
1093    fn commands_that_arrived_before_a_protocol_error_are_still_answered() {
1094        let (mut r, conn, mut batch) = engine();
1095        let mut stream = wire(&[b"SET", b"k", b"v"]);
1096        stream.extend(wire(&[b"GET", b"k"]));
1097        stream.extend_from_slice(b"*1\r\n+notabulk\r\n");
1098        r.engine_mut().feed(conn, &stream);
1099        pump(&mut r, &mut batch);
1100
1101        // Both good commands were complete and correct before the stream went
1102        // wrong, so both are answered and the error comes after them.
1103        let sent = r.engine().sink().sent(conn);
1104        assert!(
1105            sent.starts_with(b"+OK\r\n$1\r\nv\r\n-ERR Protocol error: "),
1106            "{sent:?}"
1107        );
1108        assert!(r.engine().sink().was_closed(conn));
1109    }
1110
1111    #[test]
1112    fn a_protocol_error_is_written_and_closes_the_connection() {
1113        let (mut r, conn, mut batch) = engine();
1114        // A multibulk that says its first argument is a bulk and then does not.
1115        r.engine_mut().feed(conn, b"*1\r\n+notabulk\r\n");
1116        pump(&mut r, &mut batch);
1117
1118        let sent = r.engine().sink().sent(conn);
1119        assert!(sent.starts_with(b"-ERR Protocol error: "), "{sent:?}");
1120        assert!(r.engine().sink().was_closed(conn));
1121        assert_eq!(r.engine().clients(), 0);
1122    }
1123
1124    /// Redis's own `unit/protocol` walks a list of malformed frames, each on a
1125    /// fresh connection, which means every one of them after the first runs on
1126    /// a decoder that came back to the pool part way through a command.
1127    #[test]
1128    fn a_decoder_that_came_back_mid_command_starts_the_next_one_clean() {
1129        let (mut r, conn, mut batch) = engine();
1130        // Stops inside the third argument, on a length that is not a length.
1131        r.engine_mut()
1132            .feed(conn, b"*3\r\n$3\r\nSET\r\n$1\r\nx\r\n$blabla\r\n");
1133        pump(&mut r, &mut batch);
1134        let sent = r.engine().sink().sent(conn);
1135        assert!(
1136            sent.starts_with(b"-ERR Protocol error: invalid bulk length"),
1137            "{sent:?}"
1138        );
1139
1140        // The slot that decoder was in is now the slot the next connection
1141        // gets, and it has to be at the start of a command and not half way
1142        // through the one that went wrong.
1143        r.engine_mut().sink_mut().clear();
1144        let next = r.engine_mut().accept();
1145        r.engine_mut().feed(next, &wire(&[b"GET", b"k"]));
1146        pump(&mut r, &mut batch);
1147        assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1148
1149        r.engine_mut().sink_mut().clear();
1150        let third = r.engine_mut().accept();
1151        r.engine_mut().feed(third, b"*1\r\n+notabulk\r\n");
1152        pump(&mut r, &mut batch);
1153        let sent = r.engine().sink().sent(third);
1154        assert!(sent.starts_with(b"-ERR Protocol error: "), "{sent:?}");
1155    }
1156
1157    /// A client that hangs up mid batch is the case that gets a server killed:
1158    /// the commands already framed still point into its buffer.
1159    #[test]
1160    fn a_hangup_with_commands_in_flight_waits_for_them() {
1161        let (mut r, conn, mut batch) = engine();
1162        r.engine_mut().feed(conn, &wire(&[b"SET", b"k", b"v"]));
1163        r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1164
1165        batch.clear();
1166        r.engine_mut().take_ready(&mut batch, BATCH_MAX);
1167        r.engine_mut().hangup(conn);
1168        assert_eq!(r.engine().clients(), 1, "still holding the buffer");
1169
1170        r.execute_all(batch.drain(..));
1171        r.engine_mut().flush();
1172        assert_eq!(r.engine().clients(), 0);
1173        assert!(r.engine().sink().sent(conn).is_empty(), "nobody to answer");
1174
1175        // And the slot is usable again, with the decoders both back in the
1176        // pool rather than lost with the connection.
1177        let decoders = r.engine().decoders();
1178        let again = r.engine_mut().accept();
1179        assert_eq!(again, conn);
1180        r.engine_mut().feed(again, &wire(&[b"PING"]));
1181        pump(&mut r, &mut batch);
1182        assert_eq!(r.engine().sink().sent(again), b"+PONG\r\n");
1183        assert_eq!(r.engine().decoders(), decoders);
1184    }
1185
1186    /// The claim that the steady state does not allocate, checked the only way
1187    /// a library test can check it: nothing grows.
1188    #[test]
1189    fn the_buffers_and_the_decoder_pool_stop_growing() {
1190        let (mut r, conn, mut batch) = engine();
1191        let mut stream = Vec::new();
1192        for i in 0..32 {
1193            stream.extend(wire(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
1194        }
1195
1196        r.engine_mut().feed(conn, &stream);
1197        pump(&mut r, &mut batch);
1198        let decoders = r.engine().decoders();
1199        let batch_cap = batch.capacity();
1200
1201        for _ in 0..10 {
1202            r.engine_mut().feed(conn, &stream);
1203            pump(&mut r, &mut batch);
1204        }
1205        assert_eq!(r.engine().decoders(), decoders, "the pool is reused");
1206        assert_eq!(batch.capacity(), batch_cap, "the batch buffer is reused");
1207        assert!(
1208            decoders <= BATCH_MAX + 1,
1209            "{decoders} decoders for 32 commands"
1210        );
1211    }
1212
1213    /// The read buffer holds what has not been dealt with yet and nothing else.
1214    ///
1215    /// A client that pipelines sixteen commands, waits for the sixteen replies
1216    /// and goes again is what `redis-benchmark -P 16` does and what half of the
1217    /// clients in the world do. Every one of those rounds leaves the buffer
1218    /// exactly caught up, and a buffer that never drops what it has already
1219    /// dealt with grows to everything the connection has ever sent: 16 MiB
1220    /// apiece on server3 for four connections sending 100000 sets each.
1221    #[test]
1222    fn a_pipelining_client_does_not_grow_the_read_buffer() {
1223        let (mut r, conn, mut batch) = engine();
1224        let mut round = Vec::new();
1225        for i in 0..16 {
1226            round.extend(wire(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
1227        }
1228
1229        r.engine_mut().feed(conn, &round);
1230        pump(&mut r, &mut batch);
1231        r.engine_mut().sink_mut().clear();
1232        let after_one = r.engine().buffer_bytes();
1233
1234        // A thousand rounds is sixteen thousand commands and about a megabyte
1235        // of wire bytes, which is a hundred times what the buffer starts with.
1236        // Fifty is a twentieth of that and it is what runs under Miri, where
1237        // sixteen thousand commands through the whole engine was a quarter of
1238        // an hour. The check below is that the size is the one it was after the
1239        // first round, exactly, so a buffer that keeps anything at all is
1240        // caught on the second round and every one after it, whichever count
1241        // this is.
1242        let rounds = if cfg!(miri) { 50 } else { 1000 };
1243        for _ in 0..rounds {
1244            r.engine_mut().feed(conn, &round);
1245            pump(&mut r, &mut batch);
1246            r.engine_mut().sink_mut().clear();
1247        }
1248
1249        assert_eq!(
1250            r.engine().buffer_bytes(),
1251            after_one,
1252            "the buffers grew over {rounds} rounds of the same sixteen commands"
1253        );
1254        assert!(
1255            r.engine().server().memory_bytes() >= after_one,
1256            "the buffers are counted in what the server reports"
1257        );
1258    }
1259
1260    /// Half a command in the buffer is the case compaction has to be careful
1261    /// about, because the decoder holding it kept offsets into those bytes.
1262    #[test]
1263    fn a_command_split_across_reads_survives_compaction() {
1264        let (mut r, conn, mut batch) = engine();
1265        let cmd = wire(&[b"SET", b"key", b"value"]);
1266        let (head, tail) = cmd.split_at(cmd.len() - 4);
1267
1268        // A complete command, so that there is something in front to drop, then
1269        // most of a second one.
1270        r.engine_mut().feed(conn, &wire(&[b"PING"]));
1271        r.engine_mut().feed(conn, head);
1272        pump(&mut r, &mut batch);
1273        assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n");
1274
1275        // The rest of it arrives after the buffer has been compacted under it.
1276        r.engine_mut().feed(conn, tail);
1277        pump(&mut r, &mut batch);
1278        assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n+OK\r\n");
1279
1280        r.engine_mut().feed(conn, &wire(&[b"GET", b"key"]));
1281        pump(&mut r, &mut batch);
1282        assert!(r.engine().sink().sent(conn).ends_with(b"$5\r\nvalue\r\n"));
1283    }
1284
1285    /// The two walks are the reactor's, not this module's, so the test is that
1286    /// the engine can be driven by them at all: same commands, same replies.
1287    #[test]
1288    fn the_batch_goes_through_the_reactors_two_walks() {
1289        let (mut r, conn, mut batch) = engine();
1290        for i in 0..100 {
1291            r.engine_mut()
1292                .feed(conn, &wire(&[b"INCR", format!("k{}", i % 7).as_bytes()]));
1293        }
1294        let ran = pump(&mut r, &mut batch);
1295
1296        assert_eq!(ran, 100);
1297        assert_eq!(r.commands(), 100);
1298        // Two batches, because a hundred commands do not fit in sixty four.
1299        assert_eq!(r.turns(), 2);
1300        // The hundredth command is the fifteenth `INCR` of `k1`.
1301        assert!(r.engine().sink().sent(conn).ends_with(b":15\r\n"));
1302    }
1303
1304    /// A sink that takes four bytes at a time, which is what a full socket
1305    /// looks like from in here.
1306    #[derive(Default)]
1307    struct Trickle {
1308        sent: Vec<u8>,
1309        writes: usize,
1310    }
1311
1312    impl Sink for Trickle {
1313        fn write(&mut self, _conn: ConnId, bytes: &[u8]) -> usize {
1314            self.writes += 1;
1315            let n = bytes.len().min(4);
1316            self.sent.extend_from_slice(&bytes[..n]);
1317            n
1318        }
1319    }
1320
1321    /// A blocking command that does not block costs nothing: no waiter, no
1322    /// allocation, the same three lines the non blocking one runs.
1323    #[test]
1324    fn a_blpop_on_a_list_with_something_in_it_never_waits() {
1325        let (mut r, conn, mut batch) = engine();
1326        r.engine_mut().feed(conn, &wire(&[b"RPUSH", b"q", b"a"]));
1327        r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"q", b"0"]));
1328        pump(&mut r, &mut batch);
1329
1330        assert_eq!(
1331            r.engine().sink().sent(conn),
1332            b":1\r\n*2\r\n$1\r\nq\r\n$1\r\na\r\n"
1333        );
1334        assert_eq!(r.engine().server().parked(), 0);
1335    }
1336
1337    /// The whole point: a client with nothing to pop is answered later, by
1338    /// somebody else's command.
1339    #[test]
1340    fn a_parked_client_is_answered_by_another_connections_push() {
1341        let (mut r, a, mut batch) = engine();
1342        let b = r.engine_mut().accept();
1343
1344        r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1345        pump(&mut r, &mut batch);
1346        assert!(r.engine().sink().sent(a).is_empty(), "nothing to say yet");
1347        assert_eq!(r.engine().server().parked(), 1);
1348
1349        r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"one"]));
1350        pump(&mut r, &mut batch);
1351
1352        assert_eq!(r.engine().sink().sent(a), b"*2\r\n$1\r\nq\r\n$3\r\none\r\n");
1353        // The push still reports the length it made, even though the element was
1354        // gone again before the reply was written.
1355        assert_eq!(r.engine().sink().sent(b), b":1\r\n");
1356        assert_eq!(r.engine().server().parked(), 0);
1357    }
1358
1359    /// A push to a key nobody named, and a key of another type on a key
1360    /// somebody did: neither is a wake up, and the client stays parked.
1361    #[test]
1362    fn only_a_list_arriving_under_a_named_key_wakes_a_waiter() {
1363        let (mut r, a, mut batch) = engine();
1364        let b = r.engine_mut().accept();
1365        r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1366        pump(&mut r, &mut batch);
1367
1368        r.engine_mut()
1369            .feed(b, &wire(&[b"RPUSH", b"elsewhere", b"x"]));
1370        r.engine_mut().feed(b, &wire(&[b"SADD", b"q", b"x"]));
1371        pump(&mut r, &mut batch);
1372
1373        assert!(r.engine().sink().sent(a).is_empty());
1374        assert_eq!(r.engine().server().parked(), 1, "still waiting");
1375        // And the set is intact, so the waiter did not take anything out of it
1376        // on its way past.
1377        assert_eq!(r.engine().sink().sent(b), b":1\r\n:1\r\n");
1378    }
1379
1380    /// Two workers on one queue, which is what `BLPOP` is for. They are served
1381    /// in the order they arrived and not in whatever order the list is walked.
1382    #[test]
1383    fn two_parked_clients_are_served_in_the_order_they_arrived() {
1384        let (mut r, a, mut batch) = engine();
1385        let b = r.engine_mut().accept();
1386        let c = r.engine_mut().accept();
1387
1388        r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1389        pump(&mut r, &mut batch);
1390        r.engine_mut().feed(b, &wire(&[b"BLPOP", b"q", b"0"]));
1391        pump(&mut r, &mut batch);
1392        assert_eq!(r.engine().server().parked(), 2);
1393
1394        r.engine_mut()
1395            .feed(c, &wire(&[b"RPUSH", b"q", b"first", b"second"]));
1396        pump(&mut r, &mut batch);
1397
1398        assert_eq!(
1399            r.engine().sink().sent(a),
1400            b"*2\r\n$1\r\nq\r\n$5\r\nfirst\r\n"
1401        );
1402        assert_eq!(
1403            r.engine().sink().sent(b),
1404            b"*2\r\n$1\r\nq\r\n$6\r\nsecond\r\n"
1405        );
1406        assert_eq!(r.engine().server().parked(), 0);
1407    }
1408
1409    /// A client waiting for an answer is not a client that has sent another
1410    /// question, so what it pipelined behind its `BLPOP` waits for the `BLPOP`.
1411    #[test]
1412    fn what_a_client_pipelined_behind_a_block_waits_for_the_block() {
1413        let (mut r, a, mut batch) = engine();
1414        let b = r.engine_mut().accept();
1415
1416        // Framed together, so the `PING` is already on its way to the reactor
1417        // when the `BLPOP` in front of it parks.
1418        let mut stream = wire(&[b"BLPOP", b"q", b"0"]);
1419        stream.extend(wire(&[b"PING"]));
1420        r.engine_mut().feed(a, &stream);
1421        pump(&mut r, &mut batch);
1422        assert!(
1423            r.engine().sink().sent(a).is_empty(),
1424            "the PING went out in front of the answer it was sent behind"
1425        );
1426
1427        // And one that arrives while it is parked is not even framed.
1428        r.engine_mut().feed(a, &wire(&[b"ECHO", b"after"]));
1429        pump(&mut r, &mut batch);
1430        assert!(r.engine().sink().sent(a).is_empty());
1431
1432        r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"x"]));
1433        pump(&mut r, &mut batch);
1434        assert_eq!(
1435            r.engine().sink().sent(a),
1436            b"*2\r\n$1\r\nq\r\n$1\r\nx\r\n+PONG\r\n$5\r\nafter\r\n"
1437        );
1438    }
1439
1440    /// Redis serves parked clients after every command rather than once per
1441    /// turn of the loop, and a pipeline is where the difference shows: the
1442    /// waiter has to be served between the two pushes, so it answers with the
1443    /// key the first push filled and not with the one it named first.
1444    #[test]
1445    fn a_waiter_is_served_between_two_pipelined_pushes() {
1446        let (mut r, a, mut batch) = engine();
1447        let b = r.engine_mut().accept();
1448        r.engine_mut()
1449            .feed(a, &wire(&[b"BLPOP", b"p1", b"p2", b"0"]));
1450        pump(&mut r, &mut batch);
1451
1452        let mut stream = wire(&[b"RPUSH", b"p2", b"second"]);
1453        stream.extend(wire(&[b"RPUSH", b"p1", b"first"]));
1454        r.engine_mut().feed(b, &stream);
1455        pump(&mut r, &mut batch);
1456
1457        assert_eq!(
1458            r.engine().sink().sent(a),
1459            b"*2\r\n$2\r\np2\r\n$6\r\nsecond\r\n"
1460        );
1461        // Which leaves the key it named first holding what was pushed to it.
1462        r.engine_mut()
1463            .feed(b, &wire(&[b"LRANGE", b"p1", b"0", b"-1"]));
1464        pump(&mut r, &mut batch);
1465        assert!(
1466            r.engine()
1467                .sink()
1468                .sent(b)
1469                .ends_with(b"*1\r\n$5\r\nfirst\r\n")
1470        );
1471    }
1472
1473    /// A `BLMOVE` that serves itself is a push, so it wakes the client waiting
1474    /// on the key it pushed to, in the same moment and without a turn of the
1475    /// loop in between.
1476    #[test]
1477    fn a_waiter_woken_by_another_waiter() {
1478        let (mut r, a, mut batch) = engine();
1479        let b = r.engine_mut().accept();
1480        let c = r.engine_mut().accept();
1481
1482        r.engine_mut()
1483            .feed(a, &wire(&[b"BLMOVE", b"x", b"y", b"LEFT", b"RIGHT", b"0"]));
1484        pump(&mut r, &mut batch);
1485        r.engine_mut().feed(b, &wire(&[b"BLPOP", b"y", b"0"]));
1486        pump(&mut r, &mut batch);
1487        assert_eq!(r.engine().server().parked(), 2);
1488
1489        r.engine_mut().feed(c, &wire(&[b"RPUSH", b"x", b"chain"]));
1490        pump(&mut r, &mut batch);
1491
1492        assert_eq!(r.engine().sink().sent(a), b"$5\r\nchain\r\n");
1493        assert_eq!(
1494            r.engine().sink().sent(b),
1495            b"*2\r\n$1\r\ny\r\n$5\r\nchain\r\n"
1496        );
1497        assert_eq!(r.engine().server().parked(), 0);
1498    }
1499
1500    /// A waiter on one database is not woken by a push on another, even though
1501    /// the key has the same name.
1502    #[test]
1503    fn a_waiter_is_only_woken_on_the_database_it_blocked_on() {
1504        let (mut r, a, mut batch) = engine();
1505        let b = r.engine_mut().accept();
1506        r.engine_mut().feed(a, &wire(&[b"SELECT", b"3"]));
1507        r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1508        pump(&mut r, &mut batch);
1509        assert_eq!(r.engine().sink().sent(a), b"+OK\r\n");
1510
1511        r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"wrongdb"]));
1512        pump(&mut r, &mut batch);
1513        assert_eq!(r.engine().sink().sent(a), b"+OK\r\n", "still waiting");
1514
1515        r.engine_mut().feed(b, &wire(&[b"SELECT", b"3"]));
1516        r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"rightdb"]));
1517        pump(&mut r, &mut batch);
1518        assert!(r.engine().sink().sent(a).ends_with(b"$7\r\nrightdb\r\n"));
1519    }
1520
1521    /// The deadline sweep, which runs on a turn that has nothing else to do.
1522    #[test]
1523    fn a_client_that_waited_long_enough_gets_a_null_array() {
1524        let (mut r, conn, mut batch) = timed();
1525        r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"q", b"30"]));
1526        pump(&mut r, &mut batch);
1527        assert!(r.engine().sink().sent(conn).is_empty());
1528
1529        r.engine_mut().server_mut().set_clock_ms(START_MS + 29_999);
1530        pump(&mut r, &mut batch);
1531        assert!(
1532            r.engine().sink().sent(conn).is_empty(),
1533            "a millisecond short"
1534        );
1535
1536        r.engine_mut().server_mut().set_clock_ms(START_MS + 30_000);
1537        pump(&mut r, &mut batch);
1538        // A null array and not a null string, which a RESP2 client can see.
1539        assert_eq!(r.engine().sink().sent(conn), b"*-1\r\n");
1540        assert_eq!(r.engine().server().parked(), 0);
1541    }
1542
1543    /// The four that answer with something other than a two element array all
1544    /// answer a timeout the same way, which is not what the reply shape would
1545    /// suggest and is what Redis does.
1546    #[test]
1547    fn every_blocking_command_times_out_with_the_same_null_array() {
1548        for cmd in [
1549            &[b"BLPOP".as_slice(), b"q", b"0.001"][..],
1550            &[b"BRPOP", b"q", b"0.001"],
1551            &[b"BLMOVE", b"q", b"d", b"LEFT", b"RIGHT", b"0.001"],
1552            &[b"BRPOPLPUSH", b"q", b"d", b"0.001"],
1553            &[b"BLMPOP", b"0.001", b"1", b"q", b"LEFT"],
1554        ] {
1555            let (mut r, conn, mut batch) = timed();
1556            r.engine_mut().feed(conn, &wire(cmd));
1557            pump(&mut r, &mut batch);
1558            r.engine_mut().server_mut().set_clock_ms(START_MS + 1);
1559            pump(&mut r, &mut batch);
1560            assert_eq!(r.engine().sink().sent(conn), b"*-1\r\n", "for {cmd:?}");
1561        }
1562    }
1563
1564    /// A client that gave up does not go on holding a claim on the queue: the
1565    /// element that arrives after it stays where it was put.
1566    #[test]
1567    fn a_waiter_that_timed_out_does_not_eat_a_later_push() {
1568        let (mut r, a, mut batch) = timed();
1569        let b = r.engine_mut().accept();
1570        r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"1"]));
1571        pump(&mut r, &mut batch);
1572        r.engine_mut().server_mut().set_clock_ms(START_MS + 1000);
1573        pump(&mut r, &mut batch);
1574        assert_eq!(r.engine().sink().sent(a), b"*-1\r\n");
1575
1576        r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"late"]));
1577        r.engine_mut()
1578            .feed(b, &wire(&[b"LRANGE", b"q", b"0", b"-1"]));
1579        pump(&mut r, &mut batch);
1580        assert_eq!(r.engine().sink().sent(a), b"*-1\r\n", "nothing more");
1581        assert!(r.engine().sink().sent(b).ends_with(b"*1\r\n$4\r\nlate\r\n"));
1582    }
1583
1584    /// A `BLPOP key 0` has no deadline, so nothing but the connection closing
1585    /// will ever take it off the list. That makes the close path the one that
1586    /// has to be right, or a waiter outlives its client and the slot it names
1587    /// gets handed to somebody else.
1588    #[test]
1589    fn a_client_that_goes_away_while_it_waits_takes_its_waiter_with_it() {
1590        let (mut r, a, mut batch) = engine();
1591        let b = r.engine_mut().accept();
1592        r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1593        pump(&mut r, &mut batch);
1594        assert_eq!(r.engine().server().parked(), 1);
1595
1596        r.engine_mut().hangup(a);
1597        pump(&mut r, &mut batch);
1598        assert_eq!(r.engine().server().parked(), 0);
1599        assert_eq!(r.engine().clients(), 1);
1600
1601        // The slot is handed straight back out, which is what the waiter would
1602        // have been pointing at.
1603        let again = r.engine_mut().accept();
1604        assert_eq!(again, a);
1605        r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"x"]));
1606        r.engine_mut()
1607            .feed(again, &wire(&[b"LRANGE", b"q", b"0", b"-1"]));
1608        pump(&mut r, &mut batch);
1609        assert_eq!(r.engine().sink().sent(again), b"*1\r\n$1\r\nx\r\n");
1610    }
1611
1612    /// The same, with commands the client had already sent sitting behind the
1613    /// block. Those are what `pending` counts, so a close that forgets them is a
1614    /// connection slot that never comes back.
1615    #[test]
1616    fn a_hangup_while_parked_gives_back_the_slot_and_the_decoders() {
1617        let (mut r, a, mut batch) = engine();
1618        let mut stream = wire(&[b"BLPOP", b"q", b"0"]);
1619        stream.extend(wire(&[b"PING"]));
1620        stream.extend(wire(&[b"PING"]));
1621        r.engine_mut().feed(a, &stream);
1622        pump(&mut r, &mut batch);
1623
1624        let decoders = r.engine().decoders();
1625        r.engine_mut().hangup(a);
1626        pump(&mut r, &mut batch);
1627
1628        assert_eq!(r.engine().clients(), 0);
1629        assert!(r.engine().sink().was_closed(a));
1630        assert_eq!(r.engine().decoders(), decoders, "the pool came back whole");
1631        let again = r.engine_mut().accept();
1632        assert_eq!(again, a);
1633        r.engine_mut().feed(again, &wire(&[b"PING"]));
1634        pump(&mut r, &mut batch);
1635        assert_eq!(r.engine().sink().sent(again), b"+PONG\r\n");
1636    }
1637
1638    /// The whole point of a mailbox: a publish on one connection turns into
1639    /// bytes on another, in the same flush.
1640    #[test]
1641    fn a_published_message_lands_on_the_subscriber() {
1642        let (mut r, sub, mut batch) = engine();
1643        let pubr = r.engine_mut().accept();
1644
1645        r.engine_mut().feed(sub, &wire(&[b"SUBSCRIBE", b"news"]));
1646        pump(&mut r, &mut batch);
1647        assert_eq!(
1648            r.engine().sink().sent(sub),
1649            b"*3\r\n$9\r\nsubscribe\r\n$4\r\nnews\r\n:1\r\n"
1650        );
1651        r.engine_mut().sink_mut().clear();
1652
1653        r.engine_mut()
1654            .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1655        pump(&mut r, &mut batch);
1656        assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1657        assert_eq!(
1658            r.engine().sink().sent(sub),
1659            b"*3\r\n$7\r\nmessage\r\n$4\r\nnews\r\n$2\r\nhi\r\n"
1660        );
1661    }
1662
1663    /// A pattern subscriber is told which of its patterns matched as well as
1664    /// which channel the message went to, so the reply is one field longer.
1665    #[test]
1666    fn a_pattern_subscriber_is_told_the_pattern_and_the_channel() {
1667        let (mut r, sub, mut batch) = engine();
1668        let pubr = r.engine_mut().accept();
1669
1670        r.engine_mut().feed(sub, &wire(&[b"PSUBSCRIBE", b"ne*"]));
1671        pump(&mut r, &mut batch);
1672        r.engine_mut().sink_mut().clear();
1673
1674        r.engine_mut()
1675            .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1676        pump(&mut r, &mut batch);
1677        assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1678        assert_eq!(
1679            r.engine().sink().sent(sub),
1680            b"*4\r\n$8\r\npmessage\r\n$3\r\nne*\r\n$4\r\nnews\r\n$2\r\nhi\r\n"
1681        );
1682    }
1683
1684    /// A RESP2 client that has subscribed to anything can only leave, ping or
1685    /// subscribe to something else until it unsubscribes, because on RESP2 a
1686    /// message and a reply are the same shape and a client reading one cannot
1687    /// tell them apart.
1688    #[test]
1689    fn resp2_takes_almost_nothing_from_a_subscriber() {
1690        let (mut r, conn, mut batch) = engine();
1691
1692        r.engine_mut().feed(conn, &wire(&[b"SUBSCRIBE", b"a"]));
1693        pump(&mut r, &mut batch);
1694        r.engine_mut().sink_mut().clear();
1695
1696        r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1697        pump(&mut r, &mut batch);
1698        assert_eq!(
1699            r.engine().sink().sent(conn),
1700            b"-ERR Can't execute 'get': only (P|S)SUBSCRIBE / (P|S)UNSUBSCRIBE / PING / QUIT / RESET are allowed in this context\r\n"
1701        );
1702        r.engine_mut().sink_mut().clear();
1703
1704        // Ping is allowed, and answers in the shape the mode uses.
1705        r.engine_mut().feed(conn, &wire(&[b"PING"]));
1706        pump(&mut r, &mut batch);
1707        assert_eq!(
1708            r.engine().sink().sent(conn),
1709            b"*2\r\n$4\r\npong\r\n$0\r\n\r\n"
1710        );
1711        r.engine_mut().sink_mut().clear();
1712
1713        // And unsubscribing puts the connection back to ordinary work.
1714        r.engine_mut().feed(conn, &wire(&[b"UNSUBSCRIBE", b"a"]));
1715        r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1716        pump(&mut r, &mut batch);
1717        assert_eq!(
1718            r.engine().sink().sent(conn),
1719            b"*3\r\n$11\r\nunsubscribe\r\n$1\r\na\r\n:0\r\n$-1\r\n"
1720        );
1721    }
1722
1723    /// Shard channels are their own namespace. A name subscribed as a shard
1724    /// channel does not hear a plain publish to the same name, and a pattern
1725    /// never matches a shard publish.
1726    #[test]
1727    fn a_shard_channel_and_a_pattern_do_not_hear_each_other() {
1728        let (mut r, sub, mut batch) = engine();
1729        let pubr = r.engine_mut().accept();
1730
1731        r.engine_mut().feed(sub, &wire(&[b"SSUBSCRIBE", b"sx"]));
1732        r.engine_mut().feed(sub, &wire(&[b"PSUBSCRIBE", b"s*"]));
1733        pump(&mut r, &mut batch);
1734        r.engine_mut().sink_mut().clear();
1735
1736        r.engine_mut()
1737            .feed(pubr, &wire(&[b"SPUBLISH", b"sx", b"one"]));
1738        pump(&mut r, &mut batch);
1739        assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1740        assert_eq!(
1741            r.engine().sink().sent(sub),
1742            b"*3\r\n$8\r\nsmessage\r\n$2\r\nsx\r\n$3\r\none\r\n"
1743        );
1744        r.engine_mut().sink_mut().clear();
1745
1746        r.engine_mut()
1747            .feed(pubr, &wire(&[b"PUBLISH", b"sx", b"two"]));
1748        pump(&mut r, &mut batch);
1749        assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1750        assert_eq!(
1751            r.engine().sink().sent(sub),
1752            b"*4\r\n$8\r\npmessage\r\n$2\r\ns*\r\n$2\r\nsx\r\n$3\r\ntwo\r\n"
1753        );
1754    }
1755
1756    /// A subscriber that hangs up stops being one, which matters because the
1757    /// registry holds a connection id and that id gets handed to the next
1758    /// client through the door.
1759    #[test]
1760    fn a_subscriber_that_goes_away_leaves_the_registry() {
1761        let (mut r, sub, mut batch) = engine();
1762        let pubr = r.engine_mut().accept();
1763
1764        r.engine_mut().feed(sub, &wire(&[b"SUBSCRIBE", b"news"]));
1765        pump(&mut r, &mut batch);
1766        r.engine_mut().hangup(sub);
1767        pump(&mut r, &mut batch);
1768        r.engine_mut().sink_mut().clear();
1769
1770        r.engine_mut()
1771            .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1772        pump(&mut r, &mut batch);
1773        assert_eq!(r.engine().sink().sent(pubr), b":0\r\n");
1774
1775        // And the slot is clean for whoever gets it next.
1776        let next = r.engine_mut().accept();
1777        assert_eq!(next, sub);
1778        r.engine_mut()
1779            .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1780        pump(&mut r, &mut batch);
1781        assert_eq!(r.engine().sink().sent(next), b"");
1782    }
1783
1784    /// On RESP3 a message is a push, not a reply, so it can be read off a
1785    /// connection that is doing something else, and that connection is free to
1786    /// run ordinary commands while it is subscribed.
1787    ///
1788    /// It also pins the order a publish to yourself comes out in. Nothing in
1789    /// the code special cases it: the count is the reply to the command and the
1790    /// message is delivered on the way out with everybody else's, so the count
1791    /// is first.
1792    #[test]
1793    fn resp3_delivers_a_message_as_a_push() {
1794        let (mut r, conn, mut batch) = engine();
1795
1796        r.engine_mut().feed(conn, &wire(&[b"HELLO", b"3"]));
1797        r.engine_mut().feed(conn, &wire(&[b"SUBSCRIBE", b"a"]));
1798        pump(&mut r, &mut batch);
1799        r.engine_mut().sink_mut().clear();
1800
1801        r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1802        r.engine_mut().feed(conn, &wire(&[b"PUBLISH", b"a", b"w"]));
1803        pump(&mut r, &mut batch);
1804        assert_eq!(
1805            r.engine().sink().sent(conn),
1806            b"_\r\n:1\r\n>3\r\n$7\r\nmessage\r\n$1\r\na\r\n$1\r\nw\r\n"
1807        );
1808    }
1809
1810    /// A write publishes twice, once on the channel named after the key and
1811    /// once on the channel named after the event, in that order.
1812    #[test]
1813    fn a_write_reaches_a_keyspace_subscriber() {
1814        let (mut r, sub, mut batch) = engine();
1815        let writer = r.engine_mut().accept();
1816
1817        r.engine_mut().feed(
1818            writer,
1819            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"KEA"]),
1820        );
1821        r.engine_mut()
1822            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
1823        pump(&mut r, &mut batch);
1824        r.engine_mut().sink_mut().clear();
1825
1826        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
1827        pump(&mut r, &mut batch);
1828        assert_eq!(r.engine().sink().sent(writer), b"+OK\r\n");
1829        assert_eq!(
1830            r.engine().sink().sent(sub),
1831            b"*4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1832              $16\r\n__keyspace@0__:k\r\n$3\r\nset\r\n\
1833              *4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1834              $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n"
1835        );
1836    }
1837
1838    /// The setting is off by default, so a subscriber on the notification
1839    /// channels of a server nobody has turned them on for hears nothing.
1840    #[test]
1841    fn a_write_says_nothing_until_the_setting_turns_it_on() {
1842        let (mut r, sub, mut batch) = engine();
1843        let writer = r.engine_mut().accept();
1844
1845        r.engine_mut()
1846            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
1847        pump(&mut r, &mut batch);
1848        r.engine_mut().sink_mut().clear();
1849
1850        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
1851        pump(&mut r, &mut batch);
1852        assert_eq!(r.engine().sink().sent(sub), b"");
1853    }
1854
1855    /// `g` without `$` is the generic class and not the string one, so a
1856    /// delete goes out and the write that made the key does not.
1857    #[test]
1858    fn only_the_classes_that_were_asked_for_are_published() {
1859        let (mut r, sub, mut batch) = engine();
1860        let writer = r.engine_mut().accept();
1861
1862        r.engine_mut().feed(
1863            writer,
1864            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"Eg"]),
1865        );
1866        r.engine_mut()
1867            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
1868        pump(&mut r, &mut batch);
1869        r.engine_mut().sink_mut().clear();
1870
1871        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
1872        r.engine_mut().feed(writer, &wire(&[b"DEL", b"k"]));
1873        pump(&mut r, &mut batch);
1874        assert_eq!(
1875            r.engine().sink().sent(sub),
1876            b"*4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1877              $18\r\n__keyevent@0__:del\r\n$1\r\nk\r\n"
1878        );
1879    }
1880
1881    /// A command that took a deadline with it says two things, and they come
1882    /// out in the order the server did them rather than all at the end.
1883    #[test]
1884    fn a_write_with_a_deadline_on_it_says_two_things() {
1885        let (mut r, sub, mut batch) = engine();
1886        let writer = r.engine_mut().accept();
1887
1888        r.engine_mut().feed(
1889            writer,
1890            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
1891        );
1892        r.engine_mut()
1893            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
1894        pump(&mut r, &mut batch);
1895        r.engine_mut().sink_mut().clear();
1896
1897        r.engine_mut()
1898            .feed(writer, &wire(&[b"SETEX", b"k", b"100", b"v"]));
1899        pump(&mut r, &mut batch);
1900        assert_eq!(
1901            r.engine().sink().sent(sub),
1902            b"*4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
1903              $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n\
1904              *4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
1905              $21\r\n__keyevent@0__:expire\r\n$1\r\nk\r\n"
1906        );
1907    }
1908
1909    /// A subscriber on every event, and the writer that will make them.
1910    ///
1911    /// The three collection tests below all start the same way and all care
1912    /// about the order of what came out rather than about the bytes, so the
1913    /// setup is here once and the checking is done by [`fired`].
1914    fn watching() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
1915        watching_flags(b"EA")
1916    }
1917
1918    /// The same, for a test that needs a class `A` does not turn on.
1919    fn watching_flags(flags: &[u8]) -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
1920        let (mut r, sub, mut batch) = engine();
1921        let writer = r.engine_mut().accept();
1922        r.engine_mut().feed(
1923            writer,
1924            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", flags]),
1925        );
1926        r.engine_mut()
1927            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
1928        pump(&mut r, &mut batch);
1929        r.engine_mut().sink_mut().clear();
1930        (r, sub, writer, batch)
1931    }
1932
1933    /// The event and key of every notification the subscriber has been sent.
1934    ///
1935    /// Written against the wire bytes because that is what the subscriber
1936    /// actually got, and a command that fires four events in a fixed order
1937    /// makes for a byte literal nobody can read.
1938    fn fired(r: &Reactor<Wire<Recorder>>, sub: ConnId) -> Vec<(String, String)> {
1939        fired_on(r, sub, 0)
1940    }
1941
1942    /// The same, for a test watching a database other than the one the writer is
1943    /// on, which is the two commands that put a key somewhere else.
1944    fn fired_on(r: &Reactor<Wire<Recorder>>, sub: ConnId, db: usize) -> Vec<(String, String)> {
1945        let head = format!("__keyevent@{db}__:");
1946        let sent = String::from_utf8_lossy(r.engine().sink().sent(sub)).into_owned();
1947        let mut out = Vec::new();
1948        let mut parts = sent.split("\r\n");
1949        while let Some(p) = parts.next() {
1950            let Some(event) = p.strip_prefix(head.as_str()) else {
1951                continue;
1952            };
1953            // The pattern itself comes past on every frame ahead of the channel
1954            // and is not one of these.
1955            if event == "*" {
1956                continue;
1957            }
1958            parts.next();
1959            let key = parts.next().unwrap_or_default();
1960            out.push((event.to_owned(), key.to_owned()));
1961        }
1962        out
1963    }
1964
1965    /// A pop that took the last of a list says what it did and then that the
1966    /// key is gone, because a list with nothing in it is not a key.
1967    #[test]
1968    fn taking_the_last_of_a_collection_says_the_key_went_with_it() {
1969        let (mut r, sub, writer, mut batch) = watching();
1970
1971        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"k", b"a"]));
1972        r.engine_mut().feed(writer, &wire(&[b"LPOP", b"k"]));
1973        pump(&mut r, &mut batch);
1974        assert_eq!(
1975            fired(&r, sub),
1976            [("rpush", "k"), ("lpop", "k"), ("del", "k")]
1977                .map(|(e, k)| (e.to_owned(), k.to_owned()))
1978        );
1979    }
1980
1981    /// A move whose destination already holds the member says only the half
1982    /// that happened, since there was nothing to add on the far side.
1983    #[test]
1984    fn a_move_onto_a_member_already_there_says_only_the_removal() {
1985        let (mut r, sub, writer, mut batch) = watching();
1986
1987        r.engine_mut().feed(writer, &wire(&[b"SADD", b"a", b"m"]));
1988        r.engine_mut()
1989            .feed(writer, &wire(&[b"SADD", b"b", b"m", b"n"]));
1990        pump(&mut r, &mut batch);
1991        r.engine_mut().sink_mut().clear();
1992
1993        r.engine_mut()
1994            .feed(writer, &wire(&[b"SMOVE", b"a", b"b", b"m"]));
1995        pump(&mut r, &mut batch);
1996        assert_eq!(
1997            fired(&r, sub),
1998            [("srem", "a"), ("del", "a")].map(|(e, k)| (e.to_owned(), k.to_owned()))
1999        );
2000    }
2001
2002    /// Writing a member the score it is already sitting at is not a write, and
2003    /// the reply says as much about it as the silence does.
2004    #[test]
2005    fn a_score_that_did_not_move_says_nothing() {
2006        let (mut r, sub, writer, mut batch) = watching();
2007
2008        r.engine_mut()
2009            .feed(writer, &wire(&[b"ZADD", b"z", b"4", b"m"]));
2010        pump(&mut r, &mut batch);
2011        r.engine_mut().sink_mut().clear();
2012
2013        r.engine_mut()
2014            .feed(writer, &wire(&[b"ZADD", b"z", b"4", b"m"]));
2015        r.engine_mut()
2016            .feed(writer, &wire(&[b"ZINCRBY", b"z", b"0", b"m"]));
2017        pump(&mut r, &mut batch);
2018        assert_eq!(fired(&r, sub), []);
2019
2020        // And one that does move says so, so the silence above is the score
2021        // and not the subscriber having gone away.
2022        r.engine_mut()
2023            .feed(writer, &wire(&[b"ZINCRBY", b"z", b"1", b"m"]));
2024        pump(&mut r, &mut batch);
2025        assert_eq!(fired(&r, sub), [("zincr".to_owned(), "z".to_owned())]);
2026    }
2027
2028    /// A write that trimmed says two things, and a trim that found nothing over
2029    /// the threshold says only the one.
2030    #[test]
2031    fn a_stream_write_says_what_the_trim_behind_it_took() {
2032        let (mut r, sub, writer, mut batch) = watching();
2033
2034        r.engine_mut()
2035            .feed(writer, &wire(&[b"XADD", b"s", b"1-1", b"f", b"v"]));
2036        r.engine_mut().feed(
2037            writer,
2038            &wire(&[b"XADD", b"s", b"MAXLEN", b"9", b"2-1", b"f", b"v"]),
2039        );
2040        r.engine_mut().feed(
2041            writer,
2042            &wire(&[b"XADD", b"s", b"MAXLEN", b"1", b"3-1", b"f", b"v"]),
2043        );
2044        pump(&mut r, &mut batch);
2045        assert_eq!(
2046            fired(&r, sub),
2047            [("xadd", "s"), ("xadd", "s"), ("xadd", "s"), ("xtrim", "s")]
2048                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2049        );
2050    }
2051
2052    /// Acknowledging an entry that has already been deleted from under the
2053    /// group takes nothing out of the log, so it says nothing, even though the
2054    /// reply calls it deleted.
2055    #[test]
2056    fn acknowledging_an_entry_that_is_already_gone_says_nothing() {
2057        let (mut r, sub, writer, mut batch) = watching();
2058
2059        for cmd in [
2060            wire(&[b"XADD", b"s", b"1-1", b"f", b"v"]),
2061            wire(&[b"XGROUP", b"CREATE", b"s", b"g", b"0"]),
2062            wire(&[b"XREADGROUP", b"GROUP", b"g", b"c", b"STREAMS", b"s", b">"]),
2063            wire(&[b"XDEL", b"s", b"1-1"]),
2064        ] {
2065            r.engine_mut().feed(writer, &cmd);
2066        }
2067        pump(&mut r, &mut batch);
2068        r.engine_mut().sink_mut().clear();
2069
2070        r.engine_mut().feed(
2071            writer,
2072            &wire(&[b"XACKDEL", b"s", b"g", b"IDS", b"1", b"1-1"]),
2073        );
2074        pump(&mut r, &mut batch);
2075        assert_eq!(fired(&r, sub), []);
2076    }
2077
2078    /// Taking the last field out of a hash says the key went with it, the same
2079    /// as taking the last of a list or a set does.
2080    #[test]
2081    fn emptying_a_hash_says_the_key_went_with_the_last_field() {
2082        let (mut r, sub, writer, mut batch) = watching();
2083
2084        r.engine_mut()
2085            .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2086        r.engine_mut().feed(writer, &wire(&[b"HDEL", b"h", b"a"]));
2087        // The second names a field that has already gone and one that has not,
2088        // so it still removed something and the hash is empty behind it.
2089        r.engine_mut()
2090            .feed(writer, &wire(&[b"HDEL", b"h", b"b", b"a"]));
2091        pump(&mut r, &mut batch);
2092        assert_eq!(
2093            fired(&r, sub),
2094            [("hset", "h"), ("hdel", "h"), ("hdel", "h"), ("del", "h")]
2095                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2096        );
2097    }
2098
2099    /// A deadline that has already passed takes the field with it, so what
2100    /// comes out is the removal and not the deadline.
2101    #[test]
2102    fn a_field_deadline_already_past_reads_as_a_removal() {
2103        let (mut r, sub, writer, mut batch) = watching();
2104
2105        r.engine_mut()
2106            .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2107        pump(&mut r, &mut batch);
2108        r.engine_mut().sink_mut().clear();
2109
2110        r.engine_mut().feed(
2111            writer,
2112            &wire(&[b"HEXPIRE", b"h", b"0", b"FIELDS", b"1", b"a"]),
2113        );
2114        r.engine_mut().feed(
2115            writer,
2116            &wire(&[b"HEXPIRE", b"h", b"100", b"FIELDS", b"1", b"b"]),
2117        );
2118        pump(&mut r, &mut batch);
2119        assert_eq!(
2120            fired(&r, sub),
2121            [("hdel", "h"), ("hexpire", "h")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2122        );
2123    }
2124
2125    /// Writing fields under a deadline that has already gone says all three
2126    /// things in order: the write, the removal it brought on, and the key.
2127    #[test]
2128    fn a_write_under_a_deadline_already_gone_says_the_write_first() {
2129        let (mut r, sub, writer, mut batch) = watching();
2130
2131        r.engine_mut().feed(
2132            writer,
2133            &wire(&[b"HSETEX", b"h", b"EXAT", b"1", b"FIELDS", b"1", b"a", b"1"]),
2134        );
2135        pump(&mut r, &mut batch);
2136        assert_eq!(
2137            fired(&r, sub),
2138            [("hset", "h"), ("hdel", "h"), ("del", "h")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2139        );
2140    }
2141
2142    /// Clearing a deadline is only news for a field that had one to clear, and
2143    /// the reply cannot be read for that: it is the value either way.
2144    #[test]
2145    fn clearing_a_deadline_that_was_never_set_says_nothing() {
2146        let (mut r, sub, writer, mut batch) = watching();
2147
2148        r.engine_mut()
2149            .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2150        r.engine_mut().feed(
2151            writer,
2152            &wire(&[b"HEXPIRE", b"h", b"100", b"FIELDS", b"1", b"a"]),
2153        );
2154        pump(&mut r, &mut batch);
2155        r.engine_mut().sink_mut().clear();
2156
2157        r.engine_mut()
2158            .feed(writer, &wire(&[b"HPERSIST", b"h", b"FIELDS", b"1", b"b"]));
2159        r.engine_mut().feed(
2160            writer,
2161            &wire(&[b"HGETEX", b"h", b"PERSIST", b"FIELDS", b"1", b"b"]),
2162        );
2163        pump(&mut r, &mut batch);
2164        assert_eq!(fired(&r, sub), []);
2165
2166        // And the field that did have one says so, so the silence above is the
2167        // deadline and not the subscriber having gone away.
2168        r.engine_mut().feed(
2169            writer,
2170            &wire(&[b"HGETEX", b"h", b"PERSIST", b"FIELDS", b"2", b"a", b"b"]),
2171        );
2172        pump(&mut r, &mut batch);
2173        assert_eq!(fired(&r, sub), [("hpersist".to_owned(), "h".to_owned())]);
2174    }
2175
2176    /// A name that was free is news on its own, and a name that was taken is
2177    /// not, whatever the write did to what was under it.
2178    #[test]
2179    fn a_key_that_was_not_there_before_says_so() {
2180        let (mut r, sub, writer, mut batch) = watching_flags(b"En");
2181
2182        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2183        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"w"]));
2184        r.engine_mut().feed(writer, &wire(&[b"APPEND", b"k", b"x"]));
2185        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2186        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"b"]));
2187        pump(&mut r, &mut batch);
2188        assert_eq!(
2189            fired(&r, sub),
2190            [("new", "k"), ("new", "l")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2191        );
2192    }
2193
2194    /// And it arrives in front of the write that made it, because at the moment
2195    /// it is said the write has not finished happening yet.
2196    #[test]
2197    fn the_news_of_a_new_key_comes_before_the_write_that_made_it() {
2198        let (mut r, sub, writer, mut batch) = watching_flags(b"EAn");
2199
2200        r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"1"]));
2201        r.engine_mut().feed(writer, &wire(&[b"SET", b"b", b"2"]));
2202        pump(&mut r, &mut batch);
2203        r.engine_mut().sink_mut().clear();
2204
2205        // A rename is a key arriving under a name that was already taken, and
2206        // it is still a key arriving: what was there is gone and what is there
2207        // now was somewhere else a moment ago.
2208        r.engine_mut().feed(writer, &wire(&[b"RENAME", b"a", b"b"]));
2209        pump(&mut r, &mut batch);
2210        assert_eq!(
2211            fired(&r, sub),
2212            [("new", "b"), ("rename_from", "a"), ("rename_to", "b")]
2213                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2214        );
2215    }
2216
2217    /// A store form is the other case: the name stays where it stands and only
2218    /// what is under it changes, so there is no key arriving to say anything
2219    /// about unless the destination was not there at all.
2220    #[test]
2221    fn writing_over_a_destination_is_not_a_key_arriving() {
2222        let (mut r, sub, writer, mut batch) = watching_flags(b"EAn");
2223
2224        r.engine_mut()
2225            .feed(writer, &wire(&[b"RPUSH", b"l", b"c", b"a", b"b"]));
2226        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"d", b"x"]));
2227        pump(&mut r, &mut batch);
2228        r.engine_mut().sink_mut().clear();
2229
2230        r.engine_mut()
2231            .feed(writer, &wire(&[b"SORT", b"l", b"ALPHA", b"STORE", b"d"]));
2232        pump(&mut r, &mut batch);
2233        assert_eq!(fired(&r, sub), [("sortstore".to_owned(), "d".to_owned())]);
2234        r.engine_mut().sink_mut().clear();
2235
2236        // And the same store onto a name nobody is using says both, which is
2237        // what makes the silence above the destination and not the flag.
2238        r.engine_mut().feed(writer, &wire(&[b"DEL", b"d"]));
2239        r.engine_mut()
2240            .feed(writer, &wire(&[b"SORT", b"l", b"ALPHA", b"STORE", b"d"]));
2241        pump(&mut r, &mut batch);
2242        assert_eq!(
2243            fired(&r, sub),
2244            [("del", "d"), ("new", "d"), ("sortstore", "d")]
2245                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2246        );
2247    }
2248
2249    /// A write that throws away the whole of what was under a name says so, and
2250    /// says the kind changed when it did.
2251    #[test]
2252    fn replacing_a_value_says_what_went_and_whether_the_kind_changed() {
2253        let (mut r, sub, writer, mut batch) = watching_flags(b"Eoc");
2254
2255        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2256        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"w"]));
2257        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2258        r.engine_mut().feed(writer, &wire(&[b"SET", b"l", b"v"]));
2259        pump(&mut r, &mut batch);
2260        assert_eq!(
2261            fired(&r, sub),
2262            [
2263                ("overwritten", "k"),
2264                ("overwritten", "l"),
2265                ("type_changed", "l")
2266            ]
2267            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2268        );
2269    }
2270
2271    /// And a write that reaches into the value that is already there says
2272    /// nothing, however much of it moves.
2273    #[test]
2274    fn a_write_that_changes_part_of_a_value_has_not_replaced_it() {
2275        let (mut r, sub, writer, mut batch) = watching_flags(b"Eoc");
2276
2277        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"1"]));
2278        r.engine_mut().feed(writer, &wire(&[b"APPEND", b"k", b"2"]));
2279        r.engine_mut().feed(writer, &wire(&[b"INCR", b"k"]));
2280        r.engine_mut()
2281            .feed(writer, &wire(&[b"SETRANGE", b"k", b"0", b"9"]));
2282        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2283        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"b"]));
2284        pump(&mut r, &mut batch);
2285        assert_eq!(fired(&r, sub), []);
2286    }
2287
2288    /// The one place the pair comes last rather than first, because there the
2289    /// destination is a key arriving and not a value changing, so nothing
2290    /// notices it going until the command says what it did.
2291    #[test]
2292    fn a_rename_says_what_it_replaced_after_saying_what_it_did() {
2293        let (mut r, sub, writer, mut batch) = watching_flags(b"EAnoc");
2294
2295        r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"1"]));
2296        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"b", b"x"]));
2297        pump(&mut r, &mut batch);
2298        r.engine_mut().sink_mut().clear();
2299
2300        r.engine_mut().feed(writer, &wire(&[b"RENAME", b"a", b"b"]));
2301        pump(&mut r, &mut batch);
2302        assert_eq!(
2303            fired(&r, sub),
2304            [
2305                ("new", "b"),
2306                ("rename_from", "a"),
2307                ("rename_to", "b"),
2308                ("overwritten", "b"),
2309                ("type_changed", "b")
2310            ]
2311            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2312        );
2313    }
2314
2315    /// A store form is the other way round, since there the name stays where it
2316    /// stands and the old value goes before the command has done anything.
2317    #[test]
2318    fn a_store_form_says_what_it_replaced_before_saying_what_it_did() {
2319        let (mut r, sub, writer, mut batch) = watching_flags(b"EAnoc");
2320
2321        r.engine_mut().feed(writer, &wire(&[b"SADD", b"s", b"m"]));
2322        r.engine_mut().feed(writer, &wire(&[b"SET", b"d", b"q"]));
2323        pump(&mut r, &mut batch);
2324        r.engine_mut().sink_mut().clear();
2325
2326        r.engine_mut()
2327            .feed(writer, &wire(&[b"SINTERSTORE", b"d", b"s"]));
2328        pump(&mut r, &mut batch);
2329        assert_eq!(
2330            fired(&r, sub),
2331            [
2332                ("overwritten", "d"),
2333                ("type_changed", "d"),
2334                ("sinterstore", "d")
2335            ]
2336            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2337        );
2338    }
2339
2340    /// A bit write says so when it did something and stays quiet when it did
2341    /// not, which is not the same as whether it was a write.
2342    #[test]
2343    fn a_bit_write_that_left_the_value_alone_says_nothing() {
2344        let (mut r, sub, writer, mut batch) = watching();
2345
2346        // `a` is 0x61, so the second bit from the top is already one and the
2347        // first of these three changes nothing. The second clears it and the
2348        // third finds it clear.
2349        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"abc"]));
2350        pump(&mut r, &mut batch);
2351        r.engine_mut().sink_mut().clear();
2352
2353        r.engine_mut()
2354            .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"1"]));
2355        r.engine_mut()
2356            .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"0"]));
2357        r.engine_mut()
2358            .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"0"]));
2359        // And one that writes a zero into a value too short to hold it, which
2360        // changed no bit that was there and still counts, because the bytes it
2361        // wrote the zero into were not there before.
2362        r.engine_mut()
2363            .feed(writer, &wire(&[b"SETBIT", b"k", b"100", b"0"]));
2364        pump(&mut r, &mut batch);
2365        assert_eq!(
2366            fired(&r, sub),
2367            [("setbit", "k"), ("setbit", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2368        );
2369    }
2370
2371    /// And `BITFIELD` follows the same rule one subcommand at a time, so a call
2372    /// that wrote every field back the way it found it says nothing.
2373    #[test]
2374    fn a_bitfield_that_wrote_the_same_values_back_says_nothing() {
2375        let (mut r, sub, writer, mut batch) = watching();
2376
2377        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"abc"]));
2378        pump(&mut r, &mut batch);
2379        r.engine_mut().sink_mut().clear();
2380
2381        // `a` again, written back over itself.
2382        r.engine_mut().feed(
2383            writer,
2384            &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"0", b"97"]),
2385        );
2386        r.engine_mut()
2387            .feed(writer, &wire(&[b"BITFIELD", b"k", b"GET", b"u8", b"0"]));
2388        r.engine_mut().feed(
2389            writer,
2390            &wire(&[b"BITFIELD", b"k", b"INCRBY", b"u8", b"0", b"0"]),
2391        );
2392        pump(&mut r, &mut batch);
2393        assert_eq!(fired(&r, sub), []);
2394
2395        // One that does change a field, and one that only makes the value
2396        // longer without changing a bit that was in it.
2397        r.engine_mut().feed(
2398            writer,
2399            &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"0", b"98"]),
2400        );
2401        r.engine_mut().feed(
2402            writer,
2403            &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"800", b"0"]),
2404        );
2405        pump(&mut r, &mut batch);
2406        assert_eq!(
2407            fired(&r, sub),
2408            [("setbit", "k"), ("setbit", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2409        );
2410    }
2411
2412    /// A sketch says `pfadd` when a register moved, and a merge says it under
2413    /// the same name whatever it merged.
2414    #[test]
2415    fn the_sketch_commands_say_what_a_mass_add_says() {
2416        let (mut r, sub, writer, mut batch) = watching();
2417
2418        r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h", b"a"]));
2419        // The same element again, which moves nothing.
2420        r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h", b"a"]));
2421        // And no elements at all on a sketch that is already there.
2422        r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h"]));
2423        // A merge with no sources, which touches nothing and says it anyway.
2424        r.engine_mut().feed(writer, &wire(&[b"PFMERGE", b"d"]));
2425        r.engine_mut()
2426            .feed(writer, &wire(&[b"PFMERGE", b"d", b"h"]));
2427        pump(&mut r, &mut batch);
2428        assert_eq!(
2429            fired(&r, sub),
2430            [("pfadd", "h"), ("pfadd", "d"), ("pfadd", "d")]
2431                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2432        );
2433    }
2434
2435    /// A geo key is a sorted set, so writing to one says what the `ZADD`
2436    /// underneath says, and storing a search says a name of its own.
2437    #[test]
2438    fn the_geo_commands_say_what_the_sorted_set_under_them_did() {
2439        let (mut r, sub, writer, mut batch) = watching();
2440
2441        let point: &[&[u8]] = &[b"GEOADD", b"g", b"13.361389", b"38.115556", b"P"];
2442        r.engine_mut().feed(writer, &wire(point));
2443        // The same member at the same place, which is neither an add nor a move.
2444        r.engine_mut().feed(writer, &wire(point));
2445        // The same member somewhere else, which is a move and is a write.
2446        r.engine_mut().feed(
2447            writer,
2448            &wire(&[b"GEOADD", b"g", b"14.0", b"38.115556", b"P"]),
2449        );
2450        r.engine_mut().feed(
2451            writer,
2452            &wire(&[
2453                b"GEORADIUS",
2454                b"g",
2455                b"14.0",
2456                b"38.0",
2457                b"200",
2458                b"km",
2459                b"STORE",
2460                b"d",
2461            ]),
2462        );
2463        r.engine_mut().feed(
2464            writer,
2465            &wire(&[
2466                b"GEOSEARCHSTORE",
2467                b"e",
2468                b"g",
2469                b"FROMLONLAT",
2470                b"14.0",
2471                b"38.0",
2472                b"BYRADIUS",
2473                b"200",
2474                b"km",
2475            ]),
2476        );
2477        pump(&mut r, &mut batch);
2478        assert_eq!(
2479            fired(&r, sub),
2480            [
2481                ("zadd", "g"),
2482                ("zadd", "g"),
2483                ("georadiusstore", "d"),
2484                ("geosearchstore", "e")
2485            ]
2486            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2487        );
2488    }
2489
2490    /// And a store whose search found nothing deletes the destination and says
2491    /// so, which is the rule every store form follows.
2492    #[test]
2493    fn a_geo_store_that_found_nothing_takes_the_destination_with_it() {
2494        let (mut r, sub, writer, mut batch) = watching();
2495
2496        r.engine_mut().feed(
2497            writer,
2498            &wire(&[b"GEOADD", b"g", b"13.361389", b"38.115556", b"P"]),
2499        );
2500        r.engine_mut().feed(writer, &wire(&[b"SET", b"d", b"x"]));
2501        pump(&mut r, &mut batch);
2502        r.engine_mut().sink_mut().clear();
2503
2504        r.engine_mut().feed(
2505            writer,
2506            &wire(&[
2507                b"GEORADIUS",
2508                b"g",
2509                b"1.0",
2510                b"1.0",
2511                b"1",
2512                b"km",
2513                b"STORE",
2514                b"d",
2515            ]),
2516        );
2517        // And again, now that the destination is not there, which deletes
2518        // nothing and says nothing.
2519        r.engine_mut().feed(
2520            writer,
2521            &wire(&[
2522                b"GEORADIUS",
2523                b"g",
2524                b"1.0",
2525                b"1.0",
2526                b"1",
2527                b"km",
2528                b"STORE",
2529                b"d",
2530            ]),
2531        );
2532        pump(&mut r, &mut batch);
2533        assert_eq!(
2534            fired(&r, sub),
2535            [("del", "d")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2536        );
2537    }
2538
2539    /// A key that arrives on a database other than the one that asked for it
2540    /// says it is new there, and says nothing on the database the command ran
2541    /// on.
2542    #[test]
2543    fn a_key_that_lands_on_another_database_is_new_over_there() {
2544        let (mut r, sub, mut batch) = engine();
2545        let writer = r.engine_mut().accept();
2546        r.engine_mut().feed(
2547            writer,
2548            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EAnoc"]),
2549        );
2550        r.engine_mut().feed(
2551            sub,
2552            &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*", b"__keyevent@1__:*"]),
2553        );
2554        r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2555        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2556        pump(&mut r, &mut batch);
2557        r.engine_mut().sink_mut().clear();
2558
2559        r.engine_mut()
2560            .feed(writer, &wire(&[b"COPY", b"a", b"b", b"DB", b"1"]));
2561        r.engine_mut().feed(writer, &wire(&[b"MOVE", b"k", b"1"]));
2562        pump(&mut r, &mut batch);
2563        assert_eq!(
2564            fired_on(&r, sub, 1),
2565            [
2566                ("new", "b"),
2567                ("copy_to", "b"),
2568                ("new", "k"),
2569                ("move_to", "k")
2570            ]
2571            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2572        );
2573        // And nothing of the sort on the database the two commands ran on,
2574        // which hears only the half of the move that happened there.
2575        assert_eq!(
2576            fired_on(&r, sub, 0),
2577            [("move_from", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2578        );
2579    }
2580
2581    /// A read that found nothing says so, once for each key it went looking
2582    /// for and in the order it was given them.
2583    ///
2584    /// The class is not in `A`, the same way it is not in Redis's, so these ask
2585    /// for it by letter.
2586    #[test]
2587    fn a_read_that_found_nothing_says_which_key_it_was() {
2588        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2589
2590        r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2591        r.engine_mut()
2592            .feed(writer, &wire(&[b"MGET", b"a", b"nk", b"nk"]));
2593        r.engine_mut()
2594            .feed(writer, &wire(&[b"EXISTS", b"nj", b"a"]));
2595        pump(&mut r, &mut batch);
2596        assert_eq!(
2597            fired(&r, sub),
2598            [("keymiss", "nk"), ("keymiss", "nk"), ("keymiss", "nj")]
2599                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2600        );
2601    }
2602
2603    /// A write says nothing about a name that was free, and the shapes of the
2604    /// same command that read say it.
2605    #[test]
2606    fn only_the_shape_of_a_write_that_reads_says_it() {
2607        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2608
2609        // A plain `SET` never looks, and neither does a `BITFIELD` with a
2610        // write anywhere in the line.
2611        r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2612        r.engine_mut().feed(
2613            writer,
2614            &wire(&[b"BITFIELD", b"nk", b"SET", b"u8", b"0", b"1"]),
2615        );
2616        r.engine_mut().feed(writer, &wire(&[b"LPOP", b"nk"]));
2617        pump(&mut r, &mut batch);
2618        assert_eq!(fired(&r, sub), []);
2619
2620        // The two that do, which are the same two commands.
2621        r.engine_mut()
2622            .feed(writer, &wire(&[b"SET", b"nj", b"v", b"GET"]));
2623        r.engine_mut()
2624            .feed(writer, &wire(&[b"BITFIELD", b"nl", b"GET", b"u8", b"0"]));
2625        r.engine_mut().feed(writer, &wire(&[b"GETDEL", b"nm"]));
2626        pump(&mut r, &mut batch);
2627        assert_eq!(
2628            fired(&r, sub),
2629            [("keymiss", "nj"), ("keymiss", "nl"), ("keymiss", "nm")]
2630                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2631        );
2632    }
2633
2634    /// A store form says it for the keys it read and not for the one it is
2635    /// about to write, however empty that name is.
2636    #[test]
2637    fn a_store_form_says_it_only_for_its_sources() {
2638        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2639
2640        r.engine_mut()
2641            .feed(writer, &wire(&[b"SINTERSTORE", b"dst", b"nk", b"nj"]));
2642        r.engine_mut()
2643            .feed(writer, &wire(&[b"ZUNIONSTORE", b"dst", b"1", b"nz"]));
2644        r.engine_mut()
2645            .feed(writer, &wire(&[b"ZRANGESTORE", b"dst", b"nz", b"0", b"-1"]));
2646        pump(&mut r, &mut batch);
2647        assert_eq!(
2648            fired(&r, sub),
2649            [
2650                ("keymiss", "nk"),
2651                ("keymiss", "nj"),
2652                ("keymiss", "nz"),
2653                ("keymiss", "nz")
2654            ]
2655            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2656        );
2657    }
2658
2659    /// Both stream reads find their keys behind `STREAMS`, and `XREAD` looks
2660    /// each of them up twice, once to resolve the identifier it was handed and
2661    /// once to serve from it.
2662    #[test]
2663    fn the_stream_reads_say_it_for_the_keys_behind_the_keyword() {
2664        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2665
2666        r.engine_mut().feed(
2667            writer,
2668            &wire(&[b"XREAD", b"STREAMS", b"nk", b"nj", b"0", b"0"]),
2669        );
2670        pump(&mut r, &mut batch);
2671        assert_eq!(
2672            fired(&r, sub),
2673            [
2674                ("keymiss", "nk"),
2675                ("keymiss", "nj"),
2676                ("keymiss", "nk"),
2677                ("keymiss", "nj")
2678            ]
2679            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2680        );
2681    }
2682
2683    /// A command that failed while it was still reading its own arguments never
2684    /// looked a key up, so it says nothing, and one that failed on what it
2685    /// found keeps what it had already said.
2686    #[test]
2687    fn an_argument_that_did_not_parse_takes_the_miss_back() {
2688        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2689
2690        r.engine_mut()
2691            .feed(writer, &wire(&[b"GETRANGE", b"nk", b"x", b"-1"]));
2692        r.engine_mut()
2693            .feed(writer, &wire(&[b"LPOS", b"nk", b"a", b"RANK", b"0"]));
2694        pump(&mut r, &mut batch);
2695        assert_eq!(fired(&r, sub), []);
2696
2697        // A `WRONGTYPE` is an answer about what was under a key, which means
2698        // the lookups happened and the misses in front of the one that failed
2699        // stand.
2700        r.engine_mut().feed(writer, &wire(&[b"SET", b"s", b"v"]));
2701        pump(&mut r, &mut batch);
2702        r.engine_mut().sink_mut().clear();
2703
2704        r.engine_mut()
2705            .feed(writer, &wire(&[b"SINTER", b"nk", b"s"]));
2706        pump(&mut r, &mut batch);
2707        assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nk".to_owned())]);
2708    }
2709
2710    /// A read over several keys says nothing about the ones behind a key that
2711    /// holds the wrong thing, because the command stops there and never looks
2712    /// at them.
2713    #[test]
2714    fn a_read_stops_missing_where_it_stops_looking() {
2715        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2716
2717        r.engine_mut().feed(writer, &wire(&[b"SET", b"s", b"v"]));
2718        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"x"]));
2719        pump(&mut r, &mut batch);
2720        r.engine_mut().sink_mut().clear();
2721
2722        r.engine_mut()
2723            .feed(writer, &wire(&[b"SINTER", b"s", b"nk"]));
2724        pump(&mut r, &mut batch);
2725        assert_eq!(fired(&r, sub), []);
2726
2727        // And a read that does not stop keeps going. `MGET` answers a nil for
2728        // the list and goes on to look at the key behind it.
2729        r.engine_mut().feed(writer, &wire(&[b"MGET", b"l", b"nk"]));
2730        pump(&mut r, &mut batch);
2731        assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nk".to_owned())]);
2732    }
2733
2734    /// The keys a `SORT` builds out of its elements say it too, and they are
2735    /// the one set of keys nothing could have asked about in front of the
2736    /// command, since they do not exist until it is running.
2737    #[test]
2738    fn the_keys_a_sort_pattern_names_say_it_as_they_are_read() {
2739        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2740
2741        r.engine_mut()
2742            .feed(writer, &wire(&[b"RPUSH", b"l", b"1", b"2"]));
2743        r.engine_mut().feed(writer, &wire(&[b"SET", b"w_1", b"5"]));
2744        pump(&mut r, &mut batch);
2745        r.engine_mut().sink_mut().clear();
2746
2747        r.engine_mut().feed(
2748            writer,
2749            &wire(&[b"SORT", b"l", b"BY", b"w_*", b"GET", b"p_*"]),
2750        );
2751        pump(&mut r, &mut batch);
2752        assert_eq!(
2753            fired(&r, sub),
2754            [("keymiss", "w_2"), ("keymiss", "p_2"), ("keymiss", "p_1")]
2755                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2756        );
2757    }
2758
2759    /// A key that was there and had run out says both things in the order they
2760    /// happened: the deadline first, because the probe that noticed the key was
2761    /// gone is what reaped it.
2762    #[test]
2763    fn a_deadline_that_passed_is_news_before_the_miss_it_causes() {
2764        let (mut r, sub, mut batch) = timed();
2765        let writer = r.engine_mut().accept();
2766        r.engine_mut().feed(
2767            writer,
2768            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EgAm"]),
2769        );
2770        r.engine_mut()
2771            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2772        r.engine_mut()
2773            .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
2774        pump(&mut r, &mut batch);
2775        r.engine_mut().sink_mut().clear();
2776
2777        r.engine().server().advance_clock_ms(50);
2778        r.engine_mut().feed(writer, &wire(&[b"GET", b"k"]));
2779        pump(&mut r, &mut batch);
2780        assert_eq!(
2781            fired(&r, sub),
2782            [("expired", "k"), ("keymiss", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2783        );
2784    }
2785
2786    /// A module read says it the same way a core read does, because the module
2787    /// API opens its key through the same lookup.
2788    #[test]
2789    fn a_module_read_says_it_the_way_a_core_read_does() {
2790        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2791
2792        r.engine_mut().feed(writer, &wire(&[b"JSON.GET", b"nk"]));
2793        r.engine_mut().feed(writer, &wire(&[b"TS.GET", b"nj"]));
2794        r.engine_mut()
2795            .feed(writer, &wire(&[b"BF.EXISTS", b"nl", b"x"]));
2796        r.engine_mut().feed(writer, &wire(&[b"TDIGEST.MIN", b"nm"]));
2797        r.engine_mut().feed(writer, &wire(&[b"TOPK.LIST", b"nn"]));
2798        r.engine_mut().feed(writer, &wire(&[b"CMS.INFO", b"no"]));
2799        r.engine_mut().feed(writer, &wire(&[b"VCARD", b"np"]));
2800        pump(&mut r, &mut batch);
2801        assert_eq!(
2802            fired(&r, sub),
2803            [
2804                ("keymiss", "nk"),
2805                ("keymiss", "nj"),
2806                ("keymiss", "nl"),
2807                ("keymiss", "nm"),
2808                ("keymiss", "nn"),
2809                ("keymiss", "no"),
2810                ("keymiss", "np")
2811            ]
2812            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2813        );
2814
2815        // And the one of them that reads a list of keys says it for each,
2816        // without stopping at the first empty name.
2817        r.engine_mut().sink_mut().clear();
2818        r.engine_mut()
2819            .feed(writer, &wire(&[b"JSON.MGET", b"nk", b"nj", b"$"]));
2820        pump(&mut r, &mut batch);
2821        assert_eq!(
2822            fired(&r, sub),
2823            [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2824        );
2825    }
2826
2827    /// The module commands that say nothing, which are the writes, the two
2828    /// reads that were measured quiet, and the whole of the search group bar
2829    /// the pair that reads a key rather than an index.
2830    #[test]
2831    fn the_quiet_module_commands_stay_quiet() {
2832        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2833
2834        r.engine_mut()
2835            .feed(writer, &wire(&[b"JSON.SET", b"nk", b"$", b"1"]));
2836        r.engine_mut()
2837            .feed(writer, &wire(&[b"BF.ADD", b"nj", b"x"]));
2838        r.engine_mut()
2839            .feed(writer, &wire(&[b"TS.ADD", b"nl", b"1000", b"1"]));
2840        r.engine_mut().feed(writer, &wire(&[b"TS.INFO", b"nm"]));
2841        r.engine_mut().feed(writer, &wire(&[b"CF.COMPACT", b"nn"]));
2842        r.engine_mut()
2843            .feed(writer, &wire(&[b"JSON.DEBUG", b"HELP"]));
2844        r.engine_mut()
2845            .feed(writer, &wire(&[b"FT.GET", b"ni", b"no"]));
2846        r.engine_mut()
2847            .feed(writer, &wire(&[b"FT.SEARCH", b"ni", b"*"]));
2848        pump(&mut r, &mut batch);
2849        assert_eq!(fired(&r, sub), []);
2850
2851        // The three that do have a key of their own to be missing.
2852        r.engine_mut()
2853            .feed(writer, &wire(&[b"JSON.DEBUG", b"MEMORY", b"np"]));
2854        r.engine_mut()
2855            .feed(writer, &wire(&[b"FT.SUGGET", b"nq", b"x"]));
2856        r.engine_mut().feed(writer, &wire(&[b"FT.SUGLEN", b"nr"]));
2857        pump(&mut r, &mut batch);
2858        assert_eq!(
2859            fired(&r, sub),
2860            [("keymiss", "np"), ("keymiss", "nq"), ("keymiss", "nr")]
2861                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2862        );
2863    }
2864
2865    /// A module read keeps a miss that its own arguments went on to spoil,
2866    /// where a core read in the same shape takes it back.
2867    ///
2868    /// The two are the same question asked in a different order. A core command
2869    /// reads everything it was sent and then looks, a module command opens its
2870    /// key and then reads the rest.
2871    #[test]
2872    fn a_module_read_keeps_the_miss_a_later_argument_spoiled() {
2873        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2874
2875        r.engine_mut()
2876            .feed(writer, &wire(&[b"JSON.GET", b"nk", b"$..["]));
2877        r.engine_mut().feed(
2878            writer,
2879            &wire(&[b"VSIM", b"nj", b"ELE", b"e", b"COUNT", b"x"]),
2880        );
2881        pump(&mut r, &mut batch);
2882        assert_eq!(
2883            fired(&r, sub),
2884            [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2885        );
2886    }
2887
2888    /// The two merges read a destination and then their sources, and stop at
2889    /// the first source that is not there because that is where they fail.
2890    #[test]
2891    fn the_module_merges_stop_at_the_first_empty_source() {
2892        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2893
2894        r.engine_mut().feed(
2895            writer,
2896            &wire(&[b"TDIGEST.MERGE", b"nk", b"2", b"nj", b"nl"]),
2897        );
2898        pump(&mut r, &mut batch);
2899        assert_eq!(
2900            fired(&r, sub),
2901            [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2902        );
2903
2904        // The sketch writes its destination rather than reading it, so an empty
2905        // name there is not a miss, and it is the end of the command, so the
2906        // sources behind it are never opened.
2907        r.engine_mut().sink_mut().clear();
2908        r.engine_mut()
2909            .feed(writer, &wire(&[b"CMS.MERGE", b"nk", b"1", b"nj"]));
2910        pump(&mut r, &mut batch);
2911        assert_eq!(fired(&r, sub), []);
2912
2913        // With a destination that is there, the sources are read and the first
2914        // empty one is the last thing looked at.
2915        r.engine_mut()
2916            .feed(writer, &wire(&[b"CMS.INITBYDIM", b"cm", b"100", b"5"]));
2917        pump(&mut r, &mut batch);
2918        r.engine_mut().sink_mut().clear();
2919
2920        r.engine_mut()
2921            .feed(writer, &wire(&[b"CMS.MERGE", b"cm", b"2", b"nj", b"nl"]));
2922        pump(&mut r, &mut batch);
2923        assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nj".to_owned())]);
2924    }
2925
2926    /// A subscriber on the four subkey channels and the writer that will feed
2927    /// them.
2928    ///
2929    /// The flags name no class channel, so what the subscriber gets is only
2930    /// what those four published and nothing is in the answer twice.
2931    fn watching_fields(flags: &[u8]) -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
2932        let (mut r, sub, mut batch) = engine();
2933        let writer = r.engine_mut().accept();
2934        r.engine_mut().feed(
2935            writer,
2936            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", flags]),
2937        );
2938        r.engine_mut()
2939            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__subkey*@0__:*"]));
2940        pump(&mut r, &mut batch);
2941        r.engine_mut().sink_mut().clear();
2942        (r, sub, writer, batch)
2943    }
2944
2945    /// The channel and payload of every subkey notification the subscriber got.
2946    ///
2947    /// Read off the wire rather than checked as one byte literal, because a
2948    /// command that publishes on all four channels at once makes for a literal
2949    /// nobody can hold in their head.
2950    fn carried(r: &Reactor<Wire<Recorder>>, sub: ConnId) -> Vec<(String, String)> {
2951        let sent = String::from_utf8_lossy(r.engine().sink().sent(sub)).into_owned();
2952        let mut out = Vec::new();
2953        let mut parts = sent.split("\r\n");
2954        while let Some(p) = parts.next() {
2955            if p != "pmessage" {
2956                continue;
2957            }
2958            // Each of the three that follow is a length and then the bytes, and
2959            // the first of them is the pattern, which is the same every time.
2960            let mut next = || {
2961                parts.next();
2962                parts.next().unwrap_or_default().to_owned()
2963            };
2964            next();
2965            let channel = next();
2966            out.push((channel, next()));
2967        }
2968        out
2969    }
2970
2971    /// The four channels each spell the same event a different way, and the
2972    /// field list they carry is length prefixed so that a field holding a comma
2973    /// reads back as one field and not two.
2974    #[test]
2975    fn the_subkey_channels_carry_the_fields_an_event_touched() {
2976        let (mut r, sub, writer, mut batch) = watching_fields(b"ASTIV");
2977
2978        r.engine_mut()
2979            .feed(writer, &wire(&[b"HSET", b"h", b"a,b", b"1", b"c", b"2"]));
2980        pump(&mut r, &mut batch);
2981        assert_eq!(
2982            carried(&r, sub),
2983            [
2984                ("__subkeyspace@0__:h", "hset|3:a,b,1:c"),
2985                ("__subkeyevent@0__:hset", "1:h|3:a,b,1:c"),
2986                ("__subkeyspaceitem@0__:h\na,b", "hset"),
2987                ("__subkeyspaceitem@0__:h\nc", "hset"),
2988                ("__subkeyspaceevent@0__:hset|h", "3:a,b,1:c"),
2989            ]
2990            .map(|(c, p)| (c.to_owned(), p.to_owned()))
2991        );
2992    }
2993
2994    /// A key holding a newline cannot be told apart from the field spelled
2995    /// after it on the per field channel, so that one channel is left out for
2996    /// it rather than sent something nobody can read back.
2997    #[test]
2998    fn a_key_holding_a_newline_skips_the_per_field_channel() {
2999        let (mut r, sub, writer, mut batch) = watching_fields(b"ASTIV");
3000
3001        r.engine_mut()
3002            .feed(writer, &wire(&[b"HSET", b"h\nx", b"f", b"1"]));
3003        pump(&mut r, &mut batch);
3004        assert_eq!(
3005            carried(&r, sub),
3006            [
3007                ("__subkeyspace@0__:h\nx", "hset|1:f"),
3008                ("__subkeyevent@0__:hset", "3:h\nx|1:f"),
3009                ("__subkeyspaceevent@0__:hset|h\nx", "1:f"),
3010            ]
3011            .map(|(c, p)| (c.to_owned(), p.to_owned()))
3012        );
3013    }
3014
3015    /// An event with no fields behind it goes out on the two ordinary channels
3016    /// and on none of these four, however they are set, which is every event
3017    /// outside the hash class and the `del` behind an emptied hash with it.
3018    #[test]
3019    fn an_event_with_no_fields_stays_off_the_subkey_channels() {
3020        let (mut r, sub, writer, mut batch) = watching_fields(b"AS");
3021
3022        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
3023        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
3024        r.engine_mut()
3025            .feed(writer, &wire(&[b"HSET", b"h", b"f", b"1"]));
3026        r.engine_mut().feed(writer, &wire(&[b"HDEL", b"h", b"f"]));
3027        pump(&mut r, &mut batch);
3028        assert_eq!(
3029            carried(&r, sub),
3030            [
3031                ("__subkeyspace@0__:h", "hset|1:f"),
3032                ("__subkeyspace@0__:h", "hdel|1:f"),
3033            ]
3034            .map(|(c, p)| (c.to_owned(), p.to_owned()))
3035        );
3036    }
3037
3038    /// A subscriber, a writer and a clock the test moves by hand.
3039    ///
3040    /// The same arrangement [`watching`] sets up, on the fixed clock
3041    /// [`timed`] builds, because every deadline in a test has to arrive on
3042    /// request rather than in its own time.
3043    fn watching_clock() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
3044        let (mut r, sub, mut batch) = timed();
3045        let writer = r.engine_mut().accept();
3046        r.engine_mut().feed(
3047            writer,
3048            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
3049        );
3050        r.engine_mut()
3051            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
3052        pump(&mut r, &mut batch);
3053        r.engine_mut().sink_mut().clear();
3054        (r, sub, writer, batch)
3055    }
3056
3057    /// A key that reached its deadline says so when a reader trips over it, and
3058    /// the reader's own command says nothing, because as far as it is concerned
3059    /// the key was never there.
3060    #[test]
3061    fn a_deadline_that_passed_is_news_when_a_reader_finds_it() {
3062        let (mut r, sub, writer, mut batch) = watching_clock();
3063
3064        r.engine_mut()
3065            .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
3066        pump(&mut r, &mut batch);
3067        r.engine_mut().sink_mut().clear();
3068
3069        r.engine().server().advance_clock_ms(50);
3070        r.engine_mut().feed(writer, &wire(&[b"GET", b"k"]));
3071        pump(&mut r, &mut batch);
3072        assert_eq!(
3073            fired(&r, sub),
3074            [("expired", "k")].map(|(e, k)| (e.to_owned(), k.to_owned())),
3075            "and not a del alongside it, which is a different piece of news"
3076        );
3077    }
3078
3079    /// And a key nobody ever reads back says it too, because the housekeeping
3080    /// the driver runs between batches goes looking for them.
3081    ///
3082    /// This is the whole reason a cache that writes under a deadline and never
3083    /// reads does not grow forever, and it is worth a test of its own: the sweep
3084    /// lives behind a driver call rather than behind a command, so nothing in
3085    /// the command tests would notice if it stopped running.
3086    #[test]
3087    fn a_deadline_that_passed_is_news_with_nobody_reading() {
3088        let (mut r, sub, writer, mut batch) = watching_clock();
3089
3090        r.engine_mut()
3091            .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
3092        pump(&mut r, &mut batch);
3093        r.engine_mut().sink_mut().clear();
3094
3095        r.engine().server().advance_clock_ms(50);
3096        // Nothing to run, so this turn is housekeeping and nothing else.
3097        pump(&mut r, &mut batch);
3098        assert_eq!(
3099            fired(&r, sub),
3100            [("expired", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
3101        );
3102
3103        r.engine_mut().sink_mut().clear();
3104        pump(&mut r, &mut batch);
3105        assert!(fired(&r, sub).is_empty(), "and it only goes once");
3106    }
3107
3108    /// A key an eviction took says that instead, since a client that lost a key
3109    /// to a memory limit and a client whose key ran out of time are owed two
3110    /// different explanations.
3111    #[test]
3112    fn a_key_a_limit_took_says_it_was_evicted() {
3113        let (mut r, sub, writer, mut batch) = watching();
3114
3115        let val = vec![b'v'; 256];
3116        for i in 0..2000u32 {
3117            let k = format!("key:{i:08}");
3118            r.engine_mut()
3119                .feed(writer, &wire(&[b"SET", k.as_bytes(), &val]));
3120        }
3121        pump(&mut r, &mut batch);
3122        r.engine().server().refresh_memory();
3123        let full = r.engine().server().memory_bytes();
3124        r.engine_mut().sink_mut().clear();
3125
3126        // Under what it is already holding, so the next write has to take
3127        // something out before it can put anything in.
3128        let limit = (full / 2).to_string();
3129        r.engine_mut().feed(
3130            writer,
3131            &wire(&[b"CONFIG", b"SET", b"maxmemory-policy", b"allkeys-random"]),
3132        );
3133        r.engine_mut().feed(
3134            writer,
3135            &wire(&[b"CONFIG", b"SET", b"maxmemory", limit.as_bytes()]),
3136        );
3137        r.engine_mut()
3138            .feed(writer, &wire(&[b"SET", b"newcomer", &val]));
3139        pump(&mut r, &mut batch);
3140
3141        let events = fired(&r, sub);
3142        assert!(
3143            events.iter().any(|(e, _)| e == "evicted"),
3144            "the write made room and never said so: {events:?}"
3145        );
3146        assert!(
3147            events
3148                .iter()
3149                .all(|(e, k)| e != "evicted" || k != "newcomer"),
3150            "the key the write was for is the one key it cannot have taken"
3151        );
3152    }
3153
3154    /// Inside a transaction each command's notifications go out before the
3155    /// next command runs, so `EXEC` does not bunch them all up at the end.
3156    #[test]
3157    fn a_transaction_publishes_between_its_commands_and_not_after_them() {
3158        let (mut r, sub, mut batch) = engine();
3159        let writer = r.engine_mut().accept();
3160
3161        r.engine_mut().feed(
3162            writer,
3163            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
3164        );
3165        r.engine_mut()
3166            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
3167        pump(&mut r, &mut batch);
3168        r.engine_mut().sink_mut().clear();
3169
3170        r.engine_mut().feed(writer, &wire(&[b"MULTI"]));
3171        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
3172        r.engine_mut().feed(writer, &wire(&[b"DEL", b"k"]));
3173        r.engine_mut().feed(writer, &wire(&[b"EXEC"]));
3174        pump(&mut r, &mut batch);
3175        assert_eq!(
3176            r.engine().sink().sent(sub),
3177            b"*4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
3178              $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n\
3179              *4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
3180              $18\r\n__keyevent@0__:del\r\n$1\r\nk\r\n"
3181        );
3182    }
3183
3184    #[test]
3185    fn a_reply_the_socket_would_not_take_is_offered_again() {
3186        let mut r = Reactor::inline(Wire::new(Trickle::default()));
3187        let conn = r.engine_mut().accept();
3188        let mut batch = Vec::new();
3189
3190        r.engine_mut().feed(conn, &wire(&[b"PING"]));
3191        pump(&mut r, &mut batch);
3192        // Two flushes in a pump, so four bytes and then three.
3193        assert_eq!(r.engine().sink().sent, b"+PONG\r\n");
3194        assert_eq!(r.engine().sink().writes, 2);
3195    }
3196}