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