Skip to main content

yo_resp/dispatch/
repl.rs

1//! Being a master: the replication identity, the stream and the link.
2//!
3//! A replica is a second copy of this server's keyspace that keeps up by being
4//! told every change as it happens. Getting there is two halves. First it needs
5//! the dataset as it stands, which is a snapshot sent down the socket, and then
6//! it needs everything that happens after that snapshot, which is a stream of
7//! commands that never ends. The hard part is the seam between the two, because
8//! a change that lands in neither is lost forever and a change that lands in
9//! both is applied twice, and applying `INCR` twice is not the same as applying
10//! it once.
11//!
12//! # The handshake
13//!
14//! A replica opens an ordinary connection and sends `PING`, then
15//! `REPLCONF listening-port <port>`, then `REPLCONF capa ...`, and then `PSYNC
16//! <replid> <offset>`. Everything up to the `PSYNC` is a normal command with a
17//! normal reply. The `PSYNC` is where the connection stops being a client: the
18//! master answers `+FULLRESYNC <replid> <offset>`, then the snapshot as a bulk
19//! string with no trailing newline after it, and from then on writes only the
20//! command stream and never replies to anything the replica sends. A replica
21//! sends `REPLCONF ACK <offset>` about once a second forever, and a master that
22//! answers one of those with `+OK` has put a reply into the middle of a stream
23//! the replica is parsing as commands, which a real replica reports as
24//! `Protocol error (Master using the inline protocol. Desync?)` and then drops
25//! the link. So the silence is not an optimisation, it is the protocol.
26//!
27//! # The identity and the offset
28//!
29//! The replication id is forty hex characters naming this server's history, and
30//! the offset is how many bytes of stream have gone out under that id. Together
31//! they are a position in a history, which is what lets a replica that lost the
32//! link for a moment ask to carry on rather than start again: it sends back the
33//! id and offset it had, and if the id is still ours and the offset is still in
34//! the backlog the master answers `+CONTINUE` and replays the missing bytes.
35//!
36//! There is a second id for the same reason a chain needs one. When a replica is
37//! promoted it keeps the old master's id as `replid2` and takes a new one of its
38//! own, so the replicas that were following the old master can be handed over
39//! without all of them resyncing from nothing.
40//!
41//! # The snapshot has to be one instant
42//!
43//! `SAVE` here walks the databases one stripe at a time and does not stop the
44//! server, so the file it writes is not one instant of the keyspace: a write to
45//! database nine while database two is being walked is in the file and a write
46//! to database two after it has been walked is not. For a file on disk that is a
47//! fair trade, because the file is read by itself and nothing is going to be
48//! replayed on top of it.
49//!
50//! It is not a fair trade here. The replica loads the snapshot and then applies
51//! the stream from the offset the snapshot was stamped with, so every byte of
52//! the keyspace has to be either in the snapshot or after that offset, and never
53//! both and never neither. A real server gets that for free by forking, which
54//! hands the child an instant of the whole address space and costs the parent
55//! nothing but the page faults afterwards. There is no fork here, so a full
56//! resync takes every stripe of every database at once, stamps the offset,
57//! builds the image and lets go. The server stops for as long as that takes,
58//! which is a real cost on a large dataset and is registered as a divergence.
59//! The alternative is a replica that is quietly wrong, which is worse than a
60//! replica that took a pause to be right.
61//!
62//! # What goes on the stream
63//!
64//! Every command that changed something, in the form the replica has to be given
65//! rather than the form the client sent. Most commands are the same both ways.
66//! The ones that are not are the ones whose result depends on something the
67//! replica has not got: the clock, for anything that sets a deadline, and the
68//! server's own random state, for `SPOP`. `EXPIRE k 50` becomes `PEXPIREAT k
69//! <absolute>`, `SET k v EX 100` becomes `SET k v PXAT <absolute>`, `SPOP s`
70//! becomes `SREM s <the member that actually went>`, and `XADD s *` becomes an
71//! `XADD` naming the id that was actually made. Without the rewrite the two
72//! copies drift apart the moment either of them is asked a question.
73//!
74//! The rewrite is pushed by the command that knows, through a thread local, the
75//! same way this crate already hands keyspace events up from underneath. A
76//! command that pushes nothing is sent as it arrived, which is the common case
77//! and costs nothing to decide.
78//!
79//! # What it costs a server with no replica
80//!
81//! One relaxed load of a count that is zero, per write command. The same shape
82//! `MONITOR` and the pub/sub registry use, and for the same reason: nearly every
83//! server in the world is running on its own.
84
85use std::sync::Arc;
86use std::sync::atomic::Ordering::{Acquire, Relaxed, Release};
87use std::sync::atomic::{AtomicBool, AtomicI64, AtomicU64, AtomicUsize};
88use std::time::Duration;
89
90use core::cell::{Cell, RefCell};
91
92use yo_common::lock::Lock;
93use yo_common::{Code, Error, Result};
94
95use crate::reply::Out;
96
97use super::args::{self, Args};
98use super::clients::{self, Client};
99use super::pubsub::Envelope;
100use super::{Server, Session};
101
102/// How many characters name a history, which is Redis's forty hex digits.
103pub(super) const ID_LEN: usize = 40;
104
105/// The id a server that has never been anybody's replica reports as its second,
106/// which Redis writes as forty zeroes rather than leaving out.
107const NO_ID: &[u8; ID_LEN] = b"0000000000000000000000000000000000000000";
108
109/// How much stream is kept for a replica that dropped the link, in bytes.
110///
111/// Redis's default, and the number `repl-backlog-size` reads back as. A replica
112/// that reconnects inside this many bytes carries on where it was and one that
113/// falls further behind starts again from a snapshot.
114pub(super) const BACKLOG_BYTES: usize = 1024 * 1024;
115
116/// One connection that has stopped being a client and is now a copy of us.
117pub(super) struct Replica {
118    /// The row every other part of the server knows the connection by, so that
119    /// `CLIENT LIST` and `CLIENT KILL` see a replica the way they see anything
120    /// else.
121    row: Arc<Client>,
122    /// The port the replica says it is listening on, which is what `INFO`
123    /// reports rather than the port its outgoing connection came from. A replica
124    /// that has not said is reported as zero, which is what Redis does too.
125    port: AtomicU64,
126    /// The last offset it said it had, and when it said so.
127    ///
128    /// `WAIT` counts the replicas whose acknowledged offset has caught up, and
129    /// `INFO` turns the time into a lag in seconds.
130    ack: AtomicU64,
131    ack_ms: AtomicU64,
132    /// Whether the snapshot has gone and the stream has started.
133    online: AtomicBool,
134}
135
136impl Replica {
137    /// The address the replica is reachable at, which is its address and the
138    /// port it told us rather than the port it dialled out from.
139    fn address(&self) -> (String, u64) {
140        let text = self.row.text.lock();
141        let peer = text.peer.clone();
142        drop(text);
143        let host = match peer.iter().rposition(|&b| b == b':') {
144            Some(at) => peer[..at].to_vec(),
145            None => peer.clone(),
146        };
147        (
148            String::from_utf8_lossy(&host).into_owned(),
149            self.port.load(Relaxed),
150        )
151    }
152}
153
154/// Everything about being a master, all of it idle on a server with no replica.
155pub(crate) struct Replication {
156    /// The forty characters naming the history this server is writing.
157    id: Lock<[u8; ID_LEN]>,
158    /// The history it was writing before, for a server that was promoted.
159    id2: Lock<[u8; ID_LEN]>,
160    /// How many bytes of stream have been produced under [`Replication::id`].
161    offset: AtomicU64,
162    /// The offset the second id runs up to, or minus one when there is no
163    /// second id, which is what Redis reports on a server that was never a
164    /// replica.
165    second: AtomicI64,
166    /// What has gone out lately, so a replica that blinked can catch up without
167    /// a whole snapshot.
168    backlog: Lock<Backlog>,
169    /// The connections being fed.
170    rows: Lock<Vec<Arc<Replica>>>,
171    /// How many there are, so a write command can ask without taking the lock.
172    live: AtomicUsize,
173    /// The port a connection said it was listening on, before it asked to
174    /// become a replica.
175    ///
176    /// `REPLCONF listening-port` arrives two commands before `PSYNC`, so there
177    /// is no replica to hang it on yet and it has to be kept somewhere until
178    /// there is. Here rather than on the connection row, because a row is paid
179    /// for by every connection on the server and this is paid for only by the
180    /// few that are about to become replicas. Oldest first out at a small cap,
181    /// so a client that sends the one and never the other cannot grow it.
182    ports: Lock<Vec<(u64, u64)>>,
183    /// Whether a full resync is building an image right now.
184    ///
185    /// A write that arrives while this is set is held and run again afterwards,
186    /// which is what makes the image one instant. Read on the command path by
187    /// every write, so it is a relaxed load of a bool that is nearly always
188    /// false, next to the one `CLIENT PAUSE` already costs.
189    frozen: AtomicBool,
190    /// One resync builds at a time.
191    ///
192    /// Two threads freezing the server at once would each wait for the other's
193    /// writes to drain and neither would be able to, so the second one waits
194    /// here instead and then finds a backlog it can probably be caught up from.
195    building: Lock<()>,
196    /// Which database the stream is on, so `SELECT` goes out only when it has
197    /// to. Minus one before anything has been written, which is why the first
198    /// command on any database is preceded by a `SELECT` even for database
199    /// zero.
200    on_db: AtomicI64,
201    /// When something last went out on the stream, so the periodic `PING` a
202    /// master owes its replicas is only sent on a link that has gone quiet.
203    last_io: AtomicU64,
204}
205
206impl Default for Replication {
207    fn default() -> Replication {
208        Replication {
209            id: Lock::new(make_id()),
210            id2: Lock::new(*NO_ID),
211            offset: AtomicU64::new(0),
212            second: AtomicI64::new(-1),
213            backlog: Lock::new(Backlog::default()),
214            rows: Lock::new(Vec::new()),
215            live: AtomicUsize::new(0),
216            ports: Lock::new(Vec::new()),
217            frozen: AtomicBool::new(false),
218            building: Lock::new(()),
219            on_db: AtomicI64::new(-1),
220            last_io: AtomicU64::new(0),
221        }
222    }
223}
224
225/// The last stretch of stream, kept so a reconnect does not cost a snapshot.
226///
227/// A ring of a fixed size with the offset of its first byte beside it. `histlen`
228/// is how much of the ring is real, which is less than its size only until it
229/// has filled once.
230#[derive(Default)]
231struct Backlog {
232    ring: Vec<u8>,
233    /// Where the next byte goes.
234    at: usize,
235    /// How many bytes of the ring are real.
236    filled: usize,
237    /// The stream offset of the oldest real byte.
238    first: u64,
239}
240
241impl Backlog {
242    /// Take bytes in, dropping whatever falls off the back.
243    fn push(&mut self, bytes: &[u8], upto: u64) {
244        if self.ring.is_empty() {
245            self.ring = vec![0; BACKLOG_BYTES];
246            self.first = upto - bytes.len() as u64;
247        }
248        for &b in bytes {
249            self.ring[self.at] = b;
250            self.at = (self.at + 1) % BACKLOG_BYTES;
251            if self.filled < BACKLOG_BYTES {
252                self.filled += 1;
253            }
254        }
255        self.first = upto - self.filled as u64;
256    }
257
258    /// Everything from `from` onwards, or `None` if that much history has gone.
259    fn since(&self, from: u64, upto: u64) -> Option<Vec<u8>> {
260        if self.filled == 0 || from < self.first || from > upto {
261            return None;
262        }
263        let skip = (from - self.first) as usize;
264        let want = self.filled - skip;
265        let start = (self.at + BACKLOG_BYTES - self.filled + skip) % BACKLOG_BYTES;
266        let mut out = Vec::with_capacity(want);
267        for i in 0..want {
268            out.push(self.ring[(start + i) % BACKLOG_BYTES]);
269        }
270        Some(out)
271    }
272}
273
274#[cfg(test)]
275impl Server {
276    /// Say there is a replica, without one.
277    ///
278    /// What a test wants to look at is the byte stream and not the socket it
279    /// would have gone down, and [`emit`] writes the stream into the backlog
280    /// before it looks for anybody to post it to. So a server told this writes
281    /// everything a real master would write and posts none of it, which is the
282    /// whole of what these tests need and needs no connection at all.
283    pub(super) fn pretend_replica(&self) {
284        self.repl.live.store(1, Relaxed);
285    }
286
287    /// The stream from `from` onwards, as text, and where it has got to.
288    ///
289    /// Text because every rewrite these tests are about is text, and reading
290    /// `*3\r\n$3\r\nSET\r\n` in a failure message beats reading a byte array.
291    pub(super) fn stream_since(&self, from: u64) -> (String, u64) {
292        let upto = self.repl.offset.load(Acquire);
293        let backlog = self.repl.backlog.lock();
294        let bytes = backlog.since(from, upto).unwrap_or_default();
295        (String::from_utf8_lossy(&bytes).into_owned(), upto)
296    }
297}
298
299/// Whether a replica is the one at this host and port.
300///
301/// The host is compared as text and not as an address, which is Redis's own
302/// rule: what an operator types has to be what the server prints in `INFO`,
303/// because that is where they read it from.
304fn at(held: &Replica, host: &str, port: u16) -> bool {
305    let (theirs, their_port) = held.address();
306    theirs == host && their_port == u64::from(port)
307}
308
309/// Forty hex characters from the operating system's generator.
310///
311/// From the system and not from the engine's own seeded one, because two servers
312/// started from the same image at the same moment must not be able to claim the
313/// same history. That is the same reasoning `ACL GENPASS` is built on.
314fn make_id() -> [u8; ID_LEN] {
315    const HEX: &[u8; 16] = b"0123456789abcdef";
316    let mut raw = [0u8; ID_LEN / 2];
317    yo_common::entropy::fill(&mut raw);
318    let mut id = [0u8; ID_LEN];
319    for (i, byte) in raw.iter().enumerate() {
320        id[i * 2] = HEX[usize::from(byte >> 4)];
321        id[i * 2 + 1] = HEX[usize::from(byte & 15)];
322    }
323    id
324}
325
326// ------------------------------------------------------------- the override
327
328thread_local! {
329    /// What the running command wants sent instead of itself, if anything.
330    ///
331    /// A command that leaves this empty is propagated as it arrived. One that
332    /// puts something here is propagated as whatever it put, however many
333    /// commands that is, and a command that puts an empty list here is
334    /// propagated as nothing at all. See the module header for why a thread
335    /// local rather than a return value.
336    static INSTEAD: RefCell<Option<Vec<Vec<Vec<u8>>>>> = const { RefCell::new(None) };
337}
338
339thread_local! {
340    /// Whether anything this thread does has somewhere to be copied to.
341    ///
342    /// A flag rather than a question put to the server, because the call sites
343    /// that ask are inside the command bodies, a long way from anything holding
344    /// a `Server`, and threading one down to them for a question that is nearly
345    /// always no would be a worse trade than a thread local read. The same trade
346    /// the keyspace events make, next door.
347    ///
348    /// It says whether there is a replica and not whether a write is running,
349    /// which are two different questions and this is the wider one on purpose. A
350    /// read takes keys away, because a lookup that finds one past its deadline
351    /// removes it there and then, and `XGROUP CREATE` changes a stream while
352    /// carrying no write flag, since the flag is on the subcommand and there is
353    /// no subcommand table yet. Both have something to send and neither is a
354    /// write by the funnel's reckoning, so the funnel decides whether the
355    /// verbatim command may be sent and this decides whether anybody is
356    /// listening at all.
357    static ARMED: Cell<bool> = const { Cell::new(false) };
358
359    /// The removals nobody asked for, waiting for a lock that is not held.
360    static REAPED: RefCell<Vec<Vec<Vec<u8>>>> = const { RefCell::new(Vec::new()) };
361}
362
363/// Say whether what runs next is going to be copied, answering what the last
364/// answer was.
365///
366/// Set in front of every write on a server with a replica and put back
367/// afterwards, so that a command run by a script or by `EXEC` leaves the flag
368/// the way it found it.
369pub(super) fn arm(on: bool) -> bool {
370    ARMED.replace(on)
371}
372
373/// Whether a rewrite would be heard, which is what keeps every call site that
374/// would build one off the path of a server with no replica.
375#[must_use]
376pub(crate) fn armed() -> bool {
377    ARMED.get()
378}
379
380/// Send this instead of the command that is running.
381///
382/// Called by a command whose own arguments do not say what happened, so more
383/// than once for a command with more than one effect. The first call replaces
384/// the command and the rest are added after it.
385pub(crate) fn instead(parts: Vec<Vec<u8>>) {
386    INSTEAD.with(|cell| {
387        let mut held = cell.borrow_mut();
388        held.get_or_insert_with(Vec::new).push(parts);
389    });
390}
391
392/// The same thing said in pieces, which is how nearly every call site has it.
393///
394/// A rewrite is a command name and a key and usually a number, none of which
395/// arrive owned, so this is the shape that keeps the copying in one place rather
396/// than a `to_vec` on every argument of every site.
397pub(crate) fn rewrite(parts: &[&[u8]]) {
398    instead(parts.iter().map(|part| part.to_vec()).collect());
399}
400
401/// Send nothing at all for the command that is running.
402///
403/// For a write command that turned out to change nothing and whose verbatim form
404/// would be wrong rather than merely wasteful, which is any of the ones that are
405/// rewritten: a `SPOP` on a missing key has no `SREM` to send and must not send
406/// the `SPOP`.
407pub(crate) fn nothing() {
408    INSTEAD.with(|cell| {
409        let mut held = cell.borrow_mut();
410        held.get_or_insert_with(Vec::new);
411    });
412}
413
414/// Take whatever the command left, clearing it for the next one.
415fn taken() -> Option<Vec<Vec<Vec<u8>>>> {
416    INSTEAD.with(|cell| cell.borrow_mut().take())
417}
418
419// --------------------------------------------------------------- the server
420
421impl Server {
422    /// Whether anybody is being fed, which is the whole cost of this file on a
423    /// server that is on its own.
424    #[must_use]
425    pub(crate) fn replicated(&self) -> bool {
426        self.repl.live.load(Relaxed) != 0
427    }
428
429    /// How many of them there are, which `INFO clients` takes off its count.
430    ///
431    /// A replica is a connection and is not a client: Redis counts the sockets
432    /// and then subtracts the replicas, so `connected_clients` is the number of
433    /// people talking to the server rather than the number of file descriptors
434    /// it is holding, and the replicas are reported next door as their own
435    /// number.
436    #[must_use]
437    pub(crate) fn replica_count(&self) -> u64 {
438        self.repl.live.load(Relaxed) as u64
439    }
440
441    /// The forty characters naming this server's history.
442    pub(crate) fn repl_id(&self) -> [u8; ID_LEN] {
443        *self.repl.id.lock()
444    }
445
446    /// How many bytes of stream have gone out.
447    #[must_use]
448    pub(crate) fn repl_offset(&self) -> u64 {
449        self.repl.offset.load(Acquire)
450    }
451
452    /// Whether a replica is attached at this address, and whether it is past its
453    /// snapshot, which are the two questions `FAILOVER TO` asks in that order.
454    ///
455    /// `None` is nobody there and is a different answer from `Some(false)`,
456    /// which is somebody there who is still loading. The address is matched the
457    /// way Redis matches it, against where the connection came from and against
458    /// the port the replica said it listens on rather than the port it dialled
459    /// out from, because the second one is not something an operator can type.
460    #[must_use]
461    pub(super) fn replica_online_at(&self, host: &str, port: u16) -> Option<bool> {
462        self.replica_rows()
463            .iter()
464            .find(|held| at(held, host, port))
465            .map(|held| held.online.load(Relaxed))
466    }
467
468    /// Whether the replica at this address has acknowledged every byte written.
469    ///
470    /// The wait a failover is, put as one question. A replica that has gone away
471    /// answers no rather than yes, which is what keeps a failover to a target
472    /// that died waiting rather than handing the job to nobody.
473    #[must_use]
474    pub(super) fn replica_caught_up(&self, host: &str, port: u16) -> bool {
475        let upto = self.repl_offset();
476        self.replica_rows()
477            .iter()
478            .any(|held| at(held, host, port) && held.ack.load(Relaxed) >= upto)
479    }
480
481    /// Where the first replica that has everything is, for a failover that was
482    /// not told which one to hand the job to.
483    ///
484    /// In the order they attached, which is the order `INFO` lists them in, so
485    /// two operators reading the same server pick the same one.
486    #[must_use]
487    pub(super) fn first_caught_up(&self) -> Option<(String, u16)> {
488        let upto = self.repl_offset();
489        yo_alloc::allow(|| {
490            self.replica_rows()
491                .iter()
492                .filter(|held| held.online.load(Relaxed) && held.ack.load(Relaxed) >= upto)
493                .map(|held| held.address())
494                .find_map(|(host, port)| u16::try_from(port).ok().map(|port| (host, port)))
495        })
496    }
497
498    /// A handle to every replica, copied out so the bytes can be posted with the
499    /// lock let go of.
500    ///
501    /// The same trade `CLIENT LIST` and the monitor feed make, for the same
502    /// reason: a replica that drops while a command is being rendered leaves a
503    /// row that is still readable, and the bytes land in a mailbox that is about
504    /// to be told the slot has moved on.
505    fn replica_rows(&self) -> Vec<Arc<Replica>> {
506        let rows = self.repl.rows.lock();
507        yo_alloc::allow(|| rows.clone())
508    }
509
510    /// Remember the port a connection says it is listening on.
511    ///
512    /// See [`Replication::ports`] for why it cannot go straight on a replica.
513    fn note_replica_port(&self, id: u64, port: u64) {
514        const KEEP: usize = 64;
515        let mut ports = self.repl.ports.lock();
516        yo_alloc::allow(|| {
517            if let Some(row) = ports.iter_mut().find(|(who, _)| *who == id) {
518                row.1 = port;
519                return;
520            }
521            if ports.len() >= KEEP {
522                ports.remove(0);
523            }
524            ports.push((id, port));
525        });
526    }
527
528    /// Take the port back out, for a connection that has got as far as `PSYNC`.
529    fn take_replica_port(&self, id: u64) -> u64 {
530        let mut ports = self.repl.ports.lock();
531        match ports.iter().position(|(who, _)| *who == id) {
532            Some(at) => ports.remove(at).1,
533            None => 0,
534        }
535    }
536
537    /// Take a connection on as a replica.
538    fn take_replica(&self, row: &Arc<Client>) -> Arc<Replica> {
539        let mut rows = self.repl.rows.lock();
540        let held = yo_alloc::allow(|| {
541            let held = Arc::new(Replica {
542                row: Arc::clone(row),
543                port: AtomicU64::new(self.take_replica_port(row.id)),
544                ack: AtomicU64::new(0),
545                ack_ms: AtomicU64::new(self.clock.now_ms()),
546                online: AtomicBool::new(true),
547            });
548            rows.push(Arc::clone(&held));
549            held
550        });
551        self.repl.live.store(rows.len(), Release);
552        row.set_flag(clients::REPLICA, true);
553        self.note_here(row.thread.load(Relaxed), 1);
554        held
555    }
556
557    /// Let one go, which is the connection closing or being killed.
558    pub(crate) fn drop_replica(&self, id: u64) {
559        let mut rows = self.repl.rows.lock();
560        let Some(at) = rows.iter().position(|r| r.row.id == id) else {
561            return;
562        };
563        let gone = rows.remove(at);
564        self.repl.live.store(rows.len(), Release);
565        drop(rows);
566        gone.row.set_flag(clients::REPLICA, false);
567        self.note_here(gone.row.thread.load(Relaxed), -1);
568    }
569
570    /// Whether a full resync is holding the keyspace still.
571    ///
572    /// One relaxed load per write command on a server nobody is syncing from,
573    /// which is the same shape and the same cost as the pause check it sits
574    /// beside.
575    #[must_use]
576    pub(crate) fn frozen(&self) -> bool {
577        self.repl.frozen.load(Relaxed)
578    }
579
580    /// The whole dataset as one image, and the offset it is an image as of.
581    ///
582    /// Everything between the two has to be nothing at all, which is what the
583    /// freeze is for. Writes are held from before the barrier until after the
584    /// image is finished, so a change is either inside the image or after the
585    /// offset and never both. See the module header for why there is no fork to
586    /// get this for free.
587    pub(crate) fn snapshot_at_an_instant(&self) -> (Vec<u8>, u64) {
588        self.at_an_instant(|| super::persist::build(self).0)
589    }
590
591    /// Run `f` with nothing writing, and say which offset it ran at.
592    ///
593    /// The freeze is the whole of how this server gets what a real one gets from
594    /// a fork: whatever `f` reads is one moment of the dataset, and the offset
595    /// that comes back is the point in the stream that moment sits at, so a
596    /// caller feeding a replica knows exactly where to carry on from.
597    ///
598    /// Every write is held off for as long as `f` runs, so `f` has to be worth
599    /// it. Building a whole image is; anything that waits on a client is not.
600    pub(crate) fn at_an_instant<T>(&self, f: impl FnOnce() -> T) -> (T, u64) {
601        let building = self.repl.building.lock();
602        self.repl.frozen.store(true, Release);
603        // A write already running holds the stripe it is writing to, so taking
604        // every stripe once and letting it go again is a barrier: once it is
605        // through, no write is in flight and the freeze above stops any more
606        // starting. One pass is enough, in whatever order, because nothing being
607        // waited for can start again behind it.
608        for db in &self.dbs {
609            for stripe in 0..db.width() {
610                drop(db.hold_stripe(stripe));
611            }
612        }
613        let offset = self.repl.offset.load(Acquire);
614        let made = f();
615        self.repl.frozen.store(false, Release);
616        drop(building);
617        (made, offset)
618    }
619
620    /// Take a master's history as our own, which is what a replica does.
621    ///
622    /// Everything this server writes from here on is under the master's id and
623    /// at the master's offsets, so a sub-replica underneath is handed positions
624    /// its own master would recognise. The backlog goes with it, because what is
625    /// in it is a stretch of a history this server is no longer writing and
626    /// answering a partial resync out of it would send a replica bytes from
627    /// somebody else's stream.
628    pub(crate) fn adopt(&self, id: [u8; ID_LEN], offset: u64) {
629        let mut ours = self.repl.id.lock();
630        if *ours == id && self.repl.offset.load(Acquire) == offset {
631            return;
632        }
633        *ours = id;
634        drop(ours);
635        let mut backlog = self.repl.backlog.lock();
636        *backlog = Backlog::default();
637        self.repl.offset.store(offset, Release);
638        drop(backlog);
639        self.repl.on_db.store(-1, Relaxed);
640    }
641
642    /// Stop following and start a history of our own, keeping the old one.
643    ///
644    /// The id this server was writing under becomes the second id and the offset
645    /// it had reached becomes the second offset, and a new id is taken. That is
646    /// what lets the replicas that were following the same master be handed over
647    /// to this one without every one of them starting from a snapshot: each of
648    /// them asks about a history this server can still say it was part of, up to
649    /// the point where the two part, and the second offset is that point.
650    pub(crate) fn promote(&self) {
651        let mut id = self.repl.id.lock();
652        let mut id2 = self.repl.id2.lock();
653        *id2 = *id;
654        *id = make_id();
655        // One past the last byte of the old history, which is the first byte
656        // that is only ours, because a replica asks about the first byte it
657        // wants and counts from one.
658        self.repl
659            .second
660            .store(self.repl.offset.load(Acquire) as i64 + 1, Relaxed);
661    }
662
663    /// Take a fresh replication id and forget the old one, which is what
664    /// `DEBUG CHANGE-REPL-ID` is for.
665    ///
666    /// Not a promotion. A promotion keeps the old id as the second one so that
667    /// the replicas that shared it can carry on, and this throws it away, which
668    /// is the point: it is how a test makes two servers that were part of the
669    /// same history stop being able to prove it, so the next `PSYNC` between
670    /// them has to be a full one.
671    pub(crate) fn change_id(&self) {
672        let mut id = self.repl.id.lock();
673        let mut id2 = self.repl.id2.lock();
674        *id = make_id();
675        *id2 = [b'0'; ID_LEN];
676        self.repl.second.store(-1, Relaxed);
677    }
678
679    /// The replica row for a connection, if it is one.
680    fn replica_of(&self, id: u64) -> Option<Arc<Replica>> {
681        let rows = self.repl.rows.lock();
682        rows.iter().find(|r| r.row.id == id).map(Arc::clone)
683    }
684}
685
686// ------------------------------------------------------------ the heartbeat
687
688/// How long a quiet replication link goes before its master pings it.
689///
690/// Ten seconds is `repl-ping-replica-period`'s default. The setting itself is
691/// not in the config table yet, so this is the number rather than a lookup.
692const PING_REPLICAS_MS: u64 = 10_000;
693
694/// How often the heartbeat thread wakes up to see whether one is due.
695const HEARTBEAT_MS: u64 = 1000;
696
697impl Server {
698    /// Start the thread that pings the replicas of a quiet master.
699    ///
700    /// A master pings so that a replica can tell a link that has gone away from
701    /// a master with nothing to say, since a TCP connection that nobody writes
702    /// to gives no sign either way. It is also what moves the offset on a server
703    /// nobody is writing to, and a replica whose offset is still zero is one a
704    /// real server leaves out of `CLUSTER SLOTS` on the grounds that it has
705    /// never caught up with anything.
706    ///
707    /// Its own thread because the housekeeping the engine does runs per batch,
708    /// so a server with no traffic does none of it, and a server with no traffic
709    /// is exactly the one that owes its replicas a ping.
710    pub fn start_replica_heartbeat(self: &Arc<Server>) {
711        let beating = Arc::clone(self);
712        yo_alloc::allow(|| {
713            let _ = std::thread::Builder::new()
714                .name(String::from("yo-repl-ping"))
715                .spawn(move || heartbeat(&beating));
716        });
717    }
718}
719
720/// One ping every `PING_REPLICAS_MS` on a link that has been quiet that long.
721fn heartbeat(server: &Arc<Server>) {
722    loop {
723        std::thread::sleep(Duration::from_millis(HEARTBEAT_MS));
724        // Only a top level master. A replica passes on the stream it is given
725        // rather than writing one, so a ping from here would put bytes in the
726        // middle of somebody else's history.
727        if !server.replicated() || server.following() {
728            continue;
729        }
730        let now = server.now_ms();
731        if now.saturating_sub(server.repl.last_io.load(Relaxed)) < PING_REPLICAS_MS {
732            continue;
733        }
734        // No `SELECT` in front of it, which is what the reference's `dictid` of
735        // minus one means: a ping touches no key, so it does not move the
736        // stream's database and must not look as though it did.
737        emit(server, render(&[b"PING"]));
738    }
739}
740
741// ---------------------------------------------------------------- the feed
742
743/// One command as a RESP array, which is the only shape the stream has.
744fn render(parts: &[&[u8]]) -> Vec<u8> {
745    let mut out = Vec::with_capacity(16 + parts.iter().map(|p| p.len() + 16).sum::<usize>());
746    out.extend_from_slice(b"*");
747    out.extend_from_slice(parts.len().to_string().as_bytes());
748    out.extend_from_slice(b"\r\n");
749    for part in parts {
750        out.extend_from_slice(b"$");
751        out.extend_from_slice(part.len().to_string().as_bytes());
752        out.extend_from_slice(b"\r\n");
753        out.extend_from_slice(part);
754        out.extend_from_slice(b"\r\n");
755    }
756    out
757}
758
759/// Put bytes on the stream: into the backlog, onto the offset, out to everybody.
760///
761/// The offset moves under the backlog lock so that the backlog and the number
762/// never disagree. A replica attaching between the two would otherwise be given
763/// an offset the backlog cannot honour.
764fn emit(server: &Server, bytes: Vec<u8>) {
765    server.repl.last_io.store(server.now_ms(), Relaxed);
766    let shared = {
767        let mut backlog = server.repl.backlog.lock();
768        let upto = server.repl.offset.load(Relaxed) + bytes.len() as u64;
769        yo_alloc::allow(|| backlog.push(&bytes, upto));
770        server.repl.offset.store(upto, Release);
771        yo_alloc::allow(|| Arc::new(bytes))
772    };
773    for held in server.replica_rows() {
774        if !held.online.load(Relaxed) {
775            continue;
776        }
777        server.post(
778            held.row.thread.load(Relaxed),
779            Envelope::raw(
780                held.row.conn.load(Relaxed),
781                held.row.id,
782                Arc::clone(&shared),
783            ),
784        );
785    }
786}
787
788/// Put one command on the stream, with a `SELECT` in front of it if the stream
789/// is not on the right database.
790fn send(server: &Server, db: usize, parts: &[&[u8]]) {
791    let body = render(parts);
792    // A slot migration listens here as well, because this is the one place
793    // everything propagated comes through: a rewrite, a key that went away on
794    // its own, what a script did. It takes the command already rendered and
795    // keeps or drops it on the slot its key is in, and it never gets the
796    // `SELECT` below, since a cluster has one database and the far side would
797    // have nothing to do with it.
798    server.asm_feed(&body);
799    let mut bytes = Vec::new();
800    if server.repl.on_db.load(Relaxed) != db as i64 {
801        let n = db.to_string();
802        bytes = render(&[b"SELECT", n.as_bytes()]);
803        server.repl.on_db.store(db as i64, Relaxed);
804    }
805    bytes.extend_from_slice(&body);
806    emit(server, bytes);
807}
808
809/// Put one command on the stream from outside a command.
810///
811/// The funnel below is arranged around a client running something, and there is
812/// one thing that reaches it without one: the bus, dropping the keys of a slot
813/// that has just moved to another node. That happens on a bus thread with no
814/// session and no arguments to fall back on, so the caller says exactly what to
815/// send and this is the door it goes through.
816pub(super) fn announce(server: &Server, db: usize, parts: &[&[u8]]) {
817    send(server, db, parts);
818}
819
820/// Pass a master's bytes on, unchanged, and count them.
821///
822/// What a replica owes anybody following it is the stream it was given rather
823/// than an account of what running it did, because the offsets in that stream
824/// are positions in the master's history and this server is not writing one. So
825/// the bytes go on as they arrived. The count moves either way, because it is
826/// the number this server acknowledges to its own master and a chain of nobody
827/// still has to be able to say where it has got to.
828pub(crate) fn relayed(server: &Server, bytes: Vec<u8>, db: usize) {
829    if server.replicated() {
830        server.repl.on_db.store(db as i64, Relaxed);
831        emit(server, bytes);
832        return;
833    }
834    server.repl.offset.fetch_add(bytes.len() as u64, Release);
835}
836
837/// Report a command to every replica, in the form it has to be given.
838///
839/// The caller has already checked [`Server::replicated`] and that the command
840/// did not fail, so what is decided here is only the shape.
841///
842/// `verbatim` is whether the command as it arrived is a fair thing to send when
843/// the body said nothing. It is the write flag, and it is false for a read,
844/// which sends nothing, and for a container like `XGROUP` whose flags are on its
845/// subcommands, which sends what its body pushed and nothing otherwise.
846pub(super) fn feed(server: &Server, db: usize, args: Args<'_>, verbatim: bool) {
847    if super::follow::applying() {
848        forget();
849        return;
850    }
851    let instead = taken();
852    yo_alloc::allow(|| match instead {
853        None if !verbatim => {}
854        None => {
855            let parts: Vec<&[u8]> = (0..args.len()).map(|i| args.get(i)).collect();
856            send(server, db, &parts);
857        }
858        Some(each) => {
859            for one in &each {
860                let parts: Vec<&[u8]> = one.iter().map(Vec::as_slice).collect();
861                send(server, db, &parts);
862            }
863        }
864    });
865}
866
867/// Report what a command that nobody is running left behind.
868///
869/// A blocked client is answered by the thread that woke it, a long way outside
870/// the funnel and with no arguments to fall back on, so unlike [`feed`] there is
871/// no verbatim form here: whatever the answering left is all there is, and an
872/// answering that left nothing did nothing.
873pub(super) fn served(server: &Server, db: usize) {
874    if super::follow::applying() {
875        forget();
876        return;
877    }
878    let Some(each) = taken() else {
879        return;
880    };
881    yo_alloc::allow(|| {
882        for one in &each {
883            let parts: Vec<&[u8]> = one.iter().map(Vec::as_slice).collect();
884            send(server, db, &parts);
885        }
886    });
887}
888
889/// Throw away whatever the last command left, for a command that is not
890/// propagated at all.
891///
892/// A read that pushed a rewrite is a bug, but a rewrite left behind by a command
893/// that was refused after it pushed one is not, and it must not be handed to the
894/// next command that runs on this thread.
895pub(super) fn forget() {
896    let _ = taken();
897}
898
899/// Note a key or a field the storage layer took away on its own.
900///
901/// A replica never expires and never evicts. It cannot: the two decisions are
902/// made from a clock reading and a memory figure that are the master's and not
903/// its own, and a replica that made them itself would answer a read differently
904/// from the master for as long as the two disagreed. So it holds a key past its
905/// deadline until it is told, and being told is this. Redis sends the same thing
906/// for the same reason, and it is why a replica's `dbsize` can be ahead of the
907/// master's for a moment and never behind it.
908///
909/// Collected rather than sent, because the point at which a key goes is inside a
910/// stripe lock and the send takes a different one.
911pub(crate) fn reaped(parts: &[&[u8]]) {
912    if !ARMED.get() {
913        return;
914    }
915    REAPED.with_borrow_mut(|list| {
916        yo_alloc::allow(|| list.push(parts.iter().map(|part| part.to_vec()).collect()));
917    });
918}
919
920/// Send what [`reaped`] collected, ahead of whatever the command itself did.
921///
922/// Ahead, because that is the order it happened in and the order matters: a
923/// `SET k v` that found an expired `k` on the way in has to reach a replica as
924/// the deletion and then the write, or a replica that has kept a `k` of the
925/// wrong type refuses the write it is sent.
926pub(super) fn swept(server: &Server, db: usize) {
927    if REAPED.with_borrow(Vec::is_empty) {
928        return;
929    }
930    let each = REAPED.with_borrow_mut(core::mem::take);
931    // A replica that reaped a key on its own has nothing to tell anybody. The
932    // master is going to send the deletion in a moment and that is the copy that
933    // counts, because it is the one at the offset everybody else is counting
934    // from. See the `follow` module on why a chain passes bytes on rather than
935    // effects.
936    if super::follow::applying() {
937        return;
938    }
939    yo_alloc::allow(|| {
940        for one in &each {
941            let parts: Vec<&[u8]> = one.iter().map(Vec::as_slice).collect();
942            send(server, db, &parts);
943        }
944    });
945}
946
947// ------------------------------------------------------------- the commands
948
949/// `REPLCONF`, which is how a replica tells a master about itself.
950///
951/// Everything here is a pair, and a master answers `OK` to a pair it does not
952/// know rather than refusing it, because the whole point of the command is that
953/// a newer replica can tell an older master things it has never heard of. The
954/// one exception is `ACK`, which is not a question and is answered with silence:
955/// by the time a replica sends one the connection is a stream, and a reply on it
956/// is a protocol error at the other end.
957pub(super) fn replconf(
958    server: &Server,
959    session: &Session,
960    args: Args<'_>,
961    out: &mut Out,
962) -> Result<()> {
963    if args.len() < 3 || args.len().is_multiple_of(2) {
964        return Err(args::wrong_arity("replconf"));
965    }
966    let mut at = 1;
967    while at < args.len() {
968        let name = args.get(at).to_ascii_lowercase();
969        match name.as_slice() {
970            b"listening-port" => {
971                let port = args.int(at + 1)?;
972                server.note_replica_port(session.row().id, port.max(0) as u64);
973            }
974            b"ack" => {
975                // Not answered, ever. See the doc comment.
976                let ack = args.int(at + 1).unwrap_or(0);
977                if let Some(held) = server.replica_of(session.row().id) {
978                    held.ack.store(ack.max(0) as u64, Relaxed);
979                    held.ack_ms.store(server.clock.now_ms(), Relaxed);
980                }
981                return Ok(());
982            }
983            b"getack" => {
984                // A master sends this and a replica answers it. Reaching it here
985                // means somebody sent it to a master, which Redis refuses.
986                return Err(Error::new(
987                    Code::Invalid,
988                    "REPLCONF GETACK is only supported by a replica",
989                ));
990            }
991            _ => {}
992        }
993        at += 2;
994    }
995    out.ok();
996    Ok(())
997}
998
999/// `PSYNC <replid> <offset>`, which is where a connection stops being a client.
1000///
1001/// Answers `+CONTINUE` and the missing bytes when the replica is asking to carry
1002/// on a history we are still writing and still hold enough of, and a full resync
1003/// otherwise. `SYNC` is the same thing without the negotiation, from before
1004/// Redis had one, and is a snapshot with no header in front of it.
1005pub(super) fn psync(
1006    server: &Server,
1007    session: &mut Session,
1008    args: Args<'_>,
1009    out: &mut Out,
1010) -> Result<()> {
1011    let partial = if args.name().eq_ignore_ascii_case(b"sync") {
1012        if args.len() != 1 {
1013            return Err(args::wrong_arity("sync"));
1014        }
1015        None
1016    } else {
1017        // Four words when the fourth is `FAILOVER`, which is a master that has
1018        // stopped writing telling us to take over from it. Three otherwise, and
1019        // a fourth word that is not that one is not a spelling of anything.
1020        let handover = args.len() == 4 && args.get(3).eq_ignore_ascii_case(b"failover");
1021        if args.len() != 3 && !handover {
1022            return Err(args::wrong_arity("psync"));
1023        }
1024        let asked = args.get(1);
1025        // Before anything else is read, because this is the one form of the
1026        // command that changes what this server is rather than asking it for
1027        // something, and a master that has already stopped writing is waiting on
1028        // the answer.
1029        if handover {
1030            take_over(server, asked)?;
1031        }
1032        let from = args.int(2)?;
1033        // The number a replica sends is the position of the first byte it
1034        // wants counted from one, so a replica that has everything asks for one
1035        // past the end of the stream. Everything on this side counts bytes
1036        // written, so the two are a step apart, and the step is taken here
1037        // rather than inside the backlog, where every other caller means the
1038        // count. A nought is nobody's answer and would mean the byte before the
1039        // first, so it starts again, which is what a real master does with it.
1040        (asked != b"?" && from >= 1).then(|| (asked.to_vec(), from as u64 - 1))
1041    };
1042    // Nobody may attach to a server that is in the middle of handing its job
1043    // over, because the offsets it is about to start reporting are somebody
1044    // else's. The `FAILOVER` form above got past this, which is the point: that
1045    // one is the handover and this is everybody else.
1046    if server.failing_over() {
1047        out.error(b"NOMASTERLINK Can't SYNC while failing over");
1048        return Ok(());
1049    }
1050    // Nor to a replica whose own link is not up, because what it would be
1051    // handing out is a history it has not finished reading.
1052    if server.following() && !server.master_link_up() {
1053        out.error(b"NOMASTERLINK Can't SYNC while not connected with my master");
1054        return Ok(());
1055    }
1056    if session.running() {
1057        return Err(Error::new(
1058            Code::Invalid,
1059            "PSYNC isn't allowed for DENY BLOCKING client",
1060        ));
1061    }
1062    // A partial resync first, since it is the cheap answer and the whole reason
1063    // the replica bothered to remember where it was.
1064    if let Some((asked, from)) = partial
1065        && let Some(bytes) = catch_up(server, &asked, from)
1066    {
1067        {
1068            let id = server.repl_id();
1069            out.raw(b"+CONTINUE ");
1070            out.raw(&id);
1071            out.raw(b"\r\n");
1072            out.raw(&bytes);
1073            attach(server, session);
1074            return Ok(());
1075        }
1076    }
1077    full(server, session, out)
1078}
1079
1080/// Take the master's job, because the master asked us to.
1081///
1082/// The fourth word of a `PSYNC` is how a `FAILOVER` finishes. Everything hard
1083/// about it happened on the other side: the master stopped writing, waited until
1084/// this server had acknowledged every byte, and only then sent this. So all that
1085/// is left here is to check that it is talking to the right server and then stop
1086/// being a replica, after which the `PSYNC` carries on as an ordinary one and is
1087/// answered with a `+CONTINUE` that costs nothing, because the two sides are in
1088/// step by construction.
1089///
1090/// The promotion is `REPLICAOF NO ONE`, so the history that was being followed
1091/// is kept as the second id. That is what makes the old master's `PSYNC`, which
1092/// names that very history, something this server can answer at all.
1093fn take_over(server: &Server, asked: &[u8]) -> Result<()> {
1094    if !server.following() {
1095        return Err(Error::new(
1096            Code::Invalid,
1097            "PSYNC FAILOVER can't be sent to a master.",
1098        ));
1099    }
1100    if asked != server.repl_id() {
1101        return Err(Error::new(
1102            Code::Invalid,
1103            "PSYNC FAILOVER replid must match my replid.",
1104        ));
1105    }
1106    let Some(shared) = server.myself() else {
1107        return Err(Error::new(
1108            Code::Invalid,
1109            "PSYNC FAILOVER is not available on an embedded server",
1110        ));
1111    };
1112    shared.stop_following();
1113    Ok(())
1114}
1115
1116/// The bytes a reconnecting replica missed, or `None` if it has to start again.
1117///
1118/// A replica asking about the history we are writing is caught up from the
1119/// backlog. One asking about the history we were writing before we were promoted
1120/// is caught up too, but only up to the point where the histories part, which is
1121/// what the second offset records.
1122fn catch_up(server: &Server, asked: &[u8], from: u64) -> Option<Vec<u8>> {
1123    let ours = server.repl_id();
1124    let theirs = *server.repl.id2.lock();
1125    let second = server.repl.second.load(Relaxed);
1126    let matches = asked == ours
1127        || (asked == theirs && second >= 0 && from <= u64::try_from(second).unwrap_or(0));
1128    if !matches {
1129        return None;
1130    }
1131    let upto = server.repl.offset.load(Acquire);
1132    let backlog = server.repl.backlog.lock();
1133    yo_alloc::allow(|| backlog.since(from, upto))
1134}
1135
1136/// A full resync: the header, then the whole keyspace as one image.
1137///
1138/// The image and the offset are taken with every stripe of every database held,
1139/// so what the replica loads and what it is then told about are the two halves
1140/// of one instant and neither overlaps the other. See the module header.
1141fn full(server: &Server, session: &mut Session, out: &mut Out) -> Result<()> {
1142    let (image, offset) = server.snapshot_at_an_instant();
1143    let id = server.repl_id();
1144    out.raw(b"+FULLRESYNC ");
1145    out.raw(&id);
1146    out.raw(b" ");
1147    out.raw(offset.to_string().as_bytes());
1148    out.raw(b"\r\n");
1149    // A bulk string with no newline after it, which is the one place in the
1150    // protocol where that is so. The replica reads the length and then exactly
1151    // that many bytes, and anything after them is the stream.
1152    out.raw(b"$");
1153    out.raw(image.len().to_string().as_bytes());
1154    out.raw(b"\r\n");
1155    out.raw(&image);
1156    attach(server, session);
1157    Ok(())
1158}
1159
1160/// Turn the connection into a replica, once the answer has been written.
1161///
1162/// Everything it was holding as a client goes first: a transaction it had open,
1163/// the keys it was watching and any subscription. All three are promises of a
1164/// reply, and a connection that has become a stream has no way left to keep one.
1165fn attach(server: &Server, session: &mut Session) {
1166    super::forget_session(server, session);
1167    server.take_replica(session.row());
1168}
1169
1170/// How many replicas have acknowledged everything written so far.
1171///
1172/// What `WAIT` answers with. It is the count that is already there rather than
1173/// one waited for, which is the right answer when it is already enough and is a
1174/// divergence when it is not. Waiting here means holding a connection until an
1175/// acknowledgement arrives, which needs the waiter list to be woken by something
1176/// that is not a key changing, and that is the same wakeup D-115 is about.
1177pub(super) fn caught_up(server: &Server) -> usize {
1178    let upto = server.repl_offset();
1179    server
1180        .replica_rows()
1181        .iter()
1182        .filter(|r| r.online.load(Relaxed) && r.ack.load(Relaxed) >= upto)
1183        .count()
1184}
1185
1186// ------------------------------------------------------------------- report
1187
1188/// What `ROLE` answers on a master.
1189///
1190/// The word, then the offset as an integer, then one row per replica. Only the
1191/// replicas that are online are listed, because a replica still being sent its
1192/// snapshot has no offset of its own to report and Redis leaves it out for the
1193/// same reason. Inside a row every field is a bulk string, including the port
1194/// and the offset, which is a shape nobody would pick today and is the shape
1195/// every client library already parses.
1196pub(super) fn role(server: &Server, out: &mut Out) {
1197    if server.following() {
1198        super::follow::role(server, out);
1199        return;
1200    }
1201    let rows = server.replica_rows();
1202    out.array(3);
1203    out.bulk(b"master");
1204    out.int(server.repl_offset() as i64);
1205    let at = out.len();
1206    let mut n = 0;
1207    for held in &rows {
1208        if !held.online.load(Relaxed) {
1209            continue;
1210        }
1211        let (host, port) = held.address();
1212        out.array(3);
1213        out.bulk(host.as_bytes());
1214        out.bulk(port.to_string().as_bytes());
1215        out.bulk(held.ack.load(Relaxed).to_string().as_bytes());
1216        n += 1;
1217    }
1218    out.close_array(at, n);
1219}
1220
1221/// The `Replication` section of `INFO`.
1222///
1223/// Redis reports a dozen fields on a master and a few more on a replica. This is
1224/// the master's set, since nothing here can be a replica yet, plus one `slaveN`
1225/// row per replica in the order they attached, which is what tooling reads to
1226/// find out who is following whom.
1227pub(super) fn info(server: &Server, s: &mut String) {
1228    use core::fmt::Write as _;
1229    let rows = server.replica_rows();
1230    let id = server.repl_id();
1231    let id2 = *server.repl.id2.lock();
1232    let offset = server.repl_offset();
1233    let now = server.clock.now_ms();
1234    let _ = write!(
1235        s,
1236        "# Replication\r\nrole:{}\r\n",
1237        super::follow::role_word(server)
1238    );
1239    // The master's own fields first when there is a master, which is where Redis
1240    // puts them: a tool reading the section top to bottom finds out what this
1241    // server is, then who it follows, then who follows it.
1242    super::follow::info(server, s);
1243    let _ = write!(s, "connected_slaves:{}\r\n", rows.len());
1244    for (i, held) in rows.iter().enumerate() {
1245        let (host, port) = held.address();
1246        let state = if held.online.load(Relaxed) {
1247            "online"
1248        } else {
1249            "wait_bgsave"
1250        };
1251        let lag = now.saturating_sub(held.ack_ms.load(Relaxed)) / 1000;
1252        let _ = write!(
1253            s,
1254            "slave{i}:ip={host},port={port},state={state},offset={},lag={lag}\r\n",
1255            held.ack.load(Relaxed),
1256        );
1257    }
1258    let _ = write!(
1259        s,
1260        "master_failover_state:{}\r\n\
1261         master_replid:{}\r\nmaster_replid2:{}\r\n\
1262         master_repl_offset:{offset}\r\nsecond_repl_offset:{}\r\n",
1263        server.failover_word(),
1264        String::from_utf8_lossy(&id),
1265        String::from_utf8_lossy(&id2),
1266        server.repl.second.load(Relaxed),
1267    );
1268    // The backlog is made when the first replica attaches and is never given
1269    // back, which is what `repl_backlog_active` is saying. The histlen is how
1270    // much of it is real, so a server that has never had a replica reports a
1271    // backlog that is off and empty rather than one that is on and zero long.
1272    let (active, first, histlen) = {
1273        let backlog = server.repl.backlog.lock();
1274        (
1275            usize::from(!backlog.ring.is_empty()),
1276            // Counted from one, the way a replica counts when it asks to carry
1277            // on, because this is the number it is being compared against. A
1278            // server that has never had a replica has no backlog and reports a
1279            // nought rather than the one that would be the first byte of the
1280            // one it has not made.
1281            if backlog.ring.is_empty() {
1282                0
1283            } else {
1284                backlog.first + 1
1285            },
1286            backlog.filled,
1287        )
1288    };
1289    let _ = write!(
1290        s,
1291        "repl_backlog_active:{active}\r\nrepl_backlog_size:{BACKLOG_BYTES}\r\n\
1292         repl_backlog_first_byte_offset:{first}\r\nrepl_backlog_histlen:{histlen}\r\n\r\n",
1293    );
1294}