Skip to main content

yo_resp/
engine.rs

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