Skip to main content

yo_resp/
engine.rs

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