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, Reply, 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    /// This thread's connections that are holding a command because the server
194    /// is paused.
195    ///
196    /// The connection and the client id that was on it, for the reason the
197    /// waiter list keeps both: a slot is reused and an id is not, and this is
198    /// what decides which connection gets let go of. Empty on a server nobody
199    /// has paused, which is what keeps the check on the flush path to a length.
200    held: Vec<(ConnId, u64)>,
201}
202
203impl<S: Sink> Wire<S> {
204    /// An engine with an empty server.
205    #[must_use]
206    pub fn new(sink: S) -> Wire<S> {
207        Wire::with_server(Server::new(), sink)
208    }
209
210    /// An engine over a server the caller built, which is how a test gives it a
211    /// clock it can move by hand.
212    #[must_use]
213    pub fn with_server(server: Server, sink: S) -> Wire<S> {
214        Wire::over(Arc::new(server), sink)
215    }
216
217    /// An engine over a server that already exists, which is how the second
218    /// thread and every thread after it gets one.
219    ///
220    /// Each thread builds its own front and they never see each other's. What
221    /// they share is behind the handle, and the reason the handle is counted
222    /// rather than borrowed is that the threads outlive whichever call started
223    /// them by design: a scope that borrows would tie the server's lifetime to
224    /// a frame that is meant to return.
225    #[must_use]
226    pub fn over(server: Arc<Server>, sink: S) -> Wire<S> {
227        Wire {
228            front: Front::new(sink),
229            parked: Vec::new(),
230            post: Vec::new(),
231            held: Vec::new(),
232            server,
233        }
234    }
235
236    /// The databases and the numbers `INFO` reports.
237    #[must_use]
238    pub fn server(&self) -> &Server {
239        &self.server
240    }
241
242    /// Another handle on the same server, for building the next thread's
243    /// engine.
244    #[must_use]
245    pub fn shared(&self) -> Arc<Server> {
246        Arc::clone(&self.server)
247    }
248
249    /// The server, for the few settings that have to be made before it is
250    /// serving.
251    ///
252    /// That is the directory and the thread count, both of which are read
253    /// everywhere and written once at startup, so they are settings and not
254    /// state. This works while this engine holds the only handle, which is the
255    /// case from the moment the server is built until the threads are started,
256    /// and it is the caller's job to do its setting up in that window.
257    ///
258    /// # Panics
259    ///
260    /// If a second handle already exists, because there is no honest answer to
261    /// give: changing the directory under a thread that is already serving out
262    /// of it is the bug this would otherwise hide.
263    pub fn server_mut(&mut self) -> &mut Server {
264        Arc::get_mut(&mut self.server)
265            .expect("the server is set up before the threads that share it are started")
266    }
267
268    /// Where the replies went.
269    #[must_use]
270    pub const fn sink(&self) -> &S {
271        self.front.sink()
272    }
273
274    /// The same, mutably.
275    pub const fn sink_mut(&mut self) -> &mut S {
276        self.front.sink_mut()
277    }
278
279    /// Change the protocol limits, which is `proto-max-bulk-len` and friends.
280    pub fn set_limits(&mut self, limits: Limits) {
281        self.front.set_limits(limits);
282    }
283
284    /// Open a connection and give back its id.
285    pub fn accept(&mut self) -> ConnId {
286        self.server.counted().opened();
287        let at = self.front.open(self.server.next_client());
288        let now = self.server.now_ms();
289        // Whether this connection has to say a password before it says anything
290        // else, decided here and not on the first command, which is what leaves
291        // the connections that are already open alone when a password is set
292        // under them. See the `auth` module.
293        let guarded = self.server.guarded();
294        let row = if let Some(session) = self.front.session_mut(at) {
295            session.opened(now);
296            session.admit(!guarded);
297            Some(session.row().clone())
298        } else {
299            None
300        };
301        // The row goes into the table here and not in the front, because the
302        // front cannot reach the server and because this is the one place that
303        // knows both which thread the connection landed on and that it is now
304        // ready to be reported on.
305        if let Some(row) = row {
306            self.server.register_client(&row);
307        }
308        self.note_buffers();
309        at
310    }
311
312    /// The same, for a caller that knows what the socket underneath is.
313    ///
314    /// The two addresses arrive already in the spelling `CLIENT INFO` reports
315    /// them in, because turning a socket address into that spelling belongs to
316    /// whoever has the socket. A caller with no socket to describe uses
317    /// `Engine::accept` and the connection reports an empty address and a
318    /// descriptor of minus one, which is every embedded caller and every test.
319    pub fn accept_from(&mut self, peer: &str, local: &str, fd: i32, unix: bool) -> ConnId {
320        let at = self.accept();
321        if let Some(session) = self.front.session_mut(at) {
322            session.set_socket(peer, local, fd, unix);
323        }
324        at
325    }
326
327    /// Tell the server what the connection buffers are holding now.
328    ///
329    /// The front cannot reach the server, so it keeps the change and this is
330    /// where it is handed over: at the end of whichever call moved a buffer.
331    fn note_buffers(&mut self) {
332        let delta = self.front.buffer_delta();
333        if delta != 0 {
334            self.server.note_conn_bytes(delta);
335        }
336    }
337
338    /// The peer went away.
339    ///
340    /// Whatever is buffered for it is dropped rather than written, and the slot
341    /// comes back as soon as the commands already framed out of its buffer have
342    /// run, because those commands' arguments still point into it.
343    pub fn hangup(&mut self, conn: ConnId) {
344        if !self.front.live(conn) {
345            return;
346        }
347        self.front.mark_gone(conn);
348        // A parked client holds its own commands, and those commands are what
349        // `pending` counts, so leaving it parked here would leave the slot owed
350        // to a connection that is never going to be answered. They go back to
351        // the queue and run as the no-ops a gone connection's commands are.
352        if self.front.blocked(conn) {
353            self.front.unpark(conn);
354        }
355        if self.front.pending(conn) == 0 {
356            self.release(conn);
357        }
358        self.note_buffers();
359    }
360
361    /// Answer everybody this thread can answer, and let go of everybody whose
362    /// deadline has passed.
363    ///
364    /// The walk is over the waiter list rather than over the connections, so it
365    /// costs what blocking costs and not what the server costs. Every caller
366    /// checks that somebody is parked before calling, which is the load and the
367    /// branch a server with nobody blocked pays.
368    ///
369    /// Only this thread's waiters, because a reply goes into a buffer this
370    /// thread owns and another thread's waiter is another thread's to answer.
371    /// The list is copied out under the lock and then let go of, so the work of
372    /// answering does not hold up a thread trying to park a client.
373    fn serve_waiters(&mut self) {
374        let now = self.server.now_ms();
375        let mine = self.server.my_slot();
376        self.server.waiters().mine(mine, &mut self.parked);
377        for at in 0..self.parked.len() {
378            let p = self.parked[at];
379            // The slot is reused and the client id is not. `release` forgets
380            // waiters, so this should never fire; it is here because being
381            // wrong about it writes a reply into somebody else's socket rather
382            // than dropping one.
383            if !self.front.answers(p.conn, p.client) {
384                self.server.forget_waiters(p.client);
385                continue;
386            }
387            // The front cannot reach the databases and the server cannot reach
388            // the connections, so the two halves are taken apart here and the
389            // one buffer this waiter needs is handed over.
390            let served = {
391                let Wire { server, front, .. } = self;
392                server.serve_waiter(p.client, now, front.out(p.conn))
393            };
394            if served {
395                self.server.forget_waiters(p.client);
396                self.front.unpark(p.conn);
397                self.front.soil(p.conn);
398            }
399        }
400        self.parked.clear();
401    }
402
403    /// Write out everything published for this thread's connections.
404    ///
405    /// The mailbox is emptied under its lock and then let go of, so a thread
406    /// rendering a thousand messages is not holding up the publishers filling
407    /// its box. The client id on each envelope is checked against the slot
408    /// because a slot is reused and an id is not, which is the same guard the
409    /// waiter list uses and for the same reason: being wrong here writes into
410    /// somebody else's socket rather than dropping a message.
411    fn deliver(&mut self) {
412        // Taken and put back so the loop can reach the front, the way the dirty
413        // list is. The capacity comes back with it.
414        let mut post = core::mem::take(&mut self.post);
415        self.server.take_mail(&mut post);
416        for env in post.drain(..) {
417            let conn = env.conn();
418            if !self.front.answers(conn, env.client()) {
419                continue;
420            }
421            env.write(self.front.out(conn));
422            self.front.soil(conn);
423        }
424        self.post = post;
425    }
426
427    /// How many connections are open.
428    #[must_use]
429    pub fn clients(&self) -> usize {
430        self.front.clients()
431    }
432
433    /// Commands framed and waiting for the reactor.
434    #[must_use]
435    pub fn ready(&self) -> usize {
436        self.front.ready()
437    }
438
439    /// Connections with a reply that has not gone out yet.
440    ///
441    /// Non zero means a socket was full and what is left is being held for a
442    /// later flush, which a driver waiting on readability needs to know: there
443    /// is work here that no incoming byte will ever wake it up for.
444    #[must_use]
445    pub fn owed(&self) -> usize {
446        self.front.owed()
447    }
448
449    /// Clients of this thread's that are blocked on a key, and ones it is
450    /// holding a command for because the server is paused.
451    ///
452    /// The other thing a driver waiting on readability needs to know, and for
453    /// the same reason `owed` is: there is work here that no incoming byte will
454    /// wake it for. A blocked client is answered by a write another thread made
455    /// or by its own deadline passing, a held one by a deadline nobody else can
456    /// see, and none of those is a byte arriving on this thread's poller, so a
457    /// driver that reads this keeps its wait short while anybody is waiting on
458    /// it.
459    #[must_use]
460    pub fn waiting(&self) -> usize {
461        self.server.parked_here() + self.held.len()
462    }
463
464    /// Mail waiting for this thread, plus subscribers of its own that mail
465    /// could arrive for.
466    ///
467    /// The third thing a driver waiting on readability needs to know, and for
468    /// the reason the other two are: a published message is a write another
469    /// thread made and no byte arriving here will wake this thread for it. So a
470    /// thread that has a subscriber keeps its wait short, and one that has none
471    /// is not affected.
472    #[must_use]
473    pub fn posted(&self) -> usize {
474        self.server.posted()
475    }
476
477    /// Whether a client has asked the server to stop.
478    ///
479    /// The driver reads this once a turn, next to the flag a signal sets, and
480    /// leaves its loop when either is set. Asked after the batch rather than
481    /// during it, so the `SHUTDOWN` and everything that shared its batch is
482    /// finished and written out before anything closes.
483    #[must_use]
484    pub fn stopping(&self) -> bool {
485        self.server.stopping()
486    }
487
488    /// Decoders in the pool, which is the high water mark of one batch.
489    #[must_use]
490    pub fn decoders(&self) -> usize {
491        self.front.decoders()
492    }
493
494    /// What every connection's read and reply buffers are holding.
495    #[must_use]
496    pub fn buffer_bytes(&self) -> usize {
497        self.front.buffer_bytes()
498    }
499
500    /// Take bytes off a connection and frame whatever commands they complete.
501    ///
502    /// Anything left over stays in the connection's buffer, half a command
503    /// included, so the caller hands over whatever the socket gave it without
504    /// looking at it.
505    pub fn feed(&mut self, conn: ConnId, bytes: &[u8]) {
506        self.front.feed(conn, bytes);
507        self.note_buffers();
508    }
509
510    /// Hand the slot and its buffers back, and let the server go of the client.
511    fn release(&mut self, conn: ConnId) {
512        // Before the slot goes back, because the watches this connection took
513        // are rows on the server and the session that names them is about to be
514        // reused by whoever gets the slot next.
515        if let Some(session) = self.front.session_mut(conn) {
516            dispatch::forget_session(&self.server, session);
517        }
518        let Some(client) = self.front.close(conn) else {
519            return;
520        };
521        self.forget(client);
522    }
523
524    /// The server side of a connection ending.
525    ///
526    /// It happens in the same call the slot was freed in, and before anything
527    /// else can run, because the slot is handed out again by the next accept
528    /// and a waiter still holding this client id would then be a waiter
529    /// pointing at somebody else's connection.
530    fn forget(&mut self, client: u64) {
531        self.server.forget_waiters(client);
532        self.server.forget_client(client);
533        self.server.counted().closed();
534    }
535
536    /// Close the connections of this thread's that somebody has killed.
537    ///
538    /// The pair on the row is a slot and a client id, and the slot is reused
539    /// while the id is not, so the id is checked back against the front before
540    /// anything happens: a row that outlived its connection would otherwise
541    /// close whoever took the slot next.
542    /// Give every connection this thread is holding its commands back.
543    ///
544    /// In the order they were held, so a pause that caught two connections lets
545    /// them go in the order they arrived. The commands go back to the front of
546    /// the ready queue and run on the next pass, which is this same turn of the
547    /// loop: nothing is written here, because nothing was written when they were
548    /// held.
549    fn resume(&mut self) {
550        // Taken and put back so the loop can reach the front, the way the dirty
551        // list is. The capacity comes back with it.
552        let mut held = core::mem::take(&mut self.held);
553        for &(conn, client) in &held {
554            // The slot is reused and the client id is not. A connection that
555            // went away while it was held was already given its commands back by
556            // `hangup`, so this is the check that stops them being handed back
557            // twice, to whoever has the slot now.
558            if self.front.answers(conn, client) && self.front.blocked(conn) {
559                self.front.unpark(conn);
560            }
561        }
562        held.clear();
563        self.held = held;
564    }
565
566    fn reap(&mut self) {
567        for (conn, client) in self.server.my_kills() {
568            self.server.kill_done();
569            if self.front.answers(conn, client) {
570                self.hangup(conn);
571            }
572        }
573    }
574
575    /// Move up to `max` framed commands into `into`.
576    ///
577    /// The reactor wants a batch it owns, and the front keeps the buffers, so
578    /// what crosses between them is this: numbers, no borrows.
579    pub fn take_ready(&mut self, into: &mut Vec<Cmd>, max: usize) -> usize {
580        self.front.take_ready(into, max)
581    }
582
583    /// Take a clock reading for the whole batch.
584    ///
585    /// `04` section 5: once per turn, never per command, so every command in a
586    /// batch compares against the same millisecond and two keys written
587    /// together expire together.
588    pub fn tick(&mut self) {
589        self.server.refresh_clock();
590    }
591
592    /// Do one batch's worth of housekeeping.
593    ///
594    /// That is the dead keys and then one segment of arena compaction at most,
595    /// which between them are what stop a server that rewrites the same keys,
596    /// or writes them under a deadline and never reads them back, from holding
597    /// every version of everything it has ever been sent. It is separate from
598    /// [`Wire::tick`] because the clock has to move before a batch runs and this
599    /// does not: it can wait until the replies are out, and the driver decides
600    /// when that is.
601    ///
602    /// Per batch and not per turn of the loop. A turn can carry one command or
603    /// a thousand, so a per turn call means the rate at which garbage is
604    /// collected has nothing to do with the rate at which it is made, and on a
605    /// saturated server the second one wins. That was measured: with this on
606    /// the loop's turn the server settled at seven segments for six segments'
607    /// worth of keys, which is where an unloaded process running the same
608    /// writes settled at six.
609    pub fn maintain(&mut self) -> Option<usize> {
610        // `DEBUG PAUSE-CRON 1`, which stops the lot rather than any one part of
611        // it, because that is what it stops on a real server: the whole of
612        // `serverCron` and not a chosen job inside it. The clock is not in here,
613        // so a paused server still knows what time it is and still expires a key
614        // somebody reads.
615        if !self.server.cron_running() {
616            return None;
617        }
618        // Before the compaction and not after it, because the reading the next
619        // batch judges its limit against should be the one taken after the last
620        // batch's writes rather than the one taken after this call's collecting.
621        // Both are true, and the first is the one that is a batch old at worst.
622        // Nothing at all on a server with no `maxmemory`, which is the default.
623        self.server.refresh_memory();
624        // Two fields and a return on a server that has never taken a backup,
625        // which is nearly all of them. It is here rather than on a timer for the
626        // same reason the compaction is: one loop turns everything.
627        self.server.backup_expire();
628        // The keys whose deadline has passed with nobody there to read them
629        // back. A slice's worth at most and gated to once a millisecond inside,
630        // so a driver that calls this after every batch does not turn a busy
631        // server into a server that spends its time sampling.
632        self.server.expire_slice(SWEEP_LOOKS);
633        self.server.compact_step()
634    }
635}
636
637impl<S: Sink> Engine for Wire<S> {
638    type Work = Cmd;
639
640    fn key_hash(&self, cmd: &Cmd) -> Option<u64> {
641        // Before the argument list is built, because most of the commands that
642        // get this far and answer `None` answer it on the spec alone, and
643        // building an `Args` to then throw it away is the sort of thing that
644        // does not show up in a profile and does show up in a total.
645        let spec = table::at(cmd.spec)?;
646        if spec.first_key <= 0 {
647            return None;
648        }
649        let args = self.front.args(cmd);
650        // The first key only. A command with more than one, which is `MSET` and
651        // `MGET`, warms the first and takes the miss on the rest; warming all of
652        // them means a hash list per command and that is the batch's own job
653        // once multi key commands are worth measuring.
654        let key = args.opt(spec.first_key as usize)?;
655        Some(Keyspace::hash_of(key))
656    }
657
658    fn prefetch(&self, cmd: &Cmd, hash: u64) {
659        let db = self.front.db(cmd.conn());
660        // The hash picks the stripe as well as the record, so this warms the
661        // line the command is going to read and not a line on some other
662        // stripe. It is the same hash the command itself will route on, which
663        // is why the stripe is worked out from a hash rather than from a key.
664        self.server.striped_ref(db).prefetch_hashed(hash);
665    }
666
667    fn run(&mut self, cmd: Cmd, _hash: Option<u64>) -> yo_reactor::Flow {
668        let conn = cmd.conn();
669        // Framed with the batch that blocked, so it is a command the client sent
670        // before it knew it would be waiting. It keeps its decoder and it keeps
671        // its place in `pending`, which is what stops the buffer it points into
672        // being compacted while it waits.
673        if self.front.blocked(conn) {
674            self.front.park(conn, cmd);
675            return yo_reactor::Flow::Next;
676        }
677
678        // The one place both halves are held at once. The front hands over the
679        // arguments, the session and the reply buffer, the server hands over
680        // the databases, and the command layer sees the two as one call.
681        let flow = if self.front.start(&cmd) {
682            let Wire { front, server, .. } = self;
683            let (args, session, out) = front.parts(&cmd);
684            let spec = table::at(cmd.spec);
685            let mark = out.len();
686            let flow = dispatch::resolved(server, session, spec, args, out);
687            // A command the pause held has not run and is going to be run
688            // again, so none of the bookkeeping below happens for it: it is not
689            // a command this connection has sent yet, as far as everything that
690            // counts commands and steps the reply mode is concerned.
691            if flow != Flow::Hold {
692                // `CLIENT REPLY` is the one thing that can take a reply back
693                // after the command has written it, and this is the only place
694                // holding both the buffer and the decision. The mode is read
695                // after the command rather than before so that `CLIENT REPLY
696                // ON` still answers, which is what a client turning replies
697                // back on needs and is what a real server does.
698                session.finished();
699                session.note_proto(out.proto().version());
700                let mode = session.reply_mode();
701                session.step_reply();
702                if mode != Reply::On {
703                    out.truncate(mark);
704                }
705            }
706            flow
707        } else {
708            // Nobody to answer, or nobody who should be. The decoder still has
709            // to come back and the slot still has to be released, which is why
710            // this is not an early return.
711            Flow::Continue
712        };
713
714        // The server is paused and this command has not run. It goes back to the
715        // connection, decoder and all, and the connection stops taking commands
716        // until the pause is over, which is the same shape a blocking command
717        // leaves things in. The client id goes on this thread's list because a
718        // slot is reused and an id is not, and letting go is the one thing that
719        // must not happen to the wrong connection.
720        if flow == Flow::Hold {
721            self.front.hold(conn, cmd);
722            let client = self.front.client(conn);
723            yo_alloc::allow(|| self.held.push((conn, client)));
724            return yo_reactor::Flow::Next;
725        }
726
727        self.front.done(&cmd);
728        if self.front.gone(conn) {
729            if self.front.pending(conn) == 0 {
730                self.release(conn);
731            }
732        } else {
733            match flow {
734                Flow::Close => {
735                    self.front.quit(conn);
736                    self.front.soil(conn);
737                }
738                // Nothing was written, so there is nothing to flush and no
739                // reason to put this connection on the dirty list. The waiter
740                // carries the slot from here on, and it needs to know which one:
741                // the command layer only ever saw the client id.
742                Flow::Block => {
743                    self.front.block(conn);
744                    let client = self.front.client(conn);
745                    self.server.bind_waiter(client, conn);
746                }
747                // Answered above and returned from there, so there is nothing
748                // left to do with it here.
749                Flow::Hold => {}
750                Flow::Continue => self.front.soil(conn),
751            }
752        }
753
754        // After each command and not once per batch. A client blocked on two
755        // keys and woken by `RPUSH b` then `RPUSH a` in one pipeline has to
756        // answer with `b`, because that is the push that was in front of it, and
757        // it can only do that if it was served in between the two.
758        if self.server.parked_here() != 0 {
759            self.serve_waiters();
760        }
761        yo_reactor::Flow::Next
762    }
763
764    fn flush(&mut self) {
765        // The deadline sweep, and it is here because this is the one thing the
766        // driver calls on a turn that ran nothing at all. A client whose timeout
767        // passes while the server is idle is answered within the loop's idle
768        // wait, which the loop shortens to a millisecond on a thread that has
769        // somebody waiting. That is finer than the 10hz Redis checks its own
770        // blocked clients at.
771        //
772        // This thread's count and not the server's, because the sweep can only
773        // answer this thread's waiters, so on any other thread it is a lock
774        // taken to find nothing.
775        if self.server.parked_here() != 0 {
776            self.server.refresh_clock();
777            self.serve_waiters();
778        }
779
780        // Then the connections this thread is holding a command for, if the
781        // pause they are waiting on has run out. A length on a server nobody has
782        // paused, and it is here for the reason the sweep above is: the pause
783        // ends by a clock and not by anything arriving, so the turn that ran
784        // nothing is the turn that has to notice.
785        if !self.held.is_empty() {
786            self.server.refresh_clock();
787            if self.server.paused(self.server.now_ms()).is_none() {
788                self.resume();
789            }
790        }
791
792        // Then the connections another thread asked to have closed. One load on
793        // a server nobody has run `CLIENT KILL` on, which is nearly all of them,
794        // and it is here rather than beside the command because the buffers of
795        // the connection being closed belong to this thread.
796        if self.server.kills() != 0 {
797            self.reap();
798        }
799
800        // Then the published messages, before the write out below and after
801        // everything this batch answered, which is the order a client that
802        // publishes to itself sees on a real server: the count first and the
803        // message second, checked on the wire against 8.10.1.
804        if self.server.mail_here() != 0 {
805            self.deliver();
806        }
807
808        // Taken and put back so the loop below can reach the rest of the
809        // engine. The capacity comes back with it, so this is not an
810        // allocation.
811        let mut dirty = self.front.take_dirty();
812        let mut at = 0;
813        while at < dirty.len() {
814            let conn = dirty[at];
815            match self.front.write_out(conn) {
816                // The socket was full. The connection stays on the list with
817                // what is left of its reply, and the next flush offers it
818                // again, which is the whole of the backpressure story here.
819                Wrote::Owed => at += 1,
820                Wrote::Done => {
821                    dirty.swap_remove(at);
822                }
823                Wrote::Ended(client) => {
824                    self.forget(client);
825                    dirty.swap_remove(at);
826                }
827            }
828        }
829        self.front.give_dirty(dirty);
830        self.note_buffers();
831    }
832
833    fn maintain(&mut self, budget: &mut yo_reactor::Budget) {
834        // The clock is the first thing the maintenance slice does, because
835        // everything else in it compares against a time.
836        if !budget.spend(1) {
837            return;
838        }
839        self.tick();
840        // Then the dead keys, which is what stops a cache that writes with a
841        // deadline and never reads back from holding every key it has ever
842        // written. One unit a key looked at, so the slice bounds the sweep the
843        // same way it bounds everything else in here, and a server where nothing
844        // has a deadline spends nothing at all.
845        let looks = budget.left() as usize;
846        let spent = self.server.expire_slice(looks);
847        budget.spend(u32::try_from(spent).unwrap_or(u32::MAX));
848    }
849}
850
851/// Run everything that is framed, in batches, and write the replies.
852///
853/// The inline driver: it is what a caller who is already on the shard thread
854/// uses in place of the loop, and it goes through the same two walks the loop
855/// goes through (`15` section 7). `batch` is the caller's, so a driver in a hot
856/// loop hands the same `Vec` back every time and never allocates.
857pub fn pump<S: Sink>(reactor: &mut Reactor<Wire<S>>, batch: &mut Vec<Cmd>) -> usize {
858    let mut ran = 0;
859    reactor.engine_mut().tick();
860    // The outer round is for the pause and nothing else. The flush at the end of
861    // the inner one is what lets go of a connection the pause was holding, and
862    // what that hands back is commands rather than replies, so there has to be
863    // somewhere for them to run. It goes round twice at most: the pause is over
864    // by the time anything is handed back, so nothing can be held again.
865    loop {
866        loop {
867            batch.clear();
868            if reactor.engine_mut().take_ready(batch, BATCH_MAX) == 0 {
869                break;
870            }
871            // The command path, and therefore the thing Y7 is about. The guard is
872            // what arms `yo-alloc`, and it covers dispatch and nothing else: framing
873            // before it and writing the replies after it are both allowed to reach
874            // for the heap, and only running the commands is not.
875            //
876            // It goes here rather than around the whole loop because `take_ready`
877            // and `flush` are on the other side of that line, and because a batch is
878            // the unit a caller can reason about. Under the default mode this is one
879            // relaxed load.
880            let armed = yo_alloc::guard();
881            ran += reactor.execute_all(batch.drain(..));
882            drop(armed);
883            reactor.engine_mut().flush();
884            // After the replies are out, so the batch that made the garbage is not
885            // the batch that waits for it to be collected.
886            reactor.engine_mut().maintain();
887        }
888        // Once for a turn that ran nothing at all, which is where a server that has
889        // gone quiet catches up on what the last busy turn left behind.
890        reactor.engine_mut().maintain();
891        // Then once more for a connection with something to say and nothing to run:
892        // a protocol error, or a socket that was full the last time round, or a
893        // subscriber the housekeeping above owes the news that a key it was told to
894        // watch reached its deadline. That last one is why the flush is after the
895        // call rather than before it: an idle server turns every twenty
896        // milliseconds, and news that waits for the next turn is news that arrives
897        // twenty milliseconds after the thing it is about.
898        reactor.engine_mut().flush();
899        if reactor.engine().ready() == 0 {
900            break;
901        }
902    }
903    ran
904}
905
906#[cfg(test)]
907mod tests {
908    use super::*;
909
910    /// The wire bytes for a command, built the way a client would.
911    fn wire(args: &[&[u8]]) -> Vec<u8> {
912        let mut b = format!("*{}\r\n", args.len()).into_bytes();
913        for a in args {
914            b.extend_from_slice(format!("${}\r\n", a.len()).as_bytes());
915            b.extend_from_slice(a);
916            b.extend_from_slice(b"\r\n");
917        }
918        b
919    }
920
921    fn engine() -> (Reactor<Wire<Recorder>>, ConnId, Vec<Cmd>) {
922        let mut r = Reactor::inline(Wire::new(Recorder::new()));
923        let conn = r.engine_mut().accept();
924        (r, conn, Vec::new())
925    }
926
927    /// Where the fixed clock a blocking test moves by hand starts.
928    const START_MS: u64 = 1_000_000;
929
930    /// The same, on a clock the test moves rather than the system's.
931    ///
932    /// A test about a timeout cannot wait for one: waiting a hundred
933    /// milliseconds is a test that fails on a loaded machine and waiting a
934    /// hundred seconds is not a test.
935    fn timed() -> (Reactor<Wire<Recorder>>, ConnId, Vec<Cmd>) {
936        let server = crate::dispatch::Server::with_clock(yo_kv::Clock::fixed(START_MS));
937        let mut r = Reactor::inline(Wire::with_server(server, Recorder::new()));
938        let conn = r.engine_mut().accept();
939        (r, conn, Vec::new())
940    }
941
942    #[test]
943    fn a_pipelined_batch_comes_back_in_order_and_in_one_write() {
944        let (mut r, conn, mut batch) = engine();
945        let mut stream = wire(&[b"SET", b"k", b"v"]);
946        stream.extend(wire(&[b"GET", b"k"]));
947        stream.extend(wire(&[b"INCR", b"n"]));
948
949        r.engine_mut().feed(conn, &stream);
950        assert_eq!(r.engine().ready(), 3);
951        assert_eq!(pump(&mut r, &mut batch), 3);
952
953        assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$1\r\nv\r\n:1\r\n");
954        assert_eq!(r.engine().ready(), 0);
955    }
956
957    /// The framing has to survive a command arriving in pieces, because that is
958    /// what a socket does.
959    #[test]
960    fn a_command_split_across_reads_resumes_rather_than_restarts() {
961        let (mut r, conn, mut batch) = engine();
962        let bytes = wire(&[b"SET", b"key", b"value"]);
963
964        for at in 1..bytes.len() {
965            r.engine_mut().feed(conn, &bytes[at - 1..at]);
966            assert_eq!(r.engine().ready(), 0, "not a command yet at {at}");
967        }
968        r.engine_mut().feed(conn, &bytes[bytes.len() - 1..]);
969        assert_eq!(r.engine().ready(), 1);
970        assert_eq!(pump(&mut r, &mut batch), 1);
971        assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
972
973        // And the value that arrived in single bytes is the value that was
974        // stored, which is the part a naive resume gets wrong.
975        r.engine_mut().feed(conn, &wire(&[b"GET", b"key"]));
976        pump(&mut r, &mut batch);
977        assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$5\r\nvalue\r\n");
978    }
979
980    #[test]
981    fn two_connections_are_two_sessions_over_one_server() {
982        let (mut r, a, mut batch) = engine();
983        let b = r.engine_mut().accept();
984
985        r.engine_mut().feed(a, &wire(&[b"SELECT", b"3"]));
986        r.engine_mut().feed(a, &wire(&[b"SET", b"k", b"a"]));
987        r.engine_mut().feed(b, &wire(&[b"SET", b"k", b"b"]));
988        r.engine_mut().feed(a, &wire(&[b"GET", b"k"]));
989        r.engine_mut().feed(b, &wire(&[b"GET", b"k"]));
990        pump(&mut r, &mut batch);
991
992        assert_eq!(r.engine().sink().sent(a), b"+OK\r\n+OK\r\n$1\r\na\r\n");
993        assert_eq!(r.engine().sink().sent(b), b"+OK\r\n$1\r\nb\r\n");
994        assert_eq!(r.engine().clients(), 2);
995    }
996
997    /// The point of the whole exercise: two engines, two threads, one server.
998    ///
999    /// The server is told it will have two threads before either starts, the
1000    /// way `yodb serve` tells it. Without that it has one set of counters and
1001    /// both threads land on it, which is the wrap round `Server::mine_at`
1002    /// documents and which loses counts: a bump is a load and a store rather
1003    /// than a fetch and add, because the fast path is one thread writing its
1004    /// own set and paying for a locked instruction on every command to make a
1005    /// shared set exact would be paying it on the path that is never shared.
1006    /// Miri found this by running the two threads far enough apart to lose one,
1007    /// which a real machine does rarely enough to have passed here for months.
1008    #[test]
1009    fn two_threads_write_into_one_server() {
1010        const EACH: usize = 200;
1011
1012        let mut server = Server::new();
1013        server.set_threads(2);
1014        let first = Wire::with_server(server, Recorder::new());
1015        let second = Wire::over(first.shared(), Recorder::new());
1016        let server = first.shared();
1017
1018        std::thread::scope(|s| {
1019            for (at, engine) in [first, second].into_iter().enumerate() {
1020                s.spawn(move || {
1021                    let mut r = Reactor::inline(engine);
1022                    let mut batch = Vec::new();
1023                    let conn = r.engine_mut().accept();
1024                    for i in 0..EACH {
1025                        let key = format!("t{at}:{i}");
1026                        r.engine_mut()
1027                            .feed(conn, &wire(&[b"SET", key.as_bytes(), b"v"]));
1028                        pump(&mut r, &mut batch);
1029                    }
1030                });
1031            }
1032        });
1033
1034        // Every key both threads wrote is in the one database, which is the
1035        // whole claim: the fronts were separate and the keyspace was not.
1036        assert_eq!(server.striped_ref(0).len(), 2 * EACH);
1037        // And both threads counted into the same total, each from its own set
1038        // of counters, which is what the sum over the threads is for.
1039        assert_eq!(server.totals().connections, 2);
1040    }
1041
1042    /// A blocked client is answered into a buffer one thread owns, so it is
1043    /// that thread's to answer and nobody else's to throw away.
1044    #[test]
1045    fn a_waiter_belongs_to_the_thread_that_parked_it() {
1046        let mut server = Server::new();
1047        server.set_threads(2);
1048        let first = Wire::with_server(server, Recorder::new());
1049        let second = Wire::over(first.shared(), Recorder::new());
1050        let server = first.shared();
1051
1052        let parked = std::sync::Barrier::new(2);
1053        let swept = std::sync::Barrier::new(2);
1054
1055        std::thread::scope(|s| {
1056            let (parked, swept) = (&parked, &swept);
1057            s.spawn(move || {
1058                let mut r = Reactor::inline(first);
1059                let mut batch = Vec::new();
1060                let conn = r.engine_mut().accept();
1061                r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"a", b"0"]));
1062                pump(&mut r, &mut batch);
1063                parked.wait();
1064
1065                // Turns with nothing on them, each of which walks a list whose
1066                // one other entry belongs to the thread next door.
1067                for _ in 0..50 {
1068                    pump(&mut r, &mut batch);
1069                }
1070                swept.wait();
1071                assert!(r.engine().sink().sent(conn).is_empty(), "nothing to say");
1072            });
1073            s.spawn(move || {
1074                let mut r = Reactor::inline(second);
1075                let mut batch = Vec::new();
1076                let conn = r.engine_mut().accept();
1077                r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"b", b"0"]));
1078                pump(&mut r, &mut batch);
1079                parked.wait();
1080                swept.wait();
1081
1082                // The push comes in on a second connection, because the first
1083                // one is not reading anything while it waits.
1084                let pusher = r.engine_mut().accept();
1085                r.engine_mut().feed(pusher, &wire(&[b"RPUSH", b"b", b"v"]));
1086                pump(&mut r, &mut batch);
1087                assert_eq!(
1088                    r.engine().sink().sent(conn),
1089                    b"*2\r\n$1\r\nb\r\n$1\r\nv\r\n",
1090                    "served by the thread that parked it"
1091                );
1092            });
1093        });
1094
1095        assert_eq!(server.parked(), 1, "and the other one is still waiting");
1096    }
1097
1098    /// The count a thread branches on before it reaches for the shared list is
1099    /// its own, because the list is one lock and a thread can only answer what
1100    /// it parked itself. Branching on the server wide count instead would put
1101    /// every thread through that lock after every command as soon as one client
1102    /// blocked anywhere.
1103    #[test]
1104    fn a_thread_counts_the_clients_it_blocked_and_nobody_else_s() {
1105        let mut server = Server::new();
1106        server.set_threads(2);
1107        let first = Wire::with_server(server, Recorder::new());
1108        let second = Wire::over(first.shared(), Recorder::new());
1109        let server = first.shared();
1110
1111        let parked = std::sync::Barrier::new(2);
1112        let looked = std::sync::Barrier::new(2);
1113
1114        std::thread::scope(|s| {
1115            let (parked, looked) = (&parked, &looked);
1116            s.spawn(move || {
1117                let mut r = Reactor::inline(first);
1118                let mut batch = Vec::new();
1119                let conn = r.engine_mut().accept();
1120                r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"a", b"0"]));
1121                pump(&mut r, &mut batch);
1122                assert_eq!(r.engine().waiting(), 1, "the one this thread blocked");
1123                parked.wait();
1124                looked.wait();
1125
1126                // A second client of this thread's that never blocked, opened
1127                // and closed. It is not on the list, so the count stays where
1128                // it was rather than following the disconnect down.
1129                let other = r.engine_mut().accept();
1130                r.engine_mut().feed(other, &wire(&[b"PING"]));
1131                pump(&mut r, &mut batch);
1132                r.engine_mut().hangup(other);
1133                pump(&mut r, &mut batch);
1134                assert_eq!(r.engine().waiting(), 1, "still just the blocked one");
1135            });
1136            s.spawn(move || {
1137                let mut r = Reactor::inline(second);
1138                let mut batch = Vec::new();
1139                parked.wait();
1140
1141                // A thread with nothing of its own blocked, on a server that
1142                // has one client blocked on it.
1143                pump(&mut r, &mut batch);
1144                assert_eq!(r.engine().waiting(), 0, "none of them are this one's");
1145                assert_eq!(r.engine().server().parked(), 1, "one on the server");
1146                looked.wait();
1147            });
1148        });
1149
1150        assert_eq!(server.parked(), 1);
1151    }
1152
1153    /// Two fronts hand out connection slots from zero, so the number that tells
1154    /// two clients apart cannot come from a front.
1155    #[test]
1156    fn client_ids_are_the_server_s_to_hand_out() {
1157        let first = Wire::new(Recorder::new());
1158        let second = Wire::over(first.shared(), Recorder::new());
1159        let mut a = Reactor::inline(first);
1160        let mut b = Reactor::inline(second);
1161
1162        let (one, two) = (a.engine_mut().accept(), b.engine_mut().accept());
1163        assert_eq!(one, two, "the same slot on each front");
1164
1165        // HELLO answers with the connection id, which is the number CLIENT
1166        // KILL and CLIENT UNPAUSE take, so two fronts agreeing on it is two
1167        // clients that cannot be told apart. Protocol three so that the proto
1168        // field in the same reply is not one of the ids being looked for.
1169        let mut batch = Vec::new();
1170        a.engine_mut().feed(one, &wire(&[b"HELLO", b"3"]));
1171        b.engine_mut().feed(two, &wire(&[b"HELLO", b"3"]));
1172        pump(&mut a, &mut batch);
1173        pump(&mut b, &mut batch);
1174
1175        let first = String::from_utf8_lossy(a.engine().sink().sent(one)).into_owned();
1176        let second = String::from_utf8_lossy(b.engine().sink().sent(two)).into_owned();
1177        assert!(first.contains(":1\r\n"), "{first}");
1178        assert!(second.contains(":2\r\n"), "{second}");
1179    }
1180
1181    #[test]
1182    fn quit_is_answered_and_then_the_connection_goes() {
1183        let (mut r, conn, mut batch) = engine();
1184        r.engine_mut().feed(conn, &wire(&[b"PING"]));
1185        r.engine_mut().feed(conn, &wire(&[b"QUIT"]));
1186        pump(&mut r, &mut batch);
1187
1188        assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n+OK\r\n");
1189        assert!(r.engine().sink().was_closed(conn));
1190        assert_eq!(r.engine().clients(), 0);
1191
1192        // The slot comes back, buffers and all.
1193        let again = r.engine_mut().accept();
1194        assert_eq!(again, conn);
1195        assert_eq!(r.engine().clients(), 1);
1196    }
1197
1198    /// Redis's own unit/quit, which caught this: we answered the `QUIT` and
1199    /// then ran the `SET` behind it.
1200    #[test]
1201    fn what_a_client_pipelined_behind_quit_is_never_run() {
1202        let (mut r, conn, mut batch) = engine();
1203        let mut stream = wire(&[b"QUIT"]);
1204        stream.extend(wire(&[b"SET", b"foo", b"bar"]));
1205        r.engine_mut().feed(conn, &stream);
1206        // Both were framed, because framing happens before anything runs.
1207        assert_eq!(r.engine().ready(), 2);
1208        pump(&mut r, &mut batch);
1209
1210        // One reply and not two, and the connection is gone.
1211        assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
1212        assert!(r.engine().sink().was_closed(conn));
1213
1214        // And the write never happened, which is the part a client can see
1215        // after it reconnects. The recorder is cleared first because the next
1216        // connection lands back in the slot this one just left, and what was
1217        // written to the slot before is still sitting in it.
1218        r.engine_mut().sink_mut().clear();
1219        let next = r.engine_mut().accept();
1220        r.engine_mut().feed(next, &wire(&[b"GET", b"foo"]));
1221        pump(&mut r, &mut batch);
1222        assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1223    }
1224
1225    /// A connection that never said `HELLO` is answered in RESP2, whatever the
1226    /// last client in that slot was speaking.
1227    ///
1228    /// The protocol is kept in the reply buffer and the reply buffer outlives
1229    /// the connection, so this is the one piece of connection state that a
1230    /// recycled slot used to carry over. A client got a RESP3 null back from
1231    /// the first `GET` that missed and could not parse it, which is as bad as a
1232    /// compatibility bug gets: nothing the client did caused it and nothing it
1233    /// could send would have avoided it.
1234    #[test]
1235    fn a_slot_that_last_spoke_resp3_answers_the_next_client_in_resp2() {
1236        let (mut r, conn, mut batch) = engine();
1237        r.engine_mut().feed(conn, &wire(&[b"HELLO", b"3"]));
1238        r.engine_mut().feed(conn, &wire(&[b"GET", b"nothing"]));
1239        pump(&mut r, &mut batch);
1240        assert!(r.engine().sink().sent(conn).ends_with(b"_\r\n"));
1241        r.engine_mut().feed(conn, &wire(&[b"QUIT"]));
1242        pump(&mut r, &mut batch);
1243
1244        r.engine_mut().sink_mut().clear();
1245        let next = r.engine_mut().accept();
1246        assert_eq!(next, conn, "the same slot, which is what this is about");
1247        r.engine_mut().feed(next, &wire(&[b"GET", b"nothing"]));
1248        pump(&mut r, &mut batch);
1249        assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1250    }
1251
1252    /// The other way a connection ends, which does not throw anything away.
1253    #[test]
1254    fn commands_that_arrived_before_a_protocol_error_are_still_answered() {
1255        let (mut r, conn, mut batch) = engine();
1256        let mut stream = wire(&[b"SET", b"k", b"v"]);
1257        stream.extend(wire(&[b"GET", b"k"]));
1258        stream.extend_from_slice(b"*1\r\n+notabulk\r\n");
1259        r.engine_mut().feed(conn, &stream);
1260        pump(&mut r, &mut batch);
1261
1262        // Both good commands were complete and correct before the stream went
1263        // wrong, so both are answered and the error comes after them.
1264        let sent = r.engine().sink().sent(conn);
1265        assert!(
1266            sent.starts_with(b"+OK\r\n$1\r\nv\r\n-ERR Protocol error: "),
1267            "{sent:?}"
1268        );
1269        assert!(r.engine().sink().was_closed(conn));
1270    }
1271
1272    #[test]
1273    fn a_protocol_error_is_written_and_closes_the_connection() {
1274        let (mut r, conn, mut batch) = engine();
1275        // A multibulk that says its first argument is a bulk and then does not.
1276        r.engine_mut().feed(conn, b"*1\r\n+notabulk\r\n");
1277        pump(&mut r, &mut batch);
1278
1279        let sent = r.engine().sink().sent(conn);
1280        assert!(sent.starts_with(b"-ERR Protocol error: "), "{sent:?}");
1281        assert!(r.engine().sink().was_closed(conn));
1282        assert_eq!(r.engine().clients(), 0);
1283    }
1284
1285    /// Redis's own `unit/protocol` walks a list of malformed frames, each on a
1286    /// fresh connection, which means every one of them after the first runs on
1287    /// a decoder that came back to the pool part way through a command.
1288    #[test]
1289    fn a_decoder_that_came_back_mid_command_starts_the_next_one_clean() {
1290        let (mut r, conn, mut batch) = engine();
1291        // Stops inside the third argument, on a length that is not a length.
1292        r.engine_mut()
1293            .feed(conn, b"*3\r\n$3\r\nSET\r\n$1\r\nx\r\n$blabla\r\n");
1294        pump(&mut r, &mut batch);
1295        let sent = r.engine().sink().sent(conn);
1296        assert!(
1297            sent.starts_with(b"-ERR Protocol error: invalid bulk length"),
1298            "{sent:?}"
1299        );
1300
1301        // The slot that decoder was in is now the slot the next connection
1302        // gets, and it has to be at the start of a command and not half way
1303        // through the one that went wrong.
1304        r.engine_mut().sink_mut().clear();
1305        let next = r.engine_mut().accept();
1306        r.engine_mut().feed(next, &wire(&[b"GET", b"k"]));
1307        pump(&mut r, &mut batch);
1308        assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1309
1310        r.engine_mut().sink_mut().clear();
1311        let third = r.engine_mut().accept();
1312        r.engine_mut().feed(third, b"*1\r\n+notabulk\r\n");
1313        pump(&mut r, &mut batch);
1314        let sent = r.engine().sink().sent(third);
1315        assert!(sent.starts_with(b"-ERR Protocol error: "), "{sent:?}");
1316    }
1317
1318    /// A client that hangs up mid batch is the case that gets a server killed:
1319    /// the commands already framed still point into its buffer.
1320    #[test]
1321    fn a_hangup_with_commands_in_flight_waits_for_them() {
1322        let (mut r, conn, mut batch) = engine();
1323        r.engine_mut().feed(conn, &wire(&[b"SET", b"k", b"v"]));
1324        r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1325
1326        batch.clear();
1327        r.engine_mut().take_ready(&mut batch, BATCH_MAX);
1328        r.engine_mut().hangup(conn);
1329        assert_eq!(r.engine().clients(), 1, "still holding the buffer");
1330
1331        r.execute_all(batch.drain(..));
1332        r.engine_mut().flush();
1333        assert_eq!(r.engine().clients(), 0);
1334        assert!(r.engine().sink().sent(conn).is_empty(), "nobody to answer");
1335
1336        // And the slot is usable again, with the decoders both back in the
1337        // pool rather than lost with the connection.
1338        let decoders = r.engine().decoders();
1339        let again = r.engine_mut().accept();
1340        assert_eq!(again, conn);
1341        r.engine_mut().feed(again, &wire(&[b"PING"]));
1342        pump(&mut r, &mut batch);
1343        assert_eq!(r.engine().sink().sent(again), b"+PONG\r\n");
1344        assert_eq!(r.engine().decoders(), decoders);
1345    }
1346
1347    /// The claim that the steady state does not allocate, checked the only way
1348    /// a library test can check it: nothing grows.
1349    #[test]
1350    fn the_buffers_and_the_decoder_pool_stop_growing() {
1351        let (mut r, conn, mut batch) = engine();
1352        let mut stream = Vec::new();
1353        for i in 0..32 {
1354            stream.extend(wire(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
1355        }
1356
1357        r.engine_mut().feed(conn, &stream);
1358        pump(&mut r, &mut batch);
1359        let decoders = r.engine().decoders();
1360        let batch_cap = batch.capacity();
1361
1362        for _ in 0..10 {
1363            r.engine_mut().feed(conn, &stream);
1364            pump(&mut r, &mut batch);
1365        }
1366        assert_eq!(r.engine().decoders(), decoders, "the pool is reused");
1367        assert_eq!(batch.capacity(), batch_cap, "the batch buffer is reused");
1368        assert!(
1369            decoders <= BATCH_MAX + 1,
1370            "{decoders} decoders for 32 commands"
1371        );
1372    }
1373
1374    /// The read buffer holds what has not been dealt with yet and nothing else.
1375    ///
1376    /// A client that pipelines sixteen commands, waits for the sixteen replies
1377    /// and goes again is what `redis-benchmark -P 16` does and what half of the
1378    /// clients in the world do. Every one of those rounds leaves the buffer
1379    /// exactly caught up, and a buffer that never drops what it has already
1380    /// dealt with grows to everything the connection has ever sent: 16 MiB
1381    /// apiece on server3 for four connections sending 100000 sets each.
1382    #[test]
1383    fn a_pipelining_client_does_not_grow_the_read_buffer() {
1384        let (mut r, conn, mut batch) = engine();
1385        let mut round = Vec::new();
1386        for i in 0..16 {
1387            round.extend(wire(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
1388        }
1389
1390        r.engine_mut().feed(conn, &round);
1391        pump(&mut r, &mut batch);
1392        r.engine_mut().sink_mut().clear();
1393        let after_one = r.engine().buffer_bytes();
1394
1395        // A thousand rounds is sixteen thousand commands and about a megabyte
1396        // of wire bytes, which is a hundred times what the buffer starts with.
1397        // Fifty is a twentieth of that and it is what runs under Miri, where
1398        // sixteen thousand commands through the whole engine was a quarter of
1399        // an hour. The check below is that the size is the one it was after the
1400        // first round, exactly, so a buffer that keeps anything at all is
1401        // caught on the second round and every one after it, whichever count
1402        // this is.
1403        let rounds = if cfg!(miri) { 50 } else { 1000 };
1404        for _ in 0..rounds {
1405            r.engine_mut().feed(conn, &round);
1406            pump(&mut r, &mut batch);
1407            r.engine_mut().sink_mut().clear();
1408        }
1409
1410        assert_eq!(
1411            r.engine().buffer_bytes(),
1412            after_one,
1413            "the buffers grew over {rounds} rounds of the same sixteen commands"
1414        );
1415        assert!(
1416            r.engine().server().memory_bytes() >= after_one,
1417            "the buffers are counted in what the server reports"
1418        );
1419    }
1420
1421    /// Half a command in the buffer is the case compaction has to be careful
1422    /// about, because the decoder holding it kept offsets into those bytes.
1423    #[test]
1424    fn a_command_split_across_reads_survives_compaction() {
1425        let (mut r, conn, mut batch) = engine();
1426        let cmd = wire(&[b"SET", b"key", b"value"]);
1427        let (head, tail) = cmd.split_at(cmd.len() - 4);
1428
1429        // A complete command, so that there is something in front to drop, then
1430        // most of a second one.
1431        r.engine_mut().feed(conn, &wire(&[b"PING"]));
1432        r.engine_mut().feed(conn, head);
1433        pump(&mut r, &mut batch);
1434        assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n");
1435
1436        // The rest of it arrives after the buffer has been compacted under it.
1437        r.engine_mut().feed(conn, tail);
1438        pump(&mut r, &mut batch);
1439        assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n+OK\r\n");
1440
1441        r.engine_mut().feed(conn, &wire(&[b"GET", b"key"]));
1442        pump(&mut r, &mut batch);
1443        assert!(r.engine().sink().sent(conn).ends_with(b"$5\r\nvalue\r\n"));
1444    }
1445
1446    /// The two walks are the reactor's, not this module's, so the test is that
1447    /// the engine can be driven by them at all: same commands, same replies.
1448    #[test]
1449    fn the_batch_goes_through_the_reactors_two_walks() {
1450        let (mut r, conn, mut batch) = engine();
1451        for i in 0..100 {
1452            r.engine_mut()
1453                .feed(conn, &wire(&[b"INCR", format!("k{}", i % 7).as_bytes()]));
1454        }
1455        let ran = pump(&mut r, &mut batch);
1456
1457        assert_eq!(ran, 100);
1458        assert_eq!(r.commands(), 100);
1459        // Two batches, because a hundred commands do not fit in sixty four.
1460        assert_eq!(r.turns(), 2);
1461        // The hundredth command is the fifteenth `INCR` of `k1`.
1462        assert!(r.engine().sink().sent(conn).ends_with(b":15\r\n"));
1463    }
1464
1465    /// A sink that takes four bytes at a time, which is what a full socket
1466    /// looks like from in here.
1467    #[derive(Default)]
1468    struct Trickle {
1469        sent: Vec<u8>,
1470        writes: usize,
1471    }
1472
1473    impl Sink for Trickle {
1474        fn write(&mut self, _conn: ConnId, bytes: &[u8]) -> usize {
1475            self.writes += 1;
1476            let n = bytes.len().min(4);
1477            self.sent.extend_from_slice(&bytes[..n]);
1478            n
1479        }
1480    }
1481
1482    /// A blocking command that does not block costs nothing: no waiter, no
1483    /// allocation, the same three lines the non blocking one runs.
1484    #[test]
1485    fn a_blpop_on_a_list_with_something_in_it_never_waits() {
1486        let (mut r, conn, mut batch) = engine();
1487        r.engine_mut().feed(conn, &wire(&[b"RPUSH", b"q", b"a"]));
1488        r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"q", b"0"]));
1489        pump(&mut r, &mut batch);
1490
1491        assert_eq!(
1492            r.engine().sink().sent(conn),
1493            b":1\r\n*2\r\n$1\r\nq\r\n$1\r\na\r\n"
1494        );
1495        assert_eq!(r.engine().server().parked(), 0);
1496    }
1497
1498    /// The whole point: a client with nothing to pop is answered later, by
1499    /// somebody else's command.
1500    #[test]
1501    fn a_parked_client_is_answered_by_another_connections_push() {
1502        let (mut r, a, mut batch) = engine();
1503        let b = r.engine_mut().accept();
1504
1505        r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1506        pump(&mut r, &mut batch);
1507        assert!(r.engine().sink().sent(a).is_empty(), "nothing to say yet");
1508        assert_eq!(r.engine().server().parked(), 1);
1509
1510        r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"one"]));
1511        pump(&mut r, &mut batch);
1512
1513        assert_eq!(r.engine().sink().sent(a), b"*2\r\n$1\r\nq\r\n$3\r\none\r\n");
1514        // The push still reports the length it made, even though the element was
1515        // gone again before the reply was written.
1516        assert_eq!(r.engine().sink().sent(b), b":1\r\n");
1517        assert_eq!(r.engine().server().parked(), 0);
1518    }
1519
1520    /// A push to a key nobody named, and a key of another type on a key
1521    /// somebody did: neither is a wake up, and the client stays parked.
1522    #[test]
1523    fn only_a_list_arriving_under_a_named_key_wakes_a_waiter() {
1524        let (mut r, a, mut batch) = engine();
1525        let b = r.engine_mut().accept();
1526        r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1527        pump(&mut r, &mut batch);
1528
1529        r.engine_mut()
1530            .feed(b, &wire(&[b"RPUSH", b"elsewhere", b"x"]));
1531        r.engine_mut().feed(b, &wire(&[b"SADD", b"q", b"x"]));
1532        pump(&mut r, &mut batch);
1533
1534        assert!(r.engine().sink().sent(a).is_empty());
1535        assert_eq!(r.engine().server().parked(), 1, "still waiting");
1536        // And the set is intact, so the waiter did not take anything out of it
1537        // on its way past.
1538        assert_eq!(r.engine().sink().sent(b), b":1\r\n:1\r\n");
1539    }
1540
1541    /// Two workers on one queue, which is what `BLPOP` is for. They are served
1542    /// in the order they arrived and not in whatever order the list is walked.
1543    #[test]
1544    fn two_parked_clients_are_served_in_the_order_they_arrived() {
1545        let (mut r, a, mut batch) = engine();
1546        let b = r.engine_mut().accept();
1547        let c = r.engine_mut().accept();
1548
1549        r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1550        pump(&mut r, &mut batch);
1551        r.engine_mut().feed(b, &wire(&[b"BLPOP", b"q", b"0"]));
1552        pump(&mut r, &mut batch);
1553        assert_eq!(r.engine().server().parked(), 2);
1554
1555        r.engine_mut()
1556            .feed(c, &wire(&[b"RPUSH", b"q", b"first", b"second"]));
1557        pump(&mut r, &mut batch);
1558
1559        assert_eq!(
1560            r.engine().sink().sent(a),
1561            b"*2\r\n$1\r\nq\r\n$5\r\nfirst\r\n"
1562        );
1563        assert_eq!(
1564            r.engine().sink().sent(b),
1565            b"*2\r\n$1\r\nq\r\n$6\r\nsecond\r\n"
1566        );
1567        assert_eq!(r.engine().server().parked(), 0);
1568    }
1569
1570    /// A client waiting for an answer is not a client that has sent another
1571    /// question, so what it pipelined behind its `BLPOP` waits for the `BLPOP`.
1572    #[test]
1573    fn what_a_client_pipelined_behind_a_block_waits_for_the_block() {
1574        let (mut r, a, mut batch) = engine();
1575        let b = r.engine_mut().accept();
1576
1577        // Framed together, so the `PING` is already on its way to the reactor
1578        // when the `BLPOP` in front of it parks.
1579        let mut stream = wire(&[b"BLPOP", b"q", b"0"]);
1580        stream.extend(wire(&[b"PING"]));
1581        r.engine_mut().feed(a, &stream);
1582        pump(&mut r, &mut batch);
1583        assert!(
1584            r.engine().sink().sent(a).is_empty(),
1585            "the PING went out in front of the answer it was sent behind"
1586        );
1587
1588        // And one that arrives while it is parked is not even framed.
1589        r.engine_mut().feed(a, &wire(&[b"ECHO", b"after"]));
1590        pump(&mut r, &mut batch);
1591        assert!(r.engine().sink().sent(a).is_empty());
1592
1593        r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"x"]));
1594        pump(&mut r, &mut batch);
1595        assert_eq!(
1596            r.engine().sink().sent(a),
1597            b"*2\r\n$1\r\nq\r\n$1\r\nx\r\n+PONG\r\n$5\r\nafter\r\n"
1598        );
1599    }
1600
1601    /// Redis serves parked clients after every command rather than once per
1602    /// turn of the loop, and a pipeline is where the difference shows: the
1603    /// waiter has to be served between the two pushes, so it answers with the
1604    /// key the first push filled and not with the one it named first.
1605    #[test]
1606    fn a_waiter_is_served_between_two_pipelined_pushes() {
1607        let (mut r, a, mut batch) = engine();
1608        let b = r.engine_mut().accept();
1609        r.engine_mut()
1610            .feed(a, &wire(&[b"BLPOP", b"p1", b"p2", b"0"]));
1611        pump(&mut r, &mut batch);
1612
1613        let mut stream = wire(&[b"RPUSH", b"p2", b"second"]);
1614        stream.extend(wire(&[b"RPUSH", b"p1", b"first"]));
1615        r.engine_mut().feed(b, &stream);
1616        pump(&mut r, &mut batch);
1617
1618        assert_eq!(
1619            r.engine().sink().sent(a),
1620            b"*2\r\n$2\r\np2\r\n$6\r\nsecond\r\n"
1621        );
1622        // Which leaves the key it named first holding what was pushed to it.
1623        r.engine_mut()
1624            .feed(b, &wire(&[b"LRANGE", b"p1", b"0", b"-1"]));
1625        pump(&mut r, &mut batch);
1626        assert!(
1627            r.engine()
1628                .sink()
1629                .sent(b)
1630                .ends_with(b"*1\r\n$5\r\nfirst\r\n")
1631        );
1632    }
1633
1634    /// A `BLMOVE` that serves itself is a push, so it wakes the client waiting
1635    /// on the key it pushed to, in the same moment and without a turn of the
1636    /// loop in between.
1637    #[test]
1638    fn a_waiter_woken_by_another_waiter() {
1639        let (mut r, a, mut batch) = engine();
1640        let b = r.engine_mut().accept();
1641        let c = r.engine_mut().accept();
1642
1643        r.engine_mut()
1644            .feed(a, &wire(&[b"BLMOVE", b"x", b"y", b"LEFT", b"RIGHT", b"0"]));
1645        pump(&mut r, &mut batch);
1646        r.engine_mut().feed(b, &wire(&[b"BLPOP", b"y", b"0"]));
1647        pump(&mut r, &mut batch);
1648        assert_eq!(r.engine().server().parked(), 2);
1649
1650        r.engine_mut().feed(c, &wire(&[b"RPUSH", b"x", b"chain"]));
1651        pump(&mut r, &mut batch);
1652
1653        assert_eq!(r.engine().sink().sent(a), b"$5\r\nchain\r\n");
1654        assert_eq!(
1655            r.engine().sink().sent(b),
1656            b"*2\r\n$1\r\ny\r\n$5\r\nchain\r\n"
1657        );
1658        assert_eq!(r.engine().server().parked(), 0);
1659    }
1660
1661    /// A waiter on one database is not woken by a push on another, even though
1662    /// the key has the same name.
1663    #[test]
1664    fn a_waiter_is_only_woken_on_the_database_it_blocked_on() {
1665        let (mut r, a, mut batch) = engine();
1666        let b = r.engine_mut().accept();
1667        r.engine_mut().feed(a, &wire(&[b"SELECT", b"3"]));
1668        r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1669        pump(&mut r, &mut batch);
1670        assert_eq!(r.engine().sink().sent(a), b"+OK\r\n");
1671
1672        r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"wrongdb"]));
1673        pump(&mut r, &mut batch);
1674        assert_eq!(r.engine().sink().sent(a), b"+OK\r\n", "still waiting");
1675
1676        r.engine_mut().feed(b, &wire(&[b"SELECT", b"3"]));
1677        r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"rightdb"]));
1678        pump(&mut r, &mut batch);
1679        assert!(r.engine().sink().sent(a).ends_with(b"$7\r\nrightdb\r\n"));
1680    }
1681
1682    /// The deadline sweep, which runs on a turn that has nothing else to do.
1683    #[test]
1684    fn a_client_that_waited_long_enough_gets_a_null_array() {
1685        let (mut r, conn, mut batch) = timed();
1686        r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"q", b"30"]));
1687        pump(&mut r, &mut batch);
1688        assert!(r.engine().sink().sent(conn).is_empty());
1689
1690        r.engine_mut().server_mut().set_clock_ms(START_MS + 29_999);
1691        pump(&mut r, &mut batch);
1692        assert!(
1693            r.engine().sink().sent(conn).is_empty(),
1694            "a millisecond short"
1695        );
1696
1697        r.engine_mut().server_mut().set_clock_ms(START_MS + 30_000);
1698        pump(&mut r, &mut batch);
1699        // A null array and not a null string, which a RESP2 client can see.
1700        assert_eq!(r.engine().sink().sent(conn), b"*-1\r\n");
1701        assert_eq!(r.engine().server().parked(), 0);
1702    }
1703
1704    /// The four that answer with something other than a two element array all
1705    /// answer a timeout the same way, which is not what the reply shape would
1706    /// suggest and is what Redis does.
1707    #[test]
1708    fn every_blocking_command_times_out_with_the_same_null_array() {
1709        for cmd in [
1710            &[b"BLPOP".as_slice(), b"q", b"0.001"][..],
1711            &[b"BRPOP", b"q", b"0.001"],
1712            &[b"BLMOVE", b"q", b"d", b"LEFT", b"RIGHT", b"0.001"],
1713            &[b"BRPOPLPUSH", b"q", b"d", b"0.001"],
1714            &[b"BLMPOP", b"0.001", b"1", b"q", b"LEFT"],
1715        ] {
1716            let (mut r, conn, mut batch) = timed();
1717            r.engine_mut().feed(conn, &wire(cmd));
1718            pump(&mut r, &mut batch);
1719            r.engine_mut().server_mut().set_clock_ms(START_MS + 1);
1720            pump(&mut r, &mut batch);
1721            assert_eq!(r.engine().sink().sent(conn), b"*-1\r\n", "for {cmd:?}");
1722        }
1723    }
1724
1725    /// A client that gave up does not go on holding a claim on the queue: the
1726    /// element that arrives after it stays where it was put.
1727    #[test]
1728    fn a_waiter_that_timed_out_does_not_eat_a_later_push() {
1729        let (mut r, a, mut batch) = timed();
1730        let b = r.engine_mut().accept();
1731        r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"1"]));
1732        pump(&mut r, &mut batch);
1733        r.engine_mut().server_mut().set_clock_ms(START_MS + 1000);
1734        pump(&mut r, &mut batch);
1735        assert_eq!(r.engine().sink().sent(a), b"*-1\r\n");
1736
1737        r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"late"]));
1738        r.engine_mut()
1739            .feed(b, &wire(&[b"LRANGE", b"q", b"0", b"-1"]));
1740        pump(&mut r, &mut batch);
1741        assert_eq!(r.engine().sink().sent(a), b"*-1\r\n", "nothing more");
1742        assert!(r.engine().sink().sent(b).ends_with(b"*1\r\n$4\r\nlate\r\n"));
1743    }
1744
1745    /// A `BLPOP key 0` has no deadline, so nothing but the connection closing
1746    /// will ever take it off the list. That makes the close path the one that
1747    /// has to be right, or a waiter outlives its client and the slot it names
1748    /// gets handed to somebody else.
1749    #[test]
1750    fn a_client_that_goes_away_while_it_waits_takes_its_waiter_with_it() {
1751        let (mut r, a, mut batch) = engine();
1752        let b = r.engine_mut().accept();
1753        r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1754        pump(&mut r, &mut batch);
1755        assert_eq!(r.engine().server().parked(), 1);
1756
1757        r.engine_mut().hangup(a);
1758        pump(&mut r, &mut batch);
1759        assert_eq!(r.engine().server().parked(), 0);
1760        assert_eq!(r.engine().clients(), 1);
1761
1762        // The slot is handed straight back out, which is what the waiter would
1763        // have been pointing at.
1764        let again = r.engine_mut().accept();
1765        assert_eq!(again, a);
1766        r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"x"]));
1767        r.engine_mut()
1768            .feed(again, &wire(&[b"LRANGE", b"q", b"0", b"-1"]));
1769        pump(&mut r, &mut batch);
1770        assert_eq!(r.engine().sink().sent(again), b"*1\r\n$1\r\nx\r\n");
1771    }
1772
1773    /// The same, with commands the client had already sent sitting behind the
1774    /// block. Those are what `pending` counts, so a close that forgets them is a
1775    /// connection slot that never comes back.
1776    #[test]
1777    fn a_hangup_while_parked_gives_back_the_slot_and_the_decoders() {
1778        let (mut r, a, mut batch) = engine();
1779        let mut stream = wire(&[b"BLPOP", b"q", b"0"]);
1780        stream.extend(wire(&[b"PING"]));
1781        stream.extend(wire(&[b"PING"]));
1782        r.engine_mut().feed(a, &stream);
1783        pump(&mut r, &mut batch);
1784
1785        let decoders = r.engine().decoders();
1786        r.engine_mut().hangup(a);
1787        pump(&mut r, &mut batch);
1788
1789        assert_eq!(r.engine().clients(), 0);
1790        assert!(r.engine().sink().was_closed(a));
1791        assert_eq!(r.engine().decoders(), decoders, "the pool came back whole");
1792        let again = r.engine_mut().accept();
1793        assert_eq!(again, a);
1794        r.engine_mut().feed(again, &wire(&[b"PING"]));
1795        pump(&mut r, &mut batch);
1796        assert_eq!(r.engine().sink().sent(again), b"+PONG\r\n");
1797    }
1798
1799    /// The whole point of a mailbox: a publish on one connection turns into
1800    /// bytes on another, in the same flush.
1801    #[test]
1802    fn a_published_message_lands_on_the_subscriber() {
1803        let (mut r, sub, mut batch) = engine();
1804        let pubr = r.engine_mut().accept();
1805
1806        r.engine_mut().feed(sub, &wire(&[b"SUBSCRIBE", b"news"]));
1807        pump(&mut r, &mut batch);
1808        assert_eq!(
1809            r.engine().sink().sent(sub),
1810            b"*3\r\n$9\r\nsubscribe\r\n$4\r\nnews\r\n:1\r\n"
1811        );
1812        r.engine_mut().sink_mut().clear();
1813
1814        r.engine_mut()
1815            .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1816        pump(&mut r, &mut batch);
1817        assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1818        assert_eq!(
1819            r.engine().sink().sent(sub),
1820            b"*3\r\n$7\r\nmessage\r\n$4\r\nnews\r\n$2\r\nhi\r\n"
1821        );
1822    }
1823
1824    /// A pattern subscriber is told which of its patterns matched as well as
1825    /// which channel the message went to, so the reply is one field longer.
1826    #[test]
1827    fn a_pattern_subscriber_is_told_the_pattern_and_the_channel() {
1828        let (mut r, sub, mut batch) = engine();
1829        let pubr = r.engine_mut().accept();
1830
1831        r.engine_mut().feed(sub, &wire(&[b"PSUBSCRIBE", b"ne*"]));
1832        pump(&mut r, &mut batch);
1833        r.engine_mut().sink_mut().clear();
1834
1835        r.engine_mut()
1836            .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1837        pump(&mut r, &mut batch);
1838        assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1839        assert_eq!(
1840            r.engine().sink().sent(sub),
1841            b"*4\r\n$8\r\npmessage\r\n$3\r\nne*\r\n$4\r\nnews\r\n$2\r\nhi\r\n"
1842        );
1843    }
1844
1845    /// A RESP2 client that has subscribed to anything can only leave, ping or
1846    /// subscribe to something else until it unsubscribes, because on RESP2 a
1847    /// message and a reply are the same shape and a client reading one cannot
1848    /// tell them apart.
1849    #[test]
1850    fn resp2_takes_almost_nothing_from_a_subscriber() {
1851        let (mut r, conn, mut batch) = engine();
1852
1853        r.engine_mut().feed(conn, &wire(&[b"SUBSCRIBE", b"a"]));
1854        pump(&mut r, &mut batch);
1855        r.engine_mut().sink_mut().clear();
1856
1857        r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1858        pump(&mut r, &mut batch);
1859        assert_eq!(
1860            r.engine().sink().sent(conn),
1861            b"-ERR Can't execute 'get': only (P|S)SUBSCRIBE / (P|S)UNSUBSCRIBE / PING / QUIT / RESET are allowed in this context\r\n"
1862        );
1863        r.engine_mut().sink_mut().clear();
1864
1865        // Ping is allowed, and answers in the shape the mode uses.
1866        r.engine_mut().feed(conn, &wire(&[b"PING"]));
1867        pump(&mut r, &mut batch);
1868        assert_eq!(
1869            r.engine().sink().sent(conn),
1870            b"*2\r\n$4\r\npong\r\n$0\r\n\r\n"
1871        );
1872        r.engine_mut().sink_mut().clear();
1873
1874        // And unsubscribing puts the connection back to ordinary work.
1875        r.engine_mut().feed(conn, &wire(&[b"UNSUBSCRIBE", b"a"]));
1876        r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1877        pump(&mut r, &mut batch);
1878        assert_eq!(
1879            r.engine().sink().sent(conn),
1880            b"*3\r\n$11\r\nunsubscribe\r\n$1\r\na\r\n:0\r\n$-1\r\n"
1881        );
1882    }
1883
1884    /// Shard channels are their own namespace. A name subscribed as a shard
1885    /// channel does not hear a plain publish to the same name, and a pattern
1886    /// never matches a shard publish.
1887    #[test]
1888    fn a_shard_channel_and_a_pattern_do_not_hear_each_other() {
1889        let (mut r, sub, mut batch) = engine();
1890        let pubr = r.engine_mut().accept();
1891
1892        r.engine_mut().feed(sub, &wire(&[b"SSUBSCRIBE", b"sx"]));
1893        r.engine_mut().feed(sub, &wire(&[b"PSUBSCRIBE", b"s*"]));
1894        pump(&mut r, &mut batch);
1895        r.engine_mut().sink_mut().clear();
1896
1897        r.engine_mut()
1898            .feed(pubr, &wire(&[b"SPUBLISH", b"sx", b"one"]));
1899        pump(&mut r, &mut batch);
1900        assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1901        assert_eq!(
1902            r.engine().sink().sent(sub),
1903            b"*3\r\n$8\r\nsmessage\r\n$2\r\nsx\r\n$3\r\none\r\n"
1904        );
1905        r.engine_mut().sink_mut().clear();
1906
1907        r.engine_mut()
1908            .feed(pubr, &wire(&[b"PUBLISH", b"sx", b"two"]));
1909        pump(&mut r, &mut batch);
1910        assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1911        assert_eq!(
1912            r.engine().sink().sent(sub),
1913            b"*4\r\n$8\r\npmessage\r\n$2\r\ns*\r\n$2\r\nsx\r\n$3\r\ntwo\r\n"
1914        );
1915    }
1916
1917    /// A subscriber that hangs up stops being one, which matters because the
1918    /// registry holds a connection id and that id gets handed to the next
1919    /// client through the door.
1920    #[test]
1921    fn a_subscriber_that_goes_away_leaves_the_registry() {
1922        let (mut r, sub, mut batch) = engine();
1923        let pubr = r.engine_mut().accept();
1924
1925        r.engine_mut().feed(sub, &wire(&[b"SUBSCRIBE", b"news"]));
1926        pump(&mut r, &mut batch);
1927        r.engine_mut().hangup(sub);
1928        pump(&mut r, &mut batch);
1929        r.engine_mut().sink_mut().clear();
1930
1931        r.engine_mut()
1932            .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1933        pump(&mut r, &mut batch);
1934        assert_eq!(r.engine().sink().sent(pubr), b":0\r\n");
1935
1936        // And the slot is clean for whoever gets it next.
1937        let next = r.engine_mut().accept();
1938        assert_eq!(next, sub);
1939        r.engine_mut()
1940            .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1941        pump(&mut r, &mut batch);
1942        assert_eq!(r.engine().sink().sent(next), b"");
1943    }
1944
1945    /// On RESP3 a message is a push, not a reply, so it can be read off a
1946    /// connection that is doing something else, and that connection is free to
1947    /// run ordinary commands while it is subscribed.
1948    ///
1949    /// It also pins the order a publish to yourself comes out in. Nothing in
1950    /// the code special cases it: the count is the reply to the command and the
1951    /// message is delivered on the way out with everybody else's, so the count
1952    /// is first.
1953    #[test]
1954    fn resp3_delivers_a_message_as_a_push() {
1955        let (mut r, conn, mut batch) = engine();
1956
1957        r.engine_mut().feed(conn, &wire(&[b"HELLO", b"3"]));
1958        r.engine_mut().feed(conn, &wire(&[b"SUBSCRIBE", b"a"]));
1959        pump(&mut r, &mut batch);
1960        r.engine_mut().sink_mut().clear();
1961
1962        r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1963        r.engine_mut().feed(conn, &wire(&[b"PUBLISH", b"a", b"w"]));
1964        pump(&mut r, &mut batch);
1965        assert_eq!(
1966            r.engine().sink().sent(conn),
1967            b"_\r\n:1\r\n>3\r\n$7\r\nmessage\r\n$1\r\na\r\n$1\r\nw\r\n"
1968        );
1969    }
1970
1971    /// A write publishes twice, once on the channel named after the key and
1972    /// once on the channel named after the event, in that order.
1973    #[test]
1974    fn a_write_reaches_a_keyspace_subscriber() {
1975        let (mut r, sub, mut batch) = engine();
1976        let writer = r.engine_mut().accept();
1977
1978        r.engine_mut().feed(
1979            writer,
1980            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"KEA"]),
1981        );
1982        r.engine_mut()
1983            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
1984        pump(&mut r, &mut batch);
1985        r.engine_mut().sink_mut().clear();
1986
1987        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
1988        pump(&mut r, &mut batch);
1989        assert_eq!(r.engine().sink().sent(writer), b"+OK\r\n");
1990        assert_eq!(
1991            r.engine().sink().sent(sub),
1992            b"*4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1993              $16\r\n__keyspace@0__:k\r\n$3\r\nset\r\n\
1994              *4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1995              $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n"
1996        );
1997    }
1998
1999    /// The setting is off by default, so a subscriber on the notification
2000    /// channels of a server nobody has turned them on for hears nothing.
2001    #[test]
2002    fn a_write_says_nothing_until_the_setting_turns_it_on() {
2003        let (mut r, sub, mut batch) = engine();
2004        let writer = r.engine_mut().accept();
2005
2006        r.engine_mut()
2007            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
2008        pump(&mut r, &mut batch);
2009        r.engine_mut().sink_mut().clear();
2010
2011        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2012        pump(&mut r, &mut batch);
2013        assert_eq!(r.engine().sink().sent(sub), b"");
2014    }
2015
2016    /// `g` without `$` is the generic class and not the string one, so a
2017    /// delete goes out and the write that made the key does not.
2018    #[test]
2019    fn only_the_classes_that_were_asked_for_are_published() {
2020        let (mut r, sub, mut batch) = engine();
2021        let writer = r.engine_mut().accept();
2022
2023        r.engine_mut().feed(
2024            writer,
2025            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"Eg"]),
2026        );
2027        r.engine_mut()
2028            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
2029        pump(&mut r, &mut batch);
2030        r.engine_mut().sink_mut().clear();
2031
2032        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2033        r.engine_mut().feed(writer, &wire(&[b"DEL", b"k"]));
2034        pump(&mut r, &mut batch);
2035        assert_eq!(
2036            r.engine().sink().sent(sub),
2037            b"*4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
2038              $18\r\n__keyevent@0__:del\r\n$1\r\nk\r\n"
2039        );
2040    }
2041
2042    /// A command that took a deadline with it says two things, and they come
2043    /// out in the order the server did them rather than all at the end.
2044    #[test]
2045    fn a_write_with_a_deadline_on_it_says_two_things() {
2046        let (mut r, sub, mut batch) = engine();
2047        let writer = r.engine_mut().accept();
2048
2049        r.engine_mut().feed(
2050            writer,
2051            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
2052        );
2053        r.engine_mut()
2054            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2055        pump(&mut r, &mut batch);
2056        r.engine_mut().sink_mut().clear();
2057
2058        r.engine_mut()
2059            .feed(writer, &wire(&[b"SETEX", b"k", b"100", b"v"]));
2060        pump(&mut r, &mut batch);
2061        assert_eq!(
2062            r.engine().sink().sent(sub),
2063            b"*4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
2064              $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n\
2065              *4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
2066              $21\r\n__keyevent@0__:expire\r\n$1\r\nk\r\n"
2067        );
2068    }
2069
2070    /// A subscriber on every event, and the writer that will make them.
2071    ///
2072    /// The three collection tests below all start the same way and all care
2073    /// about the order of what came out rather than about the bytes, so the
2074    /// setup is here once and the checking is done by [`fired`].
2075    fn watching() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
2076        watching_flags(b"EA")
2077    }
2078
2079    /// The same, for a test that needs a class `A` does not turn on.
2080    fn watching_flags(flags: &[u8]) -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
2081        let (mut r, sub, mut batch) = engine();
2082        let writer = r.engine_mut().accept();
2083        r.engine_mut().feed(
2084            writer,
2085            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", flags]),
2086        );
2087        r.engine_mut()
2088            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2089        pump(&mut r, &mut batch);
2090        r.engine_mut().sink_mut().clear();
2091        (r, sub, writer, batch)
2092    }
2093
2094    /// The event and key of every notification the subscriber has been sent.
2095    ///
2096    /// Written against the wire bytes because that is what the subscriber
2097    /// actually got, and a command that fires four events in a fixed order
2098    /// makes for a byte literal nobody can read.
2099    fn fired(r: &Reactor<Wire<Recorder>>, sub: ConnId) -> Vec<(String, String)> {
2100        fired_on(r, sub, 0)
2101    }
2102
2103    /// The same, for a test watching a database other than the one the writer is
2104    /// on, which is the two commands that put a key somewhere else.
2105    fn fired_on(r: &Reactor<Wire<Recorder>>, sub: ConnId, db: usize) -> Vec<(String, String)> {
2106        let head = format!("__keyevent@{db}__:");
2107        let sent = String::from_utf8_lossy(r.engine().sink().sent(sub)).into_owned();
2108        let mut out = Vec::new();
2109        let mut parts = sent.split("\r\n");
2110        while let Some(p) = parts.next() {
2111            let Some(event) = p.strip_prefix(head.as_str()) else {
2112                continue;
2113            };
2114            // The pattern itself comes past on every frame ahead of the channel
2115            // and is not one of these.
2116            if event == "*" {
2117                continue;
2118            }
2119            parts.next();
2120            let key = parts.next().unwrap_or_default();
2121            out.push((event.to_owned(), key.to_owned()));
2122        }
2123        out
2124    }
2125
2126    /// A pop that took the last of a list says what it did and then that the
2127    /// key is gone, because a list with nothing in it is not a key.
2128    #[test]
2129    fn taking_the_last_of_a_collection_says_the_key_went_with_it() {
2130        let (mut r, sub, writer, mut batch) = watching();
2131
2132        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"k", b"a"]));
2133        r.engine_mut().feed(writer, &wire(&[b"LPOP", b"k"]));
2134        pump(&mut r, &mut batch);
2135        assert_eq!(
2136            fired(&r, sub),
2137            [("rpush", "k"), ("lpop", "k"), ("del", "k")]
2138                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2139        );
2140    }
2141
2142    /// A move whose destination already holds the member says only the half
2143    /// that happened, since there was nothing to add on the far side.
2144    #[test]
2145    fn a_move_onto_a_member_already_there_says_only_the_removal() {
2146        let (mut r, sub, writer, mut batch) = watching();
2147
2148        r.engine_mut().feed(writer, &wire(&[b"SADD", b"a", b"m"]));
2149        r.engine_mut()
2150            .feed(writer, &wire(&[b"SADD", b"b", b"m", b"n"]));
2151        pump(&mut r, &mut batch);
2152        r.engine_mut().sink_mut().clear();
2153
2154        r.engine_mut()
2155            .feed(writer, &wire(&[b"SMOVE", b"a", b"b", b"m"]));
2156        pump(&mut r, &mut batch);
2157        assert_eq!(
2158            fired(&r, sub),
2159            [("srem", "a"), ("del", "a")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2160        );
2161    }
2162
2163    /// Writing a member the score it is already sitting at is not a write, and
2164    /// the reply says as much about it as the silence does.
2165    #[test]
2166    fn a_score_that_did_not_move_says_nothing() {
2167        let (mut r, sub, writer, mut batch) = watching();
2168
2169        r.engine_mut()
2170            .feed(writer, &wire(&[b"ZADD", b"z", b"4", b"m"]));
2171        pump(&mut r, &mut batch);
2172        r.engine_mut().sink_mut().clear();
2173
2174        r.engine_mut()
2175            .feed(writer, &wire(&[b"ZADD", b"z", b"4", b"m"]));
2176        r.engine_mut()
2177            .feed(writer, &wire(&[b"ZINCRBY", b"z", b"0", b"m"]));
2178        pump(&mut r, &mut batch);
2179        assert_eq!(fired(&r, sub), []);
2180
2181        // And one that does move says so, so the silence above is the score
2182        // and not the subscriber having gone away.
2183        r.engine_mut()
2184            .feed(writer, &wire(&[b"ZINCRBY", b"z", b"1", b"m"]));
2185        pump(&mut r, &mut batch);
2186        assert_eq!(fired(&r, sub), [("zincr".to_owned(), "z".to_owned())]);
2187    }
2188
2189    /// A write that trimmed says two things, and a trim that found nothing over
2190    /// the threshold says only the one.
2191    #[test]
2192    fn a_stream_write_says_what_the_trim_behind_it_took() {
2193        let (mut r, sub, writer, mut batch) = watching();
2194
2195        r.engine_mut()
2196            .feed(writer, &wire(&[b"XADD", b"s", b"1-1", b"f", b"v"]));
2197        r.engine_mut().feed(
2198            writer,
2199            &wire(&[b"XADD", b"s", b"MAXLEN", b"9", b"2-1", b"f", b"v"]),
2200        );
2201        r.engine_mut().feed(
2202            writer,
2203            &wire(&[b"XADD", b"s", b"MAXLEN", b"1", b"3-1", b"f", b"v"]),
2204        );
2205        pump(&mut r, &mut batch);
2206        assert_eq!(
2207            fired(&r, sub),
2208            [("xadd", "s"), ("xadd", "s"), ("xadd", "s"), ("xtrim", "s")]
2209                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2210        );
2211    }
2212
2213    /// Acknowledging an entry that has already been deleted from under the
2214    /// group takes nothing out of the log, so it says nothing, even though the
2215    /// reply calls it deleted.
2216    #[test]
2217    fn acknowledging_an_entry_that_is_already_gone_says_nothing() {
2218        let (mut r, sub, writer, mut batch) = watching();
2219
2220        for cmd in [
2221            wire(&[b"XADD", b"s", b"1-1", b"f", b"v"]),
2222            wire(&[b"XGROUP", b"CREATE", b"s", b"g", b"0"]),
2223            wire(&[b"XREADGROUP", b"GROUP", b"g", b"c", b"STREAMS", b"s", b">"]),
2224            wire(&[b"XDEL", b"s", b"1-1"]),
2225        ] {
2226            r.engine_mut().feed(writer, &cmd);
2227        }
2228        pump(&mut r, &mut batch);
2229        r.engine_mut().sink_mut().clear();
2230
2231        r.engine_mut().feed(
2232            writer,
2233            &wire(&[b"XACKDEL", b"s", b"g", b"IDS", b"1", b"1-1"]),
2234        );
2235        pump(&mut r, &mut batch);
2236        assert_eq!(fired(&r, sub), []);
2237    }
2238
2239    /// Taking the last field out of a hash says the key went with it, the same
2240    /// as taking the last of a list or a set does.
2241    #[test]
2242    fn emptying_a_hash_says_the_key_went_with_the_last_field() {
2243        let (mut r, sub, writer, mut batch) = watching();
2244
2245        r.engine_mut()
2246            .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2247        r.engine_mut().feed(writer, &wire(&[b"HDEL", b"h", b"a"]));
2248        // The second names a field that has already gone and one that has not,
2249        // so it still removed something and the hash is empty behind it.
2250        r.engine_mut()
2251            .feed(writer, &wire(&[b"HDEL", b"h", b"b", b"a"]));
2252        pump(&mut r, &mut batch);
2253        assert_eq!(
2254            fired(&r, sub),
2255            [("hset", "h"), ("hdel", "h"), ("hdel", "h"), ("del", "h")]
2256                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2257        );
2258    }
2259
2260    /// A deadline that has already passed takes the field with it, so what
2261    /// comes out is the removal and not the deadline.
2262    #[test]
2263    fn a_field_deadline_already_past_reads_as_a_removal() {
2264        let (mut r, sub, writer, mut batch) = watching();
2265
2266        r.engine_mut()
2267            .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2268        pump(&mut r, &mut batch);
2269        r.engine_mut().sink_mut().clear();
2270
2271        r.engine_mut().feed(
2272            writer,
2273            &wire(&[b"HEXPIRE", b"h", b"0", b"FIELDS", b"1", b"a"]),
2274        );
2275        r.engine_mut().feed(
2276            writer,
2277            &wire(&[b"HEXPIRE", b"h", b"100", b"FIELDS", b"1", b"b"]),
2278        );
2279        pump(&mut r, &mut batch);
2280        assert_eq!(
2281            fired(&r, sub),
2282            [("hdel", "h"), ("hexpire", "h")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2283        );
2284    }
2285
2286    /// Writing fields under a deadline that has already gone says all three
2287    /// things in order: the write, the removal it brought on, and the key.
2288    #[test]
2289    fn a_write_under_a_deadline_already_gone_says_the_write_first() {
2290        let (mut r, sub, writer, mut batch) = watching();
2291
2292        r.engine_mut().feed(
2293            writer,
2294            &wire(&[b"HSETEX", b"h", b"EXAT", b"1", b"FIELDS", b"1", b"a", b"1"]),
2295        );
2296        pump(&mut r, &mut batch);
2297        assert_eq!(
2298            fired(&r, sub),
2299            [("hset", "h"), ("hdel", "h"), ("del", "h")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2300        );
2301    }
2302
2303    /// Clearing a deadline is only news for a field that had one to clear, and
2304    /// the reply cannot be read for that: it is the value either way.
2305    #[test]
2306    fn clearing_a_deadline_that_was_never_set_says_nothing() {
2307        let (mut r, sub, writer, mut batch) = watching();
2308
2309        r.engine_mut()
2310            .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2311        r.engine_mut().feed(
2312            writer,
2313            &wire(&[b"HEXPIRE", b"h", b"100", b"FIELDS", b"1", b"a"]),
2314        );
2315        pump(&mut r, &mut batch);
2316        r.engine_mut().sink_mut().clear();
2317
2318        r.engine_mut()
2319            .feed(writer, &wire(&[b"HPERSIST", b"h", b"FIELDS", b"1", b"b"]));
2320        r.engine_mut().feed(
2321            writer,
2322            &wire(&[b"HGETEX", b"h", b"PERSIST", b"FIELDS", b"1", b"b"]),
2323        );
2324        pump(&mut r, &mut batch);
2325        assert_eq!(fired(&r, sub), []);
2326
2327        // And the field that did have one says so, so the silence above is the
2328        // deadline and not the subscriber having gone away.
2329        r.engine_mut().feed(
2330            writer,
2331            &wire(&[b"HGETEX", b"h", b"PERSIST", b"FIELDS", b"2", b"a", b"b"]),
2332        );
2333        pump(&mut r, &mut batch);
2334        assert_eq!(fired(&r, sub), [("hpersist".to_owned(), "h".to_owned())]);
2335    }
2336
2337    /// A name that was free is news on its own, and a name that was taken is
2338    /// not, whatever the write did to what was under it.
2339    #[test]
2340    fn a_key_that_was_not_there_before_says_so() {
2341        let (mut r, sub, writer, mut batch) = watching_flags(b"En");
2342
2343        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2344        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"w"]));
2345        r.engine_mut().feed(writer, &wire(&[b"APPEND", b"k", b"x"]));
2346        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2347        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"b"]));
2348        pump(&mut r, &mut batch);
2349        assert_eq!(
2350            fired(&r, sub),
2351            [("new", "k"), ("new", "l")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2352        );
2353    }
2354
2355    /// And it arrives in front of the write that made it, because at the moment
2356    /// it is said the write has not finished happening yet.
2357    #[test]
2358    fn the_news_of_a_new_key_comes_before_the_write_that_made_it() {
2359        let (mut r, sub, writer, mut batch) = watching_flags(b"EAn");
2360
2361        r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"1"]));
2362        r.engine_mut().feed(writer, &wire(&[b"SET", b"b", b"2"]));
2363        pump(&mut r, &mut batch);
2364        r.engine_mut().sink_mut().clear();
2365
2366        // A rename is a key arriving under a name that was already taken, and
2367        // it is still a key arriving: what was there is gone and what is there
2368        // now was somewhere else a moment ago.
2369        r.engine_mut().feed(writer, &wire(&[b"RENAME", b"a", b"b"]));
2370        pump(&mut r, &mut batch);
2371        assert_eq!(
2372            fired(&r, sub),
2373            [("new", "b"), ("rename_from", "a"), ("rename_to", "b")]
2374                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2375        );
2376    }
2377
2378    /// A store form is the other case: the name stays where it stands and only
2379    /// what is under it changes, so there is no key arriving to say anything
2380    /// about unless the destination was not there at all.
2381    #[test]
2382    fn writing_over_a_destination_is_not_a_key_arriving() {
2383        let (mut r, sub, writer, mut batch) = watching_flags(b"EAn");
2384
2385        r.engine_mut()
2386            .feed(writer, &wire(&[b"RPUSH", b"l", b"c", b"a", b"b"]));
2387        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"d", b"x"]));
2388        pump(&mut r, &mut batch);
2389        r.engine_mut().sink_mut().clear();
2390
2391        r.engine_mut()
2392            .feed(writer, &wire(&[b"SORT", b"l", b"ALPHA", b"STORE", b"d"]));
2393        pump(&mut r, &mut batch);
2394        assert_eq!(fired(&r, sub), [("sortstore".to_owned(), "d".to_owned())]);
2395        r.engine_mut().sink_mut().clear();
2396
2397        // And the same store onto a name nobody is using says both, which is
2398        // what makes the silence above the destination and not the flag.
2399        r.engine_mut().feed(writer, &wire(&[b"DEL", b"d"]));
2400        r.engine_mut()
2401            .feed(writer, &wire(&[b"SORT", b"l", b"ALPHA", b"STORE", b"d"]));
2402        pump(&mut r, &mut batch);
2403        assert_eq!(
2404            fired(&r, sub),
2405            [("del", "d"), ("new", "d"), ("sortstore", "d")]
2406                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2407        );
2408    }
2409
2410    /// A write that throws away the whole of what was under a name says so, and
2411    /// says the kind changed when it did.
2412    #[test]
2413    fn replacing_a_value_says_what_went_and_whether_the_kind_changed() {
2414        let (mut r, sub, writer, mut batch) = watching_flags(b"Eoc");
2415
2416        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2417        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"w"]));
2418        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2419        r.engine_mut().feed(writer, &wire(&[b"SET", b"l", b"v"]));
2420        pump(&mut r, &mut batch);
2421        assert_eq!(
2422            fired(&r, sub),
2423            [
2424                ("overwritten", "k"),
2425                ("overwritten", "l"),
2426                ("type_changed", "l")
2427            ]
2428            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2429        );
2430    }
2431
2432    /// And a write that reaches into the value that is already there says
2433    /// nothing, however much of it moves.
2434    #[test]
2435    fn a_write_that_changes_part_of_a_value_has_not_replaced_it() {
2436        let (mut r, sub, writer, mut batch) = watching_flags(b"Eoc");
2437
2438        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"1"]));
2439        r.engine_mut().feed(writer, &wire(&[b"APPEND", b"k", b"2"]));
2440        r.engine_mut().feed(writer, &wire(&[b"INCR", b"k"]));
2441        r.engine_mut()
2442            .feed(writer, &wire(&[b"SETRANGE", b"k", b"0", b"9"]));
2443        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2444        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"b"]));
2445        pump(&mut r, &mut batch);
2446        assert_eq!(fired(&r, sub), []);
2447    }
2448
2449    /// The one place the pair comes last rather than first, because there the
2450    /// destination is a key arriving and not a value changing, so nothing
2451    /// notices it going until the command says what it did.
2452    #[test]
2453    fn a_rename_says_what_it_replaced_after_saying_what_it_did() {
2454        let (mut r, sub, writer, mut batch) = watching_flags(b"EAnoc");
2455
2456        r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"1"]));
2457        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"b", b"x"]));
2458        pump(&mut r, &mut batch);
2459        r.engine_mut().sink_mut().clear();
2460
2461        r.engine_mut().feed(writer, &wire(&[b"RENAME", b"a", b"b"]));
2462        pump(&mut r, &mut batch);
2463        assert_eq!(
2464            fired(&r, sub),
2465            [
2466                ("new", "b"),
2467                ("rename_from", "a"),
2468                ("rename_to", "b"),
2469                ("overwritten", "b"),
2470                ("type_changed", "b")
2471            ]
2472            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2473        );
2474    }
2475
2476    /// A store form is the other way round, since there the name stays where it
2477    /// stands and the old value goes before the command has done anything.
2478    #[test]
2479    fn a_store_form_says_what_it_replaced_before_saying_what_it_did() {
2480        let (mut r, sub, writer, mut batch) = watching_flags(b"EAnoc");
2481
2482        r.engine_mut().feed(writer, &wire(&[b"SADD", b"s", b"m"]));
2483        r.engine_mut().feed(writer, &wire(&[b"SET", b"d", b"q"]));
2484        pump(&mut r, &mut batch);
2485        r.engine_mut().sink_mut().clear();
2486
2487        r.engine_mut()
2488            .feed(writer, &wire(&[b"SINTERSTORE", b"d", b"s"]));
2489        pump(&mut r, &mut batch);
2490        assert_eq!(
2491            fired(&r, sub),
2492            [
2493                ("overwritten", "d"),
2494                ("type_changed", "d"),
2495                ("sinterstore", "d")
2496            ]
2497            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2498        );
2499    }
2500
2501    /// A bit write says so when it did something and stays quiet when it did
2502    /// not, which is not the same as whether it was a write.
2503    #[test]
2504    fn a_bit_write_that_left_the_value_alone_says_nothing() {
2505        let (mut r, sub, writer, mut batch) = watching();
2506
2507        // `a` is 0x61, so the second bit from the top is already one and the
2508        // first of these three changes nothing. The second clears it and the
2509        // third finds it clear.
2510        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"abc"]));
2511        pump(&mut r, &mut batch);
2512        r.engine_mut().sink_mut().clear();
2513
2514        r.engine_mut()
2515            .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"1"]));
2516        r.engine_mut()
2517            .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"0"]));
2518        r.engine_mut()
2519            .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"0"]));
2520        // And one that writes a zero into a value too short to hold it, which
2521        // changed no bit that was there and still counts, because the bytes it
2522        // wrote the zero into were not there before.
2523        r.engine_mut()
2524            .feed(writer, &wire(&[b"SETBIT", b"k", b"100", b"0"]));
2525        pump(&mut r, &mut batch);
2526        assert_eq!(
2527            fired(&r, sub),
2528            [("setbit", "k"), ("setbit", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2529        );
2530    }
2531
2532    /// And `BITFIELD` follows the same rule one subcommand at a time, so a call
2533    /// that wrote every field back the way it found it says nothing.
2534    #[test]
2535    fn a_bitfield_that_wrote_the_same_values_back_says_nothing() {
2536        let (mut r, sub, writer, mut batch) = watching();
2537
2538        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"abc"]));
2539        pump(&mut r, &mut batch);
2540        r.engine_mut().sink_mut().clear();
2541
2542        // `a` again, written back over itself.
2543        r.engine_mut().feed(
2544            writer,
2545            &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"0", b"97"]),
2546        );
2547        r.engine_mut()
2548            .feed(writer, &wire(&[b"BITFIELD", b"k", b"GET", b"u8", b"0"]));
2549        r.engine_mut().feed(
2550            writer,
2551            &wire(&[b"BITFIELD", b"k", b"INCRBY", b"u8", b"0", b"0"]),
2552        );
2553        pump(&mut r, &mut batch);
2554        assert_eq!(fired(&r, sub), []);
2555
2556        // One that does change a field, and one that only makes the value
2557        // longer without changing a bit that was in it.
2558        r.engine_mut().feed(
2559            writer,
2560            &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"0", b"98"]),
2561        );
2562        r.engine_mut().feed(
2563            writer,
2564            &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"800", b"0"]),
2565        );
2566        pump(&mut r, &mut batch);
2567        assert_eq!(
2568            fired(&r, sub),
2569            [("setbit", "k"), ("setbit", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2570        );
2571    }
2572
2573    /// A sketch says `pfadd` when a register moved, and a merge says it under
2574    /// the same name whatever it merged.
2575    #[test]
2576    fn the_sketch_commands_say_what_a_mass_add_says() {
2577        let (mut r, sub, writer, mut batch) = watching();
2578
2579        r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h", b"a"]));
2580        // The same element again, which moves nothing.
2581        r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h", b"a"]));
2582        // And no elements at all on a sketch that is already there.
2583        r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h"]));
2584        // A merge with no sources, which touches nothing and says it anyway.
2585        r.engine_mut().feed(writer, &wire(&[b"PFMERGE", b"d"]));
2586        r.engine_mut()
2587            .feed(writer, &wire(&[b"PFMERGE", b"d", b"h"]));
2588        pump(&mut r, &mut batch);
2589        assert_eq!(
2590            fired(&r, sub),
2591            [("pfadd", "h"), ("pfadd", "d"), ("pfadd", "d")]
2592                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2593        );
2594    }
2595
2596    /// A geo key is a sorted set, so writing to one says what the `ZADD`
2597    /// underneath says, and storing a search says a name of its own.
2598    #[test]
2599    fn the_geo_commands_say_what_the_sorted_set_under_them_did() {
2600        let (mut r, sub, writer, mut batch) = watching();
2601
2602        let point: &[&[u8]] = &[b"GEOADD", b"g", b"13.361389", b"38.115556", b"P"];
2603        r.engine_mut().feed(writer, &wire(point));
2604        // The same member at the same place, which is neither an add nor a move.
2605        r.engine_mut().feed(writer, &wire(point));
2606        // The same member somewhere else, which is a move and is a write.
2607        r.engine_mut().feed(
2608            writer,
2609            &wire(&[b"GEOADD", b"g", b"14.0", b"38.115556", b"P"]),
2610        );
2611        r.engine_mut().feed(
2612            writer,
2613            &wire(&[
2614                b"GEORADIUS",
2615                b"g",
2616                b"14.0",
2617                b"38.0",
2618                b"200",
2619                b"km",
2620                b"STORE",
2621                b"d",
2622            ]),
2623        );
2624        r.engine_mut().feed(
2625            writer,
2626            &wire(&[
2627                b"GEOSEARCHSTORE",
2628                b"e",
2629                b"g",
2630                b"FROMLONLAT",
2631                b"14.0",
2632                b"38.0",
2633                b"BYRADIUS",
2634                b"200",
2635                b"km",
2636            ]),
2637        );
2638        pump(&mut r, &mut batch);
2639        assert_eq!(
2640            fired(&r, sub),
2641            [
2642                ("zadd", "g"),
2643                ("zadd", "g"),
2644                ("georadiusstore", "d"),
2645                ("geosearchstore", "e")
2646            ]
2647            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2648        );
2649    }
2650
2651    /// And a store whose search found nothing deletes the destination and says
2652    /// so, which is the rule every store form follows.
2653    #[test]
2654    fn a_geo_store_that_found_nothing_takes_the_destination_with_it() {
2655        let (mut r, sub, writer, mut batch) = watching();
2656
2657        r.engine_mut().feed(
2658            writer,
2659            &wire(&[b"GEOADD", b"g", b"13.361389", b"38.115556", b"P"]),
2660        );
2661        r.engine_mut().feed(writer, &wire(&[b"SET", b"d", b"x"]));
2662        pump(&mut r, &mut batch);
2663        r.engine_mut().sink_mut().clear();
2664
2665        r.engine_mut().feed(
2666            writer,
2667            &wire(&[
2668                b"GEORADIUS",
2669                b"g",
2670                b"1.0",
2671                b"1.0",
2672                b"1",
2673                b"km",
2674                b"STORE",
2675                b"d",
2676            ]),
2677        );
2678        // And again, now that the destination is not there, which deletes
2679        // nothing and says nothing.
2680        r.engine_mut().feed(
2681            writer,
2682            &wire(&[
2683                b"GEORADIUS",
2684                b"g",
2685                b"1.0",
2686                b"1.0",
2687                b"1",
2688                b"km",
2689                b"STORE",
2690                b"d",
2691            ]),
2692        );
2693        pump(&mut r, &mut batch);
2694        assert_eq!(
2695            fired(&r, sub),
2696            [("del", "d")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2697        );
2698    }
2699
2700    /// A key that arrives on a database other than the one that asked for it
2701    /// says it is new there, and says nothing on the database the command ran
2702    /// on.
2703    #[test]
2704    fn a_key_that_lands_on_another_database_is_new_over_there() {
2705        let (mut r, sub, mut batch) = engine();
2706        let writer = r.engine_mut().accept();
2707        r.engine_mut().feed(
2708            writer,
2709            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EAnoc"]),
2710        );
2711        r.engine_mut().feed(
2712            sub,
2713            &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*", b"__keyevent@1__:*"]),
2714        );
2715        r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2716        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2717        pump(&mut r, &mut batch);
2718        r.engine_mut().sink_mut().clear();
2719
2720        r.engine_mut()
2721            .feed(writer, &wire(&[b"COPY", b"a", b"b", b"DB", b"1"]));
2722        r.engine_mut().feed(writer, &wire(&[b"MOVE", b"k", b"1"]));
2723        pump(&mut r, &mut batch);
2724        assert_eq!(
2725            fired_on(&r, sub, 1),
2726            [
2727                ("new", "b"),
2728                ("copy_to", "b"),
2729                ("new", "k"),
2730                ("move_to", "k")
2731            ]
2732            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2733        );
2734        // And nothing of the sort on the database the two commands ran on,
2735        // which hears only the half of the move that happened there.
2736        assert_eq!(
2737            fired_on(&r, sub, 0),
2738            [("move_from", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2739        );
2740    }
2741
2742    /// A read that found nothing says so, once for each key it went looking
2743    /// for and in the order it was given them.
2744    ///
2745    /// The class is not in `A`, the same way it is not in Redis's, so these ask
2746    /// for it by letter.
2747    #[test]
2748    fn a_read_that_found_nothing_says_which_key_it_was() {
2749        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2750
2751        r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2752        r.engine_mut()
2753            .feed(writer, &wire(&[b"MGET", b"a", b"nk", b"nk"]));
2754        r.engine_mut()
2755            .feed(writer, &wire(&[b"EXISTS", b"nj", b"a"]));
2756        pump(&mut r, &mut batch);
2757        assert_eq!(
2758            fired(&r, sub),
2759            [("keymiss", "nk"), ("keymiss", "nk"), ("keymiss", "nj")]
2760                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2761        );
2762    }
2763
2764    /// A write says nothing about a name that was free, and the shapes of the
2765    /// same command that read say it.
2766    #[test]
2767    fn only_the_shape_of_a_write_that_reads_says_it() {
2768        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2769
2770        // A plain `SET` never looks, and neither does a `BITFIELD` with a
2771        // write anywhere in the line.
2772        r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2773        r.engine_mut().feed(
2774            writer,
2775            &wire(&[b"BITFIELD", b"nk", b"SET", b"u8", b"0", b"1"]),
2776        );
2777        r.engine_mut().feed(writer, &wire(&[b"LPOP", b"nk"]));
2778        pump(&mut r, &mut batch);
2779        assert_eq!(fired(&r, sub), []);
2780
2781        // The two that do, which are the same two commands.
2782        r.engine_mut()
2783            .feed(writer, &wire(&[b"SET", b"nj", b"v", b"GET"]));
2784        r.engine_mut()
2785            .feed(writer, &wire(&[b"BITFIELD", b"nl", b"GET", b"u8", b"0"]));
2786        r.engine_mut().feed(writer, &wire(&[b"GETDEL", b"nm"]));
2787        pump(&mut r, &mut batch);
2788        assert_eq!(
2789            fired(&r, sub),
2790            [("keymiss", "nj"), ("keymiss", "nl"), ("keymiss", "nm")]
2791                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2792        );
2793    }
2794
2795    /// A store form says it for the keys it read and not for the one it is
2796    /// about to write, however empty that name is.
2797    #[test]
2798    fn a_store_form_says_it_only_for_its_sources() {
2799        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2800
2801        r.engine_mut()
2802            .feed(writer, &wire(&[b"SINTERSTORE", b"dst", b"nk", b"nj"]));
2803        r.engine_mut()
2804            .feed(writer, &wire(&[b"ZUNIONSTORE", b"dst", b"1", b"nz"]));
2805        r.engine_mut()
2806            .feed(writer, &wire(&[b"ZRANGESTORE", b"dst", b"nz", b"0", b"-1"]));
2807        pump(&mut r, &mut batch);
2808        assert_eq!(
2809            fired(&r, sub),
2810            [
2811                ("keymiss", "nk"),
2812                ("keymiss", "nj"),
2813                ("keymiss", "nz"),
2814                ("keymiss", "nz")
2815            ]
2816            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2817        );
2818    }
2819
2820    /// Both stream reads find their keys behind `STREAMS`, and `XREAD` looks
2821    /// each of them up twice, once to resolve the identifier it was handed and
2822    /// once to serve from it.
2823    #[test]
2824    fn the_stream_reads_say_it_for_the_keys_behind_the_keyword() {
2825        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2826
2827        r.engine_mut().feed(
2828            writer,
2829            &wire(&[b"XREAD", b"STREAMS", b"nk", b"nj", b"0", b"0"]),
2830        );
2831        pump(&mut r, &mut batch);
2832        assert_eq!(
2833            fired(&r, sub),
2834            [
2835                ("keymiss", "nk"),
2836                ("keymiss", "nj"),
2837                ("keymiss", "nk"),
2838                ("keymiss", "nj")
2839            ]
2840            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2841        );
2842    }
2843
2844    /// A command that failed while it was still reading its own arguments never
2845    /// looked a key up, so it says nothing, and one that failed on what it
2846    /// found keeps what it had already said.
2847    #[test]
2848    fn an_argument_that_did_not_parse_takes_the_miss_back() {
2849        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2850
2851        r.engine_mut()
2852            .feed(writer, &wire(&[b"GETRANGE", b"nk", b"x", b"-1"]));
2853        r.engine_mut()
2854            .feed(writer, &wire(&[b"LPOS", b"nk", b"a", b"RANK", b"0"]));
2855        pump(&mut r, &mut batch);
2856        assert_eq!(fired(&r, sub), []);
2857
2858        // A `WRONGTYPE` is an answer about what was under a key, which means
2859        // the lookups happened and the misses in front of the one that failed
2860        // stand.
2861        r.engine_mut().feed(writer, &wire(&[b"SET", b"s", b"v"]));
2862        pump(&mut r, &mut batch);
2863        r.engine_mut().sink_mut().clear();
2864
2865        r.engine_mut()
2866            .feed(writer, &wire(&[b"SINTER", b"nk", b"s"]));
2867        pump(&mut r, &mut batch);
2868        assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nk".to_owned())]);
2869    }
2870
2871    /// A read over several keys says nothing about the ones behind a key that
2872    /// holds the wrong thing, because the command stops there and never looks
2873    /// at them.
2874    #[test]
2875    fn a_read_stops_missing_where_it_stops_looking() {
2876        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2877
2878        r.engine_mut().feed(writer, &wire(&[b"SET", b"s", b"v"]));
2879        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"x"]));
2880        pump(&mut r, &mut batch);
2881        r.engine_mut().sink_mut().clear();
2882
2883        r.engine_mut()
2884            .feed(writer, &wire(&[b"SINTER", b"s", b"nk"]));
2885        pump(&mut r, &mut batch);
2886        assert_eq!(fired(&r, sub), []);
2887
2888        // And a read that does not stop keeps going. `MGET` answers a nil for
2889        // the list and goes on to look at the key behind it.
2890        r.engine_mut().feed(writer, &wire(&[b"MGET", b"l", b"nk"]));
2891        pump(&mut r, &mut batch);
2892        assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nk".to_owned())]);
2893    }
2894
2895    /// The keys a `SORT` builds out of its elements say it too, and they are
2896    /// the one set of keys nothing could have asked about in front of the
2897    /// command, since they do not exist until it is running.
2898    #[test]
2899    fn the_keys_a_sort_pattern_names_say_it_as_they_are_read() {
2900        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2901
2902        r.engine_mut()
2903            .feed(writer, &wire(&[b"RPUSH", b"l", b"1", b"2"]));
2904        r.engine_mut().feed(writer, &wire(&[b"SET", b"w_1", b"5"]));
2905        pump(&mut r, &mut batch);
2906        r.engine_mut().sink_mut().clear();
2907
2908        r.engine_mut().feed(
2909            writer,
2910            &wire(&[b"SORT", b"l", b"BY", b"w_*", b"GET", b"p_*"]),
2911        );
2912        pump(&mut r, &mut batch);
2913        assert_eq!(
2914            fired(&r, sub),
2915            [("keymiss", "w_2"), ("keymiss", "p_2"), ("keymiss", "p_1")]
2916                .map(|(e, k)| (e.to_owned(), k.to_owned()))
2917        );
2918    }
2919
2920    /// A key that was there and had run out says both things in the order they
2921    /// happened: the deadline first, because the probe that noticed the key was
2922    /// gone is what reaped it.
2923    #[test]
2924    fn a_deadline_that_passed_is_news_before_the_miss_it_causes() {
2925        let (mut r, sub, mut batch) = timed();
2926        let writer = r.engine_mut().accept();
2927        r.engine_mut().feed(
2928            writer,
2929            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EgAm"]),
2930        );
2931        r.engine_mut()
2932            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2933        r.engine_mut()
2934            .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
2935        pump(&mut r, &mut batch);
2936        r.engine_mut().sink_mut().clear();
2937
2938        r.engine().server().advance_clock_ms(50);
2939        r.engine_mut().feed(writer, &wire(&[b"GET", b"k"]));
2940        pump(&mut r, &mut batch);
2941        assert_eq!(
2942            fired(&r, sub),
2943            [("expired", "k"), ("keymiss", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2944        );
2945    }
2946
2947    /// A module read says it the same way a core read does, because the module
2948    /// API opens its key through the same lookup.
2949    #[test]
2950    fn a_module_read_says_it_the_way_a_core_read_does() {
2951        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2952
2953        r.engine_mut().feed(writer, &wire(&[b"JSON.GET", b"nk"]));
2954        r.engine_mut().feed(writer, &wire(&[b"TS.GET", b"nj"]));
2955        r.engine_mut()
2956            .feed(writer, &wire(&[b"BF.EXISTS", b"nl", b"x"]));
2957        r.engine_mut().feed(writer, &wire(&[b"TDIGEST.MIN", b"nm"]));
2958        r.engine_mut().feed(writer, &wire(&[b"TOPK.LIST", b"nn"]));
2959        r.engine_mut().feed(writer, &wire(&[b"CMS.INFO", b"no"]));
2960        r.engine_mut().feed(writer, &wire(&[b"VCARD", b"np"]));
2961        pump(&mut r, &mut batch);
2962        assert_eq!(
2963            fired(&r, sub),
2964            [
2965                ("keymiss", "nk"),
2966                ("keymiss", "nj"),
2967                ("keymiss", "nl"),
2968                ("keymiss", "nm"),
2969                ("keymiss", "nn"),
2970                ("keymiss", "no"),
2971                ("keymiss", "np")
2972            ]
2973            .map(|(e, k)| (e.to_owned(), k.to_owned()))
2974        );
2975
2976        // And the one of them that reads a list of keys says it for each,
2977        // without stopping at the first empty name.
2978        r.engine_mut().sink_mut().clear();
2979        r.engine_mut()
2980            .feed(writer, &wire(&[b"JSON.MGET", b"nk", b"nj", b"$"]));
2981        pump(&mut r, &mut batch);
2982        assert_eq!(
2983            fired(&r, sub),
2984            [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2985        );
2986    }
2987
2988    /// The module commands that say nothing, which are the writes, the two
2989    /// reads that were measured quiet, and the whole of the search group bar
2990    /// the pair that reads a key rather than an index.
2991    #[test]
2992    fn the_quiet_module_commands_stay_quiet() {
2993        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2994
2995        r.engine_mut()
2996            .feed(writer, &wire(&[b"JSON.SET", b"nk", b"$", b"1"]));
2997        r.engine_mut()
2998            .feed(writer, &wire(&[b"BF.ADD", b"nj", b"x"]));
2999        r.engine_mut()
3000            .feed(writer, &wire(&[b"TS.ADD", b"nl", b"1000", b"1"]));
3001        r.engine_mut().feed(writer, &wire(&[b"TS.INFO", b"nm"]));
3002        r.engine_mut().feed(writer, &wire(&[b"CF.COMPACT", b"nn"]));
3003        r.engine_mut()
3004            .feed(writer, &wire(&[b"JSON.DEBUG", b"HELP"]));
3005        r.engine_mut()
3006            .feed(writer, &wire(&[b"FT.GET", b"ni", b"no"]));
3007        r.engine_mut()
3008            .feed(writer, &wire(&[b"FT.SEARCH", b"ni", b"*"]));
3009        pump(&mut r, &mut batch);
3010        assert_eq!(fired(&r, sub), []);
3011
3012        // The three that do have a key of their own to be missing.
3013        r.engine_mut()
3014            .feed(writer, &wire(&[b"JSON.DEBUG", b"MEMORY", b"np"]));
3015        r.engine_mut()
3016            .feed(writer, &wire(&[b"FT.SUGGET", b"nq", b"x"]));
3017        r.engine_mut().feed(writer, &wire(&[b"FT.SUGLEN", b"nr"]));
3018        pump(&mut r, &mut batch);
3019        assert_eq!(
3020            fired(&r, sub),
3021            [("keymiss", "np"), ("keymiss", "nq"), ("keymiss", "nr")]
3022                .map(|(e, k)| (e.to_owned(), k.to_owned()))
3023        );
3024    }
3025
3026    /// A module read keeps a miss that its own arguments went on to spoil,
3027    /// where a core read in the same shape takes it back.
3028    ///
3029    /// The two are the same question asked in a different order. A core command
3030    /// reads everything it was sent and then looks, a module command opens its
3031    /// key and then reads the rest.
3032    #[test]
3033    fn a_module_read_keeps_the_miss_a_later_argument_spoiled() {
3034        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
3035
3036        r.engine_mut()
3037            .feed(writer, &wire(&[b"JSON.GET", b"nk", b"$..["]));
3038        r.engine_mut().feed(
3039            writer,
3040            &wire(&[b"VSIM", b"nj", b"ELE", b"e", b"COUNT", b"x"]),
3041        );
3042        pump(&mut r, &mut batch);
3043        assert_eq!(
3044            fired(&r, sub),
3045            [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
3046        );
3047    }
3048
3049    /// The two merges read a destination and then their sources, and stop at
3050    /// the first source that is not there because that is where they fail.
3051    #[test]
3052    fn the_module_merges_stop_at_the_first_empty_source() {
3053        let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
3054
3055        r.engine_mut().feed(
3056            writer,
3057            &wire(&[b"TDIGEST.MERGE", b"nk", b"2", b"nj", b"nl"]),
3058        );
3059        pump(&mut r, &mut batch);
3060        assert_eq!(
3061            fired(&r, sub),
3062            [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
3063        );
3064
3065        // The sketch writes its destination rather than reading it, so an empty
3066        // name there is not a miss, and it is the end of the command, so the
3067        // sources behind it are never opened.
3068        r.engine_mut().sink_mut().clear();
3069        r.engine_mut()
3070            .feed(writer, &wire(&[b"CMS.MERGE", b"nk", b"1", b"nj"]));
3071        pump(&mut r, &mut batch);
3072        assert_eq!(fired(&r, sub), []);
3073
3074        // With a destination that is there, the sources are read and the first
3075        // empty one is the last thing looked at.
3076        r.engine_mut()
3077            .feed(writer, &wire(&[b"CMS.INITBYDIM", b"cm", b"100", b"5"]));
3078        pump(&mut r, &mut batch);
3079        r.engine_mut().sink_mut().clear();
3080
3081        r.engine_mut()
3082            .feed(writer, &wire(&[b"CMS.MERGE", b"cm", b"2", b"nj", b"nl"]));
3083        pump(&mut r, &mut batch);
3084        assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nj".to_owned())]);
3085    }
3086
3087    /// A subscriber on the four subkey channels and the writer that will feed
3088    /// them.
3089    ///
3090    /// The flags name no class channel, so what the subscriber gets is only
3091    /// what those four published and nothing is in the answer twice.
3092    fn watching_fields(flags: &[u8]) -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
3093        let (mut r, sub, mut batch) = engine();
3094        let writer = r.engine_mut().accept();
3095        r.engine_mut().feed(
3096            writer,
3097            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", flags]),
3098        );
3099        r.engine_mut()
3100            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__subkey*@0__:*"]));
3101        pump(&mut r, &mut batch);
3102        r.engine_mut().sink_mut().clear();
3103        (r, sub, writer, batch)
3104    }
3105
3106    /// The channel and payload of every subkey notification the subscriber got.
3107    ///
3108    /// Read off the wire rather than checked as one byte literal, because a
3109    /// command that publishes on all four channels at once makes for a literal
3110    /// nobody can hold in their head.
3111    fn carried(r: &Reactor<Wire<Recorder>>, sub: ConnId) -> Vec<(String, String)> {
3112        let sent = String::from_utf8_lossy(r.engine().sink().sent(sub)).into_owned();
3113        let mut out = Vec::new();
3114        let mut parts = sent.split("\r\n");
3115        while let Some(p) = parts.next() {
3116            if p != "pmessage" {
3117                continue;
3118            }
3119            // Each of the three that follow is a length and then the bytes, and
3120            // the first of them is the pattern, which is the same every time.
3121            let mut next = || {
3122                parts.next();
3123                parts.next().unwrap_or_default().to_owned()
3124            };
3125            next();
3126            let channel = next();
3127            out.push((channel, next()));
3128        }
3129        out
3130    }
3131
3132    /// The four channels each spell the same event a different way, and the
3133    /// field list they carry is length prefixed so that a field holding a comma
3134    /// reads back as one field and not two.
3135    #[test]
3136    fn the_subkey_channels_carry_the_fields_an_event_touched() {
3137        let (mut r, sub, writer, mut batch) = watching_fields(b"ASTIV");
3138
3139        r.engine_mut()
3140            .feed(writer, &wire(&[b"HSET", b"h", b"a,b", b"1", b"c", b"2"]));
3141        pump(&mut r, &mut batch);
3142        assert_eq!(
3143            carried(&r, sub),
3144            [
3145                ("__subkeyspace@0__:h", "hset|3:a,b,1:c"),
3146                ("__subkeyevent@0__:hset", "1:h|3:a,b,1:c"),
3147                ("__subkeyspaceitem@0__:h\na,b", "hset"),
3148                ("__subkeyspaceitem@0__:h\nc", "hset"),
3149                ("__subkeyspaceevent@0__:hset|h", "3:a,b,1:c"),
3150            ]
3151            .map(|(c, p)| (c.to_owned(), p.to_owned()))
3152        );
3153    }
3154
3155    /// A key holding a newline cannot be told apart from the field spelled
3156    /// after it on the per field channel, so that one channel is left out for
3157    /// it rather than sent something nobody can read back.
3158    #[test]
3159    fn a_key_holding_a_newline_skips_the_per_field_channel() {
3160        let (mut r, sub, writer, mut batch) = watching_fields(b"ASTIV");
3161
3162        r.engine_mut()
3163            .feed(writer, &wire(&[b"HSET", b"h\nx", b"f", b"1"]));
3164        pump(&mut r, &mut batch);
3165        assert_eq!(
3166            carried(&r, sub),
3167            [
3168                ("__subkeyspace@0__:h\nx", "hset|1:f"),
3169                ("__subkeyevent@0__:hset", "3:h\nx|1:f"),
3170                ("__subkeyspaceevent@0__:hset|h\nx", "1:f"),
3171            ]
3172            .map(|(c, p)| (c.to_owned(), p.to_owned()))
3173        );
3174    }
3175
3176    /// An event with no fields behind it goes out on the two ordinary channels
3177    /// and on none of these four, however they are set, which is every event
3178    /// outside the hash class and the `del` behind an emptied hash with it.
3179    #[test]
3180    fn an_event_with_no_fields_stays_off_the_subkey_channels() {
3181        let (mut r, sub, writer, mut batch) = watching_fields(b"AS");
3182
3183        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
3184        r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
3185        r.engine_mut()
3186            .feed(writer, &wire(&[b"HSET", b"h", b"f", b"1"]));
3187        r.engine_mut().feed(writer, &wire(&[b"HDEL", b"h", b"f"]));
3188        pump(&mut r, &mut batch);
3189        assert_eq!(
3190            carried(&r, sub),
3191            [
3192                ("__subkeyspace@0__:h", "hset|1:f"),
3193                ("__subkeyspace@0__:h", "hdel|1:f"),
3194            ]
3195            .map(|(c, p)| (c.to_owned(), p.to_owned()))
3196        );
3197    }
3198
3199    /// A subscriber, a writer and a clock the test moves by hand.
3200    ///
3201    /// The same arrangement [`watching`] sets up, on the fixed clock
3202    /// [`timed`] builds, because every deadline in a test has to arrive on
3203    /// request rather than in its own time.
3204    fn watching_clock() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
3205        let (mut r, sub, mut batch) = timed();
3206        let writer = r.engine_mut().accept();
3207        r.engine_mut().feed(
3208            writer,
3209            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
3210        );
3211        r.engine_mut()
3212            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
3213        pump(&mut r, &mut batch);
3214        r.engine_mut().sink_mut().clear();
3215        (r, sub, writer, batch)
3216    }
3217
3218    /// A key that reached its deadline says so when a reader trips over it, and
3219    /// the reader's own command says nothing, because as far as it is concerned
3220    /// the key was never there.
3221    #[test]
3222    fn a_deadline_that_passed_is_news_when_a_reader_finds_it() {
3223        let (mut r, sub, writer, mut batch) = watching_clock();
3224
3225        r.engine_mut()
3226            .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
3227        pump(&mut r, &mut batch);
3228        r.engine_mut().sink_mut().clear();
3229
3230        r.engine().server().advance_clock_ms(50);
3231        r.engine_mut().feed(writer, &wire(&[b"GET", b"k"]));
3232        pump(&mut r, &mut batch);
3233        assert_eq!(
3234            fired(&r, sub),
3235            [("expired", "k")].map(|(e, k)| (e.to_owned(), k.to_owned())),
3236            "and not a del alongside it, which is a different piece of news"
3237        );
3238    }
3239
3240    /// And a key nobody ever reads back says it too, because the housekeeping
3241    /// the driver runs between batches goes looking for them.
3242    ///
3243    /// This is the whole reason a cache that writes under a deadline and never
3244    /// reads does not grow forever, and it is worth a test of its own: the sweep
3245    /// lives behind a driver call rather than behind a command, so nothing in
3246    /// the command tests would notice if it stopped running.
3247    #[test]
3248    fn a_deadline_that_passed_is_news_with_nobody_reading() {
3249        let (mut r, sub, writer, mut batch) = watching_clock();
3250
3251        r.engine_mut()
3252            .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
3253        pump(&mut r, &mut batch);
3254        r.engine_mut().sink_mut().clear();
3255
3256        r.engine().server().advance_clock_ms(50);
3257        // Nothing to run, so this turn is housekeeping and nothing else.
3258        pump(&mut r, &mut batch);
3259        assert_eq!(
3260            fired(&r, sub),
3261            [("expired", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
3262        );
3263
3264        r.engine_mut().sink_mut().clear();
3265        pump(&mut r, &mut batch);
3266        assert!(fired(&r, sub).is_empty(), "and it only goes once");
3267    }
3268
3269    /// A key an eviction took says that instead, since a client that lost a key
3270    /// to a memory limit and a client whose key ran out of time are owed two
3271    /// different explanations.
3272    #[test]
3273    fn a_key_a_limit_took_says_it_was_evicted() {
3274        let (mut r, sub, writer, mut batch) = watching();
3275
3276        let val = vec![b'v'; 256];
3277        for i in 0..2000u32 {
3278            let k = format!("key:{i:08}");
3279            r.engine_mut()
3280                .feed(writer, &wire(&[b"SET", k.as_bytes(), &val]));
3281        }
3282        pump(&mut r, &mut batch);
3283        r.engine().server().refresh_memory();
3284        let full = r.engine().server().memory_bytes();
3285        r.engine_mut().sink_mut().clear();
3286
3287        // Under what it is already holding, so the next write has to take
3288        // something out before it can put anything in.
3289        let limit = (full / 2).to_string();
3290        r.engine_mut().feed(
3291            writer,
3292            &wire(&[b"CONFIG", b"SET", b"maxmemory-policy", b"allkeys-random"]),
3293        );
3294        r.engine_mut().feed(
3295            writer,
3296            &wire(&[b"CONFIG", b"SET", b"maxmemory", limit.as_bytes()]),
3297        );
3298        r.engine_mut()
3299            .feed(writer, &wire(&[b"SET", b"newcomer", &val]));
3300        pump(&mut r, &mut batch);
3301
3302        let events = fired(&r, sub);
3303        assert!(
3304            events.iter().any(|(e, _)| e == "evicted"),
3305            "the write made room and never said so: {events:?}"
3306        );
3307        assert!(
3308            events
3309                .iter()
3310                .all(|(e, k)| e != "evicted" || k != "newcomer"),
3311            "the key the write was for is the one key it cannot have taken"
3312        );
3313    }
3314
3315    /// Inside a transaction each command's notifications go out before the
3316    /// next command runs, so `EXEC` does not bunch them all up at the end.
3317    #[test]
3318    fn a_transaction_publishes_between_its_commands_and_not_after_them() {
3319        let (mut r, sub, mut batch) = engine();
3320        let writer = r.engine_mut().accept();
3321
3322        r.engine_mut().feed(
3323            writer,
3324            &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
3325        );
3326        r.engine_mut()
3327            .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
3328        pump(&mut r, &mut batch);
3329        r.engine_mut().sink_mut().clear();
3330
3331        r.engine_mut().feed(writer, &wire(&[b"MULTI"]));
3332        r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
3333        r.engine_mut().feed(writer, &wire(&[b"DEL", b"k"]));
3334        r.engine_mut().feed(writer, &wire(&[b"EXEC"]));
3335        pump(&mut r, &mut batch);
3336        assert_eq!(
3337            r.engine().sink().sent(sub),
3338            b"*4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
3339              $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n\
3340              *4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
3341              $18\r\n__keyevent@0__:del\r\n$1\r\nk\r\n"
3342        );
3343    }
3344
3345    #[test]
3346    fn a_reply_the_socket_would_not_take_is_offered_again() {
3347        let mut r = Reactor::inline(Wire::new(Trickle::default()));
3348        let conn = r.engine_mut().accept();
3349        let mut batch = Vec::new();
3350
3351        r.engine_mut().feed(conn, &wire(&[b"PING"]));
3352        pump(&mut r, &mut batch);
3353        // Two flushes in a pump, so four bytes and then three.
3354        assert_eq!(r.engine().sink().sent, b"+PONG\r\n");
3355        assert_eq!(r.engine().sink().writes, 2);
3356    }
3357    /// `CLIENT REPLY OFF` and `SKIP` are the one thing that takes a reply back
3358    /// after the command has written it, and the engine is the only place
3359    /// holding both the buffer and the decision.
3360    #[test]
3361    fn client_reply_skip_covers_the_command_after_it_and_nothing_else() {
3362        let (mut r, conn, mut batch) = engine();
3363
3364        r.engine_mut()
3365            .feed(conn, &wire(&[b"CLIENT", b"REPLY", b"SKIP"]));
3366        r.engine_mut().feed(conn, &wire(&[b"SET", b"a", b"1"]));
3367        r.engine_mut().feed(conn, &wire(&[b"SET", b"b", b"2"]));
3368        pump(&mut r, &mut batch);
3369        // Nothing for the `SKIP` itself, nothing for the `SET` after it, and
3370        // the second `SET` is answered. Byte for byte what 8.10.1 sends.
3371        assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
3372    }
3373
3374    #[test]
3375    fn client_reply_off_stays_off_until_it_is_turned_back_on() {
3376        let (mut r, conn, mut batch) = engine();
3377
3378        r.engine_mut()
3379            .feed(conn, &wire(&[b"CLIENT", b"REPLY", b"OFF"]));
3380        r.engine_mut().feed(conn, &wire(&[b"SET", b"c", b"3"]));
3381        r.engine_mut().feed(conn, &wire(&[b"PING"]));
3382        r.engine_mut()
3383            .feed(conn, &wire(&[b"CLIENT", b"REPLY", b"ON"]));
3384        r.engine_mut().feed(conn, &wire(&[b"PING"]));
3385        pump(&mut r, &mut batch);
3386        // The `ON` answers, because the mode is read after the command rather
3387        // than before it, and everything between the two is silent.
3388        assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n+PONG\r\n");
3389
3390        // And the writes went through while nobody was being answered.
3391        r.engine_mut().sink_mut().clear();
3392        r.engine_mut().feed(conn, &wire(&[b"GET", b"c"]));
3393        pump(&mut r, &mut batch);
3394        assert_eq!(r.engine().sink().sent(conn), b"$1\r\n3\r\n");
3395    }
3396
3397    /// The two addresses and the descriptor come from whoever accepted the
3398    /// socket, and a caller that has one has to be able to say so.
3399    #[test]
3400    fn a_connection_reports_the_socket_it_was_opened_on() {
3401        let mut r = Reactor::inline(Wire::new(Recorder::new()));
3402        let conn = r
3403            .engine_mut()
3404            .accept_from("10.0.0.7:54321", "10.0.0.1:6379", 11, false);
3405        let mut batch = Vec::new();
3406
3407        r.engine_mut().feed(conn, &wire(&[b"CLIENT", b"INFO"]));
3408        pump(&mut r, &mut batch);
3409        let sent = String::from_utf8_lossy(r.engine().sink().sent(conn)).into_owned();
3410        assert!(sent.contains("addr=10.0.0.7:54321"), "{sent}");
3411        assert!(sent.contains("laddr=10.0.0.1:6379"), "{sent}");
3412        assert!(sent.contains("fd=11"), "{sent}");
3413    }
3414
3415    /// `tot-net-in`, `tot-net-out` and `tot-cmds` are counted by the front and
3416    /// by the engine, so nothing below the engine can check them.
3417    #[test]
3418    fn a_connection_counts_the_bytes_and_the_commands_that_went_over_it() {
3419        let (mut r, conn, mut batch) = engine();
3420        let mut stream = wire(&[b"PING"]);
3421        stream.extend(wire(&[b"PING"]));
3422        let sent_in = stream.len();
3423
3424        r.engine_mut().feed(conn, &stream);
3425        pump(&mut r, &mut batch);
3426        r.engine_mut().sink_mut().clear();
3427
3428        r.engine_mut().feed(conn, &wire(&[b"CLIENT", b"INFO"]));
3429        pump(&mut r, &mut batch);
3430        let sent = String::from_utf8_lossy(r.engine().sink().sent(conn)).into_owned();
3431        // Two pings, counted after they ran, so the report asking does not
3432        // count itself, which is what a real server answers too. Two reads,
3433        // because the two pings arrived in one and the report in the other.
3434        assert!(sent.contains("tot-cmds=2"), "{sent}");
3435        assert!(sent.contains("read-events=2"), "{sent}");
3436        assert!(
3437            sent.contains(&format!("tot-net-in={}", sent_in + 26)),
3438            "{sent}"
3439        );
3440        assert!(sent.contains("tot-net-out=14"), "{sent}");
3441    }
3442
3443    /// `CLIENT LIST` is the one command that reports connections other than the
3444    /// one asking, so nothing below the engine can check it: it needs two
3445    /// connections and a front to hold them both.
3446    #[test]
3447    fn client_list_reports_every_connection_and_not_just_the_one_asking() {
3448        let mut r = Reactor::inline(Wire::new(Recorder::new()));
3449        let one = r
3450            .engine_mut()
3451            .accept_from("10.0.0.7:1111", "10.0.0.1:6379", 11, false);
3452        let two = r
3453            .engine_mut()
3454            .accept_from("10.0.0.8:2222", "10.0.0.1:6379", 12, false);
3455        let mut batch = Vec::new();
3456
3457        r.engine_mut()
3458            .feed(two, &wire(&[b"CLIENT", b"SETNAME", b"worker"]));
3459        r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3460        pump(&mut r, &mut batch);
3461
3462        let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
3463        let lines: Vec<&str> = sent.lines().filter(|l| l.starts_with("id=")).collect();
3464        assert_eq!(lines.len(), 2, "{sent}");
3465        assert!(lines[0].contains("addr=10.0.0.7:1111"), "{sent}");
3466        assert!(lines[0].contains("cmd=client|list"), "{sent}");
3467        assert!(lines[1].contains("addr=10.0.0.8:2222"), "{sent}");
3468        assert!(lines[1].contains("name=worker"), "{sent}");
3469        assert!(lines[1].contains("cmd=client|setname"), "{sent}");
3470    }
3471
3472    /// The listing is in the order the connections were opened, with the holes
3473    /// left by the ones that closed taken out.
3474    #[test]
3475    fn client_list_keeps_the_order_the_connections_were_opened_in() {
3476        let mut r = Reactor::inline(Wire::new(Recorder::new()));
3477        let one = r.engine_mut().accept();
3478        let two = r.engine_mut().accept();
3479        let three = r.engine_mut().accept();
3480        let mut batch = Vec::new();
3481
3482        r.engine_mut().hangup(two);
3483        r.engine_mut().feed(three, &wire(&[b"CLIENT", b"LIST"]));
3484        pump(&mut r, &mut batch);
3485
3486        let sent = String::from_utf8_lossy(r.engine().sink().sent(three)).into_owned();
3487        let ids: Vec<&str> = sent
3488            .lines()
3489            .filter(|l| l.starts_with("id="))
3490            .map(|l| l.split(' ').next().unwrap_or(""))
3491            .collect();
3492        assert_eq!(ids, vec!["id=1", "id=3"], "{sent}");
3493        let _ = one;
3494    }
3495
3496    /// A kill on somebody else is not carried out by the thread that ran it, so
3497    /// the close has to be checked through the front rather than through the
3498    /// reply.
3499    #[test]
3500    fn client_kill_closes_the_connection_it_names_and_answers_a_count() {
3501        let mut r = Reactor::inline(Wire::new(Recorder::new()));
3502        let one = r
3503            .engine_mut()
3504            .accept_from("10.0.0.7:1111", "10.0.0.1:6379", 11, false);
3505        let two = r
3506            .engine_mut()
3507            .accept_from("10.0.0.8:2222", "10.0.0.1:6379", 12, false);
3508        let mut batch = Vec::new();
3509
3510        r.engine_mut()
3511            .feed(one, &wire(&[b"CLIENT", b"KILL", b"ADDR", b"10.0.0.8:2222"]));
3512        pump(&mut r, &mut batch);
3513
3514        assert_eq!(r.engine().sink().sent(one), b":1\r\n");
3515        assert!(r.engine().sink().was_closed(two), "the named one went away");
3516        assert!(!r.engine().sink().was_closed(one), "the caller did not");
3517    }
3518
3519    /// The old form names one address, answers `OK`, and is the one shape that
3520    /// will take the caller's own connection.
3521    #[test]
3522    fn the_old_kill_takes_one_address_and_will_take_the_caller() {
3523        let mut r = Reactor::inline(Wire::new(Recorder::new()));
3524        let one = r
3525            .engine_mut()
3526            .accept_from("10.0.0.7:1111", "10.0.0.1:6379", 11, false);
3527        let mut batch = Vec::new();
3528
3529        r.engine_mut()
3530            .feed(one, &wire(&[b"CLIENT", b"KILL", b"10.0.0.9:9999"]));
3531        pump(&mut r, &mut batch);
3532        assert_eq!(r.engine().sink().sent(one), b"-ERR No such client\r\n");
3533
3534        r.engine_mut().sink_mut().clear();
3535        r.engine_mut()
3536            .feed(one, &wire(&[b"CLIENT", b"KILL", b"10.0.0.7:1111"]));
3537        pump(&mut r, &mut batch);
3538        assert_eq!(r.engine().sink().sent(one), b"+OK\r\n");
3539        assert!(r.engine().sink().was_closed(one), "it took itself");
3540    }
3541
3542    /// `SKIPME no` is the only way the new form reaches the caller, and the
3543    /// reply still goes out before the socket does.
3544    #[test]
3545    fn a_kill_spares_the_caller_unless_it_is_told_not_to() {
3546        let (mut r, conn, mut batch) = engine();
3547        r.engine_mut()
3548            .feed(conn, &wire(&[b"CLIENT", b"KILL", b"TYPE", b"normal"]));
3549        pump(&mut r, &mut batch);
3550        assert_eq!(r.engine().sink().sent(conn), b":0\r\n");
3551        assert!(!r.engine().sink().was_closed(conn));
3552
3553        r.engine_mut().sink_mut().clear();
3554        r.engine_mut().feed(
3555            conn,
3556            &wire(&[b"CLIENT", b"KILL", b"TYPE", b"normal", b"SKIPME", b"no"]),
3557        );
3558        pump(&mut r, &mut batch);
3559        assert_eq!(r.engine().sink().sent(conn), b":1\r\n");
3560        assert!(r.engine().sink().was_closed(conn));
3561    }
3562
3563    /// A connection that closed is out of the table, so the report is of what is
3564    /// open and not of what has ever been open.
3565    #[test]
3566    fn a_connection_that_went_away_is_off_the_list() {
3567        let mut r = Reactor::inline(Wire::new(Recorder::new()));
3568        let one = r.engine_mut().accept();
3569        let two = r.engine_mut().accept();
3570        let mut batch = Vec::new();
3571        assert_eq!(r.engine().server().client_count(), 2);
3572
3573        r.engine_mut().hangup(two);
3574        assert_eq!(r.engine().server().client_count(), 1);
3575
3576        r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3577        pump(&mut r, &mut batch);
3578        let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
3579        assert_eq!(sent.lines().filter(|l| l.starts_with("id=")).count(), 1);
3580    }
3581
3582    /// A write pause holds the writes and lets the reads through, and the write
3583    /// runs by itself once the pause has run out.
3584    #[test]
3585    fn a_write_pause_holds_the_writes_and_lets_the_reads_through() {
3586        let (mut r, one, mut batch) = timed();
3587        let two = r.engine_mut().accept();
3588
3589        r.engine_mut()
3590            .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3591        pump(&mut r, &mut batch);
3592        assert_eq!(r.engine().sink().sent(one), b"+OK\r\n");
3593
3594        r.engine_mut().sink_mut().clear();
3595        r.engine_mut().feed(two, &wire(&[b"GET", b"k"]));
3596        r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3597        pump(&mut r, &mut batch);
3598        assert_eq!(
3599            r.engine().sink().sent(two),
3600            b"$-1\r\n",
3601            "the read answered and the write is being held"
3602        );
3603        assert_eq!(r.engine().waiting(), 1, "the held connection");
3604
3605        r.engine_mut().sink_mut().clear();
3606        r.engine().server().advance_clock_ms(500);
3607        pump(&mut r, &mut batch);
3608        assert_eq!(r.engine().sink().sent(two), b"+OK\r\n");
3609        assert_eq!(r.engine().waiting(), 0);
3610    }
3611
3612    /// Everything, including the command that would call the pause off.
3613    #[test]
3614    fn an_all_pause_holds_every_command_and_cannot_be_called_off() {
3615        let (mut r, one, mut batch) = timed();
3616        let two = r.engine_mut().accept();
3617
3618        r.engine_mut()
3619            .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"ALL"]));
3620        pump(&mut r, &mut batch);
3621
3622        r.engine_mut().sink_mut().clear();
3623        r.engine_mut().feed(two, &wire(&[b"PING"]));
3624        r.engine_mut().feed(two, &wire(&[b"CLIENT", b"UNPAUSE"]));
3625        pump(&mut r, &mut batch);
3626        assert_eq!(r.engine().sink().sent(two), b"", "not even the ping");
3627
3628        r.engine().server().advance_clock_ms(499);
3629        pump(&mut r, &mut batch);
3630        assert_eq!(r.engine().sink().sent(two), b"", "still inside the pause");
3631
3632        r.engine().server().advance_clock_ms(1);
3633        pump(&mut r, &mut batch);
3634        assert_eq!(
3635            r.engine().sink().sent(two),
3636            b"+PONG\r\n+OK\r\n",
3637            "both, in the order they were sent"
3638        );
3639    }
3640
3641    /// A pause already running is widened by the next one and never narrowed.
3642    #[test]
3643    fn a_shorter_pause_does_not_shorten_the_one_already_running() {
3644        let (mut r, one, mut batch) = timed();
3645        let two = r.engine_mut().accept();
3646
3647        r.engine_mut()
3648            .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3649        r.engine_mut()
3650            .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"10", b"WRITE"]));
3651        pump(&mut r, &mut batch);
3652        assert_eq!(r.engine().server().pause_ends(), START_MS + 500);
3653
3654        r.engine_mut().sink_mut().clear();
3655        r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3656        r.engine().server().advance_clock_ms(100);
3657        pump(&mut r, &mut batch);
3658        assert_eq!(r.engine().sink().sent(two), b"", "the longer end holds");
3659
3660        r.engine().server().advance_clock_ms(400);
3661        pump(&mut r, &mut batch);
3662        assert_eq!(r.engine().sink().sent(two), b"+OK\r\n");
3663    }
3664
3665    /// And a write pause on top of an all pause leaves it holding everything.
3666    #[test]
3667    fn a_write_pause_on_top_of_an_all_pause_still_holds_the_reads() {
3668        let (mut r, one, mut batch) = timed();
3669        let two = r.engine_mut().accept();
3670
3671        r.engine_mut()
3672            .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"ALL"]));
3673        pump(&mut r, &mut batch);
3674        // From the connection that armed it, which is held by it as well, so
3675        // this is the one that runs when the pause runs out.
3676        r.engine_mut()
3677            .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3678
3679        r.engine_mut().sink_mut().clear();
3680        r.engine_mut().feed(two, &wire(&[b"GET", b"k"]));
3681        r.engine().server().advance_clock_ms(200);
3682        pump(&mut r, &mut batch);
3683        assert_eq!(r.engine().sink().sent(two), b"", "still everything");
3684    }
3685
3686    /// `CLIENT UNPAUSE` lets go of a write pause at once.
3687    #[test]
3688    fn unpause_lets_go_of_a_write_pause_at_once() {
3689        let (mut r, one, mut batch) = timed();
3690        let two = r.engine_mut().accept();
3691
3692        r.engine_mut()
3693            .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"5000", b"WRITE"]));
3694        pump(&mut r, &mut batch);
3695        r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3696        pump(&mut r, &mut batch);
3697        assert_eq!(r.engine().sink().sent(two), b"");
3698
3699        r.engine_mut().sink_mut().clear();
3700        r.engine_mut().feed(one, &wire(&[b"CLIENT", b"UNPAUSE"]));
3701        pump(&mut r, &mut batch);
3702        assert_eq!(r.engine().sink().sent(two), b"+OK\r\n");
3703    }
3704
3705    /// A transaction of nothing but reads runs through a write pause, and one
3706    /// write anywhere in it makes the whole transaction wait.
3707    #[test]
3708    fn a_write_pause_holds_an_exec_only_when_the_transaction_writes() {
3709        let (mut r, one, mut batch) = timed();
3710        let two = r.engine_mut().accept();
3711        let three = r.engine_mut().accept();
3712
3713        for conn in [two, three] {
3714            r.engine_mut().feed(conn, &wire(&[b"MULTI"]));
3715            r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
3716        }
3717        r.engine_mut().feed(three, &wire(&[b"SET", b"k", b"v"]));
3718        pump(&mut r, &mut batch);
3719
3720        r.engine_mut()
3721            .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3722        pump(&mut r, &mut batch);
3723
3724        r.engine_mut().sink_mut().clear();
3725        r.engine_mut().feed(two, &wire(&[b"EXEC"]));
3726        r.engine_mut().feed(three, &wire(&[b"EXEC"]));
3727        pump(&mut r, &mut batch);
3728        assert_eq!(r.engine().sink().sent(two), b"*1\r\n$-1\r\n", "reads only");
3729        assert_eq!(r.engine().sink().sent(three), b"", "one write in it");
3730
3731        r.engine_mut().sink_mut().clear();
3732        r.engine().server().advance_clock_ms(500);
3733        pump(&mut r, &mut batch);
3734        assert_eq!(r.engine().sink().sent(three), b"*2\r\n$-1\r\n+OK\r\n");
3735    }
3736
3737    /// A connection that goes away while it is being held does not leave the
3738    /// slot owed to somebody who is never coming back for it.
3739    #[test]
3740    fn a_held_connection_that_hangs_up_lets_go_of_its_slot() {
3741        let (mut r, one, mut batch) = timed();
3742        let two = r.engine_mut().accept();
3743
3744        r.engine_mut()
3745            .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"ALL"]));
3746        pump(&mut r, &mut batch);
3747        r.engine_mut().feed(two, &wire(&[b"PING"]));
3748        pump(&mut r, &mut batch);
3749        assert_eq!(r.engine().waiting(), 1);
3750
3751        r.engine_mut().hangup(two);
3752        pump(&mut r, &mut batch);
3753        assert_eq!(r.engine().server().client_count(), 1);
3754
3755        r.engine().server().advance_clock_ms(500);
3756        pump(&mut r, &mut batch);
3757        assert_eq!(r.engine().waiting(), 0, "nothing left holding a slot");
3758    }
3759
3760    /// The command a connection is being held on is the one its row names, the
3761    /// way a real server names the command it postponed.
3762    #[test]
3763    fn a_held_connection_names_the_command_it_is_waiting_to_run() {
3764        let (mut r, one, mut batch) = timed();
3765        let two = r.engine_mut().accept();
3766
3767        r.engine_mut()
3768            .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3769        pump(&mut r, &mut batch);
3770        r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3771        pump(&mut r, &mut batch);
3772
3773        r.engine_mut().sink_mut().clear();
3774        r.engine().server().advance_clock_ms(0);
3775        r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3776        // The connection that asked is held by its own pause, so the answer only
3777        // arrives once the pause is over, and the row it reports is the one the
3778        // held connection published before it was held.
3779        r.engine().server().advance_clock_ms(500);
3780        pump(&mut r, &mut batch);
3781        let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
3782        assert!(sent.contains("cmd=set"), "{sent}");
3783    }
3784
3785    /// A monitor watching, with the clock stopped so the stamp is a constant.
3786    ///
3787    /// The first connection back is the monitor and the second is the client,
3788    /// which is the way round every test below wants them.
3789    fn watched() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
3790        let (mut r, eye, mut batch) = timed();
3791        let one = r.engine_mut().accept();
3792        r.engine_mut().feed(eye, &wire(&[b"MONITOR"]));
3793        pump(&mut r, &mut batch);
3794        assert_eq!(r.engine().sink().sent(eye), b"+OK\r\n");
3795        r.engine_mut().sink_mut().clear();
3796        (r, eye, one, batch)
3797    }
3798
3799    /// What the fixed clock stamps every line in these tests with.
3800    const STAMP: &str = "1000.000000";
3801
3802    /// Everything the monitor has been sent, as a string.
3803    fn fed(r: &Reactor<Wire<Recorder>>, eye: ConnId) -> String {
3804        String::from_utf8_lossy(r.engine().sink().sent(eye)).into_owned()
3805    }
3806
3807    #[test]
3808    fn a_monitor_is_fed_a_command_another_connection_ran() {
3809        let (mut r, eye, one, mut batch) = watched();
3810
3811        r.engine_mut().feed(one, &wire(&[b"SET", b"k", b"v"]));
3812        pump(&mut r, &mut batch);
3813
3814        assert_eq!(
3815            fed(&r, eye),
3816            format!("+{STAMP} [0 ?:0] \"SET\" \"k\" \"v\"\r\n")
3817        );
3818    }
3819
3820    /// The database is the one the connection is on afterwards, which is what
3821    /// makes `SELECT` report itself where it landed rather than where it was.
3822    #[test]
3823    fn a_select_is_reported_on_the_database_it_moved_to() {
3824        let (mut r, eye, one, mut batch) = watched();
3825
3826        r.engine_mut().feed(one, &wire(&[b"SELECT", b"3"]));
3827        r.engine_mut().feed(one, &wire(&[b"GET", b"k"]));
3828        r.engine_mut().feed(one, &wire(&[b"SELECT", b"0"]));
3829        pump(&mut r, &mut batch);
3830
3831        assert_eq!(
3832            fed(&r, eye),
3833            format!(
3834                "+{STAMP} [3 ?:0] \"SELECT\" \"3\"\r\n\
3835                 +{STAMP} [3 ?:0] \"GET\" \"k\"\r\n\
3836                 +{STAMP} [0 ?:0] \"SELECT\" \"0\"\r\n"
3837            )
3838        );
3839    }
3840
3841    /// The quoting is `sdscatrepr`, which is what every tool that reads this
3842    /// feed is written against.
3843    #[test]
3844    fn an_argument_is_quoted_the_way_a_real_server_quotes_it() {
3845        let (mut r, eye, one, mut batch) = watched();
3846
3847        r.engine_mut()
3848            .feed(one, &wire(&[b"SET", b"a b", b"q\"s\\n\nt\tz\x01\xff"]));
3849        pump(&mut r, &mut batch);
3850
3851        assert_eq!(
3852            fed(&r, eye),
3853            format!("+{STAMP} [0 ?:0] \"SET\" \"a b\" \"q\\\"s\\\\n\\nt\\tz\\x01\\xff\"\r\n")
3854        );
3855    }
3856
3857    /// A command that never reached its body is not reported, and one that
3858    /// failed inside it is.
3859    #[test]
3860    fn only_a_command_that_ran_is_reported() {
3861        let (mut r, eye, one, mut batch) = watched();
3862
3863        r.engine_mut().feed(one, &wire(&[b"NOSUCHCOMMAND", b"a"]));
3864        r.engine_mut().feed(one, &wire(&[b"GET"]));
3865        r.engine_mut().feed(one, &wire(&[b"LPUSH", b"l", b"x"]));
3866        r.engine_mut().feed(one, &wire(&[b"GET", b"l"]));
3867        pump(&mut r, &mut batch);
3868
3869        assert_eq!(
3870            fed(&r, eye),
3871            format!(
3872                "+{STAMP} [0 ?:0] \"LPUSH\" \"l\" \"x\"\r\n\
3873                 +{STAMP} [0 ?:0] \"GET\" \"l\"\r\n"
3874            ),
3875            "the unknown command and the wrong arity are not commands that ran"
3876        );
3877    }
3878
3879    /// `MULTI` when it is sent, the queued commands as `EXEC` replays them, and
3880    /// `EXEC` last, which falls out of every one of those being its own trip
3881    /// through the funnel.
3882    #[test]
3883    fn a_transaction_is_reported_at_exec_and_in_order() {
3884        let (mut r, eye, one, mut batch) = watched();
3885
3886        r.engine_mut().feed(one, &wire(&[b"MULTI"]));
3887        r.engine_mut().feed(one, &wire(&[b"SET", b"t", b"1"]));
3888        r.engine_mut().feed(one, &wire(&[b"INCR", b"t"]));
3889        r.engine_mut().feed(one, &wire(&[b"EXEC"]));
3890        pump(&mut r, &mut batch);
3891
3892        assert_eq!(
3893            fed(&r, eye),
3894            format!(
3895                "+{STAMP} [0 ?:0] \"MULTI\"\r\n\
3896                 +{STAMP} [0 ?:0] \"SET\" \"t\" \"1\"\r\n\
3897                 +{STAMP} [0 ?:0] \"INCR\" \"t\"\r\n\
3898                 +{STAMP} [0 ?:0] \"EXEC\"\r\n"
3899            )
3900        );
3901    }
3902
3903    /// A script is reported before it runs, so that what it did arrives behind
3904    /// it, and what it did is reported against `lua` rather than an address.
3905    #[test]
3906    fn a_script_is_reported_in_front_of_its_own_effects() {
3907        let (mut r, eye, one, mut batch) = watched();
3908
3909        r.engine_mut().feed(
3910            one,
3911            &wire(&[
3912                b"EVAL",
3913                b"redis.call('set', KEYS[1], 'z') return 1",
3914                b"1",
3915                b"sk",
3916            ]),
3917        );
3918        pump(&mut r, &mut batch);
3919
3920        assert_eq!(
3921            fed(&r, eye),
3922            format!(
3923                "+{STAMP} [0 ?:0] \"EVAL\" \"redis.call('set', KEYS[1], 'z') return 1\" \"1\" \"sk\"\r\n\
3924                 +{STAMP} [0 lua] \"set\" \"sk\" \"z\"\r\n"
3925            )
3926        );
3927    }
3928
3929    /// The administrative commands are kept off the feed, and that is decided
3930    /// per subcommand: `CLIENT ID` is on it and `CLIENT LIST` is not.
3931    #[test]
3932    fn an_administrative_command_is_not_reported() {
3933        let (mut r, eye, one, mut batch) = watched();
3934
3935        r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3936        r.engine_mut()
3937            .feed(one, &wire(&[b"CONFIG", b"GET", b"maxmemory"]));
3938        r.engine_mut().feed(one, &wire(&[b"CLIENT", b"ID"]));
3939        r.engine_mut().feed(one, &wire(&[b"CONFIG", b"HELP"]));
3940        pump(&mut r, &mut batch);
3941
3942        assert_eq!(
3943            fed(&r, eye),
3944            format!(
3945                "+{STAMP} [0 ?:0] \"CLIENT\" \"ID\"\r\n\
3946                 +{STAMP} [0 ?:0] \"CONFIG\" \"HELP\"\r\n"
3947            )
3948        );
3949    }
3950
3951    /// The password in a `HELLO` is replaced rather than left out, so the line
3952    /// still has the shape the command had.
3953    #[test]
3954    fn a_password_is_not_echoed_to_a_monitor() {
3955        let (mut r, eye, one, mut batch) = watched();
3956
3957        r.engine_mut().feed(
3958            one,
3959            &wire(&[b"HELLO", b"3", b"AUTH", b"default", b"hunter2"]),
3960        );
3961        pump(&mut r, &mut batch);
3962
3963        let sent = fed(&r, eye);
3964        assert!(
3965            sent.contains("\"HELLO\" \"3\" \"AUTH\" \"(redacted)\" \"(redacted)\""),
3966            "{sent}"
3967        );
3968        assert!(!sent.contains("hunter2"), "{sent}");
3969    }
3970
3971    /// A monitor is not a client any more, so it is refused everything that
3972    /// reaches a key and allowed everything that does not.
3973    #[test]
3974    fn a_monitor_may_not_touch_the_keyspace() {
3975        let (mut r, eye, _one, mut batch) = watched();
3976
3977        // One at a time, because a monitor watching itself reads its own reply
3978        // and then the line, and the mail is handed over at the end of a batch.
3979        // A monitor that pipelines gets both replies and then both lines, which
3980        // is D-124 and is the only place the order differs from a real server's.
3981        r.engine_mut().feed(eye, &wire(&[b"PING"]));
3982        pump(&mut r, &mut batch);
3983        r.engine_mut().feed(eye, &wire(&[b"GET", b"k"]));
3984        pump(&mut r, &mut batch);
3985
3986        assert_eq!(
3987            fed(&r, eye),
3988            format!(
3989                "+PONG\r\n\
3990                 +{STAMP} [0 ?:0] \"PING\"\r\n\
3991                 -ERR Replica can't interact with the keyspace\r\n"
3992            )
3993        );
3994    }
3995
3996    /// And the refusal lands as the command is queued, which is what turns the
3997    /// transaction into an `EXECABORT`.
3998    #[test]
3999    fn a_monitor_is_refused_the_keyspace_at_queue_time() {
4000        let (mut r, eye, _one, mut batch) = watched();
4001
4002        r.engine_mut().feed(eye, &wire(&[b"MULTI"]));
4003        r.engine_mut().feed(eye, &wire(&[b"GET", b"k"]));
4004        r.engine_mut().feed(eye, &wire(&[b"EXEC"]));
4005        pump(&mut r, &mut batch);
4006
4007        let sent = fed(&r, eye);
4008        assert!(
4009            sent.contains("-ERR Replica can't interact with the keyspace"),
4010            "{sent}"
4011        );
4012        assert!(sent.contains("-EXECABORT"), "{sent}");
4013    }
4014
4015    /// A monitor is exempt from a pause, which is the whole reason the refusal
4016    /// above has to be there.
4017    #[test]
4018    fn a_monitor_runs_through_a_pause() {
4019        let (mut r, eye, one, mut batch) = watched();
4020
4021        r.engine_mut()
4022            .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"5000", b"ALL"]));
4023        pump(&mut r, &mut batch);
4024        r.engine_mut().sink_mut().clear();
4025
4026        r.engine_mut().feed(eye, &wire(&[b"PING"]));
4027        r.engine_mut().feed(one, &wire(&[b"PING"]));
4028        pump(&mut r, &mut batch);
4029
4030        assert!(
4031            fed(&r, eye).starts_with("+PONG\r\n"),
4032            "the monitor is let through"
4033        );
4034        assert_eq!(r.engine().sink().sent(one), b"", "and the client is not");
4035    }
4036
4037    /// `MONITOR` from a connection that is already one is answered nothing at
4038    /// all, which is a real server's behaviour and not an oversight of one.
4039    #[test]
4040    fn monitor_sent_twice_answers_nothing_the_second_time() {
4041        let (mut r, eye, _one, mut batch) = watched();
4042
4043        r.engine_mut().feed(eye, &wire(&[b"MONITOR"]));
4044        pump(&mut r, &mut batch);
4045
4046        assert_eq!(fed(&r, eye), "", "no reply and no line either");
4047    }
4048
4049    /// `RESET` is the way out, and the connection is a client again after it.
4050    #[test]
4051    fn reset_takes_a_connection_out_of_monitor_mode() {
4052        let (mut r, eye, one, mut batch) = watched();
4053
4054        r.engine_mut().feed(eye, &wire(&[b"RESET"]));
4055        pump(&mut r, &mut batch);
4056        r.engine_mut().sink_mut().clear();
4057
4058        r.engine_mut().feed(one, &wire(&[b"SET", b"k", b"v"]));
4059        r.engine_mut().feed(eye, &wire(&[b"GET", b"k"]));
4060        pump(&mut r, &mut batch);
4061
4062        assert_eq!(fed(&r, eye), "$1\r\nv\r\n", "not watching and not refused");
4063    }
4064
4065    /// A monitor that closes is taken off the list, which is what puts the
4066    /// server back to one load per command.
4067    #[test]
4068    fn a_monitor_that_closes_stops_being_one() {
4069        let (mut r, eye, one, mut batch) = watched();
4070
4071        r.engine_mut().hangup(eye);
4072        pump(&mut r, &mut batch);
4073        assert!(!r.engine().server().monitored());
4074
4075        r.engine_mut().feed(one, &wire(&[b"SET", b"k", b"v"]));
4076        pump(&mut r, &mut batch);
4077        assert_eq!(r.engine().sink().sent(one), b"+OK\r\n");
4078    }
4079
4080    /// Two monitors get the same line, because it is rendered once.
4081    #[test]
4082    fn two_monitors_are_fed_the_same_bytes() {
4083        let (mut r, eye, one, mut batch) = watched();
4084        let other = r.engine_mut().accept();
4085        r.engine_mut().feed(other, &wire(&[b"MONITOR"]));
4086        pump(&mut r, &mut batch);
4087        r.engine_mut().sink_mut().clear();
4088
4089        r.engine_mut().feed(one, &wire(&[b"SET", b"k", b"v"]));
4090        pump(&mut r, &mut batch);
4091
4092        assert_eq!(fed(&r, eye), fed(&r, other));
4093        assert_eq!(
4094            fed(&r, eye),
4095            format!("+{STAMP} [0 ?:0] \"SET\" \"k\" \"v\"\r\n")
4096        );
4097    }
4098
4099    /// And it is reported as a monitor, with the letter in front of the others.
4100    #[test]
4101    fn a_monitor_is_reported_as_one_in_client_list() {
4102        let (mut r, _eye, one, mut batch) = watched();
4103
4104        r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
4105        pump(&mut r, &mut batch);
4106
4107        let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
4108        assert!(sent.contains("flags=O"), "{sent}");
4109        assert!(sent.contains("flags=N"), "and the other one is not: {sent}");
4110    }
4111}