Skip to main content

yo_resp/dispatch/cluster/
bus.rs

1//! The cluster bus, which is how nodes find each other and agree on who owns
2//! what.
3//!
4//! Every cluster node listens on a second port, the client port plus ten
5//! thousand, and speaks a small binary protocol on it that has nothing to do
6//! with RESP. Nodes ping each other about once a second, and every ping carries
7//! a header describing the sender, a handful of gossip entries describing other
8//! nodes the sender has heard from lately, and a few extensions on the end. Out
9//! of that falls everything a cluster knows: who exists, who owns which slots,
10//! who is a replica of whom, and who has stopped answering.
11//!
12//! The format here is the reference's, field for field and offset for offset,
13//! because the whole point of it is that a yo node and a real Redis node can be
14//! in the same cluster. The reference guarantees its own layout with static
15//! asserts in `cluster_legacy.h`, which is a promise that the offsets are part
16//! of the protocol and not an accident of one compiler, so copying them is
17//! reading a specification rather than reading an implementation.
18//!
19//! # Why this has its own threads
20//!
21//! Every client connection in this server is driven by a poller that lives in
22//! the binary crate, and this crate cannot reach it, so the bus cannot join it.
23//! That sounds like a limitation and is really a preference. Bus traffic is
24//! roughly one packet a second per node in a cluster that is behaving, which
25//! means a thread per link costs a thread that is asleep almost all of the time
26//! and buys code that reads top to bottom with no state machine in it. A
27//! cluster of a hundred nodes is a hundred sleeping threads, which is nothing,
28//! and a cluster larger than that is not a thing anybody runs. It is registered
29//! as a divergence anyway, because a reader who knows the reference will expect
30//! the bus to be in the event loop and should not have to find out by grep.
31//!
32//! # What is not here
33//!
34//! The failover vote. `FAILOVER_AUTH_REQUEST`, `FAILOVER_AUTH_ACK` and
35//! `MFSTART` are recognised and dropped rather than answered, so a yo node
36//! neither runs an election nor votes in one. That is a change of its own with
37//! its own tests, and shipping the link layer without it is what lets a cluster
38//! be built and watched while the election is being written.
39
40use std::io::{Read, Write};
41use std::net::{Shutdown, TcpListener, TcpStream};
42use std::sync::atomic::Ordering::Relaxed;
43use std::sync::atomic::{AtomicBool, AtomicU64};
44use std::sync::{Arc, Mutex};
45use std::time::Duration;
46
47use yo_common::lock::Lock;
48
49use super::super::Server;
50use super::super::pubsub::{self, Kind};
51use super::{
52    FLAG_FAIL, FLAG_HANDSHAKE, FLAG_MASTER, FLAG_MEET, FLAG_MIGRATE_TO, FLAG_MYSELF, FLAG_NOADDR,
53    FLAG_NOFAILOVER, FLAG_PFAIL, FLAG_SLAVE, Map, Node, SLOTS, new_id,
54};
55use crate::reply::Out;
56
57// ------------------------------------------------------------- the wire format
58
59/// The four bytes every packet starts with, which is the only thing that tells
60/// a bus port from anything else somebody might connect to it.
61const SIG: &[u8; 4] = b"RCmb";
62
63/// The protocol version. A packet claiming anything else is dropped without a
64/// word, because a node that cannot read a packet cannot say so either.
65const PROTO_VER: u16 = 1;
66
67/// How long a node id is, in bytes of lowercase hex.
68const NAME_LEN: usize = 40;
69
70/// How much room an address gets, which is enough for the longest IPv6 text
71/// form and is fixed because the header is fixed.
72const IP_LEN: usize = 46;
73
74/// The slot bitmap, one bit per slot.
75const BITMAP_LEN: usize = SLOTS / 8;
76
77/// The header every packet carries, whatever its type. The reference calls this
78/// `CLUSTERMSG_MIN_LEN` and asserts it.
79const HDR_LEN: usize = 2256;
80
81/// One gossip entry.
82const GOSSIP_LEN: usize = 104;
83
84/// The most a packet may be before it is treated as noise rather than as a
85/// packet. The reference grows its receive buffer to whatever the header claims,
86/// which is fine when the peer is trusted and is a way to be talked into
87/// allocating a lot when it is not, so there is a ceiling here. A publish of a
88/// megabyte over the bus is already an unusual thing to do.
89const MAX_PACKET: usize = 64 * 1024 * 1024;
90
91/// Where each header field starts. These are the reference's, and the reference
92/// asserts them, so they are the protocol.
93const O_TOTLEN: usize = 4;
94const O_VER: usize = 8;
95const O_PORT: usize = 10;
96const O_TYPE: usize = 12;
97const O_COUNT: usize = 14;
98const O_CURRENT_EPOCH: usize = 16;
99const O_CONFIG_EPOCH: usize = 24;
100const O_OFFSET: usize = 32;
101const O_SENDER: usize = 40;
102const O_SLOTS: usize = 80;
103const O_SLAVEOF: usize = 2128;
104const O_MYIP: usize = 2168;
105const O_EXTENSIONS: usize = 2214;
106const O_PPORT: usize = 2246;
107const O_CPORT: usize = 2248;
108const O_FLAGS: usize = 2250;
109const O_STATE: usize = 2252;
110const O_MFLAGS: usize = 2253;
111
112/// Where each field of a gossip entry starts, from the start of the entry.
113const G_NAME: usize = 0;
114const G_PING: usize = 40;
115const G_PONG: usize = 44;
116const G_IP: usize = 48;
117const G_PORT: usize = 94;
118const G_CPORT: usize = 96;
119const G_FLAGS: usize = 98;
120
121/// The message types, which are the reference's numbers and cannot move.
122const T_PING: u16 = 0;
123const T_PONG: u16 = 1;
124const T_MEET: u16 = 2;
125const T_FAIL: u16 = 3;
126const T_PUBLISH: u16 = 4;
127const T_AUTH_REQUEST: u16 = 5;
128const T_AUTH_ACK: u16 = 6;
129const T_UPDATE: u16 = 7;
130const T_MFSTART: u16 = 8;
131const T_MODULE: u16 = 9;
132const T_PUBLISHSHARD: u16 = 10;
133
134/// The one message flag that goes out on everything, which says this node
135/// understands the extensions on the end of a ping and is safe to send them to.
136const MF_EXT_DATA: u8 = 4;
137
138/// The extension types.
139const X_HOSTNAME: u16 = 0;
140const X_HUMAN_NAME: u16 = 1;
141const X_FORGOTTEN: u16 = 2;
142const X_SHARDID: u16 = 3;
143const X_SECRET: u16 = 4;
144
145/// `CLUSTER_OK` and `CLUSTER_FAIL`, which is the one byte of state a packet
146/// carries and is what lets a node see that the rest of the cluster has given
147/// up even when it has not.
148const STATE_OK: u8 = 0;
149const STATE_FAIL: u8 = 1;
150
151/// How long a node id stays unwelcome after `CLUSTER FORGET`, in milliseconds.
152///
153/// Forgetting a node means nothing on its own, because the next gossip packet
154/// from anybody who has not forgotten it would put it straight back. So a forget
155/// is a forget plus a minute of refusing to learn it again, by which time the
156/// forget has been passed round the cluster in the extension that carries it.
157const BLACKLIST_MS: u64 = 60_000;
158
159/// How often the bus wakes up, which is the reference's `clusterCron`.
160const CRON_MS: u64 = 100;
161
162/// How often a node is pinged when nothing else has prompted a ping. The
163/// reference derives this from the node timeout and lets it be set outright;
164/// this is the derived default.
165const PING_MS: u64 = 1000;
166
167/// How long a node has to be silent before this one calls it possibly failed.
168const NODE_TIMEOUT_MS: u64 = 15_000;
169
170/// How long to wait on a connect to another node's bus port before giving up
171/// and trying again on the next tick.
172const CONNECT_TIMEOUT: Duration = Duration::from_millis(500);
173
174/// Read a big endian field out of a packet, or nought when it is off the end.
175///
176/// Every read here is bounds checked rather than trusted, because the packet
177/// came off a socket and the length checks in front of it are checks and not
178/// proofs. A truncated field reading as nought loses a packet, which is what
179/// losing a packet on a gossip protocol is for.
180fn be16(p: &[u8], at: usize) -> u16 {
181    p.get(at..at + 2)
182        .map_or(0, |b| u16::from_be_bytes([b[0], b[1]]))
183}
184
185fn be32(p: &[u8], at: usize) -> u32 {
186    p.get(at..at + 4)
187        .map_or(0, |b| u32::from_be_bytes([b[0], b[1], b[2], b[3]]))
188}
189
190fn be64(p: &[u8], at: usize) -> u64 {
191    p.get(at..at + 8).map_or(0, |b| {
192        u64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
193    })
194}
195
196/// Put a big endian field into a packet being built, which is always in range
197/// because the buffer was sized first.
198fn put16(p: &mut [u8], at: usize, v: u16) {
199    p[at..at + 2].copy_from_slice(&v.to_be_bytes());
200}
201
202fn put64(p: &mut [u8], at: usize, v: u64) {
203    p[at..at + 8].copy_from_slice(&v.to_be_bytes());
204}
205
206/// A fixed width text field, which is NUL padded and may not be terminated when
207/// it is exactly full.
208fn text(p: &[u8], at: usize, len: usize) -> String {
209    let Some(raw) = p.get(at..at + len) else {
210        return String::new();
211    };
212    let end = raw.iter().position(|b| *b == 0).unwrap_or(len);
213    String::from_utf8_lossy(&raw[..end]).into_owned()
214}
215
216/// A node id out of a packet, which has to be forty hex characters or it is not
217/// one. An id that is all zeros is the reference's way of saying no node, and
218/// comes back as `None` here so the caller cannot mistake it for one.
219fn node_id(p: &[u8], at: usize) -> Option<String> {
220    let raw = p.get(at..at + NAME_LEN)?;
221    if raw.iter().all(|b| *b == 0) {
222        return None;
223    }
224    if !raw.iter().all(u8::is_ascii_hexdigit) {
225        return None;
226    }
227    Some(String::from_utf8_lossy(raw).into_owned())
228}
229
230/// Whether a slot is set in a bitmap, which the reference stores least
231/// significant bit first inside each byte.
232fn bit(bitmap: &[u8], slot: usize) -> bool {
233    bitmap
234        .get(slot / 8)
235        .is_some_and(|b| b & (1 << (slot % 8)) != 0)
236}
237
238/// Set a slot in a bitmap being built.
239fn set_bit(bitmap: &mut [u8], slot: usize) {
240    bitmap[slot / 8] |= 1 << (slot % 8);
241}
242
243/// A node index drawn at random out of `n`, which is how the gossip section
244/// picks who to talk about. Random and not round robin because every node
245/// picking independently is what spreads news in a few rounds rather than in a
246/// lap of the table.
247fn pick(n: usize) -> u16 {
248    let mut raw = [0u8; 8];
249    yo_common::entropy::fill(&mut raw);
250    (u64::from_be_bytes(raw) % n as u64) as u16
251}
252
253// ------------------------------------------------------------------ the links
254
255/// One connection to another node's bus.
256///
257/// There are two of these per pair of nodes and not one, which looks wasteful
258/// and is the reference's design for a good reason: a link is owned by whoever
259/// opened it, so a node that decides a peer is unreachable can drop its own link
260/// and reconnect without having to agree with the peer about whose turn it is.
261/// The outbound one carries this node's pings and the inbound one carries the
262/// peer's, and each is answered on the socket it arrived on.
263pub(super) struct Wire {
264    /// Whether this node accepted it rather than opened it, which is the
265    /// `from` and `to` of `CLUSTER LINKS`.
266    pub(super) inbound: bool,
267    /// The node at the far end, empty on an inbound link until a packet says
268    /// who is sending it.
269    pub(super) node: Lock<String>,
270    /// When it was made, which `CLUSTER LINKS` reports.
271    pub(super) created: u64,
272    /// The address the peer connected from or was connected to, which is how a
273    /// node learns the address of a peer that did not announce one.
274    peer: String,
275    /// The address on this side of it, which is how a node learns its own.
276    local: String,
277    /// The socket, behind a real mutex rather than the spin lock the tables use,
278    /// because writing to it blocks and a spin lock held across a blocking write
279    /// is a spin lock held for a millisecond.
280    sock: Mutex<TcpStream>,
281    /// Whether it has failed, so that a writer stops trying and the cron drops
282    /// it on the next tick.
283    dead: AtomicBool,
284    /// How many bytes have been handed to the kernel on it, which is the closest
285    /// honest answer to `CLUSTER LINKS`'s send buffer questions on a link that
286    /// has no send queue of its own.
287    sent: AtomicU64,
288}
289
290impl Wire {
291    /// Wrap an open socket.
292    fn new(sock: TcpStream, inbound: bool, node: &str, now: u64) -> Option<Arc<Wire>> {
293        let peer = sock.peer_addr().ok()?.ip().to_string();
294        let local = sock.local_addr().ok()?.ip().to_string();
295        Some(Arc::new(Wire {
296            inbound,
297            node: Lock::new(String::from(node)),
298            created: now,
299            peer,
300            local,
301            sock: Mutex::new(sock),
302            dead: AtomicBool::new(false),
303            sent: AtomicU64::new(0),
304        }))
305    }
306
307    /// The id of the node at the far end, or empty for one nobody has named.
308    fn named(&self) -> String {
309        let held = self.node.lock();
310        yo_alloc::allow(|| held.clone())
311    }
312
313    /// Point this link at a node, which happens on an inbound link the first
314    /// time a packet on it says who is sending.
315    fn name(&self, id: &str) {
316        let mut held = self.node.lock();
317        yo_alloc::allow(|| {
318            held.clear();
319            held.push_str(id);
320        });
321    }
322
323    /// Write a packet, and mark the link dead if that did not work.
324    ///
325    /// A failed write is not reported anywhere, because there is nobody to
326    /// report it to: the peer is either coming back, in which case the cron
327    /// reconnects, or it is not, in which case the timeout is the thing that
328    /// notices. That is the same as the reference, which frees the link and
329    /// carries on.
330    fn send(&self, packet: &[u8]) {
331        if self.dead.load(Relaxed) {
332            return;
333        }
334        let Ok(mut sock) = self.sock.lock() else {
335            self.dead.store(true, Relaxed);
336            return;
337        };
338        if sock.write_all(packet).is_err() {
339            self.dead.store(true, Relaxed);
340            let _ = sock.shutdown(Shutdown::Both);
341            return;
342        }
343        self.sent.store(packet.len() as u64, Relaxed);
344    }
345
346    /// Shut it down, which wakes the reader thread sitting on it.
347    fn kill(&self) {
348        self.dead.store(true, Relaxed);
349        if let Ok(sock) = self.sock.lock() {
350            let _ = sock.shutdown(Shutdown::Both);
351        }
352    }
353}
354
355/// Everything the bus owns that is not in the node table.
356///
357/// Separate from [`super::Cluster`] because none of it exists until the bus
358/// starts and none of it is looked at by a command on the hot path, so it is one
359/// lock rather than four fields on a struct every server has.
360#[derive(Default)]
361pub(super) struct Bus {
362    /// Every open link, both directions.
363    links: Lock<Vec<Arc<Wire>>>,
364    /// Ids that may not be learned again yet, and when they stop being unwelcome.
365    blacklist: Lock<Vec<(String, u64)>>,
366    /// The shared secret nodes use to recognise each other. Forty hex characters
367    /// made at start, and the whole cluster converges on whichever is smallest,
368    /// which is a rule that needs no coordinator to settle.
369    pub(super) secret: Lock<String>,
370    /// Whether the threads are up, so that starting twice is a no-op.
371    on: AtomicBool,
372    /// Whether the table has changed since it was last written.
373    dirty: AtomicBool,
374}
375
376impl Bus {
377    /// Add a link, dropping any that have died since the last look.
378    fn add(&self, wire: &Arc<Wire>) {
379        let mut links = self.links.lock();
380        yo_alloc::allow(|| {
381            links.retain(|held| !held.dead.load(Relaxed));
382            links.push(Arc::clone(wire));
383        });
384    }
385
386    /// The outbound link to a node, or `None` when there is not one.
387    fn outbound(&self, id: &str) -> Option<Arc<Wire>> {
388        let links = self.links.lock();
389        links
390            .iter()
391            .find(|held| !held.inbound && !held.dead.load(Relaxed) && *held.node.lock() == *id)
392            .map(Arc::clone)
393    }
394
395    /// Every live link, for a broadcast.
396    fn all(&self) -> Vec<Arc<Wire>> {
397        let links = self.links.lock();
398        yo_alloc::allow(|| {
399            links
400                .iter()
401                .filter(|held| !held.dead.load(Relaxed))
402                .map(Arc::clone)
403                .collect()
404        })
405    }
406
407    /// Drop every link to one node, which is what forgetting it means at this
408    /// level.
409    fn cut(&self, id: &str) {
410        let mut links = self.links.lock();
411        links.retain(|held| {
412            let theirs = held.node.lock();
413            if *theirs != *id {
414                return true;
415            }
416            drop(theirs);
417            held.kill();
418            false
419        });
420    }
421
422    /// Whether an id is unwelcome, and forget the entries that have aged out
423    /// while looking.
424    fn blacklisted(&self, id: &str, now: u64) -> bool {
425        let mut list = self.blacklist.lock();
426        list.retain(|(_, until)| *until > now);
427        list.iter().any(|(held, _)| held == id)
428    }
429
430    /// Make an id unwelcome for the next minute.
431    fn blacklist(&self, id: &str, now: u64) {
432        let mut list = self.blacklist.lock();
433        yo_alloc::allow(|| {
434            list.retain(|(held, until)| held != id && *until > now);
435            list.push((String::from(id), now + BLACKLIST_MS));
436        });
437    }
438}
439
440// ------------------------------------------------------------- starting it up
441
442impl Server {
443    /// Bring the bus up, which binds the bus port and starts the three kinds of
444    /// thread that run it.
445    ///
446    /// Called once, from whoever is about to start serving clients. A server
447    /// that is not a cluster node does nothing here and pays one relaxed load
448    /// for asking.
449    ///
450    /// # Errors
451    ///
452    /// When the bus port cannot be bound. That is fatal on a real server and is
453    /// fatal here too, because a cluster node nobody can gossip with is a node
454    /// that will be voted out of its own slots in fifteen seconds.
455    pub fn start_cluster_bus(self: &Arc<Server>) -> Result<(), String> {
456        if !self.cluster_enabled() || self.cluster.bus.on.swap(true, Relaxed) {
457            return Ok(());
458        }
459        let (port, id) = {
460            let map = self.cluster.map.lock();
461            (
462                map.nodes[0].bus,
463                yo_alloc::allow(|| map.nodes[0].id.clone()),
464            )
465        };
466        let door = TcpListener::bind(("0.0.0.0", port))
467            .map_err(|e| format!("cluster bus port {port} could not be bound: {e}"))?;
468        let _ = id;
469        let accepting = Arc::clone(self);
470        spawn("yo-bus-accept", move || accept(&accepting, &door));
471        let ticking = Arc::clone(self);
472        spawn("yo-bus-cron", move || cron(&ticking));
473        Ok(())
474    }
475}
476
477/// Start a bus thread, whose name is what a stack trace will show.
478fn spawn(name: &str, body: impl FnOnce() + Send + 'static) {
479    yo_alloc::allow(|| {
480        let _ = std::thread::Builder::new()
481            .name(String::from(name))
482            .spawn(body);
483    });
484}
485
486/// Take connections on the bus port for as long as the process lives.
487fn accept(server: &Arc<Server>, door: &TcpListener) {
488    loop {
489        let Ok((sock, _)) = door.accept() else {
490            std::thread::sleep(Duration::from_millis(CRON_MS));
491            continue;
492        };
493        let _ = sock.set_nodelay(true);
494        let now = server.now_ms();
495        let Some(wire) = Wire::new(sock, true, "", now) else {
496            continue;
497        };
498        server.cluster.bus.add(&wire);
499        let reading = Arc::clone(server);
500        spawn("yo-bus-link", move || pump(&reading, &wire));
501    }
502}
503
504/// Open a link to a node and start reading it.
505///
506/// Returns whether it worked, which the cron uses to decide whether the node is
507/// linked. The connect is blocking with a short timeout, which is why this is
508/// never called with the node table locked.
509fn dial(server: &Arc<Server>, id: &str, host: &str, bus: u16, meet: bool) -> bool {
510    let Ok(addrs) = std::net::ToSocketAddrs::to_socket_addrs(&(host, bus)) else {
511        return false;
512    };
513    let mut sock = None;
514    for addr in addrs {
515        if let Ok(open) = TcpStream::connect_timeout(&addr, CONNECT_TIMEOUT) {
516            sock = Some(open);
517            break;
518        }
519    }
520    let Some(sock) = sock else {
521        return false;
522    };
523    let _ = sock.set_nodelay(true);
524    let now = server.now_ms();
525    let Some(wire) = Wire::new(sock, false, id, now) else {
526        return false;
527    };
528    server.cluster.bus.add(&wire);
529    // The first packet decides what this is. A node that was met by hand has to
530    // hear MEET, because that is the only packet a node will accept from
531    // somebody it has never heard of; everything else is a plain ping.
532    let packet = {
533        let mut map = server.cluster.map.lock();
534        let at = map.find(id.as_bytes());
535        if let Some(at) = at {
536            map.nodes[usize::from(at)].linked = true;
537            // The meet is sent once. If it does not land the handshake times out
538            // and the node goes away, which is what should happen to an address
539            // that has nothing at it.
540            map.nodes[usize::from(at)].flags &= !FLAG_MEET;
541            if !meet {
542                map.nodes[usize::from(at)].ping_sent = now;
543            }
544        }
545        ping(server, &map, if meet { T_MEET } else { T_PING }, at)
546    };
547    wire.send(&packet);
548    let reading = Arc::clone(server);
549    spawn("yo-bus-link", move || pump(&reading, &wire));
550    true
551}
552
553/// Read packets off one link until it stops giving any.
554fn pump(server: &Arc<Server>, wire: &Arc<Wire>) {
555    let sock = {
556        let Ok(held) = wire.sock.lock() else {
557            return;
558        };
559        held.try_clone()
560    };
561    let Ok(mut sock) = sock else {
562        wire.kill();
563        return;
564    };
565    let mut head = [0u8; 8];
566    let mut buf: Vec<u8> = yo_alloc::allow(|| Vec::with_capacity(HDR_LEN * 2));
567    loop {
568        if wire.dead.load(Relaxed) || sock.read_exact(&mut head).is_err() {
569            break;
570        }
571        if &head[0..4] != SIG {
572            break;
573        }
574        let total = u32::from_be_bytes([head[4], head[5], head[6], head[7]]) as usize;
575        if !(16..=MAX_PACKET).contains(&total) {
576            break;
577        }
578        yo_alloc::allow(|| {
579            buf.clear();
580            buf.resize(total, 0);
581        });
582        buf[..8].copy_from_slice(&head);
583        if sock.read_exact(&mut buf[8..]).is_err() {
584            break;
585        }
586        if !process(server, wire, &buf) {
587            break;
588        }
589    }
590    wire.kill();
591    // A link that has gone is a link this node should open again, which it will
592    // do on the next tick as long as the table does not still think it is there.
593    let name = wire.named();
594    if !name.is_empty() && !wire.inbound {
595        let mut map = server.cluster.map.lock();
596        if let Some(at) = map.find(name.as_bytes()) {
597            map.nodes[usize::from(at)].linked = false;
598        }
599    }
600}
601
602// -------------------------------------------------------------- building packets
603
604/// The fixed header, filled in from this node's view of itself.
605fn header(server: &Server, map: &Map, kind: u16) -> Vec<u8> {
606    let mut p = yo_alloc::allow(|| vec![0u8; HDR_LEN]);
607    p[0..4].copy_from_slice(SIG);
608    put16(&mut p, O_VER, PROTO_VER);
609    put16(&mut p, O_TYPE, kind);
610    put16(&mut p, O_PORT, map.nodes[0].port);
611    put16(&mut p, O_CPORT, map.nodes[0].bus);
612    put16(&mut p, O_PPORT, 0);
613    put16(&mut p, O_FLAGS, map.nodes[0].flags);
614    // A replica sends its master's slots and its master's epoch, flagged as a
615    // replica so nobody mistakes it for the owner. That is how a replica can
616    // answer a gossip round at all without having to say it knows nothing.
617    let speaking = map.nodes[0]
618        .master
619        .filter(|_| map.nodes[0].flags & FLAG_SLAVE != 0)
620        .map_or(0, usize::from);
621    put64(&mut p, O_CURRENT_EPOCH, server.cluster.epoch.load(Relaxed));
622    put64(&mut p, O_CONFIG_EPOCH, map.nodes[speaking].epoch);
623    put64(&mut p, O_OFFSET, server.repl_offset());
624    p[O_SENDER..O_SENDER + NAME_LEN].copy_from_slice(map.nodes[0].id.as_bytes());
625    for slot in 0..SLOTS {
626        if map.owner[slot] == Some(speaking as u16) {
627            set_bit(&mut p[O_SLOTS..O_SLOTS + BITMAP_LEN], slot);
628        }
629    }
630    if let Some(master) = map.nodes[0].master {
631        let id = map.nodes[usize::from(master)].id.as_bytes();
632        p[O_SLAVEOF..O_SLAVEOF + NAME_LEN].copy_from_slice(id);
633    }
634    // The address is left empty on purpose. A node does not know its own address
635    // until somebody connects to it, and the receiver takes it off the socket,
636    // which is the reference's auto discovery and is why a cluster can be built
637    // out of nodes that were never told where they are.
638    let _ = O_MYIP;
639    p[O_STATE] = if server.cluster_up() {
640        STATE_OK
641    } else {
642        STATE_FAIL
643    };
644    p[O_MFLAGS] = MF_EXT_DATA;
645    p
646}
647
648/// Finish a packet by writing the length the header promises.
649fn seal(p: &mut [u8]) {
650    let total = p.len() as u32;
651    p[O_TOTLEN..O_TOTLEN + 4].copy_from_slice(&total.to_be_bytes());
652}
653
654/// A `PING`, `PONG` or `MEET`, with its gossip and its extensions.
655///
656/// `to` is the node it is going to, which is left out of the gossip because
657/// telling somebody about themselves is the one thing they already know.
658fn ping(server: &Server, map: &Map, kind: u16, to: Option<u16>) -> Vec<u8> {
659    let mut p = header(server, map, kind);
660    let now = server.now_ms();
661    // A tenth of the cluster with a floor of three, which is the reference's
662    // rule and is what keeps the packet a fixed size as the cluster grows while
663    // still passing news round in a few rounds.
664    let mut want = (map.nodes.len() / 10).max(3);
665    if map.nodes.len() >= 2 {
666        want = want.min(map.nodes.len() - 2);
667    } else {
668        want = 0;
669    }
670    let mut count = 0u16;
671    let mut sent: Vec<u16> = yo_alloc::allow(|| Vec::with_capacity(want + 4));
672    let mut tries = want * 3;
673    while sent.len() < want && tries > 0 {
674        tries -= 1;
675        let at = pick(map.nodes.len());
676        if at == 0 || Some(at) == to || sent.contains(&at) {
677            continue;
678        }
679        let node = &map.nodes[usize::from(at)];
680        // A node in handshake has a made up name, a node with no address cannot
681        // be reached by whoever hears about it, and a node that is not linked
682        // and owns nothing is one this node is about to forget anyway.
683        if node.flags & (FLAG_HANDSHAKE | FLAG_NOADDR) != 0 {
684            continue;
685        }
686        if !node.linked && map.runs(at).is_empty() {
687            continue;
688        }
689        sent.push(at);
690    }
691    // Everybody this node thinks is down goes on the end whether or not they
692    // were drawn, because a failure report that arrives late is a failover that
693    // happens late.
694    for at in 1..map.nodes.len() as u16 {
695        if map.nodes[usize::from(at)].flags & FLAG_PFAIL != 0 && !sent.contains(&at) {
696            sent.push(at);
697        }
698    }
699    for at in sent {
700        let node = &map.nodes[usize::from(at)];
701        let mut entry = [0u8; GOSSIP_LEN];
702        entry[G_NAME..G_NAME + NAME_LEN].copy_from_slice(node.id.as_bytes());
703        entry[G_PING..G_PING + 4].copy_from_slice(&((node.ping_sent / 1000) as u32).to_be_bytes());
704        entry[G_PONG..G_PONG + 4].copy_from_slice(&((node.pong_recv / 1000) as u32).to_be_bytes());
705        let host = node.host.as_bytes();
706        let take = host.len().min(IP_LEN - 1);
707        entry[G_IP..G_IP + take].copy_from_slice(&host[..take]);
708        entry[G_PORT..G_PORT + 2].copy_from_slice(&node.port.to_be_bytes());
709        entry[G_CPORT..G_CPORT + 2].copy_from_slice(&node.bus.to_be_bytes());
710        entry[G_FLAGS..G_FLAGS + 2].copy_from_slice(&node.flags.to_be_bytes());
711        yo_alloc::allow(|| p.extend_from_slice(&entry));
712        count += 1;
713    }
714    let _ = now;
715    put16(&mut p, O_COUNT, count);
716    let mut exts = 0u16;
717    // The shard id and the secret go on every ping. Both are forty bytes and
718    // neither is optional, which is why a bare ping is never just a header.
719    push_ext(&mut p, X_SHARDID, map.nodes[0].shard.as_bytes());
720    exts += 1;
721    let secret = server.cluster.bus.secret.lock();
722    if secret.len() == NAME_LEN {
723        push_ext(&mut p, X_SECRET, secret.as_bytes());
724        exts += 1;
725    }
726    drop(secret);
727    put16(&mut p, O_EXTENSIONS, exts);
728    seal(&mut p);
729    p
730}
731
732/// Put one extension on the end of a packet, padded to the eight byte boundary
733/// the reference insists on.
734fn push_ext(p: &mut Vec<u8>, kind: u16, data: &[u8]) {
735    let len = 8 + data.len().div_ceil(8) * 8;
736    yo_alloc::allow(|| {
737        p.extend_from_slice(&(len as u32).to_be_bytes());
738        p.extend_from_slice(&kind.to_be_bytes());
739        p.extend_from_slice(&[0, 0]);
740        p.extend_from_slice(data);
741        p.resize(p.len() + (len - 8 - data.len()), 0);
742    });
743}
744
745/// A `FAIL`, which says one node is gone and is believed on sight.
746fn fail_packet(server: &Server, map: &Map, about: &str) -> Vec<u8> {
747    let mut p = header(server, map, T_FAIL);
748    yo_alloc::allow(|| p.extend_from_slice(about.as_bytes()));
749    seal(&mut p);
750    p
751}
752
753/// A `PUBLISH` or `PUBLISHSHARD`, which is how a message reaches a subscriber on
754/// another node.
755fn publish_packet(server: &Server, map: &Map, shard: bool, channel: &[u8], body: &[u8]) -> Vec<u8> {
756    let kind = if shard { T_PUBLISHSHARD } else { T_PUBLISH };
757    let mut p = header(server, map, kind);
758    yo_alloc::allow(|| {
759        p.extend_from_slice(&(channel.len() as u32).to_be_bytes());
760        p.extend_from_slice(&(body.len() as u32).to_be_bytes());
761        p.extend_from_slice(channel);
762        p.extend_from_slice(body);
763    });
764    seal(&mut p);
765    p
766}
767
768/// An `UPDATE`, which is what a node sends back to somebody claiming slots it
769/// knows belong to a newer configuration.
770fn update_packet(server: &Server, map: &Map, about: u16) -> Vec<u8> {
771    let mut p = header(server, map, T_UPDATE);
772    let node = &map.nodes[usize::from(about)];
773    let mut body = [0u8; 8 + NAME_LEN + BITMAP_LEN];
774    body[0..8].copy_from_slice(&node.epoch.to_be_bytes());
775    body[8..8 + NAME_LEN].copy_from_slice(node.id.as_bytes());
776    for slot in 0..SLOTS {
777        if map.owner[slot] == Some(about) {
778            set_bit(&mut body[8 + NAME_LEN..], slot);
779        }
780    }
781    yo_alloc::allow(|| p.extend_from_slice(&body));
782    seal(&mut p);
783    p
784}
785
786// ------------------------------------------------------------ reading packets
787
788/// What one packet asked this node to do, gathered up while the table was
789/// locked and carried out after it was not.
790///
791/// The whole of packet processing runs with the node table locked, because it
792/// reads and writes half of it and a reader that saw it half updated would route
793/// a client wrongly. Nothing that blocks may happen under that lock, so a reply
794/// is built while it is held and written after it is dropped, and that is what
795/// this carries.
796#[derive(Default)]
797struct Todo {
798    /// Packets to write back on the link the packet came in on.
799    reply: Vec<Vec<u8>>,
800    /// Packets to write to everybody.
801    shout: Vec<Vec<u8>>,
802    /// A message that arrived for the local subscribers.
803    deliver: Option<(bool, Vec<u8>, Vec<u8>)>,
804    /// Whether the table is worth writing out again.
805    save: bool,
806    /// Whether the slot coverage needs counting again once the lock is gone.
807    recount: bool,
808    /// Whether the link should be closed rather than read again.
809    close: bool,
810}
811
812/// Handle one packet, and say whether the link is still worth reading.
813fn process(server: &Arc<Server>, wire: &Arc<Wire>, p: &[u8]) -> bool {
814    if be16(p, O_VER) != PROTO_VER {
815        return true;
816    }
817    let kind = be16(p, O_TYPE);
818    let Some(explen) = expected(p, kind) else {
819        return true;
820    };
821    if explen != p.len() {
822        return true;
823    }
824    let now = server.now_ms();
825    let mut todo = Todo::default();
826    {
827        let mut map = server.cluster.map.lock();
828        digest(server, wire, p, kind, now, &mut map, &mut todo);
829    }
830    for packet in &todo.reply {
831        wire.send(packet);
832    }
833    if !todo.shout.is_empty() {
834        for link in server.cluster.bus.all() {
835            for packet in &todo.shout {
836                link.send(packet);
837            }
838        }
839    }
840    if let Some((shard, channel, body)) = todo.deliver
841        && server.anyone_subscribed()
842    {
843        let kind = if shard { Kind::Shard } else { Kind::Channel };
844        pubsub::deliver(server, kind, &channel, &body);
845    }
846    if todo.save {
847        server.cluster.bus.dirty.store(true, Relaxed);
848    }
849    if todo.recount {
850        server.recount_coverage();
851    }
852    !todo.close
853}
854
855/// How long a packet of this type should be, or `None` for one that cannot be
856/// worked out and is therefore not a packet.
857///
858/// The reference does this before it looks at anything else and refuses on a
859/// mismatch rather than reading what it can. That is worth copying exactly: a
860/// length field that disagrees with the body is the shape of every parser bug
861/// there has ever been, and the cheapest answer is to not have a parser that
862/// runs on one.
863fn expected(p: &[u8], kind: u16) -> Option<usize> {
864    match kind {
865        T_PING | T_PONG | T_MEET => {
866            let count = usize::from(be16(p, O_COUNT));
867            let mut len = HDR_LEN.checked_add(count.checked_mul(GOSSIP_LEN)?)?;
868            if p.get(O_MFLAGS).is_some_and(|f| f & MF_EXT_DATA != 0) {
869                let mut left = be16(p, O_EXTENSIONS);
870                let mut at = len;
871                while left > 0 {
872                    left -= 1;
873                    let extlen = be32(p, at) as usize;
874                    if extlen < 8 || !extlen.is_multiple_of(8) || p.len().checked_sub(len)? < extlen
875                    {
876                        return None;
877                    }
878                    len += extlen;
879                    at += extlen;
880                }
881            }
882            Some(len)
883        }
884        T_FAIL => Some(HDR_LEN + NAME_LEN),
885        T_PUBLISH | T_PUBLISHSHARD => {
886            let channel = be32(p, HDR_LEN) as usize;
887            let body = be32(p, HDR_LEN + 4) as usize;
888            HDR_LEN
889                .checked_add(8)?
890                .checked_add(channel)?
891                .checked_add(body)
892        }
893        T_AUTH_REQUEST | T_AUTH_ACK | T_MFSTART => Some(HDR_LEN),
894        T_UPDATE => Some(HDR_LEN + 8 + NAME_LEN + BITMAP_LEN),
895        // A type this node does not handle is well formed by definition, which
896        // is the reference's own answer and is what lets a newer node talk to an
897        // older one without either of them dropping the conversation.
898        _ => Some(p.len()),
899    }
900}
901
902/// Everything one packet does to the node table.
903#[allow(clippy::too_many_lines)]
904fn digest(
905    server: &Arc<Server>,
906    wire: &Arc<Wire>,
907    p: &[u8],
908    kind: u16,
909    now: u64,
910    map: &mut Map,
911    todo: &mut Todo,
912) {
913    let flags = be16(p, O_FLAGS);
914    let claimed = node_id(p, O_SENDER);
915    // Who sent it. An outbound link knows without looking, unless the node on
916    // the other end is still in handshake and therefore still has the made up
917    // name this node gave it.
918    let linked = wire.named();
919    let mut sender = None;
920    if !linked.is_empty()
921        && let Some(at) = map.find(linked.as_bytes())
922        && map.nodes[usize::from(at)].flags & FLAG_HANDSHAKE == 0
923    {
924        sender = Some(at);
925    }
926    if sender.is_none()
927        && let Some(id) = claimed.as_deref()
928    {
929        sender = map.find(id.as_bytes());
930        if sender.is_some() && linked.is_empty() {
931            wire.name(id);
932        }
933    }
934    if let Some(at) = sender {
935        let node = &mut map.nodes[usize::from(at)];
936        if p.get(O_MFLAGS).is_some_and(|f| f & MF_EXT_DATA != 0) {
937            node.flags |= super::FLAG_EXTENSIONS;
938        }
939        node.data_recv = now;
940    }
941    let sender_epoch = be64(p, O_CONFIG_EPOCH);
942    if let Some(at) = sender
943        && map.nodes[usize::from(at)].flags & FLAG_HANDSHAKE == 0
944    {
945        let theirs = be64(p, O_CURRENT_EPOCH);
946        server.cluster.epoch.fetch_max(theirs, Relaxed);
947        let node = &mut map.nodes[usize::from(at)];
948        if sender_epoch > node.epoch {
949            node.epoch = sender_epoch;
950            todo.save = true;
951        }
952        node.offset = be64(p, O_OFFSET);
953    }
954
955    if kind == T_PING || kind == T_MEET {
956        // A node learns its own address from the socket a MEET arrived on,
957        // which is the only address in the cluster that is known to be reachable
958        // from somewhere else. A plain ping is enough when there is no address
959        // at all yet, because having a wrong one is better than having none and
960        // a MEET will correct it.
961        if (kind == T_MEET || map.nodes[0].host.is_empty()) && map.nodes[0].host != wire.local {
962            yo_alloc::allow(|| map.nodes[0].host.clone_from(&wire.local));
963            todo.save = true;
964        }
965        if sender.is_none() && kind == T_MEET {
966            // Somebody was told to meet this node. Nothing about them is trusted
967            // yet beyond where they are, so they go in as a handshake node with
968            // a name this node made up, and the ping they answer with is what
969            // replaces it.
970            let host = {
971                let announced = text(p, O_MYIP, IP_LEN);
972                if announced.is_empty() {
973                    yo_alloc::allow(|| wire.peer.clone())
974                } else {
975                    announced
976                }
977            };
978            let id = yo_alloc::allow(|| String::from_utf8_lossy(&new_id()).into_owned());
979            let node = yo_alloc::allow(|| {
980                Node::new(
981                    id,
982                    host,
983                    be16(p, O_PORT),
984                    be16(p, O_CPORT),
985                    FLAG_HANDSHAKE,
986                    now,
987                )
988            });
989            yo_alloc::allow(|| map.nodes.push(node));
990            todo.save = true;
991            // The gossip on a MEET from a stranger is taken anyway, because the
992            // type of the packet is the trust: only a node that was told to meet
993            // this one sends one, and it is worth knowing who else it has met.
994            gossip(server, p, now, map, todo);
995        }
996        todo.reply.push(ping(server, map, T_PONG, sender));
997    }
998
999    match kind {
1000        T_PING | T_PONG | T_MEET => {}
1001        T_FAIL => {
1002            if sender.is_some()
1003                && let Some(id) = node_id(p, HDR_LEN)
1004                && let Some(at) = map.find(id.as_bytes())
1005                && map.nodes[usize::from(at)].flags & (FLAG_FAIL | FLAG_MYSELF) == 0
1006            {
1007                let node = &mut map.nodes[usize::from(at)];
1008                node.flags |= FLAG_FAIL;
1009                node.flags &= !FLAG_PFAIL;
1010                node.fail_time = now;
1011                todo.save = true;
1012            }
1013            return;
1014        }
1015        T_PUBLISH | T_PUBLISHSHARD => {
1016            if sender.is_none() {
1017                todo.close = true;
1018                return;
1019            }
1020            let channel = be32(p, HDR_LEN) as usize;
1021            let body = be32(p, HDR_LEN + 4) as usize;
1022            let at = HDR_LEN + 8;
1023            todo.deliver = yo_alloc::allow(|| {
1024                Some((
1025                    kind == T_PUBLISHSHARD,
1026                    p[at..at + channel].to_vec(),
1027                    p[at + channel..at + channel + body].to_vec(),
1028                ))
1029            });
1030            return;
1031        }
1032        T_UPDATE => {
1033            if sender.is_none() {
1034                todo.close = true;
1035                return;
1036            }
1037            let epoch = be64(p, HDR_LEN);
1038            let Some(id) = node_id(p, HDR_LEN + 8) else {
1039                return;
1040            };
1041            let Some(about) = map.find(id.as_bytes()) else {
1042                return;
1043            };
1044            if epoch <= map.nodes[usize::from(about)].epoch {
1045                return;
1046            }
1047            map.nodes[usize::from(about)].epoch = epoch;
1048            map.nodes[usize::from(about)].flags &= !FLAG_SLAVE;
1049            map.nodes[usize::from(about)].flags |= FLAG_MASTER;
1050            map.nodes[usize::from(about)].master = None;
1051            claim_slots(
1052                server,
1053                map,
1054                about,
1055                epoch,
1056                &p[HDR_LEN + 8 + NAME_LEN..],
1057                todo,
1058            );
1059            todo.save = true;
1060            return;
1061        }
1062        // The election is not in yet, so a vote is neither asked for nor
1063        // answered. Dropping these keeps a mixed cluster gossiping happily and
1064        // means a yo node simply never wins or grants an election.
1065        T_AUTH_REQUEST | T_AUTH_ACK | T_MFSTART | T_MODULE => return,
1066        _ => return,
1067    }
1068
1069    // From here down is the config half of a PING, PONG or MEET, which is where
1070    // a cluster actually agrees on anything.
1071    if !wire.inbound {
1072        let held = map.find(linked.as_bytes());
1073        if let Some(at) = held
1074            && map.nodes[usize::from(at)].flags & FLAG_HANDSHAKE != 0
1075        {
1076            match sender {
1077                // This node had already met them under their real name, so the
1078                // handshake node is a duplicate and goes away.
1079                Some(known) => {
1080                    let host = yo_alloc::allow(|| wire.peer.clone());
1081                    let node = &mut map.nodes[usize::from(known)];
1082                    if node.host != host {
1083                        node.host = host;
1084                        node.port = be16(p, O_PORT);
1085                        node.bus = be16(p, O_CPORT);
1086                    }
1087                    map.forget(at);
1088                    todo.save = true;
1089                    todo.close = true;
1090                    return;
1091                }
1092                // The handshake worked. The made up name is replaced with the
1093                // real one and the node is an ordinary node from here on.
1094                None => {
1095                    let Some(id) = claimed.clone() else {
1096                        return;
1097                    };
1098                    wire.name(&id);
1099                    let node = &mut map.nodes[usize::from(at)];
1100                    yo_alloc::allow(|| node.id = id);
1101                    node.flags &= !(FLAG_HANDSHAKE | FLAG_MEET);
1102                    node.flags |= flags & (FLAG_MASTER | FLAG_SLAVE);
1103                    node.pong_recv = now;
1104                    node.ping_sent = 0;
1105                    sender = Some(at);
1106                    todo.save = true;
1107                }
1108            }
1109        } else if let Some(at) = held
1110            && Some(map.nodes[usize::from(at)].id.as_str()) != claimed.as_deref()
1111        {
1112            // Somebody else is answering on the address this node had written
1113            // down for a peer. The address is wrong rather than the peer, so the
1114            // peer keeps its identity and loses its address until gossip finds
1115            // it again.
1116            let node = &mut map.nodes[usize::from(at)];
1117            node.flags |= FLAG_NOADDR;
1118            node.host.clear();
1119            node.port = 0;
1120            node.bus = 0;
1121            node.linked = false;
1122            todo.save = true;
1123            todo.close = true;
1124            return;
1125        }
1126    }
1127
1128    let Some(at) = sender else {
1129        return;
1130    };
1131    // The no failover flag is the sender's to set and everybody else's to
1132    // believe, because it is the sender saying whether it wants to be promoted.
1133    let node = &mut map.nodes[usize::from(at)];
1134    node.flags &= !FLAG_NOFAILOVER;
1135    node.flags |= flags & FLAG_NOFAILOVER;
1136    if kind == T_PING && !wire.inbound {
1137        let host = yo_alloc::allow(|| wire.peer.clone());
1138        if node.host != host {
1139            node.host = host;
1140            node.port = be16(p, O_PORT);
1141            node.bus = be16(p, O_CPORT);
1142            todo.save = true;
1143        }
1144    }
1145    if !wire.inbound && kind == T_PONG {
1146        node.pong_recv = now;
1147        node.ping_sent = 0;
1148        if node.flags & FLAG_PFAIL != 0 {
1149            node.flags &= !FLAG_PFAIL;
1150            todo.save = true;
1151        } else if node.flags & FLAG_FAIL != 0 {
1152            clear_failure(map, at, now);
1153            todo.save = true;
1154        }
1155    }
1156
1157    // Master or replica, which has to settle before the slots are looked at
1158    // because a replica's slot claim is its master's and means something else.
1159    let follows = node_id(p, O_SLAVEOF);
1160    match follows {
1161        None => {
1162            if map.nodes[usize::from(at)].flags & FLAG_SLAVE != 0 {
1163                let node = &mut map.nodes[usize::from(at)];
1164                node.flags &= !FLAG_SLAVE;
1165                node.flags |= FLAG_MASTER;
1166                node.master = None;
1167                todo.save = true;
1168            }
1169        }
1170        Some(id) => {
1171            let master = map.find(id.as_bytes());
1172            if map.nodes[usize::from(at)].is_master() {
1173                // A master that has become a replica. When its new master is in
1174                // the same shard this is the tail of a failover, so the slots
1175                // move rather than vanish, and the new master is promoted here
1176                // to match. When it is not, the node has been moved to another
1177                // shard and its slots are simply not its any more.
1178                let same_shard = master.is_some_and(|m| {
1179                    map.nodes[usize::from(m)].shard == map.nodes[usize::from(at)].shard
1180                });
1181                if same_shard && sender_epoch >= map.nodes[usize::from(at)].epoch {
1182                    let m = master.expect("same shard means there is one");
1183                    for slot in 0..SLOTS {
1184                        if map.owner[slot] == Some(at) {
1185                            map.owner[slot] = Some(m);
1186                        }
1187                    }
1188                    let promoted = &mut map.nodes[usize::from(m)];
1189                    promoted.flags &= !FLAG_SLAVE;
1190                    promoted.flags |= FLAG_MASTER;
1191                    promoted.master = None;
1192                    promoted.epoch = sender_epoch;
1193                } else if !same_shard {
1194                    for slot in 0..SLOTS {
1195                        if map.owner[slot] == Some(at) {
1196                            map.owner[slot] = None;
1197                        }
1198                    }
1199                }
1200                let node = &mut map.nodes[usize::from(at)];
1201                node.flags &= !(FLAG_MASTER | FLAG_MIGRATE_TO);
1202                node.flags |= FLAG_SLAVE;
1203                todo.save = true;
1204            }
1205            if let Some(m) = master
1206                && map.nodes[usize::from(at)].master != Some(m)
1207                && m != at
1208            {
1209                map.nodes[usize::from(at)].master = Some(m);
1210                let shard = yo_alloc::allow(|| map.nodes[usize::from(m)].shard.clone());
1211                yo_alloc::allow(|| map.nodes[usize::from(at)].shard = shard);
1212                todo.save = true;
1213            }
1214        }
1215    }
1216
1217    // The slots. Only a master's claim counts, and only when it differs from
1218    // what this node already had, which is one memcmp in front of a walk of
1219    // sixteen thousand slots and is worth having.
1220    let speaking = if map.nodes[usize::from(at)].is_master() {
1221        Some(at)
1222    } else {
1223        map.nodes[usize::from(at)].master
1224    };
1225    let claim = &p[O_SLOTS..O_SLOTS + BITMAP_LEN];
1226    let dirty = speaking
1227        .is_some_and(|m| (0..SLOTS).any(|slot| bit(claim, slot) != (map.owner[slot] == Some(m))));
1228    if dirty && map.nodes[usize::from(at)].is_master() {
1229        claim_slots(server, map, at, sender_epoch, claim, todo);
1230    }
1231    if dirty {
1232        // The other way round: the sender is claiming slots this node knows have
1233        // moved on to somebody with a newer epoch, so it is told about the first
1234        // one of them and works the rest out from there.
1235        for slot in 0..SLOTS {
1236            if !bit(claim, slot) {
1237                continue;
1238            }
1239            let Some(owner) = map.owner[slot] else {
1240                continue;
1241            };
1242            if owner == at {
1243                continue;
1244            }
1245            if map.nodes[usize::from(owner)].epoch > sender_epoch {
1246                todo.reply.push(update_packet(server, map, owner));
1247                break;
1248            }
1249        }
1250    }
1251    // Two masters with the same epoch cannot both be right, so the one with the
1252    // smaller id gives way by taking a new one. Deterministic and needs no
1253    // agreement, which is the only kind of tiebreak that works in a partition.
1254    if map.nodes[0].is_master()
1255        && map.nodes[usize::from(at)].is_master()
1256        && sender_epoch == map.nodes[0].epoch
1257        && map.nodes[0].id < map.nodes[usize::from(at)].id
1258    {
1259        let next = server.cluster.epoch.fetch_add(1, Relaxed) + 1;
1260        map.nodes[0].epoch = next;
1261        todo.save = true;
1262    }
1263    gossip(server, p, now, map, todo);
1264    extensions(server, p, now, map, at, todo);
1265}
1266
1267/// The gossip section, which is what everybody else looks like from where the
1268/// sender is standing.
1269fn gossip(server: &Arc<Server>, p: &[u8], now: u64, map: &mut Map, todo: &mut Todo) {
1270    let count = usize::from(be16(p, O_COUNT));
1271    let sender_master = node_id(p, O_SENDER)
1272        .and_then(|id| map.find(id.as_bytes()))
1273        .is_none_or(|at| map.nodes[usize::from(at)].is_master());
1274    for entry in 0..count {
1275        let base = HDR_LEN + entry * GOSSIP_LEN;
1276        let Some(id) = node_id(p, base + G_NAME) else {
1277            continue;
1278        };
1279        let flags = be16(p, base + G_FLAGS);
1280        let host = text(p, base + G_IP, IP_LEN);
1281        let port = be16(p, base + G_PORT);
1282        let bus = be16(p, base + G_CPORT);
1283        if let Some(at) = map.find(id.as_bytes()) {
1284            if at == 0 {
1285                continue;
1286            }
1287            // A master saying somebody is down is a vote; anybody else saying it
1288            // is an opinion. Both are recorded, and only the votes are counted.
1289            if sender_master {
1290                let sender = node_id(p, O_SENDER).unwrap_or_default();
1291                if flags & (FLAG_FAIL | FLAG_PFAIL) != 0 {
1292                    report(map, at, &sender, now);
1293                    if mark_failing(map, at, now) {
1294                        let about = yo_alloc::allow(|| map.nodes[usize::from(at)].id.clone());
1295                        todo.shout.push(fail_packet(server, map, &about));
1296                        todo.save = true;
1297                    }
1298                } else {
1299                    unreport(map, at, &sender);
1300                }
1301            }
1302            let node = &mut map.nodes[usize::from(at)];
1303            if node.flags & (FLAG_FAIL | FLAG_PFAIL) == 0
1304                && node.ping_sent == 0
1305                && node.reports.is_empty()
1306            {
1307                // The sender heard from them more recently than this node did, so
1308                // take their word for when. The half second ceiling is the
1309                // reference's guard against a peer whose clock is ahead.
1310                let heard = u64::from(be32(p, base + G_PONG)) * 1000;
1311                if heard > node.pong_recv && heard <= now + 500 {
1312                    node.pong_recv = heard;
1313                }
1314            } else if node.down()
1315                && flags & (FLAG_FAIL | FLAG_PFAIL | FLAG_NOADDR | FLAG_HANDSHAKE) == 0
1316                && !host.is_empty()
1317                && (node.host != host || node.port != port)
1318            {
1319                // Down here and up there, at an address this node does not have.
1320                // The address is the thing that is wrong, so it is replaced and
1321                // the next tick tries again.
1322                yo_alloc::allow(|| node.host = host);
1323                node.port = port;
1324                node.bus = bus;
1325                node.linked = false;
1326                node.flags &= !FLAG_NOADDR;
1327                todo.save = true;
1328            }
1329            continue;
1330        }
1331        // Somebody new. Taken only from a sender this node already knows, and
1332        // only when the id is not one that was just forgotten on purpose.
1333        //
1334        // It goes in under the id and the flags the gossip carried rather than
1335        // as a handshake, which is the difference between learning about a node
1336        // and meeting one. A handshake exists to find out an id that is not
1337        // known yet, and here it is: the sender said it. Adding it as a
1338        // handshake instead would mean opening a link to an address whose owner
1339        // might have changed, which is how a node ends up in somebody else's
1340        // cluster.
1341        if flags & FLAG_NOADDR != 0 {
1342            continue;
1343        }
1344        if server.cluster.bus.blacklisted(&id, now) {
1345            continue;
1346        }
1347        let flags = flags & !(FLAG_MYSELF | FLAG_HANDSHAKE | FLAG_MEET);
1348        let node = yo_alloc::allow(|| Node::new(id, host, port, bus, flags, now));
1349        yo_alloc::allow(|| map.nodes.push(node));
1350        todo.save = true;
1351    }
1352}
1353
1354/// The extensions on the end of a ping.
1355fn extensions(server: &Arc<Server>, p: &[u8], now: u64, map: &mut Map, at: u16, todo: &mut Todo) {
1356    if !p.get(O_MFLAGS).is_some_and(|f| f & MF_EXT_DATA != 0) {
1357        return;
1358    }
1359    let mut left = be16(p, O_EXTENSIONS);
1360    let mut base = HDR_LEN + usize::from(be16(p, O_COUNT)) * GOSSIP_LEN;
1361    while left > 0 && base + 8 <= p.len() {
1362        left -= 1;
1363        let extlen = be32(p, base) as usize;
1364        if extlen < 8 || base + extlen > p.len() {
1365            return;
1366        }
1367        let kind = be16(p, base + 4);
1368        let data = &p[base + 8..base + extlen];
1369        match kind {
1370            X_SHARDID => {
1371                let id = String::from_utf8_lossy(&data[..NAME_LEN.min(data.len())]);
1372                if id.len() == NAME_LEN && map.nodes[usize::from(at)].shard != id {
1373                    yo_alloc::allow(|| map.nodes[usize::from(at)].shard = id.into_owned());
1374                    todo.save = true;
1375                }
1376            }
1377            X_SECRET => {
1378                // The whole cluster ends up on the smallest secret anybody
1379                // started with, which needs no leader to decide and settles in
1380                // one gossip round.
1381                let theirs = String::from_utf8_lossy(&data[..NAME_LEN.min(data.len())]);
1382                let mut mine = server.cluster.bus.secret.lock();
1383                if theirs.len() == NAME_LEN && **mine > *theirs {
1384                    yo_alloc::allow(|| *mine = theirs.into_owned());
1385                }
1386            }
1387            X_FORGOTTEN => {
1388                // Somebody has been forgotten on purpose. Forget them here too,
1389                // and refuse to learn them again for as long as the sender says,
1390                // which is what stops the rest of the cluster putting them back.
1391                if data.len() < NAME_LEN + 8 {
1392                    return;
1393                }
1394                let Some(id) = node_id(data, 0) else {
1395                    return;
1396                };
1397                let ttl = be64(data, NAME_LEN);
1398                if map.nodes[0].id == id
1399                    || map.nodes[0].master.map(usize::from)
1400                        == map.find(id.as_bytes()).map(usize::from)
1401                {
1402                    base += extlen;
1403                    continue;
1404                }
1405                server.cluster.bus.blacklist(&id, now + ttl);
1406                if let Some(gone) = map.find(id.as_bytes())
1407                    && gone != 0
1408                {
1409                    server.cluster.bus.cut(&id);
1410                    map.forget(gone);
1411                    todo.save = true;
1412                }
1413            }
1414            // The hostname and the human readable name are carried for the
1415            // benefit of an operator reading `CLUSTER NODES` on a real server,
1416            // and nothing here routes on either of them.
1417            X_HOSTNAME | X_HUMAN_NAME => {}
1418            _ => {}
1419        }
1420        base += extlen;
1421    }
1422}
1423
1424/// Record that somebody thinks a node is down.
1425fn report(map: &mut Map, at: u16, from: &str, now: u64) {
1426    if from.is_empty() {
1427        return;
1428    }
1429    let node = &mut map.nodes[usize::from(at)];
1430    if let Some(held) = node.reports.iter_mut().find(|(who, _)| who == from) {
1431        held.1 = now;
1432        return;
1433    }
1434    yo_alloc::allow(|| node.reports.push((String::from(from), now)));
1435}
1436
1437/// Take one back, which is somebody saying they can reach a node after all.
1438fn unreport(map: &mut Map, at: u16, from: &str) {
1439    map.nodes[usize::from(at)]
1440        .reports
1441        .retain(|(who, _)| who != from);
1442}
1443
1444/// Whether enough of the cluster agrees that a node is gone, and flag it if so.
1445///
1446/// The quorum is a majority of the masters that are serving slots, which is the
1447/// same electorate a failover vote is counted against, and this node counts
1448/// itself when it is one of them. Reports older than twice the node timeout are
1449/// dropped first, so a node that flickered a long time ago does not help
1450/// condemn one that is flickering now.
1451fn mark_failing(map: &mut Map, at: u16, now: u64) -> bool {
1452    let cutoff = now.saturating_sub(NODE_TIMEOUT_MS * 2);
1453    map.nodes[usize::from(at)]
1454        .reports
1455        .retain(|(_, when)| *when > cutoff);
1456    if map.nodes[usize::from(at)].flags & (FLAG_PFAIL | FLAG_FAIL) == 0 {
1457        return false;
1458    }
1459    if map.nodes[usize::from(at)].flags & FLAG_FAIL != 0 {
1460        return false;
1461    }
1462    let needed = map.voters() / 2 + 1;
1463    let mut votes = map.nodes[usize::from(at)].reports.len();
1464    if map.nodes[0].is_master() && !map.runs(0).is_empty() {
1465        votes += 1;
1466    }
1467    if votes < needed {
1468        return false;
1469    }
1470    let node = &mut map.nodes[usize::from(at)];
1471    node.flags &= !FLAG_PFAIL;
1472    node.flags |= FLAG_FAIL;
1473    node.fail_time = now;
1474    true
1475}
1476
1477/// Undo a failure verdict, which is only allowed for a replica that came back or
1478/// for a master that came back still owning nothing.
1479///
1480/// A master that comes back owning slots is not cleared, because the cluster has
1481/// probably promoted its replica by now and clearing it would leave two nodes
1482/// claiming the same slots. It stays failed until it hears about the promotion
1483/// and stands down on its own.
1484fn clear_failure(map: &mut Map, at: u16, now: u64) {
1485    let node = &map.nodes[usize::from(at)];
1486    let replica = !node.is_master();
1487    let empty = map.runs(at).is_empty();
1488    let stale = now.saturating_sub(node.fail_time) > NODE_TIMEOUT_MS * 2;
1489    if replica || empty || stale {
1490        let node = &mut map.nodes[usize::from(at)];
1491        node.flags &= !FLAG_FAIL;
1492        node.fail_time = 0;
1493    }
1494}
1495
1496/// Take a master's word for which slots are its.
1497///
1498/// This is the one place a slot changes hands without an operator asking, so it
1499/// is careful about which claims it believes. A slot nobody owns is taken on
1500/// sight. A slot owned by somebody with an older epoch changes hands, because a
1501/// higher epoch is the cluster's way of saying this configuration is newer. A
1502/// slot this node is importing is left alone, because an import in progress is
1503/// an operator's decision and outranks gossip. And a slot this node loses while
1504/// still holding keys for it is remembered, because those keys now belong to
1505/// somebody else and keeping them would mean two nodes answering for the same
1506/// data.
1507fn claim_slots(
1508    server: &Arc<Server>,
1509    map: &mut Map,
1510    owner: u16,
1511    epoch: u64,
1512    claim: &[u8],
1513    todo: &mut Todo,
1514) {
1515    let mut lost = 0usize;
1516    for slot in 0..SLOTS {
1517        if !bit(claim, slot) {
1518            continue;
1519        }
1520        if map.owner[slot] == Some(owner) || map.importing[slot].is_some() {
1521            continue;
1522        }
1523        let held = map.owner[slot];
1524        let newer = held.is_none_or(|at| map.nodes[usize::from(at)].epoch <= epoch);
1525        if !newer {
1526            continue;
1527        }
1528        if held == Some(0) {
1529            lost += 1;
1530        }
1531        map.owner[slot] = Some(owner);
1532        map.migrating[slot] = None;
1533        todo.save = true;
1534    }
1535    // A master that has just given away its last slot is not a master any more.
1536    // Following the node that took them is what a real server does and is what
1537    // makes a failed master come back as a replica of whoever replaced it.
1538    if lost > 0 && map.runs(0).is_empty() && owner != 0 {
1539        map.nodes[0].flags &= !FLAG_MASTER;
1540        map.nodes[0].flags |= FLAG_SLAVE;
1541        map.nodes[0].master = Some(owner);
1542        let shard = yo_alloc::allow(|| map.nodes[usize::from(owner)].shard.clone());
1543        yo_alloc::allow(|| map.nodes[0].shard = shard);
1544        let (host, port) = {
1545            let node = &map.nodes[usize::from(owner)];
1546            (yo_alloc::allow(|| node.host.clone()), node.port)
1547        };
1548        let following = Arc::clone(server);
1549        spawn("yo-bus-follow", move || {
1550            following.follow_master(&host, port);
1551        });
1552    }
1553    // The coverage count is not touched here on purpose. It reads the same map
1554    // this runs under, and the lock is not reentrant, so the caller does it
1555    // once the lock is gone.
1556    todo.recount = true;
1557}
1558
1559// ---------------------------------------------------------------- the cron
1560
1561/// The bus's own clock, which is where everything that is not a reply happens.
1562fn cron(server: &Arc<Server>) {
1563    let mut tick = 0u64;
1564    loop {
1565        std::thread::sleep(Duration::from_millis(CRON_MS));
1566        tick += 1;
1567        let now = server.now_ms();
1568        // Who needs a link, who needs a ping, and who has been quiet too long.
1569        // All decided under the lock and all carried out after it, because a
1570        // connect takes half a second in the worst case and the routing path
1571        // reads this table on every command.
1572        let mut dial_list: Vec<(String, String, u16, bool)> = Vec::new();
1573        let mut ping_list: Vec<(String, Vec<u8>)> = Vec::new();
1574        let mut shout: Vec<Vec<u8>> = Vec::new();
1575        let mut follow: Option<(String, u16)> = None;
1576        let mut save = false;
1577        {
1578            let mut map = server.cluster.map.lock();
1579            let count = map.nodes.len();
1580            for at in 1..count as u16 {
1581                let node = &map.nodes[usize::from(at)];
1582                // A handshake that never completed is a node that is not there.
1583                if node.flags & FLAG_HANDSHAKE != 0
1584                    && now.saturating_sub(node.data_recv) > NODE_TIMEOUT_MS.max(1000)
1585                {
1586                    map.forget(at);
1587                    save = true;
1588                    break;
1589                }
1590                if node.flags & FLAG_NOADDR != 0 || node.host.is_empty() {
1591                    continue;
1592                }
1593                if !node.linked {
1594                    // Only a node this one was told to meet hears MEET, because
1595                    // MEET is the packet that says trust me, I am not in another
1596                    // cluster. Everything else is a plain ping, including a node
1597                    // in handshake that was met the other way round.
1598                    let meet = node.flags & FLAG_MEET != 0;
1599                    yo_alloc::allow(|| {
1600                        dial_list.push((node.id.clone(), node.host.clone(), node.bus, meet));
1601                    });
1602                    continue;
1603                }
1604                // A ping every second, or sooner for whoever this node has heard
1605                // from least recently out of five, which is the reference's way
1606                // of getting round a cluster in far fewer than N rounds.
1607                let quiet = now.saturating_sub(node.pong_recv);
1608                let due = node.ping_sent == 0 && quiet > PING_MS;
1609                if due || (tick.is_multiple_of(10) && oldest_of_five(&map, now) == Some(at)) {
1610                    let packet = ping(server, &map, T_PING, Some(at));
1611                    let id = yo_alloc::allow(|| map.nodes[usize::from(at)].id.clone());
1612                    map.nodes[usize::from(at)].ping_sent = now;
1613                    ping_list.push((id, packet));
1614                }
1615            }
1616            // Anybody who has not answered in time is possibly failed, which is
1617            // this node's opinion and becomes the cluster's once enough masters
1618            // share it.
1619            for at in 1..map.nodes.len() as u16 {
1620                let node = &map.nodes[usize::from(at)];
1621                if node.flags & (FLAG_HANDSHAKE | FLAG_FAIL | FLAG_PFAIL) != 0 {
1622                    continue;
1623                }
1624                let waiting = if node.ping_sent == 0 {
1625                    0
1626                } else {
1627                    now.saturating_sub(node.ping_sent)
1628                };
1629                let quiet = now.saturating_sub(node.data_recv);
1630                if waiting.min(quiet) > NODE_TIMEOUT_MS {
1631                    map.nodes[usize::from(at)].flags |= FLAG_PFAIL;
1632                    save = true;
1633                }
1634                if mark_failing(&mut map, at, now) {
1635                    let about = yo_alloc::allow(|| map.nodes[usize::from(at)].id.clone());
1636                    shout.push(fail_packet(server, &map, &about));
1637                    save = true;
1638                }
1639            }
1640            // A node whose table says it is a replica but which is not following
1641            // anybody starts following. That is how a replica comes back after a
1642            // restart, since the node table is on disk and the replication link
1643            // is not, and it is also how one that was told to replicate a node
1644            // it had no address for yet gets going once the address turns up.
1645            if map.nodes[0].flags & FLAG_SLAVE != 0
1646                && !server.following()
1647                && let Some(master) = map.nodes[0].master
1648                && let Some(node) = map.nodes.get(usize::from(master))
1649                && node.flags & FLAG_NOADDR == 0
1650                && !node.host.is_empty()
1651            {
1652                follow = yo_alloc::allow(|| Some((node.host.clone(), node.port)));
1653            }
1654        }
1655        // Called here and not on a thread of its own, because it starts the
1656        // replica thread and returns, and doing it here is what makes the guard
1657        // above true again before the next tick rather than a tick later.
1658        if let Some((host, port)) = follow {
1659            server.follow_master(&host, port);
1660        }
1661        for (id, host, bus, meet) in dial_list {
1662            if !dial(server, &id, &host, bus, meet) {
1663                continue;
1664            }
1665            let mut map = server.cluster.map.lock();
1666            if let Some(at) = map.find(id.as_bytes()) {
1667                map.nodes[usize::from(at)].linked = true;
1668            }
1669        }
1670        for (id, packet) in ping_list {
1671            if let Some(link) = server.cluster.bus.outbound(&id) {
1672                link.send(&packet);
1673            } else {
1674                let mut map = server.cluster.map.lock();
1675                if let Some(at) = map.find(id.as_bytes()) {
1676                    map.nodes[usize::from(at)].linked = false;
1677                    map.nodes[usize::from(at)].ping_sent = 0;
1678                }
1679            }
1680        }
1681        if !shout.is_empty() {
1682            for link in server.cluster.bus.all() {
1683                for packet in &shout {
1684                    link.send(packet);
1685                }
1686            }
1687        }
1688        if save {
1689            server.cluster.bus.dirty.store(true, Relaxed);
1690        }
1691        server.recount_coverage();
1692        server.asm_cron();
1693        server.asm_relax();
1694        // The file is written at most ten times a second and only when something
1695        // moved, which keeps a busy cluster from writing it on every packet.
1696        if tick.is_multiple_of(10) && server.cluster.bus.dirty.swap(false, Relaxed) {
1697            let _ = super::save(server);
1698        }
1699    }
1700}
1701
1702/// Whoever this node has heard from least recently, out of five drawn at random.
1703///
1704/// Five and not all of them because the point is to bias the ping order towards
1705/// the nodes that need one without walking the table every tenth of a second.
1706fn oldest_of_five(map: &Map, now: u64) -> Option<u16> {
1707    if map.nodes.len() < 2 {
1708        return None;
1709    }
1710    let mut best: Option<(u16, u64)> = None;
1711    for _ in 0..5 {
1712        let at = pick(map.nodes.len());
1713        if at == 0 {
1714            continue;
1715        }
1716        let node = &map.nodes[usize::from(at)];
1717        if node.ping_sent != 0 || node.flags & (FLAG_HANDSHAKE | FLAG_NOADDR) != 0 {
1718            continue;
1719        }
1720        let quiet = now.saturating_sub(node.pong_recv);
1721        if best.is_none_or(|(_, held)| quiet > held) {
1722            best = Some((at, quiet));
1723        }
1724    }
1725    best.map(|(at, _)| at)
1726}
1727
1728// ------------------------------------------------------- what the commands do
1729
1730impl Server {
1731    /// Start a handshake with a node at an address, which is `CLUSTER MEET`.
1732    ///
1733    /// Nothing is known about them yet, not even their id, so they go into the
1734    /// table under a name this node made up and the next tick opens a link and
1735    /// sends them a MEET. Their answer carries their real id, which replaces the
1736    /// made up one. That is why meeting a node twice is harmless and why meeting
1737    /// one that is already known is a no-op rather than a duplicate.
1738    pub(super) fn cluster_meet(&self, host: &str, port: u16, bus: u16) {
1739        let now = self.now_ms();
1740        let mut map = self.cluster.map.lock();
1741        let known = map
1742            .nodes
1743            .iter()
1744            .any(|node| node.host == host && node.port == port);
1745        if known {
1746            return;
1747        }
1748        let id = yo_alloc::allow(|| String::from_utf8_lossy(&new_id()).into_owned());
1749        let node = yo_alloc::allow(|| {
1750            Node::new(
1751                id,
1752                yo_alloc::allow(|| String::from(host)),
1753                port,
1754                bus,
1755                FLAG_HANDSHAKE | FLAG_MEET,
1756                now,
1757            )
1758        });
1759        yo_alloc::allow(|| map.nodes.push(node));
1760    }
1761
1762    /// Whether an id was forgotten on purpose recently, which is what makes
1763    /// forgetting the same node twice answer OK rather than complain.
1764    pub(super) fn cluster_blacklisted(&self, id: &str) -> bool {
1765        self.cluster.bus.blacklisted(id, self.now_ms())
1766    }
1767
1768    /// Drop a node and tell everybody else to, which is `CLUSTER FORGET`.
1769    ///
1770    /// The telling is the part that matters. Dropping a node on its own would
1771    /// last until the next gossip packet from anybody who still had it, so the
1772    /// id is refused for a minute here and the refusal is passed round in the
1773    /// extension that carries it.
1774    pub(super) fn cluster_forget(&self, at: u16) {
1775        let now = self.now_ms();
1776        let id = {
1777            let mut map = self.cluster.map.lock();
1778            let id = yo_alloc::allow(|| map.nodes[usize::from(at)].id.clone());
1779            map.forget(at);
1780            id
1781        };
1782        self.cluster.bus.blacklist(&id, now);
1783        self.cluster.bus.cut(&id);
1784        let packet = {
1785            let map = self.cluster.map.lock();
1786            let mut p = ping(self, &map, T_PING, None);
1787            // The forgotten node rides on the next ping rather than in a packet
1788            // of its own, which is the reference's design: there is no reliable
1789            // delivery on the bus, so a fact that has to reach everybody is
1790            // repeated rather than sent once.
1791            let mut body = [0u8; NAME_LEN + 8];
1792            body[..NAME_LEN].copy_from_slice(id.as_bytes());
1793            body[NAME_LEN..].copy_from_slice(&BLACKLIST_MS.to_be_bytes());
1794            push_ext(&mut p, X_FORGOTTEN, &body);
1795            let exts = be16(&p, O_EXTENSIONS) + 1;
1796            put16(&mut p, O_EXTENSIONS, exts);
1797            seal(&mut p);
1798            p
1799        };
1800        for link in self.cluster.bus.all() {
1801            link.send(&packet);
1802        }
1803        self.cluster.bus.dirty.store(true, Relaxed);
1804    }
1805
1806    /// Become a replica of another node, which is `CLUSTER REPLICATE`.
1807    pub(super) fn cluster_replicate(self: &Arc<Server>, at: u16) {
1808        let (host, port) = {
1809            let mut map = self.cluster.map.lock();
1810            // Whatever slots this node was holding are not its any more, which
1811            // is the reference's rule and is why the command refuses when there
1812            // are keys in them.
1813            for slot in 0..SLOTS {
1814                if map.owner[slot] == Some(0) {
1815                    map.owner[slot] = None;
1816                }
1817            }
1818            map.nodes[0].flags &= !(FLAG_MASTER | FLAG_MIGRATE_TO);
1819            map.nodes[0].flags |= FLAG_SLAVE;
1820            map.nodes[0].master = Some(at);
1821            let shard = yo_alloc::allow(|| map.nodes[usize::from(at)].shard.clone());
1822            yo_alloc::allow(|| map.nodes[0].shard = shard);
1823            let node = &map.nodes[usize::from(at)];
1824            (yo_alloc::allow(|| node.host.clone()), node.port)
1825        };
1826        self.recount_coverage();
1827        self.cluster.bus.dirty.store(true, Relaxed);
1828        if !host.is_empty() {
1829            self.follow_master(&host, port);
1830        }
1831    }
1832
1833    /// Send a published message to every other node, which is what makes a
1834    /// subscriber on one node hear a publish on another.
1835    ///
1836    /// Every node gets a copy of an ordinary publish, because an ordinary
1837    /// subscription is not tied to a slot and could be anywhere. A shard publish
1838    /// only needs to reach the shard that owns the slot, but the reference
1839    /// broadcasts it too and lets the far side drop it, so this does the same.
1840    pub(crate) fn cluster_publish(&self, shard: bool, channel: &[u8], body: &[u8]) {
1841        if !self.cluster_enabled() || !self.cluster.bus.on.load(Relaxed) {
1842            return;
1843        }
1844        let packet = {
1845            let map = self.cluster.map.lock();
1846            publish_packet(self, &map, shard, channel, body)
1847        };
1848        for link in self.cluster.bus.all() {
1849            link.send(&packet);
1850        }
1851    }
1852
1853    /// Send everybody a `PONG` right now rather than waiting for the cron.
1854    ///
1855    /// A `PONG` nobody asked for is how the reference tells the cluster about a
1856    /// configuration change it has just made to itself, and the only thing that
1857    /// makes it a `PONG` rather than a `PING` is that nobody is expected to
1858    /// answer it. What the far side actually reads is the header, which carries
1859    /// this node's slots and its config epoch, so one packet is the whole of the
1860    /// announcement.
1861    ///
1862    /// It matters after a slot import because the epoch has just gone up and the
1863    /// rest of the cluster is still pointing clients at the node the slot came
1864    /// from. Waiting the ordinary ping interval would leave every client that
1865    /// asked the wrong node being redirected to a node that no longer owns it.
1866    pub(super) fn cluster_broadcast_pong(&self) {
1867        if !self.cluster_enabled() || !self.cluster.bus.on.load(Relaxed) {
1868            return;
1869        }
1870        let packet = {
1871            let map = self.cluster.map.lock();
1872            ping(self, &map, T_PONG, None)
1873        };
1874        for link in self.cluster.bus.all() {
1875            link.send(&packet);
1876        }
1877    }
1878
1879    /// `CLUSTER LINKS`, which is one map per open link in each direction.
1880    pub(super) fn cluster_links(&self, out: &mut Out) {
1881        let links = self.cluster.bus.all();
1882        let at = out.len();
1883        let mut n = 0;
1884        for link in links {
1885            let node = link.named();
1886            // The reference only lists links it has associated with a node, and
1887            // an inbound link stays unassociated until a packet on it says who
1888            // is sending, so a connection that has said nothing is not a link
1889            // yet as far as this report is concerned.
1890            if node.is_empty() {
1891                continue;
1892            }
1893            out.map(6);
1894            out.bulk(b"direction");
1895            out.bulk(if link.inbound {
1896                b"from".as_slice()
1897            } else {
1898                b"to".as_slice()
1899            });
1900            out.bulk(b"node");
1901            out.bulk(node.as_bytes());
1902            out.bulk(b"create-time");
1903            out.int(link.created as i64);
1904            out.bulk(b"events");
1905            out.bulk(b"r");
1906            out.bulk(b"send-buffer-allocated");
1907            out.int(link.sent.load(Relaxed) as i64);
1908            out.bulk(b"send-buffer-used");
1909            out.int(0);
1910            n += 1;
1911        }
1912        out.close_array(at, n);
1913    }
1914}
1915
1916#[cfg(test)]
1917mod tests {
1918    use super::*;
1919
1920    #[test]
1921    fn a_bitmap_round_trips_through_the_reference_bit_order() {
1922        let mut bitmap = [0u8; BITMAP_LEN];
1923        for slot in [0usize, 1, 7, 8, 1234, 5061, 12182, SLOTS - 1] {
1924            set_bit(&mut bitmap, slot);
1925        }
1926        for slot in 0..SLOTS {
1927            let want = matches!(slot, 0 | 1 | 7 | 8 | 1234 | 5061 | 12182) || slot == SLOTS - 1;
1928            assert_eq!(bit(&bitmap, slot), want, "slot {slot}");
1929        }
1930        // Least significant bit first inside each byte, which is the one detail
1931        // a reader is likely to get backwards and the one the reference will not
1932        // forgive.
1933        assert_eq!(bitmap[0], 0b1000_0011);
1934        assert_eq!(bitmap[1], 0b0000_0001);
1935    }
1936
1937    #[test]
1938    fn an_extension_is_padded_to_the_eight_byte_boundary() {
1939        let mut p = Vec::new();
1940        push_ext(&mut p, X_SHARDID, &[b'a'; 40]);
1941        assert_eq!(p.len(), 48);
1942        assert_eq!(be32(&p, 0), 48);
1943        assert_eq!(be16(&p, 4), X_SHARDID);
1944        // A hostname is not a multiple of eight and has to be rounded up, which
1945        // is what `getAlignedPingExtSize` does.
1946        let mut q = Vec::new();
1947        push_ext(&mut q, X_HOSTNAME, b"node1.example\0");
1948        assert_eq!(q.len(), 8 + 16);
1949        assert_eq!(be32(&q, 0), 24);
1950    }
1951
1952    #[test]
1953    fn a_packet_of_the_wrong_length_is_refused() {
1954        let mut p = vec![0u8; HDR_LEN];
1955        p[0..4].copy_from_slice(SIG);
1956        put16(&mut p, O_VER, PROTO_VER);
1957        put16(&mut p, O_TYPE, T_PING);
1958        put16(&mut p, O_COUNT, 0);
1959        p[O_MFLAGS] = 0;
1960        seal(&mut p);
1961        assert_eq!(expected(&p, T_PING), Some(HDR_LEN));
1962        // One gossip entry claimed and none present is the shape every parser
1963        // bug has, so it has to come out as a length that does not match.
1964        put16(&mut p, O_COUNT, 1);
1965        assert_eq!(expected(&p, T_PING), Some(HDR_LEN + GOSSIP_LEN));
1966        assert_ne!(expected(&p, T_PING), Some(p.len()));
1967    }
1968
1969    #[test]
1970    fn a_node_id_has_to_be_forty_hex_characters() {
1971        let mut p = vec![0u8; NAME_LEN * 3];
1972        assert_eq!(node_id(&p, 0), None, "all zeros is the reference's no node");
1973        p[0..NAME_LEN].copy_from_slice(&[b'a'; NAME_LEN]);
1974        assert_eq!(node_id(&p, 0).as_deref(), Some("a".repeat(40).as_str()));
1975        p[5] = b'z';
1976        assert_eq!(node_id(&p, 0), None);
1977        assert_eq!(node_id(&p, NAME_LEN * 3), None, "off the end is not an id");
1978    }
1979}