Skip to main content

yo_resp/
engine.rs

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