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//! Modules, which are not a thing in this server at all, so the packet type that
35//! carries a module message between nodes is recognised and dropped.
36
37use std::io::{Read, Write};
38use std::net::{Shutdown, TcpListener, TcpStream};
39use std::sync::atomic::Ordering::Relaxed;
40use std::sync::atomic::{AtomicBool, AtomicU64};
41use std::sync::{Arc, Mutex};
42use std::time::Duration;
43
44use yo_common::lock::Lock;
45use yo_common::{Code, Error};
46
47use super::super::Server;
48use super::super::pubsub::{self, Kind};
49use super::{
50 FLAG_FAIL, FLAG_HANDSHAKE, FLAG_MASTER, FLAG_MEET, FLAG_MIGRATE_TO, FLAG_MYSELF, FLAG_NOADDR,
51 FLAG_NOFAILOVER, FLAG_PFAIL, FLAG_SLAVE, Map, Node, SLOTS, new_id,
52};
53use crate::reply::Out;
54
55// ------------------------------------------------------------- the wire format
56
57/// The four bytes every packet starts with, which is the only thing that tells
58/// a bus port from anything else somebody might connect to it.
59const SIG: &[u8; 4] = b"RCmb";
60
61/// The protocol version. A packet claiming anything else is dropped without a
62/// word, because a node that cannot read a packet cannot say so either.
63const PROTO_VER: u16 = 1;
64
65/// How long a node id is, in bytes of lowercase hex.
66const NAME_LEN: usize = 40;
67
68/// How much room an address gets, which is enough for the longest IPv6 text
69/// form and is fixed because the header is fixed.
70const IP_LEN: usize = 46;
71
72/// The slot bitmap, one bit per slot.
73const BITMAP_LEN: usize = SLOTS / 8;
74
75/// The header every packet carries, whatever its type. The reference calls this
76/// `CLUSTERMSG_MIN_LEN` and asserts it.
77const HDR_LEN: usize = 2256;
78
79/// One gossip entry.
80const GOSSIP_LEN: usize = 104;
81
82/// The most a packet may be before it is treated as noise rather than as a
83/// packet. The reference grows its receive buffer to whatever the header claims,
84/// which is fine when the peer is trusted and is a way to be talked into
85/// allocating a lot when it is not, so there is a ceiling here. A publish of a
86/// megabyte over the bus is already an unusual thing to do.
87const MAX_PACKET: usize = 64 * 1024 * 1024;
88
89/// Where each header field starts. These are the reference's, and the reference
90/// asserts them, so they are the protocol.
91const O_TOTLEN: usize = 4;
92const O_VER: usize = 8;
93const O_PORT: usize = 10;
94const O_TYPE: usize = 12;
95const O_COUNT: usize = 14;
96const O_CURRENT_EPOCH: usize = 16;
97const O_CONFIG_EPOCH: usize = 24;
98const O_OFFSET: usize = 32;
99const O_SENDER: usize = 40;
100const O_SLOTS: usize = 80;
101const O_SLAVEOF: usize = 2128;
102const O_MYIP: usize = 2168;
103const O_EXTENSIONS: usize = 2214;
104const O_PPORT: usize = 2246;
105const O_CPORT: usize = 2248;
106const O_FLAGS: usize = 2250;
107const O_STATE: usize = 2252;
108const O_MFLAGS: usize = 2253;
109
110/// Where each field of a gossip entry starts, from the start of the entry.
111const G_NAME: usize = 0;
112const G_PING: usize = 40;
113const G_PONG: usize = 44;
114const G_IP: usize = 48;
115const G_PORT: usize = 94;
116const G_CPORT: usize = 96;
117const G_FLAGS: usize = 98;
118
119/// The message types, which are the reference's numbers and cannot move.
120const T_PING: u16 = 0;
121const T_PONG: u16 = 1;
122const T_MEET: u16 = 2;
123const T_FAIL: u16 = 3;
124const T_PUBLISH: u16 = 4;
125const T_AUTH_REQUEST: u16 = 5;
126const T_AUTH_ACK: u16 = 6;
127const T_UPDATE: u16 = 7;
128const T_MFSTART: u16 = 8;
129const T_MODULE: u16 = 9;
130const T_PUBLISHSHARD: u16 = 10;
131
132/// The message flag a master sets on everything it sends while it is holding its
133/// clients still for a manual failover.
134///
135/// It is what turns the offset in the header into a promise: a header with this
136/// on says nothing has been written since that offset and nothing will be, so a
137/// replica that has caught up to it has caught up for good.
138const MF_PAUSED: u8 = 1;
139
140/// The message flag that says vote for me even though my master is up, which is
141/// the only thing that makes a manual failover different from any other on the
142/// side being asked.
143const MF_FORCEACK: u8 = 2;
144
145/// The one message flag that goes out on everything, which says this node
146/// understands the extensions on the end of a ping and is safe to send them to.
147const MF_EXT_DATA: u8 = 4;
148
149/// The extension types.
150const X_HOSTNAME: u16 = 0;
151const X_HUMAN_NAME: u16 = 1;
152const X_FORGOTTEN: u16 = 2;
153const X_SHARDID: u16 = 3;
154const X_SECRET: u16 = 4;
155
156/// `CLUSTER_OK` and `CLUSTER_FAIL`, which is the one byte of state a packet
157/// carries and is what lets a node see that the rest of the cluster has given
158/// up even when it has not.
159const STATE_OK: u8 = 0;
160const STATE_FAIL: u8 = 1;
161
162/// How long a node id stays unwelcome after `CLUSTER FORGET`, in milliseconds.
163///
164/// Forgetting a node means nothing on its own, because the next gossip packet
165/// from anybody who has not forgotten it would put it straight back. So a forget
166/// is a forget plus a minute of refusing to learn it again, by which time the
167/// forget has been passed round the cluster in the extension that carries it.
168const BLACKLIST_MS: u64 = 60_000;
169
170/// How often the bus wakes up, which is the reference's `clusterCron`.
171const CRON_MS: u64 = 100;
172
173/// How often a node is pinged when nothing else has prompted a ping. The
174/// reference derives this from the node timeout and lets it be set outright;
175/// this is the derived default.
176const PING_MS: u64 = 1000;
177
178/// How long a node has to be silent before this one calls it possibly failed.
179const NODE_TIMEOUT_MS: u64 = 15_000;
180
181/// How long to wait on a connect to another node's bus port before giving up
182/// and trying again on the next tick.
183const CONNECT_TIMEOUT: Duration = Duration::from_millis(500);
184
185/// The fixed part of the wait before a replica asks to be promoted.
186///
187/// Long enough for the FAIL message to have got round the cluster, because a
188/// vote asked for before the electorate agrees the master is gone is a vote
189/// nobody may grant. The reference adds a random part on top of the same size,
190/// which is what keeps two replicas that noticed at the same moment from asking
191/// at the same moment.
192const ELECTION_DELAY_MS: u64 = 500;
193
194/// How much later a replica asks for every other replica that holds more data
195/// than it does.
196///
197/// This is the whole of how the cluster picks the best replica without anybody
198/// comparing offsets: the one with the most data asks first, and the others are
199/// still waiting when it has already won.
200const RANK_DELAY_MS: u64 = 1000;
201
202/// How long an election may take before it is written off, and how long after
203/// that before another one is started.
204///
205/// Timeout is twice the node timeout with a floor of two seconds and retry is
206/// twice the timeout, which are the reference's numbers. The gap between them is
207/// what keeps a replica that cannot win from asking again and again and running
208/// the epoch up on every master in the cluster.
209const ELECTION_TIMEOUT_MS: u64 = if NODE_TIMEOUT_MS * 2 > 2000 {
210 NODE_TIMEOUT_MS * 2
211} else {
212 2000
213};
214
215/// How stale a replica's data may be and still be worth promoting.
216///
217/// The reference works this out from `repl-ping-replica-period` and
218/// `cluster-replica-validity-factor`, neither of which is in the config table
219/// yet, so this is those two at their defaults: ten seconds of ping period plus
220/// ten node timeouts. A replica further behind than that is one whose master was
221/// unreachable long before it died, and promoting it would lose more than
222/// letting the shard stay down does.
223const STALE_DATA_MS: u64 = 10_000 + NODE_TIMEOUT_MS * 10;
224
225/// How long a manual failover has to finish before it is written off.
226///
227/// The reference's `CLUSTER_MF_TIMEOUT`. It is short because everything it is
228/// waiting for is quick: a packet to the master, the master stopping its writes,
229/// and one round of replication to catch this node up on whatever was already in
230/// flight. If that has not happened in five seconds it is not going to.
231const MANUAL_TIMEOUT_MS: u64 = 5000;
232
233/// How much longer than that the master holds its clients still.
234///
235/// The reference's `CLUSTER_MF_PAUSE_MULT`, and the reason it is longer is that
236/// the master has to still be holding them when the replica gives up, or the
237/// window it was there to close would open again at exactly the wrong moment.
238const MANUAL_PAUSE_MULT: u64 = 2;
239
240/// What the master's offset reads as before the master has said what it is.
241///
242/// The reference uses minus one in a signed field. A real offset can be any
243/// value a `u64` holds except this one, which needs a stream longer than the age
244/// of the universe to reach.
245const OFFSET_UNKNOWN: u64 = u64::MAX;
246
247/// The election this node is standing in or voting in.
248///
249/// Atomics rather than a lock because they are read from the cron and written
250/// from whichever link thread a packet arrived on, and nothing here is read
251/// together with anything else here except by the cron, which is the only writer
252/// of everything but the count.
253#[derive(Default)]
254pub(super) struct Vote {
255 /// The epoch this node last gave its vote away in, which is the reference's
256 /// `lastVoteEpoch` and is the whole of one vote per epoch.
257 given: AtomicU64,
258 /// When this node may start asking, or nought when it never has.
259 at: AtomicU64,
260 /// How many votes have come back for the election in `epoch`.
261 count: AtomicU64,
262 /// The epoch this node is standing in.
263 epoch: AtomicU64,
264 /// How many replicas of the same master held more data than this one when
265 /// the delay was worked out, which is what that delay is made of.
266 rank: AtomicU64,
267 /// Whether the request has gone out, so that a reply is worth counting and
268 /// the delay is not recomputed underneath it.
269 sent: AtomicBool,
270}
271
272impl Vote {
273 /// The epoch this node last voted in, for the config file.
274 pub(super) fn given(&self) -> u64 {
275 self.given.load(Relaxed)
276 }
277
278 /// Put back what the config file said, which is why the file has it.
279 pub(super) fn reload(&self, epoch: u64) {
280 self.given.store(epoch, Relaxed);
281 }
282}
283
284/// The manual failover this node is in, on whichever side of it.
285///
286/// The same four words serve the replica that asked and the master that was
287/// asked, because a node is only ever on one side of one of these at a time and
288/// `held` says which side that is. Nothing here is on disk: a manual failover
289/// that was interrupted by a restart is one nobody is waiting for any more.
290pub(super) struct Manual {
291 /// When this is given up on, or nought when there is not one running.
292 end: AtomicU64,
293 /// Whether the replica may stand now, which on this path means at once and
294 /// without any of the waiting an automatic failover does.
295 can_start: AtomicBool,
296 /// The offset the master had when it stopped taking writes, or
297 /// [`OFFSET_UNKNOWN`] before it has said.
298 offset: AtomicU64,
299 /// On the master, the deadline of the pause it armed, which is both how it
300 /// lifts exactly that pause afterwards and how this node knows it is the
301 /// master here rather than the replica.
302 held: AtomicU64,
303}
304
305impl Default for Manual {
306 fn default() -> Manual {
307 Manual {
308 end: AtomicU64::new(0),
309 can_start: AtomicBool::new(false),
310 offset: AtomicU64::new(OFFSET_UNKNOWN),
311 held: AtomicU64::new(0),
312 }
313 }
314}
315
316/// Read a big endian field out of a packet, or nought when it is off the end.
317///
318/// Every read here is bounds checked rather than trusted, because the packet
319/// came off a socket and the length checks in front of it are checks and not
320/// proofs. A truncated field reading as nought loses a packet, which is what
321/// losing a packet on a gossip protocol is for.
322fn be16(p: &[u8], at: usize) -> u16 {
323 p.get(at..at + 2)
324 .map_or(0, |b| u16::from_be_bytes([b[0], b[1]]))
325}
326
327fn be32(p: &[u8], at: usize) -> u32 {
328 p.get(at..at + 4)
329 .map_or(0, |b| u32::from_be_bytes([b[0], b[1], b[2], b[3]]))
330}
331
332fn be64(p: &[u8], at: usize) -> u64 {
333 p.get(at..at + 8).map_or(0, |b| {
334 u64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
335 })
336}
337
338/// Put a big endian field into a packet being built, which is always in range
339/// because the buffer was sized first.
340fn put16(p: &mut [u8], at: usize, v: u16) {
341 p[at..at + 2].copy_from_slice(&v.to_be_bytes());
342}
343
344fn put64(p: &mut [u8], at: usize, v: u64) {
345 p[at..at + 8].copy_from_slice(&v.to_be_bytes());
346}
347
348/// A fixed width text field, which is NUL padded and may not be terminated when
349/// it is exactly full.
350fn text(p: &[u8], at: usize, len: usize) -> String {
351 let Some(raw) = p.get(at..at + len) else {
352 return String::new();
353 };
354 let end = raw.iter().position(|b| *b == 0).unwrap_or(len);
355 String::from_utf8_lossy(&raw[..end]).into_owned()
356}
357
358/// A node id out of a packet, which has to be forty hex characters or it is not
359/// one. An id that is all zeros is the reference's way of saying no node, and
360/// comes back as `None` here so the caller cannot mistake it for one.
361fn node_id(p: &[u8], at: usize) -> Option<String> {
362 let raw = p.get(at..at + NAME_LEN)?;
363 if raw.iter().all(|b| *b == 0) {
364 return None;
365 }
366 if !raw.iter().all(u8::is_ascii_hexdigit) {
367 return None;
368 }
369 Some(String::from_utf8_lossy(raw).into_owned())
370}
371
372/// Whether a slot is set in a bitmap, which the reference stores least
373/// significant bit first inside each byte.
374fn bit(bitmap: &[u8], slot: usize) -> bool {
375 bitmap
376 .get(slot / 8)
377 .is_some_and(|b| b & (1 << (slot % 8)) != 0)
378}
379
380/// Set a slot in a bitmap being built.
381fn set_bit(bitmap: &mut [u8], slot: usize) {
382 bitmap[slot / 8] |= 1 << (slot % 8);
383}
384
385/// A node index drawn at random out of `n`, which is how the gossip section
386/// picks who to talk about. Random and not round robin because every node
387/// picking independently is what spreads news in a few rounds rather than in a
388/// lap of the table.
389fn pick(n: usize) -> u16 {
390 let mut raw = [0u8; 8];
391 yo_common::entropy::fill(&mut raw);
392 (u64::from_be_bytes(raw) % n as u64) as u16
393}
394
395// ------------------------------------------------------------------ the links
396
397/// One connection to another node's bus.
398///
399/// There are two of these per pair of nodes and not one, which looks wasteful
400/// and is the reference's design for a good reason: a link is owned by whoever
401/// opened it, so a node that decides a peer is unreachable can drop its own link
402/// and reconnect without having to agree with the peer about whose turn it is.
403/// The outbound one carries this node's pings and the inbound one carries the
404/// peer's, and each is answered on the socket it arrived on.
405pub(super) struct Wire {
406 /// Whether this node accepted it rather than opened it, which is the
407 /// `from` and `to` of `CLUSTER LINKS`.
408 pub(super) inbound: bool,
409 /// The node at the far end, empty on an inbound link until a packet says
410 /// who is sending it.
411 pub(super) node: Lock<String>,
412 /// When it was made, which `CLUSTER LINKS` reports.
413 pub(super) created: u64,
414 /// The address the peer connected from or was connected to, which is how a
415 /// node learns the address of a peer that did not announce one.
416 peer: String,
417 /// The address on this side of it, which is how a node learns its own.
418 local: String,
419 /// The socket, behind a real mutex rather than the spin lock the tables use,
420 /// because writing to it blocks and a spin lock held across a blocking write
421 /// is a spin lock held for a millisecond.
422 sock: Mutex<TcpStream>,
423 /// Whether it has failed, so that a writer stops trying and the cron drops
424 /// it on the next tick.
425 dead: AtomicBool,
426 /// How many bytes have been handed to the kernel on it, which is the closest
427 /// honest answer to `CLUSTER LINKS`'s send buffer questions on a link that
428 /// has no send queue of its own.
429 sent: AtomicU64,
430}
431
432impl Wire {
433 /// Wrap an open socket.
434 fn new(sock: TcpStream, inbound: bool, node: &str, now: u64) -> Option<Arc<Wire>> {
435 let peer = sock.peer_addr().ok()?.ip().to_string();
436 let local = sock.local_addr().ok()?.ip().to_string();
437 Some(Arc::new(Wire {
438 inbound,
439 node: Lock::new(String::from(node)),
440 created: now,
441 peer,
442 local,
443 sock: Mutex::new(sock),
444 dead: AtomicBool::new(false),
445 sent: AtomicU64::new(0),
446 }))
447 }
448
449 /// The id of the node at the far end, or empty for one nobody has named.
450 fn named(&self) -> String {
451 let held = self.node.lock();
452 yo_alloc::allow(|| held.clone())
453 }
454
455 /// Point this link at a node, which happens on an inbound link the first
456 /// time a packet on it says who is sending.
457 fn name(&self, id: &str) {
458 let mut held = self.node.lock();
459 yo_alloc::allow(|| {
460 held.clear();
461 held.push_str(id);
462 });
463 }
464
465 /// Write a packet, and mark the link dead if that did not work.
466 ///
467 /// A failed write is not reported anywhere, because there is nobody to
468 /// report it to: the peer is either coming back, in which case the cron
469 /// reconnects, or it is not, in which case the timeout is the thing that
470 /// notices. That is the same as the reference, which frees the link and
471 /// carries on.
472 fn send(&self, packet: &[u8]) {
473 if self.dead.load(Relaxed) {
474 return;
475 }
476 let Ok(mut sock) = self.sock.lock() else {
477 self.dead.store(true, Relaxed);
478 return;
479 };
480 if sock.write_all(packet).is_err() {
481 self.dead.store(true, Relaxed);
482 let _ = sock.shutdown(Shutdown::Both);
483 return;
484 }
485 self.sent.store(packet.len() as u64, Relaxed);
486 }
487
488 /// Shut it down, which wakes the reader thread sitting on it.
489 fn kill(&self) {
490 self.dead.store(true, Relaxed);
491 if let Ok(sock) = self.sock.lock() {
492 let _ = sock.shutdown(Shutdown::Both);
493 }
494 }
495}
496
497/// Everything the bus owns that is not in the node table.
498///
499/// Separate from [`super::Cluster`] because none of it exists until the bus
500/// starts and none of it is looked at by a command on the hot path, so it is one
501/// lock rather than four fields on a struct every server has.
502#[derive(Default)]
503pub(super) struct Bus {
504 /// Every open link, both directions.
505 links: Lock<Vec<Arc<Wire>>>,
506 /// Ids that may not be learned again yet, and when they stop being unwelcome.
507 blacklist: Lock<Vec<(String, u64)>>,
508 /// The shared secret nodes use to recognise each other. Forty hex characters
509 /// made at start, and the whole cluster converges on whichever is smallest,
510 /// which is a rule that needs no coordinator to settle.
511 pub(super) secret: Lock<String>,
512 /// Whether the threads are up, so that starting twice is a no-op.
513 on: AtomicBool,
514 /// Whether the table has changed since it was last written.
515 dirty: AtomicBool,
516}
517
518impl Bus {
519 /// Add a link, dropping any that have died since the last look.
520 fn add(&self, wire: &Arc<Wire>) {
521 let mut links = self.links.lock();
522 yo_alloc::allow(|| {
523 links.retain(|held| !held.dead.load(Relaxed));
524 links.push(Arc::clone(wire));
525 });
526 }
527
528 /// The outbound link to a node, or `None` when there is not one.
529 fn outbound(&self, id: &str) -> Option<Arc<Wire>> {
530 let links = self.links.lock();
531 links
532 .iter()
533 .find(|held| !held.inbound && !held.dead.load(Relaxed) && *held.node.lock() == *id)
534 .map(Arc::clone)
535 }
536
537 /// Every live link, for a broadcast.
538 fn all(&self) -> Vec<Arc<Wire>> {
539 let links = self.links.lock();
540 yo_alloc::allow(|| {
541 links
542 .iter()
543 .filter(|held| !held.dead.load(Relaxed))
544 .map(Arc::clone)
545 .collect()
546 })
547 }
548
549 /// Drop every link to one node, which is what forgetting it means at this
550 /// level.
551 fn cut(&self, id: &str) {
552 let mut links = self.links.lock();
553 links.retain(|held| {
554 let theirs = held.node.lock();
555 if *theirs != *id {
556 return true;
557 }
558 drop(theirs);
559 held.kill();
560 false
561 });
562 }
563
564 /// Whether an id is unwelcome, and forget the entries that have aged out
565 /// while looking.
566 fn blacklisted(&self, id: &str, now: u64) -> bool {
567 let mut list = self.blacklist.lock();
568 list.retain(|(_, until)| *until > now);
569 list.iter().any(|(held, _)| held == id)
570 }
571
572 /// Make an id unwelcome for the next minute.
573 fn blacklist(&self, id: &str, now: u64) {
574 let mut list = self.blacklist.lock();
575 yo_alloc::allow(|| {
576 list.retain(|(held, until)| held != id && *until > now);
577 list.push((String::from(id), now + BLACKLIST_MS));
578 });
579 }
580}
581
582// ------------------------------------------------------------- starting it up
583
584impl Server {
585 /// Bring the bus up, which binds the bus port and starts the three kinds of
586 /// thread that run it.
587 ///
588 /// Called once, from whoever is about to start serving clients. A server
589 /// that is not a cluster node does nothing here and pays one relaxed load
590 /// for asking.
591 ///
592 /// # Errors
593 ///
594 /// When the bus port cannot be bound. That is fatal on a real server and is
595 /// fatal here too, because a cluster node nobody can gossip with is a node
596 /// that will be voted out of its own slots in fifteen seconds.
597 pub fn start_cluster_bus(self: &Arc<Server>) -> Result<(), String> {
598 if !self.cluster_enabled() || self.cluster.bus.on.swap(true, Relaxed) {
599 return Ok(());
600 }
601 let (port, id) = {
602 let map = self.cluster.map.lock();
603 (
604 map.nodes[0].bus,
605 yo_alloc::allow(|| map.nodes[0].id.clone()),
606 )
607 };
608 let door = TcpListener::bind(("0.0.0.0", port))
609 .map_err(|e| format!("cluster bus port {port} could not be bound: {e}"))?;
610 let _ = id;
611 let accepting = Arc::clone(self);
612 spawn("yo-bus-accept", move || accept(&accepting, &door));
613 let ticking = Arc::clone(self);
614 spawn("yo-bus-cron", move || cron(&ticking));
615 Ok(())
616 }
617}
618
619/// Start a bus thread, whose name is what a stack trace will show.
620fn spawn(name: &str, body: impl FnOnce() + Send + 'static) {
621 yo_alloc::allow(|| {
622 let _ = std::thread::Builder::new()
623 .name(String::from(name))
624 .spawn(body);
625 });
626}
627
628/// Take connections on the bus port for as long as the process lives.
629fn accept(server: &Arc<Server>, door: &TcpListener) {
630 loop {
631 let Ok((sock, _)) = door.accept() else {
632 std::thread::sleep(Duration::from_millis(CRON_MS));
633 continue;
634 };
635 let _ = sock.set_nodelay(true);
636 let now = server.now_ms();
637 let Some(wire) = Wire::new(sock, true, "", now) else {
638 continue;
639 };
640 server.cluster.bus.add(&wire);
641 let reading = Arc::clone(server);
642 spawn("yo-bus-link", move || pump(&reading, &wire));
643 }
644}
645
646/// Start the clock on a node this one could not open a link to.
647///
648/// Failure detection measures the time since a ping went out and a node with no
649/// link has had no ping to send, so without this a node whose address stops
650/// answering is retried for ever and never marked as failing. The reference
651/// does the same thing in the same place and for the same reason: it says it
652/// sent a ping now, which is true in the sense that one will go out the moment
653/// there is anything to send it down.
654fn unreachable(server: &Arc<Server>, id: &str) {
655 let mut map = server.cluster.map.lock();
656 if let Some(at) = map.find(id.as_bytes())
657 && map.nodes[usize::from(at)].ping_sent == 0
658 {
659 map.nodes[usize::from(at)].ping_sent = server.now_ms();
660 }
661}
662
663/// Open a link to a node and start reading it.
664///
665/// Returns whether it worked, which the cron uses to decide whether the node is
666/// linked. The connect is blocking with a short timeout, which is why this is
667/// never called with the node table locked.
668fn dial(server: &Arc<Server>, id: &str, host: &str, bus: u16, meet: bool) -> bool {
669 let Ok(addrs) = std::net::ToSocketAddrs::to_socket_addrs(&(host, bus)) else {
670 unreachable(server, id);
671 return false;
672 };
673 let mut sock = None;
674 for addr in addrs {
675 if let Ok(open) = TcpStream::connect_timeout(&addr, CONNECT_TIMEOUT) {
676 sock = Some(open);
677 break;
678 }
679 }
680 let Some(sock) = sock else {
681 unreachable(server, id);
682 return false;
683 };
684 let _ = sock.set_nodelay(true);
685 let now = server.now_ms();
686 let Some(wire) = Wire::new(sock, false, id, now) else {
687 unreachable(server, id);
688 return false;
689 };
690 server.cluster.bus.add(&wire);
691 // The first packet decides what this is. A node that was met by hand has to
692 // hear MEET, because that is the only packet a node will accept from
693 // somebody it has never heard of; everything else is a plain ping.
694 let packet = {
695 let mut map = server.cluster.map.lock();
696 let at = map.find(id.as_bytes());
697 if let Some(at) = at {
698 map.nodes[usize::from(at)].linked = true;
699 // The meet is sent once. If it does not land the handshake times out
700 // and the node goes away, which is what should happen to an address
701 // that has nothing at it.
702 map.nodes[usize::from(at)].flags &= !FLAG_MEET;
703 // A ping that was outstanding before the link went is left where it
704 // was, so that the clock failure detection runs on is the one that
705 // started when the node went quiet rather than one that is reset
706 // every time the link is opened again. That is the reference's
707 // `old_ping_sent` and without it a node that is up but unreachable
708 // is never given up on.
709 if !meet && map.nodes[usize::from(at)].ping_sent == 0 {
710 map.nodes[usize::from(at)].ping_sent = now;
711 }
712 }
713 ping(server, &map, if meet { T_MEET } else { T_PING }, at)
714 };
715 wire.send(&packet);
716 let reading = Arc::clone(server);
717 spawn("yo-bus-link", move || pump(&reading, &wire));
718 true
719}
720
721/// Read packets off one link until it stops giving any.
722fn pump(server: &Arc<Server>, wire: &Arc<Wire>) {
723 let sock = {
724 let Ok(held) = wire.sock.lock() else {
725 return;
726 };
727 held.try_clone()
728 };
729 let Ok(mut sock) = sock else {
730 wire.kill();
731 return;
732 };
733 let mut head = [0u8; 8];
734 let mut buf: Vec<u8> = yo_alloc::allow(|| Vec::with_capacity(HDR_LEN * 2));
735 loop {
736 if wire.dead.load(Relaxed) || sock.read_exact(&mut head).is_err() {
737 break;
738 }
739 if &head[0..4] != SIG {
740 break;
741 }
742 let total = u32::from_be_bytes([head[4], head[5], head[6], head[7]]) as usize;
743 if !(16..=MAX_PACKET).contains(&total) {
744 break;
745 }
746 yo_alloc::allow(|| {
747 buf.clear();
748 buf.resize(total, 0);
749 });
750 buf[..8].copy_from_slice(&head);
751 if sock.read_exact(&mut buf[8..]).is_err() {
752 break;
753 }
754 if !process(server, wire, &buf) {
755 break;
756 }
757 }
758 wire.kill();
759 // A link that has gone is a link this node should open again, which it will
760 // do on the next tick as long as the table does not still think it is there.
761 let name = wire.named();
762 if !name.is_empty() && !wire.inbound {
763 let mut map = server.cluster.map.lock();
764 if let Some(at) = map.find(name.as_bytes()) {
765 map.nodes[usize::from(at)].linked = false;
766 }
767 }
768}
769
770// -------------------------------------------------------------- building packets
771
772/// The fixed header, filled in from this node's view of itself.
773fn header(server: &Server, map: &Map, kind: u16) -> Vec<u8> {
774 let mut p = yo_alloc::allow(|| vec![0u8; HDR_LEN]);
775 p[0..4].copy_from_slice(SIG);
776 put16(&mut p, O_VER, PROTO_VER);
777 put16(&mut p, O_TYPE, kind);
778 put16(&mut p, O_PORT, map.nodes[0].port);
779 put16(&mut p, O_CPORT, map.nodes[0].bus);
780 put16(&mut p, O_PPORT, 0);
781 put16(&mut p, O_FLAGS, map.nodes[0].flags);
782 // A replica sends its master's slots and its master's epoch, flagged as a
783 // replica so nobody mistakes it for the owner. That is how a replica can
784 // answer a gossip round at all without having to say it knows nothing.
785 let speaking = map.nodes[0]
786 .master
787 .filter(|_| map.nodes[0].flags & FLAG_SLAVE != 0)
788 .map_or(0, usize::from);
789 put64(&mut p, O_CURRENT_EPOCH, server.cluster.epoch.load(Relaxed));
790 put64(&mut p, O_CONFIG_EPOCH, map.nodes[speaking].epoch);
791 put64(&mut p, O_OFFSET, server.repl_offset());
792 p[O_SENDER..O_SENDER + NAME_LEN].copy_from_slice(map.nodes[0].id.as_bytes());
793 for slot in 0..SLOTS {
794 if map.owner[slot] == Some(speaking as u16) {
795 set_bit(&mut p[O_SLOTS..O_SLOTS + BITMAP_LEN], slot);
796 }
797 }
798 if let Some(master) = map.nodes[0].master {
799 let id = map.nodes[usize::from(master)].id.as_bytes();
800 p[O_SLAVEOF..O_SLAVEOF + NAME_LEN].copy_from_slice(id);
801 }
802 // The address is left empty on purpose. A node does not know its own address
803 // until somebody connects to it, and the receiver takes it off the socket,
804 // which is the reference's auto discovery and is why a cluster can be built
805 // out of nodes that were never told where they are.
806 let _ = O_MYIP;
807 p[O_STATE] = if server.cluster_up() {
808 STATE_OK
809 } else {
810 STATE_FAIL
811 };
812 p[O_MFLAGS] = MF_EXT_DATA;
813 // A master in the middle of a manual failover says so on everything it
814 // sends, which is what tells the replica that the offset above is the last
815 // one there will ever be.
816 if map.nodes[0].is_master() && server.cluster.manual.end.load(Relaxed) != 0 {
817 p[O_MFLAGS] |= MF_PAUSED;
818 }
819 p
820}
821
822/// Finish a packet by writing the length the header promises.
823fn seal(p: &mut [u8]) {
824 let total = p.len() as u32;
825 p[O_TOTLEN..O_TOTLEN + 4].copy_from_slice(&total.to_be_bytes());
826}
827
828/// A `PING`, `PONG` or `MEET`, with its gossip and its extensions.
829///
830/// `to` is the node it is going to, which is left out of the gossip because
831/// telling somebody about themselves is the one thing they already know.
832fn ping(server: &Server, map: &Map, kind: u16, to: Option<u16>) -> Vec<u8> {
833 let mut p = header(server, map, kind);
834 let now = server.now_ms();
835 // A tenth of the cluster with a floor of three, which is the reference's
836 // rule and is what keeps the packet a fixed size as the cluster grows while
837 // still passing news round in a few rounds.
838 let mut want = (map.nodes.len() / 10).max(3);
839 if map.nodes.len() >= 2 {
840 want = want.min(map.nodes.len() - 2);
841 } else {
842 want = 0;
843 }
844 let mut count = 0u16;
845 let mut sent: Vec<u16> = yo_alloc::allow(|| Vec::with_capacity(want + 4));
846 let mut tries = want * 3;
847 while sent.len() < want && tries > 0 {
848 tries -= 1;
849 let at = pick(map.nodes.len());
850 if at == 0 || Some(at) == to || sent.contains(&at) {
851 continue;
852 }
853 let node = &map.nodes[usize::from(at)];
854 // A node in handshake has a made up name, a node with no address cannot
855 // be reached by whoever hears about it, and a node that is not linked
856 // and owns nothing is one this node is about to forget anyway.
857 if node.flags & (FLAG_HANDSHAKE | FLAG_NOADDR) != 0 {
858 continue;
859 }
860 if !node.linked && map.runs(at).is_empty() {
861 continue;
862 }
863 sent.push(at);
864 }
865 // Everybody this node thinks is down goes on the end whether or not they
866 // were drawn, because a failure report that arrives late is a failover that
867 // happens late.
868 for at in 1..map.nodes.len() as u16 {
869 if map.nodes[usize::from(at)].flags & FLAG_PFAIL != 0 && !sent.contains(&at) {
870 sent.push(at);
871 }
872 }
873 for at in sent {
874 let node = &map.nodes[usize::from(at)];
875 let mut entry = [0u8; GOSSIP_LEN];
876 entry[G_NAME..G_NAME + NAME_LEN].copy_from_slice(node.id.as_bytes());
877 entry[G_PING..G_PING + 4].copy_from_slice(&((node.ping_sent / 1000) as u32).to_be_bytes());
878 entry[G_PONG..G_PONG + 4].copy_from_slice(&((node.pong_recv / 1000) as u32).to_be_bytes());
879 let host = node.host.as_bytes();
880 let take = host.len().min(IP_LEN - 1);
881 entry[G_IP..G_IP + take].copy_from_slice(&host[..take]);
882 entry[G_PORT..G_PORT + 2].copy_from_slice(&node.port.to_be_bytes());
883 entry[G_CPORT..G_CPORT + 2].copy_from_slice(&node.bus.to_be_bytes());
884 entry[G_FLAGS..G_FLAGS + 2].copy_from_slice(&node.flags.to_be_bytes());
885 yo_alloc::allow(|| p.extend_from_slice(&entry));
886 count += 1;
887 }
888 let _ = now;
889 put16(&mut p, O_COUNT, count);
890 let mut exts = 0u16;
891 // The shard id and the secret go on every ping. Both are forty bytes and
892 // neither is optional, which is why a bare ping is never just a header.
893 push_ext(&mut p, X_SHARDID, map.nodes[0].shard.as_bytes());
894 exts += 1;
895 let secret = server.cluster.bus.secret.lock();
896 if secret.len() == NAME_LEN {
897 push_ext(&mut p, X_SECRET, secret.as_bytes());
898 exts += 1;
899 }
900 drop(secret);
901 put16(&mut p, O_EXTENSIONS, exts);
902 seal(&mut p);
903 p
904}
905
906/// Put one extension on the end of a packet, padded to the eight byte boundary
907/// the reference insists on.
908fn push_ext(p: &mut Vec<u8>, kind: u16, data: &[u8]) {
909 let len = 8 + data.len().div_ceil(8) * 8;
910 yo_alloc::allow(|| {
911 p.extend_from_slice(&(len as u32).to_be_bytes());
912 p.extend_from_slice(&kind.to_be_bytes());
913 p.extend_from_slice(&[0, 0]);
914 p.extend_from_slice(data);
915 p.resize(p.len() + (len - 8 - data.len()), 0);
916 });
917}
918
919/// A `FAIL`, which says one node is gone and is believed on sight.
920fn fail_packet(server: &Server, map: &Map, about: &str) -> Vec<u8> {
921 let mut p = header(server, map, T_FAIL);
922 yo_alloc::allow(|| p.extend_from_slice(about.as_bytes()));
923 seal(&mut p);
924 p
925}
926
927/// A `PUBLISH` or `PUBLISHSHARD`, which is how a message reaches a subscriber on
928/// another node.
929fn publish_packet(server: &Server, map: &Map, shard: bool, channel: &[u8], body: &[u8]) -> Vec<u8> {
930 let kind = if shard { T_PUBLISHSHARD } else { T_PUBLISH };
931 let mut p = header(server, map, kind);
932 yo_alloc::allow(|| {
933 p.extend_from_slice(&(channel.len() as u32).to_be_bytes());
934 p.extend_from_slice(&(body.len() as u32).to_be_bytes());
935 p.extend_from_slice(channel);
936 p.extend_from_slice(body);
937 });
938 seal(&mut p);
939 p
940}
941
942/// An `UPDATE`, which is what a node sends back to somebody claiming slots it
943/// knows belong to a newer configuration.
944fn update_packet(server: &Server, map: &Map, about: u16) -> Vec<u8> {
945 let mut p = header(server, map, T_UPDATE);
946 let node = &map.nodes[usize::from(about)];
947 let mut body = [0u8; 8 + NAME_LEN + BITMAP_LEN];
948 body[0..8].copy_from_slice(&node.epoch.to_be_bytes());
949 body[8..8 + NAME_LEN].copy_from_slice(node.id.as_bytes());
950 for slot in 0..SLOTS {
951 if map.owner[slot] == Some(about) {
952 set_bit(&mut body[8 + NAME_LEN..], slot);
953 }
954 }
955 yo_alloc::allow(|| p.extend_from_slice(&body));
956 seal(&mut p);
957 p
958}
959
960// ------------------------------------------------------------ reading packets
961
962/// What one packet asked this node to do, gathered up while the table was
963/// locked and carried out after it was not.
964///
965/// The whole of packet processing runs with the node table locked, because it
966/// reads and writes half of it and a reader that saw it half updated would route
967/// a client wrongly. Nothing that blocks may happen under that lock, so a reply
968/// is built while it is held and written after it is dropped, and that is what
969/// this carries.
970#[derive(Default)]
971struct Todo {
972 /// Packets to write back on the link the packet came in on.
973 reply: Vec<Vec<u8>>,
974 /// Packets to write to everybody.
975 shout: Vec<Vec<u8>>,
976 /// A message that arrived for the local subscribers.
977 deliver: Option<(bool, Vec<u8>, Vec<u8>)>,
978 /// Whether the table is worth writing out again.
979 save: bool,
980 /// Whether the slot coverage needs counting again once the lock is gone.
981 recount: bool,
982 /// Slots this node was serving and is not any more.
983 ///
984 /// Carried out of the lock rather than acted on inside it, because what
985 /// happens to them is a migration finishing and a walk of the keyspace, and
986 /// neither of those is a thing to do while every command on the server is
987 /// waiting on the map.
988 lost: Vec<u16>,
989 /// Whether giving them away left this node following the node that took
990 /// them, which is a node that keeps its keys rather than dropping them.
991 demoted: bool,
992 /// Whether the link should be closed rather than read again.
993 close: bool,
994}
995
996/// Handle one packet, and say whether the link is still worth reading.
997fn process(server: &Arc<Server>, wire: &Arc<Wire>, p: &[u8]) -> bool {
998 if be16(p, O_VER) != PROTO_VER {
999 return true;
1000 }
1001 let kind = be16(p, O_TYPE);
1002 let Some(explen) = expected(p, kind) else {
1003 return true;
1004 };
1005 if explen != p.len() {
1006 return true;
1007 }
1008 let now = server.now_ms();
1009 let mut todo = Todo::default();
1010 {
1011 let mut map = server.cluster.map.lock();
1012 digest(server, wire, p, kind, now, &mut map, &mut todo);
1013 }
1014 for packet in &todo.reply {
1015 wire.send(packet);
1016 }
1017 if !todo.shout.is_empty() {
1018 for link in server.cluster.bus.all() {
1019 for packet in &todo.shout {
1020 link.send(packet);
1021 }
1022 }
1023 }
1024 if let Some((shard, channel, body)) = todo.deliver
1025 && server.anyone_subscribed()
1026 {
1027 let kind = if shard { Kind::Shard } else { Kind::Channel };
1028 pubsub::deliver(server, kind, &channel, &body);
1029 }
1030 if todo.save {
1031 server.cluster.bus.dirty.store(true, Relaxed);
1032 }
1033 if todo.recount {
1034 server.recount_coverage();
1035 }
1036 // Last, and outside the lock. A slot that has gone to somebody else is where
1037 // a migration ends and where the keys behind it stop being this node's, and
1038 // both of those read the map they would otherwise be holding.
1039 server.asm_slots_moved(&todo.lost, todo.demoted);
1040 !todo.close
1041}
1042
1043/// How long a packet of this type should be, or `None` for one that cannot be
1044/// worked out and is therefore not a packet.
1045///
1046/// The reference does this before it looks at anything else and refuses on a
1047/// mismatch rather than reading what it can. That is worth copying exactly: a
1048/// length field that disagrees with the body is the shape of every parser bug
1049/// there has ever been, and the cheapest answer is to not have a parser that
1050/// runs on one.
1051fn expected(p: &[u8], kind: u16) -> Option<usize> {
1052 match kind {
1053 T_PING | T_PONG | T_MEET => {
1054 let count = usize::from(be16(p, O_COUNT));
1055 let mut len = HDR_LEN.checked_add(count.checked_mul(GOSSIP_LEN)?)?;
1056 if p.get(O_MFLAGS).is_some_and(|f| f & MF_EXT_DATA != 0) {
1057 let mut left = be16(p, O_EXTENSIONS);
1058 let mut at = len;
1059 while left > 0 {
1060 left -= 1;
1061 let extlen = be32(p, at) as usize;
1062 if extlen < 8 || !extlen.is_multiple_of(8) || p.len().checked_sub(len)? < extlen
1063 {
1064 return None;
1065 }
1066 len += extlen;
1067 at += extlen;
1068 }
1069 }
1070 Some(len)
1071 }
1072 T_FAIL => Some(HDR_LEN + NAME_LEN),
1073 T_PUBLISH | T_PUBLISHSHARD => {
1074 let channel = be32(p, HDR_LEN) as usize;
1075 let body = be32(p, HDR_LEN + 4) as usize;
1076 HDR_LEN
1077 .checked_add(8)?
1078 .checked_add(channel)?
1079 .checked_add(body)
1080 }
1081 T_AUTH_REQUEST | T_AUTH_ACK | T_MFSTART => Some(HDR_LEN),
1082 T_UPDATE => Some(HDR_LEN + 8 + NAME_LEN + BITMAP_LEN),
1083 // A type this node does not handle is well formed by definition, which
1084 // is the reference's own answer and is what lets a newer node talk to an
1085 // older one without either of them dropping the conversation.
1086 _ => Some(p.len()),
1087 }
1088}
1089
1090/// Everything one packet does to the node table.
1091#[allow(clippy::too_many_lines)]
1092fn digest(
1093 server: &Arc<Server>,
1094 wire: &Arc<Wire>,
1095 p: &[u8],
1096 kind: u16,
1097 now: u64,
1098 map: &mut Map,
1099 todo: &mut Todo,
1100) {
1101 let flags = be16(p, O_FLAGS);
1102 let claimed = node_id(p, O_SENDER);
1103 // Who sent it. An outbound link knows without looking, unless the node on
1104 // the other end is still in handshake and therefore still has the made up
1105 // name this node gave it.
1106 let linked = wire.named();
1107 let mut sender = None;
1108 if !linked.is_empty()
1109 && let Some(at) = map.find(linked.as_bytes())
1110 && map.nodes[usize::from(at)].flags & FLAG_HANDSHAKE == 0
1111 {
1112 sender = Some(at);
1113 }
1114 if sender.is_none()
1115 && let Some(id) = claimed.as_deref()
1116 {
1117 sender = map.find(id.as_bytes());
1118 if sender.is_some() && linked.is_empty() {
1119 wire.name(id);
1120 }
1121 }
1122 if let Some(at) = sender {
1123 let node = &mut map.nodes[usize::from(at)];
1124 if p.get(O_MFLAGS).is_some_and(|f| f & MF_EXT_DATA != 0) {
1125 node.flags |= super::FLAG_EXTENSIONS;
1126 }
1127 node.data_recv = now;
1128 }
1129 let sender_epoch = be64(p, O_CONFIG_EPOCH);
1130 if let Some(at) = sender
1131 && map.nodes[usize::from(at)].flags & FLAG_HANDSHAKE == 0
1132 {
1133 let theirs = be64(p, O_CURRENT_EPOCH);
1134 server.cluster.epoch.fetch_max(theirs, Relaxed);
1135 let node = &mut map.nodes[usize::from(at)];
1136 if sender_epoch > node.epoch {
1137 node.epoch = sender_epoch;
1138 todo.save = true;
1139 }
1140 node.offset = be64(p, O_OFFSET);
1141 // A manual failover this node asked for, and the answer to the only
1142 // question it was waiting on: where the master stopped. The first paused
1143 // header is the one that counts, because the ones after it say the same
1144 // thing and taking a later one would only move the target.
1145 let manual = &server.cluster.manual;
1146 if manual.end.load(Relaxed) != 0
1147 && manual.offset.load(Relaxed) == OFFSET_UNKNOWN
1148 && map.nodes[0].flags & FLAG_SLAVE != 0
1149 && map.nodes[0].master == Some(at)
1150 && p.get(O_MFLAGS).is_some_and(|f| f & MF_PAUSED != 0)
1151 {
1152 manual.offset.store(be64(p, O_OFFSET), Relaxed);
1153 }
1154 }
1155
1156 if kind == T_PING || kind == T_MEET {
1157 // A node learns its own address from the socket a MEET arrived on,
1158 // which is the only address in the cluster that is known to be reachable
1159 // from somewhere else. A plain ping is enough when there is no address
1160 // at all yet, because having a wrong one is better than having none and
1161 // a MEET will correct it.
1162 if (kind == T_MEET || map.nodes[0].host.is_empty()) && map.nodes[0].host != wire.local {
1163 yo_alloc::allow(|| map.nodes[0].host.clone_from(&wire.local));
1164 todo.save = true;
1165 }
1166 if sender.is_none() && kind == T_MEET {
1167 // Somebody was told to meet this node. Nothing about them is trusted
1168 // yet beyond where they are, so they go in as a handshake node with
1169 // a name this node made up, and the ping they answer with is what
1170 // replaces it.
1171 let host = {
1172 let announced = text(p, O_MYIP, IP_LEN);
1173 if announced.is_empty() {
1174 yo_alloc::allow(|| wire.peer.clone())
1175 } else {
1176 announced
1177 }
1178 };
1179 let id = yo_alloc::allow(|| String::from_utf8_lossy(&new_id()).into_owned());
1180 let node = yo_alloc::allow(|| {
1181 Node::new(
1182 id,
1183 host,
1184 be16(p, O_PORT),
1185 be16(p, O_CPORT),
1186 FLAG_HANDSHAKE,
1187 now,
1188 )
1189 });
1190 yo_alloc::allow(|| map.nodes.push(node));
1191 todo.save = true;
1192 // The gossip on a MEET from a stranger is taken anyway, because the
1193 // type of the packet is the trust: only a node that was told to meet
1194 // this one sends one, and it is worth knowing who else it has met.
1195 gossip(server, p, now, map, todo);
1196 }
1197 todo.reply.push(ping(server, map, T_PONG, sender));
1198 }
1199
1200 match kind {
1201 T_PING | T_PONG | T_MEET => {}
1202 T_FAIL => {
1203 if sender.is_some()
1204 && let Some(id) = node_id(p, HDR_LEN)
1205 && let Some(at) = map.find(id.as_bytes())
1206 && map.nodes[usize::from(at)].flags & (FLAG_FAIL | FLAG_MYSELF) == 0
1207 {
1208 let node = &mut map.nodes[usize::from(at)];
1209 node.flags |= FLAG_FAIL;
1210 node.flags &= !FLAG_PFAIL;
1211 node.fail_time = now;
1212 todo.save = true;
1213 }
1214 return;
1215 }
1216 T_PUBLISH | T_PUBLISHSHARD => {
1217 if sender.is_none() {
1218 todo.close = true;
1219 return;
1220 }
1221 let channel = be32(p, HDR_LEN) as usize;
1222 let body = be32(p, HDR_LEN + 4) as usize;
1223 let at = HDR_LEN + 8;
1224 todo.deliver = yo_alloc::allow(|| {
1225 Some((
1226 kind == T_PUBLISHSHARD,
1227 p[at..at + channel].to_vec(),
1228 p[at + channel..at + channel + body].to_vec(),
1229 ))
1230 });
1231 return;
1232 }
1233 T_UPDATE => {
1234 if sender.is_none() {
1235 todo.close = true;
1236 return;
1237 }
1238 let epoch = be64(p, HDR_LEN);
1239 let Some(id) = node_id(p, HDR_LEN + 8) else {
1240 return;
1241 };
1242 let Some(about) = map.find(id.as_bytes()) else {
1243 return;
1244 };
1245 if epoch <= map.nodes[usize::from(about)].epoch {
1246 return;
1247 }
1248 map.nodes[usize::from(about)].epoch = epoch;
1249 map.nodes[usize::from(about)].flags &= !FLAG_SLAVE;
1250 map.nodes[usize::from(about)].flags |= FLAG_MASTER;
1251 map.nodes[usize::from(about)].master = None;
1252 claim_slots(
1253 server,
1254 map,
1255 about,
1256 epoch,
1257 &p[HDR_LEN + 8 + NAME_LEN..],
1258 todo,
1259 );
1260 todo.save = true;
1261 return;
1262 }
1263 T_AUTH_REQUEST => {
1264 // A vote is only ever given to a node this one knows, because the
1265 // whole question is about a master this node has an opinion on.
1266 if let Some(at) = sender
1267 && vote_if_needed(server, map, at, p, now)
1268 {
1269 let mut packet = header(server, map, T_AUTH_ACK);
1270 seal(&mut packet);
1271 yo_alloc::allow(|| todo.reply.push(packet));
1272 todo.save = true;
1273 }
1274 return;
1275 }
1276 T_AUTH_ACK => {
1277 // Only a master serving slots has a vote to give, and only a vote
1278 // cast in the epoch this node is standing in counts. The second
1279 // check is what stops a late reply to a previous election being
1280 // counted towards this one.
1281 let vote = &server.cluster.vote;
1282 if let Some(at) = sender
1283 && map.nodes[usize::from(at)].is_master()
1284 && !map.runs(at).is_empty()
1285 && be64(p, O_CURRENT_EPOCH) >= vote.epoch.load(Relaxed)
1286 {
1287 vote.count.fetch_add(1, Relaxed);
1288 }
1289 return;
1290 }
1291 T_MFSTART => {
1292 if let Some(at) = sender {
1293 stand_down(server, map, at, now, todo);
1294 }
1295 return;
1296 }
1297 // Modules are not a thing here at all.
1298 T_MODULE => return,
1299 _ => return,
1300 }
1301
1302 // From here down is the config half of a PING, PONG or MEET, which is where
1303 // a cluster actually agrees on anything.
1304 if !wire.inbound {
1305 let held = map.find(linked.as_bytes());
1306 if let Some(at) = held
1307 && map.nodes[usize::from(at)].flags & FLAG_HANDSHAKE != 0
1308 {
1309 match sender {
1310 // This node had already met them under their real name, so the
1311 // handshake node is a duplicate and goes away.
1312 Some(known) => {
1313 let host = yo_alloc::allow(|| wire.peer.clone());
1314 let node = &mut map.nodes[usize::from(known)];
1315 if node.host != host {
1316 node.host = host;
1317 node.port = be16(p, O_PORT);
1318 node.bus = be16(p, O_CPORT);
1319 }
1320 map.forget(at);
1321 todo.save = true;
1322 todo.close = true;
1323 return;
1324 }
1325 // The handshake worked. The made up name is replaced with the
1326 // real one and the node is an ordinary node from here on.
1327 None => {
1328 let Some(id) = claimed.clone() else {
1329 return;
1330 };
1331 wire.name(&id);
1332 let node = &mut map.nodes[usize::from(at)];
1333 yo_alloc::allow(|| node.id = id);
1334 node.flags &= !(FLAG_HANDSHAKE | FLAG_MEET);
1335 node.flags |= flags & (FLAG_MASTER | FLAG_SLAVE);
1336 node.pong_recv = now;
1337 node.ping_sent = 0;
1338 sender = Some(at);
1339 todo.save = true;
1340 }
1341 }
1342 } else if let Some(at) = held
1343 && Some(map.nodes[usize::from(at)].id.as_str()) != claimed.as_deref()
1344 {
1345 // Somebody else is answering on the address this node had written
1346 // down for a peer. The address is wrong rather than the peer, so the
1347 // peer keeps its identity and loses its address until gossip finds
1348 // it again.
1349 let node = &mut map.nodes[usize::from(at)];
1350 node.flags |= FLAG_NOADDR;
1351 node.host.clear();
1352 node.port = 0;
1353 node.bus = 0;
1354 node.linked = false;
1355 todo.save = true;
1356 todo.close = true;
1357 return;
1358 }
1359 }
1360
1361 let Some(at) = sender else {
1362 return;
1363 };
1364 // The no failover flag is the sender's to set and everybody else's to
1365 // believe, because it is the sender saying whether it wants to be promoted.
1366 let node = &mut map.nodes[usize::from(at)];
1367 node.flags &= !FLAG_NOFAILOVER;
1368 node.flags |= flags & FLAG_NOFAILOVER;
1369 if kind == T_PING && !wire.inbound {
1370 let host = yo_alloc::allow(|| wire.peer.clone());
1371 if node.host != host {
1372 node.host = host;
1373 node.port = be16(p, O_PORT);
1374 node.bus = be16(p, O_CPORT);
1375 todo.save = true;
1376 }
1377 }
1378 if !wire.inbound && kind == T_PONG {
1379 node.pong_recv = now;
1380 node.ping_sent = 0;
1381 if node.flags & FLAG_PFAIL != 0 {
1382 node.flags &= !FLAG_PFAIL;
1383 todo.save = true;
1384 } else if node.flags & FLAG_FAIL != 0 {
1385 clear_failure(map, at, now);
1386 todo.save = true;
1387 }
1388 }
1389
1390 // Master or replica, which has to settle before the slots are looked at
1391 // because a replica's slot claim is its master's and means something else.
1392 let follows = node_id(p, O_SLAVEOF);
1393 match follows {
1394 None => {
1395 if map.nodes[usize::from(at)].flags & FLAG_SLAVE != 0 {
1396 let node = &mut map.nodes[usize::from(at)];
1397 node.flags &= !FLAG_SLAVE;
1398 node.flags |= FLAG_MASTER;
1399 node.master = None;
1400 todo.save = true;
1401 }
1402 }
1403 Some(id) => {
1404 let master = map.find(id.as_bytes());
1405 if map.nodes[usize::from(at)].is_master() {
1406 // A master that has become a replica. When its new master is in
1407 // the same shard this is the tail of a failover, so the slots
1408 // move rather than vanish, and the new master is promoted here
1409 // to match. When it is not, the node has been moved to another
1410 // shard and its slots are simply not its any more.
1411 let same_shard = master.is_some_and(|m| {
1412 map.nodes[usize::from(m)].shard == map.nodes[usize::from(at)].shard
1413 });
1414 if same_shard && sender_epoch >= map.nodes[usize::from(at)].epoch {
1415 let m = master.expect("same shard means there is one");
1416 for slot in 0..SLOTS {
1417 if map.owner[slot] == Some(at) {
1418 map.owner[slot] = Some(m);
1419 }
1420 }
1421 let promoted = &mut map.nodes[usize::from(m)];
1422 promoted.flags &= !FLAG_SLAVE;
1423 promoted.flags |= FLAG_MASTER;
1424 promoted.master = None;
1425 promoted.epoch = sender_epoch;
1426 } else if !same_shard {
1427 for slot in 0..SLOTS {
1428 if map.owner[slot] == Some(at) {
1429 map.owner[slot] = None;
1430 }
1431 }
1432 }
1433 let node = &mut map.nodes[usize::from(at)];
1434 node.flags &= !(FLAG_MASTER | FLAG_MIGRATE_TO);
1435 node.flags |= FLAG_SLAVE;
1436 todo.save = true;
1437 }
1438 if let Some(m) = master
1439 && map.nodes[usize::from(at)].master != Some(m)
1440 && m != at
1441 {
1442 map.nodes[usize::from(at)].master = Some(m);
1443 let shard = yo_alloc::allow(|| map.nodes[usize::from(m)].shard.clone());
1444 yo_alloc::allow(|| map.nodes[usize::from(at)].shard = shard);
1445 todo.save = true;
1446 }
1447 }
1448 }
1449
1450 // The slots. Only a master's claim counts, and only when it differs from
1451 // what this node already had, which is one memcmp in front of a walk of
1452 // sixteen thousand slots and is worth having.
1453 let speaking = if map.nodes[usize::from(at)].is_master() {
1454 Some(at)
1455 } else {
1456 map.nodes[usize::from(at)].master
1457 };
1458 let claim = &p[O_SLOTS..O_SLOTS + BITMAP_LEN];
1459 let dirty = speaking
1460 .is_some_and(|m| (0..SLOTS).any(|slot| bit(claim, slot) != (map.owner[slot] == Some(m))));
1461 if dirty && map.nodes[usize::from(at)].is_master() {
1462 claim_slots(server, map, at, sender_epoch, claim, todo);
1463 }
1464 if dirty {
1465 // The other way round: the sender is claiming slots this node knows have
1466 // moved on to somebody with a newer epoch, so it is told about the first
1467 // one of them and works the rest out from there.
1468 for slot in 0..SLOTS {
1469 if !bit(claim, slot) {
1470 continue;
1471 }
1472 let Some(owner) = map.owner[slot] else {
1473 continue;
1474 };
1475 if owner == at {
1476 continue;
1477 }
1478 if map.nodes[usize::from(owner)].epoch > sender_epoch {
1479 todo.reply.push(update_packet(server, map, owner));
1480 break;
1481 }
1482 }
1483 }
1484 // Two masters with the same epoch cannot both be right, so the one with the
1485 // smaller id gives way by taking a new one. Deterministic and needs no
1486 // agreement, which is the only kind of tiebreak that works in a partition.
1487 if map.nodes[0].is_master()
1488 && map.nodes[usize::from(at)].is_master()
1489 && sender_epoch == map.nodes[0].epoch
1490 && map.nodes[0].id < map.nodes[usize::from(at)].id
1491 {
1492 let next = server.cluster.epoch.fetch_add(1, Relaxed) + 1;
1493 map.nodes[0].epoch = next;
1494 todo.save = true;
1495 }
1496 gossip(server, p, now, map, todo);
1497 extensions(server, p, now, map, at, todo);
1498}
1499
1500/// The gossip section, which is what everybody else looks like from where the
1501/// sender is standing.
1502fn gossip(server: &Arc<Server>, p: &[u8], now: u64, map: &mut Map, todo: &mut Todo) {
1503 let count = usize::from(be16(p, O_COUNT));
1504 let sender_master = node_id(p, O_SENDER)
1505 .and_then(|id| map.find(id.as_bytes()))
1506 .is_none_or(|at| map.nodes[usize::from(at)].is_master());
1507 for entry in 0..count {
1508 let base = HDR_LEN + entry * GOSSIP_LEN;
1509 let Some(id) = node_id(p, base + G_NAME) else {
1510 continue;
1511 };
1512 let flags = be16(p, base + G_FLAGS);
1513 let host = text(p, base + G_IP, IP_LEN);
1514 let port = be16(p, base + G_PORT);
1515 let bus = be16(p, base + G_CPORT);
1516 if let Some(at) = map.find(id.as_bytes()) {
1517 if at == 0 {
1518 continue;
1519 }
1520 // A master saying somebody is down is a vote; anybody else saying it
1521 // is an opinion. Both are recorded, and only the votes are counted.
1522 if sender_master {
1523 let sender = node_id(p, O_SENDER).unwrap_or_default();
1524 if flags & (FLAG_FAIL | FLAG_PFAIL) != 0 {
1525 report(map, at, &sender, now);
1526 if mark_failing(map, at, now) {
1527 let about = yo_alloc::allow(|| map.nodes[usize::from(at)].id.clone());
1528 todo.shout.push(fail_packet(server, map, &about));
1529 todo.save = true;
1530 }
1531 } else {
1532 unreport(map, at, &sender);
1533 }
1534 }
1535 let node = &mut map.nodes[usize::from(at)];
1536 if node.flags & (FLAG_FAIL | FLAG_PFAIL) == 0
1537 && node.ping_sent == 0
1538 && node.reports.is_empty()
1539 {
1540 // The sender heard from them more recently than this node did, so
1541 // take their word for when. The half second ceiling is the
1542 // reference's guard against a peer whose clock is ahead.
1543 let heard = u64::from(be32(p, base + G_PONG)) * 1000;
1544 if heard > node.pong_recv && heard <= now + 500 {
1545 node.pong_recv = heard;
1546 }
1547 } else if node.down()
1548 && flags & (FLAG_FAIL | FLAG_PFAIL | FLAG_NOADDR | FLAG_HANDSHAKE) == 0
1549 && !host.is_empty()
1550 && (node.host != host || node.port != port)
1551 {
1552 // Down here and up there, at an address this node does not have.
1553 // The address is the thing that is wrong, so it is replaced and
1554 // the next tick tries again.
1555 yo_alloc::allow(|| node.host = host);
1556 node.port = port;
1557 node.bus = bus;
1558 node.linked = false;
1559 node.flags &= !FLAG_NOADDR;
1560 todo.save = true;
1561 }
1562 continue;
1563 }
1564 // Somebody new. Taken only from a sender this node already knows, and
1565 // only when the id is not one that was just forgotten on purpose.
1566 //
1567 // It goes in under the id and the flags the gossip carried rather than
1568 // as a handshake, which is the difference between learning about a node
1569 // and meeting one. A handshake exists to find out an id that is not
1570 // known yet, and here it is: the sender said it. Adding it as a
1571 // handshake instead would mean opening a link to an address whose owner
1572 // might have changed, which is how a node ends up in somebody else's
1573 // cluster.
1574 if flags & FLAG_NOADDR != 0 {
1575 continue;
1576 }
1577 if server.cluster.bus.blacklisted(&id, now) {
1578 continue;
1579 }
1580 let flags = flags & !(FLAG_MYSELF | FLAG_HANDSHAKE | FLAG_MEET);
1581 let node = yo_alloc::allow(|| Node::new(id, host, port, bus, flags, now));
1582 yo_alloc::allow(|| map.nodes.push(node));
1583 todo.save = true;
1584 }
1585}
1586
1587/// The extensions on the end of a ping.
1588fn extensions(server: &Arc<Server>, p: &[u8], now: u64, map: &mut Map, at: u16, todo: &mut Todo) {
1589 if !p.get(O_MFLAGS).is_some_and(|f| f & MF_EXT_DATA != 0) {
1590 return;
1591 }
1592 let mut left = be16(p, O_EXTENSIONS);
1593 let mut base = HDR_LEN + usize::from(be16(p, O_COUNT)) * GOSSIP_LEN;
1594 while left > 0 && base + 8 <= p.len() {
1595 left -= 1;
1596 let extlen = be32(p, base) as usize;
1597 if extlen < 8 || base + extlen > p.len() {
1598 return;
1599 }
1600 let kind = be16(p, base + 4);
1601 let data = &p[base + 8..base + extlen];
1602 match kind {
1603 X_SHARDID => {
1604 let id = String::from_utf8_lossy(&data[..NAME_LEN.min(data.len())]);
1605 if id.len() == NAME_LEN && map.nodes[usize::from(at)].shard != id {
1606 yo_alloc::allow(|| map.nodes[usize::from(at)].shard = id.into_owned());
1607 todo.save = true;
1608 }
1609 }
1610 X_SECRET => {
1611 // The whole cluster ends up on the smallest secret anybody
1612 // started with, which needs no leader to decide and settles in
1613 // one gossip round.
1614 let theirs = String::from_utf8_lossy(&data[..NAME_LEN.min(data.len())]);
1615 let mut mine = server.cluster.bus.secret.lock();
1616 if theirs.len() == NAME_LEN && **mine > *theirs {
1617 yo_alloc::allow(|| *mine = theirs.into_owned());
1618 }
1619 }
1620 X_FORGOTTEN => {
1621 // Somebody has been forgotten on purpose. Forget them here too,
1622 // and refuse to learn them again for as long as the sender says,
1623 // which is what stops the rest of the cluster putting them back.
1624 if data.len() < NAME_LEN + 8 {
1625 return;
1626 }
1627 let Some(id) = node_id(data, 0) else {
1628 return;
1629 };
1630 let ttl = be64(data, NAME_LEN);
1631 if map.nodes[0].id == id
1632 || map.nodes[0].master.map(usize::from)
1633 == map.find(id.as_bytes()).map(usize::from)
1634 {
1635 base += extlen;
1636 continue;
1637 }
1638 server.cluster.bus.blacklist(&id, now + ttl);
1639 if let Some(gone) = map.find(id.as_bytes())
1640 && gone != 0
1641 {
1642 server.cluster.bus.cut(&id);
1643 map.forget(gone);
1644 todo.save = true;
1645 }
1646 }
1647 // The hostname and the human readable name are carried for the
1648 // benefit of an operator reading `CLUSTER NODES` on a real server,
1649 // and nothing here routes on either of them.
1650 X_HOSTNAME | X_HUMAN_NAME => {}
1651 _ => {}
1652 }
1653 base += extlen;
1654 }
1655}
1656
1657/// Record that somebody thinks a node is down.
1658fn report(map: &mut Map, at: u16, from: &str, now: u64) {
1659 if from.is_empty() {
1660 return;
1661 }
1662 let node = &mut map.nodes[usize::from(at)];
1663 if let Some(held) = node.reports.iter_mut().find(|(who, _)| who == from) {
1664 held.1 = now;
1665 return;
1666 }
1667 yo_alloc::allow(|| node.reports.push((String::from(from), now)));
1668}
1669
1670/// Take one back, which is somebody saying they can reach a node after all.
1671fn unreport(map: &mut Map, at: u16, from: &str) {
1672 map.nodes[usize::from(at)]
1673 .reports
1674 .retain(|(who, _)| who != from);
1675}
1676
1677/// Whether enough of the cluster agrees that a node is gone, and flag it if so.
1678///
1679/// The quorum is a majority of the masters that are serving slots, which is the
1680/// same electorate a failover vote is counted against, and this node counts
1681/// itself when it is one of them. Reports older than twice the node timeout are
1682/// dropped first, so a node that flickered a long time ago does not help
1683/// condemn one that is flickering now.
1684fn mark_failing(map: &mut Map, at: u16, now: u64) -> bool {
1685 let cutoff = now.saturating_sub(NODE_TIMEOUT_MS * 2);
1686 map.nodes[usize::from(at)]
1687 .reports
1688 .retain(|(_, when)| *when > cutoff);
1689 if map.nodes[usize::from(at)].flags & (FLAG_PFAIL | FLAG_FAIL) == 0 {
1690 return false;
1691 }
1692 if map.nodes[usize::from(at)].flags & FLAG_FAIL != 0 {
1693 return false;
1694 }
1695 let needed = map.voters() / 2 + 1;
1696 let mut votes = map.nodes[usize::from(at)].reports.len();
1697 if map.nodes[0].is_master() && !map.runs(0).is_empty() {
1698 votes += 1;
1699 }
1700 if votes < needed {
1701 return false;
1702 }
1703 let node = &mut map.nodes[usize::from(at)];
1704 node.flags &= !FLAG_PFAIL;
1705 node.flags |= FLAG_FAIL;
1706 node.fail_time = now;
1707 true
1708}
1709
1710/// Undo a failure verdict, which is only allowed for a replica that came back or
1711/// for a master that came back still owning nothing.
1712///
1713/// A master that comes back owning slots is not cleared, because the cluster has
1714/// probably promoted its replica by now and clearing it would leave two nodes
1715/// claiming the same slots. It stays failed until it hears about the promotion
1716/// and stands down on its own.
1717fn clear_failure(map: &mut Map, at: u16, now: u64) {
1718 let node = &map.nodes[usize::from(at)];
1719 let replica = !node.is_master();
1720 let empty = map.runs(at).is_empty();
1721 let stale = now.saturating_sub(node.fail_time) > NODE_TIMEOUT_MS * 2;
1722 if replica || empty || stale {
1723 let node = &mut map.nodes[usize::from(at)];
1724 node.flags &= !FLAG_FAIL;
1725 node.fail_time = 0;
1726 }
1727}
1728
1729/// Take a master's word for which slots are its.
1730///
1731/// This is the one place a slot changes hands without an operator asking, so it
1732/// is careful about which claims it believes. A slot nobody owns is taken on
1733/// sight. A slot owned by somebody with an older epoch changes hands, because a
1734/// higher epoch is the cluster's way of saying this configuration is newer. A
1735/// slot this node is importing is left alone, because an import in progress is
1736/// an operator's decision and outranks gossip. And a slot this node loses while
1737/// still holding keys for it is remembered, because those keys now belong to
1738/// somebody else and keeping them would mean two nodes answering for the same
1739/// data.
1740fn claim_slots(
1741 server: &Arc<Server>,
1742 map: &mut Map,
1743 owner: u16,
1744 epoch: u64,
1745 claim: &[u8],
1746 todo: &mut Todo,
1747) {
1748 // Whose slots decide where this node belongs afterwards. A master answers
1749 // for its own and a replica answers for its master's, because a replica of a
1750 // master that has just lost everything is a replica of nothing and is how a
1751 // second replica of a failed master finds the one that replaced it.
1752 let ours = if map.nodes[0].is_master() {
1753 Some(0)
1754 } else {
1755 map.nodes[0].master
1756 };
1757 let mut lost = 0usize;
1758 for slot in 0..SLOTS {
1759 if !bit(claim, slot) {
1760 continue;
1761 }
1762 if map.owner[slot] == Some(owner) || map.importing[slot].is_some() {
1763 continue;
1764 }
1765 let held = map.owner[slot];
1766 let newer = held.is_none_or(|at| map.nodes[usize::from(at)].epoch <= epoch);
1767 if !newer {
1768 continue;
1769 }
1770 if held == ours {
1771 lost += 1;
1772 }
1773 if held == Some(0) {
1774 yo_alloc::allow(|| todo.lost.push(slot as u16));
1775 }
1776 map.owner[slot] = Some(owner);
1777 map.migrating[slot] = None;
1778 todo.save = true;
1779 }
1780 // A master that has just given away its last slot is not a master any more.
1781 // Following the node that took them is what a real server does and is what
1782 // makes a failed master come back as a replica of whoever replaced it.
1783 if lost > 0 && ours.is_some_and(|at| map.runs(at).is_empty()) && owner != 0 {
1784 todo.demoted = true;
1785 // Whoever took them is the node this one was standing down for, if it
1786 // was standing down at all, so the pause it armed goes now rather than
1787 // when the clock runs out.
1788 manual_reset(server);
1789 map.nodes[0].flags &= !FLAG_MASTER;
1790 map.nodes[0].flags |= FLAG_SLAVE;
1791 map.nodes[0].master = Some(owner);
1792 let shard = yo_alloc::allow(|| map.nodes[usize::from(owner)].shard.clone());
1793 yo_alloc::allow(|| map.nodes[0].shard = shard);
1794 let (host, port) = {
1795 let node = &map.nodes[usize::from(owner)];
1796 (yo_alloc::allow(|| node.host.clone()), node.port)
1797 };
1798 let following = Arc::clone(server);
1799 spawn("yo-bus-follow", move || {
1800 following.follow_master(&host, port);
1801 });
1802 }
1803 // The coverage count is not touched here on purpose. It reads the same map
1804 // this runs under, and the lock is not reentrant, so the caller does it
1805 // once the lock is gone.
1806 todo.recount = true;
1807}
1808
1809// ------------------------------------------------------------ the failover vote
1810
1811/// Answer a replica asking to be promoted, if every condition holds.
1812///
1813/// This is the reference's `clusterSendFailoverAuthIfNeeded` and the order of
1814/// the checks is its order, because the order is the safety. A master gets one
1815/// vote per epoch and gives it to the first replica that asks, and everything
1816/// in front of that is about making sure the question was a fair one to ask.
1817///
1818/// Nothing is sent back when a condition fails. There is no such thing as a no
1819/// vote on this protocol: a replica counts the yeses it got and gives up when
1820/// the election times out, which means a master that has crashed and a master
1821/// that disapproves look the same from where the replica is standing. That is
1822/// deliberate, since the alternative is a reply that a replica could be made to
1823/// wait for.
1824fn vote_if_needed(server: &Arc<Server>, map: &mut Map, at: u16, p: &[u8], now: u64) -> bool {
1825 // Only a master serving a slot has a vote, because the electorate is the
1826 // masters that serve slots and nothing else would make the quorum add up.
1827 if map.nodes[0].flags & FLAG_SLAVE != 0 || map.runs(0).is_empty() {
1828 return false;
1829 }
1830 // The asking node's epoch cannot be behind this node's. It cannot really be
1831 // ahead either, since reading the packet has already pulled this node's
1832 // epoch up to it, so what this catches is a request that was already stale
1833 // when it arrived.
1834 let epoch = server.cluster.epoch.load(Relaxed);
1835 if be64(p, O_CURRENT_EPOCH) < epoch {
1836 return false;
1837 }
1838 // One vote per epoch, and it has already gone.
1839 if server.cluster.vote.given.load(Relaxed) == epoch {
1840 return false;
1841 }
1842 // It has to be a replica, this node has to know whose, and that master has
1843 // to be one the cluster has given up on. A manual failover is the exception
1844 // and says so in the packet, because there the master is up and is in on it.
1845 let asking = &map.nodes[usize::from(at)];
1846 let Some(master) = asking.master.filter(|_| asking.flags & FLAG_SLAVE != 0) else {
1847 return false;
1848 };
1849 let forced = p.get(O_MFLAGS).is_some_and(|f| f & MF_FORCEACK != 0);
1850 if map.nodes[usize::from(master)].flags & FLAG_FAIL == 0 && !forced {
1851 return false;
1852 }
1853 // Not twice about the same master inside two node timeouts. A second replica
1854 // of the same master asking straight after the first is either the first one
1855 // having failed to win or two of them racing, and in both cases the answer
1856 // that keeps the shard with one master is to wait and see how the first one
1857 // went.
1858 if now.saturating_sub(map.nodes[usize::from(master)].voted_time) < NODE_TIMEOUT_MS * 2 {
1859 return false;
1860 }
1861 // The slots it is claiming have to be ones it would be claiming under an
1862 // epoch at least as new as whoever is serving them here. A replica asking to
1863 // take over slots that have already moved somewhere newer is a replica that
1864 // has been out of touch, and voting for it would undo the move.
1865 let claimed = be64(p, O_CONFIG_EPOCH);
1866 for slot in 0..SLOTS {
1867 if !bit(&p[O_SLOTS..O_SLOTS + BITMAP_LEN], slot) {
1868 continue;
1869 }
1870 if map.owner[slot].is_some_and(|held| map.nodes[usize::from(held)].epoch > claimed) {
1871 return false;
1872 }
1873 }
1874 server.cluster.vote.given.store(epoch, Relaxed);
1875 map.nodes[usize::from(master)].voted_time = now;
1876 true
1877}
1878
1879/// How many replicas of the same master hold more data than this node does.
1880///
1881/// The reference's `clusterGetSlaveRank`, and the offsets it compares are the
1882/// ones the other replicas put in their own packets rather than anything asked
1883/// for, so a rank is always a little out of date and that is fine: it decides a
1884/// delay and not an outcome.
1885fn rank_of(map: &Map, master: u16, mine: u64) -> u64 {
1886 map.nodes
1887 .iter()
1888 .skip(1)
1889 .filter(|node| {
1890 node.master == Some(master)
1891 && node.flags & FLAG_SLAVE != 0
1892 && node.flags & FLAG_NOFAILOVER == 0
1893 && node.offset > mine
1894 })
1895 .count() as u64
1896}
1897
1898/// What the cron has to do about the election, worked out under the lock.
1899enum Step {
1900 /// Nothing, which is the answer on nearly every tick of nearly every node.
1901 Idle,
1902 /// The delay has just been worked out, so tell the other replicas of this
1903 /// master how far this node has got in case it changes their minds.
1904 Announce,
1905 /// Ask every node for a vote.
1906 Ask(Vec<u8>),
1907 /// The quorum is in and the slots are this node's now.
1908 Won,
1909}
1910
1911/// Work out what this tick of the election does, under the map lock.
1912///
1913/// The reference's `clusterHandleSlaveFailover`. Every branch of it returns and
1914/// waits for the next tick rather than carrying on, which is what makes the
1915/// whole thing readable: the state is in one place and each tick moves it at
1916/// most one step.
1917fn decide(server: &Arc<Server>, map: &mut Map, now: u64) -> Step {
1918 let vote = &server.cluster.vote;
1919 let manual = &server.cluster.manual;
1920 // A manual failover is one somebody asked for on this node, and once it is
1921 // ready it is allowed three things an automatic one is not: it does not need
1922 // the master to be gone, it ignores the flag that says this node would
1923 // rather not stand, and it does not care how far behind the data is. All
1924 // three are safe for the same reason, which is that the master is holding
1925 // its clients still and this node has caught up with everything it wrote.
1926 let asked = manual.end.load(Relaxed) != 0;
1927 let ready = asked && manual.can_start.load(Relaxed);
1928 // A replica of a master the cluster has given up on, which is willing to be
1929 // promoted, and whose master was serving something worth taking over.
1930 let me = &map.nodes[0];
1931 if me.flags & FLAG_SLAVE == 0 || (me.flags & FLAG_NOFAILOVER != 0 && !ready) {
1932 return Step::Idle;
1933 }
1934 let Some(master) = me.master else {
1935 return Step::Idle;
1936 };
1937 if map.nodes[usize::from(master)].flags & FLAG_FAIL == 0 && !ready {
1938 return Step::Idle;
1939 }
1940 if map.runs(master).is_empty() {
1941 return Step::Idle;
1942 }
1943 // How far out of touch with the master this node was before it died. The
1944 // node timeout comes off because that much silence is what made it dead in
1945 // the first place and is not the replica's fault.
1946 if !ready && server.master_silence(now).saturating_sub(NODE_TIMEOUT_MS) > STALE_DATA_MS {
1947 return Step::Idle;
1948 }
1949 let since = now as i64 - vote.at.load(Relaxed) as i64;
1950 if since > (ELECTION_TIMEOUT_MS * 2) as i64 {
1951 // Nothing running, or the last one is long enough ago to try again. The
1952 // delay is a fixed part, a random part and a part per replica that holds
1953 // more data than this one. None of that applies to a manual failover:
1954 // there is nothing to let propagate, nobody else is standing, and the
1955 // operator is waiting, so it goes now and at the front of the queue.
1956 let rank = if asked {
1957 0
1958 } else {
1959 rank_of(map, master, server.repl_offset())
1960 };
1961 let at = if asked {
1962 now
1963 } else {
1964 now + ELECTION_DELAY_MS
1965 + u64::from(pick(ELECTION_DELAY_MS as usize))
1966 + rank * RANK_DELAY_MS
1967 };
1968 vote.at.store(at, Relaxed);
1969 vote.rank.store(rank, Relaxed);
1970 vote.count.store(0, Relaxed);
1971 vote.sent.store(false, Relaxed);
1972 return Step::Announce;
1973 }
1974 if !vote.sent.load(Relaxed) {
1975 // Another replica may have said something since the delay was worked
1976 // out. Falling further down the order pushes the delay back, and
1977 // climbing it does not pull it forward, which is the reference's rule
1978 // and is what keeps two replicas swapping places from both asking at
1979 // once. Not done on a manual failover, where the delay is nought and
1980 // there is no order to fall down.
1981 if !asked {
1982 let rank = rank_of(map, master, server.repl_offset());
1983 let was = vote.rank.load(Relaxed);
1984 if rank > was {
1985 vote.at.fetch_add((rank - was) * RANK_DELAY_MS, Relaxed);
1986 vote.rank.store(rank, Relaxed);
1987 }
1988 }
1989 if now < vote.at.load(Relaxed) {
1990 return Step::Idle;
1991 }
1992 }
1993 if since > ELECTION_TIMEOUT_MS as i64 {
1994 // Too late to be worth counting. The retry window above is what starts
1995 // the next one.
1996 return Step::Idle;
1997 }
1998 if !vote.sent.load(Relaxed) {
1999 let epoch = server.cluster.epoch.fetch_add(1, Relaxed) + 1;
2000 vote.epoch.store(epoch, Relaxed);
2001 vote.sent.store(true, Relaxed);
2002 let mut packet = header(server, map, T_AUTH_REQUEST);
2003 // The master is up and is in on it, so say so, or every master asked
2004 // would refuse on the grounds that there is nothing wrong with it.
2005 if asked {
2006 packet[O_MFLAGS] |= MF_FORCEACK;
2007 }
2008 seal(&mut packet);
2009 return Step::Ask(packet);
2010 }
2011 if vote.count.load(Relaxed) < (map.size() / 2 + 1) as u64 {
2012 return Step::Idle;
2013 }
2014 let epoch = vote.epoch.load(Relaxed);
2015 replace_master(map, master, epoch);
2016 Step::Won
2017}
2018
2019/// Take everything the master was serving, under an epoch nobody else has used.
2020///
2021/// The reference's `clusterFailoverReplaceYourMaster` as far as the table goes,
2022/// and the epoch is what makes every other node believe this over whatever it
2023/// had written down. The caller has already made sure of the epoch, either by
2024/// winning an election under it or by bumping it on its own.
2025fn replace_master(map: &mut Map, master: u16, epoch: u64) {
2026 if map.nodes[0].epoch < epoch {
2027 map.nodes[0].epoch = epoch;
2028 }
2029 map.nodes[0].flags &= !FLAG_SLAVE;
2030 map.nodes[0].flags |= FLAG_MASTER;
2031 map.nodes[0].master = None;
2032 for slot in 0..SLOTS {
2033 if map.owner[slot] == Some(master) {
2034 map.owner[slot] = Some(0);
2035 }
2036 }
2037}
2038
2039/// The half of taking over that cannot be done while the table is locked.
2040fn won(server: &Arc<Server>) {
2041 server.stop_following();
2042 manual_reset(server);
2043 server.recount_coverage();
2044 server.cluster.bus.dirty.store(true, Relaxed);
2045 let _ = super::save(server);
2046 server.cluster_broadcast_pong();
2047}
2048
2049/// Stand for election when the master is gone, and take over on winning.
2050fn failover(server: &Arc<Server>, now: u64) {
2051 let step = {
2052 let mut map = server.cluster.map.lock();
2053 decide(server, &mut map, now)
2054 };
2055 match step {
2056 Step::Idle => {}
2057 // The reference sends this to the other replicas of the same master and
2058 // this sends it to everybody, which is a packet more per node on a
2059 // cluster that has just lost one and is the same answer.
2060 Step::Announce => server.cluster_broadcast_pong(),
2061 Step::Ask(packet) => {
2062 for link in server.cluster.bus.all() {
2063 link.send(&packet);
2064 }
2065 server.cluster.bus.dirty.store(true, Relaxed);
2066 }
2067 Step::Won => won(server),
2068 }
2069}
2070
2071// ------------------------------------------------------- the manual failover
2072
2073/// Forget any manual failover, lifting the pause if this node armed one.
2074///
2075/// The reference's `resetManualFailover`, and it is called on every way out of
2076/// one: the timeout, the takeover, winning, and being stood down by the node
2077/// that replaced this one. A master that is left holding a pause it armed for a
2078/// failover that never happened is the one outcome worth going out of the way to
2079/// avoid, since from a client it looks exactly like the server having stopped.
2080fn manual_reset(server: &Server) {
2081 let manual = &server.cluster.manual;
2082 let held = manual.held.swap(0, Relaxed);
2083 if held != 0 {
2084 server.lift(held, false);
2085 }
2086 manual.end.store(0, Relaxed);
2087 manual.can_start.store(false, Relaxed);
2088 manual.offset.store(OFFSET_UNKNOWN, Relaxed);
2089}
2090
2091/// A replica has asked this node to stand down, which is the reference's
2092/// `MFSTART` arm and is the whole of the master's part in a manual failover.
2093///
2094/// It stops taking writes and says where it stopped, and everything after that
2095/// is the replica's problem. The pause is what makes the whole thing worth
2096/// having: without it the replica would be chasing an offset that kept moving
2097/// and would either never catch up or take over having missed something.
2098fn stand_down(server: &Arc<Server>, map: &Map, at: u16, now: u64, todo: &mut Todo) {
2099 // Only from one of this node's own replicas, because holding every client
2100 // on this server still is a large thing to be talked into and the only node
2101 // it helps is one that is about to replace this one.
2102 let asking = &map.nodes[usize::from(at)];
2103 if asking.master != Some(0) || asking.flags & FLAG_SLAVE == 0 || !map.nodes[0].is_master() {
2104 return;
2105 }
2106 // A slot migration and a failover both decide who owns a slot, and running
2107 // them at once is the one way to end up with two answers. The migration is
2108 // the one that gets dropped, because it can be started again and a failover
2109 // that is already under way cannot.
2110 server.cluster.asm.cancel(None, now as i64);
2111 manual_reset(server);
2112 let manual = &server.cluster.manual;
2113 manual.end.store(now + MANUAL_TIMEOUT_MS, Relaxed);
2114 let until = now + MANUAL_TIMEOUT_MS * MANUAL_PAUSE_MULT;
2115 manual.held.store(until, Relaxed);
2116 server.pause(until, false);
2117 // Answered at once rather than left to the cron, because the ping carries
2118 // the offset the writes stopped at and that is the only thing the replica
2119 // is waiting for.
2120 yo_alloc::allow(|| todo.reply.push(ping(server, map, T_PING, Some(at))));
2121}
2122
2123/// Move a manual failover along by one tick, on whichever side of it this is.
2124///
2125/// The reference's `manualFailoverCheckTimeout` and `clusterHandleManualFailover`
2126/// in one, since they run one after the other and share every condition. All the
2127/// replica is waiting for is its own offset to reach the one the master stopped
2128/// at, and all the master is waiting for is somebody to take its slots off it or
2129/// the clock to run out.
2130fn manual_cron(server: &Arc<Server>, now: u64) {
2131 let manual = &server.cluster.manual;
2132 let end = manual.end.load(Relaxed);
2133 if end == 0 {
2134 return;
2135 }
2136 if end < now {
2137 manual_reset(server);
2138 return;
2139 }
2140 if manual.can_start.load(Relaxed) {
2141 return;
2142 }
2143 let offset = manual.offset.load(Relaxed);
2144 if offset != OFFSET_UNKNOWN && offset == server.repl_offset() {
2145 // Everything the master wrote is here, and nothing more is coming. This
2146 // is the moment a manual failover is safe, and it is the only moment,
2147 // which is why the whole handshake exists.
2148 manual.can_start.store(true, Relaxed);
2149 }
2150}
2151
2152/// `CLUSTER FAILOVER [FORCE|TAKEOVER]`, which is the reference's checks and then
2153/// one of its three ways of going about it.
2154///
2155/// The plain form asks the master to hold its clients still and waits for the
2156/// two offsets to meet, which is the only form that cannot lose a write. `FORCE`
2157/// skips the asking, which is for a master that is up but not answering, and
2158/// loses whatever it had not sent yet. `TAKEOVER` skips the election as well and
2159/// simply says this node owns the slots now under an epoch it made up, which is
2160/// for a cluster that has lost too many masters to hold an election at all.
2161pub(super) fn manual_failover(
2162 server: &Arc<Server>,
2163 force: bool,
2164 takeover: bool,
2165) -> Result<(), Error> {
2166 let now = server.now_ms();
2167 let mut ask: Option<(String, Vec<u8>)> = None;
2168 let mut promoted = false;
2169 {
2170 let mut map = server.cluster.map.lock();
2171 if map.nodes[0].is_master() {
2172 return Err(Error::new(
2173 Code::Invalid,
2174 "You should send CLUSTER FAILOVER to a replica",
2175 ));
2176 }
2177 let Some(master) = map.nodes[0].master else {
2178 return Err(Error::new(
2179 Code::Invalid,
2180 "I'm a replica but my master is unknown to me",
2181 ));
2182 };
2183 let node = &map.nodes[usize::from(master)];
2184 if !force && (node.flags & FLAG_FAIL != 0 || !node.linked) {
2185 return Err(Error::new(
2186 Code::Invalid,
2187 "Master is down or failed, please use CLUSTER FAILOVER FORCE",
2188 ));
2189 }
2190 manual_reset(server);
2191 server
2192 .cluster
2193 .manual
2194 .end
2195 .store(now + MANUAL_TIMEOUT_MS, Relaxed);
2196 if takeover {
2197 super::bump_without_consensus(server, &mut map);
2198 let epoch = map.nodes[0].epoch;
2199 replace_master(&mut map, master, epoch);
2200 promoted = true;
2201 } else if force {
2202 server.cluster.manual.can_start.store(true, Relaxed);
2203 } else {
2204 let mut packet = header(server, &map, T_MFSTART);
2205 seal(&mut packet);
2206 let id = yo_alloc::allow(|| map.nodes[usize::from(master)].id.clone());
2207 ask = Some((id, packet));
2208 }
2209 }
2210 if promoted {
2211 won(server);
2212 }
2213 if let Some((id, packet)) = ask
2214 && let Some(link) = server.cluster.bus.outbound(&id)
2215 {
2216 link.send(&packet);
2217 }
2218 Ok(())
2219}
2220
2221// ---------------------------------------------------------------- the cron
2222
2223/// The bus's own clock, which is where everything that is not a reply happens.
2224fn cron(server: &Arc<Server>) {
2225 let mut tick = 0u64;
2226 loop {
2227 std::thread::sleep(Duration::from_millis(CRON_MS));
2228 tick += 1;
2229 let now = server.now_ms();
2230 // Who needs a link, who needs a ping, and who has been quiet too long.
2231 // All decided under the lock and all carried out after it, because a
2232 // connect takes half a second in the worst case and the routing path
2233 // reads this table on every command.
2234 let mut dial_list: Vec<(String, String, u16, bool)> = Vec::new();
2235 let mut ping_list: Vec<(String, Vec<u8>)> = Vec::new();
2236 let mut shout: Vec<Vec<u8>> = Vec::new();
2237 let mut follow: Option<(String, u16)> = None;
2238 let mut save = false;
2239 let paused = server.cluster.manual.held.load(Relaxed) != 0;
2240 {
2241 let mut map = server.cluster.map.lock();
2242 let count = map.nodes.len();
2243 for at in 1..count as u16 {
2244 let node = &map.nodes[usize::from(at)];
2245 // A handshake that never completed is a node that is not there.
2246 if node.flags & FLAG_HANDSHAKE != 0
2247 && now.saturating_sub(node.data_recv) > NODE_TIMEOUT_MS.max(1000)
2248 {
2249 map.forget(at);
2250 save = true;
2251 break;
2252 }
2253 if node.flags & FLAG_NOADDR != 0 || node.host.is_empty() {
2254 continue;
2255 }
2256 if !node.linked {
2257 // Only a node this one was told to meet hears MEET, because
2258 // MEET is the packet that says trust me, I am not in another
2259 // cluster. Everything else is a plain ping, including a node
2260 // in handshake that was met the other way round.
2261 let meet = node.flags & FLAG_MEET != 0;
2262 yo_alloc::allow(|| {
2263 dial_list.push((node.id.clone(), node.host.clone(), node.bus, meet));
2264 });
2265 continue;
2266 }
2267 // A ping every second, or sooner for whoever this node has heard
2268 // from least recently out of five, which is the reference's way
2269 // of getting round a cluster in far fewer than N rounds.
2270 let quiet = now.saturating_sub(node.pong_recv);
2271 let due = node.ping_sent == 0 && quiet > PING_MS;
2272 // A master holding its clients still for a manual failover pings
2273 // its replicas on every tick instead of every second, because the
2274 // replica cannot move until it has seen a header saying the
2275 // writes have stopped and where, and a second of that is a second
2276 // of a server nobody can write to.
2277 let waiting = paused && node.master == Some(0);
2278 if due
2279 || waiting
2280 || (tick.is_multiple_of(10) && oldest_of_five(&map, now) == Some(at))
2281 {
2282 let packet = ping(server, &map, T_PING, Some(at));
2283 let id = yo_alloc::allow(|| map.nodes[usize::from(at)].id.clone());
2284 map.nodes[usize::from(at)].ping_sent = now;
2285 ping_list.push((id, packet));
2286 }
2287 }
2288 // Anybody who has not answered in time is possibly failed, which is
2289 // this node's opinion and becomes the cluster's once enough masters
2290 // share it.
2291 for at in 1..map.nodes.len() as u16 {
2292 let node = &map.nodes[usize::from(at)];
2293 if node.flags & (FLAG_HANDSHAKE | FLAG_FAIL | FLAG_PFAIL) != 0 {
2294 continue;
2295 }
2296 let waiting = if node.ping_sent == 0 {
2297 0
2298 } else {
2299 now.saturating_sub(node.ping_sent)
2300 };
2301 let quiet = now.saturating_sub(node.data_recv);
2302 if waiting.min(quiet) > NODE_TIMEOUT_MS {
2303 map.nodes[usize::from(at)].flags |= FLAG_PFAIL;
2304 save = true;
2305 }
2306 if mark_failing(&mut map, at, now) {
2307 let about = yo_alloc::allow(|| map.nodes[usize::from(at)].id.clone());
2308 shout.push(fail_packet(server, &map, &about));
2309 save = true;
2310 }
2311 }
2312 // A node whose table says it is a replica but which is not following
2313 // anybody starts following. That is how a replica comes back after a
2314 // restart, since the node table is on disk and the replication link
2315 // is not, and it is also how one that was told to replicate a node
2316 // it had no address for yet gets going once the address turns up.
2317 if map.nodes[0].flags & FLAG_SLAVE != 0
2318 && !server.following()
2319 && let Some(master) = map.nodes[0].master
2320 && let Some(node) = map.nodes.get(usize::from(master))
2321 && node.flags & FLAG_NOADDR == 0
2322 && !node.host.is_empty()
2323 {
2324 follow = yo_alloc::allow(|| Some((node.host.clone(), node.port)));
2325 }
2326 }
2327 // Called here and not on a thread of its own, because it starts the
2328 // replica thread and returns, and doing it here is what makes the guard
2329 // above true again before the next tick rather than a tick later.
2330 if let Some((host, port)) = follow {
2331 server.follow_master(&host, port);
2332 }
2333 for (id, host, bus, meet) in dial_list {
2334 if !dial(server, &id, &host, bus, meet) {
2335 continue;
2336 }
2337 let mut map = server.cluster.map.lock();
2338 if let Some(at) = map.find(id.as_bytes()) {
2339 map.nodes[usize::from(at)].linked = true;
2340 }
2341 }
2342 for (id, packet) in ping_list {
2343 if let Some(link) = server.cluster.bus.outbound(&id) {
2344 link.send(&packet);
2345 } else {
2346 // The link went between deciding to ping and sending it, so the
2347 // node is dialled again on the next tick. The ping is left
2348 // standing rather than taken back, because it is what failure
2349 // detection measures and a node that cannot be sent a ping is
2350 // exactly the node that should be running out of time.
2351 let mut map = server.cluster.map.lock();
2352 if let Some(at) = map.find(id.as_bytes()) {
2353 map.nodes[usize::from(at)].linked = false;
2354 }
2355 }
2356 }
2357 if !shout.is_empty() {
2358 for link in server.cluster.bus.all() {
2359 for packet in &shout {
2360 link.send(packet);
2361 }
2362 }
2363 }
2364 if save {
2365 server.cluster.bus.dirty.store(true, Relaxed);
2366 }
2367 server.recount_coverage();
2368 manual_cron(server, now);
2369 failover(server, now);
2370 server.asm_cron();
2371 server.asm_relax();
2372 // The file is written at most ten times a second and only when something
2373 // moved, which keeps a busy cluster from writing it on every packet.
2374 if tick.is_multiple_of(10) && server.cluster.bus.dirty.swap(false, Relaxed) {
2375 let _ = super::save(server);
2376 }
2377 }
2378}
2379
2380/// Whoever this node has heard from least recently, out of five drawn at random.
2381///
2382/// Five and not all of them because the point is to bias the ping order towards
2383/// the nodes that need one without walking the table every tenth of a second.
2384fn oldest_of_five(map: &Map, now: u64) -> Option<u16> {
2385 if map.nodes.len() < 2 {
2386 return None;
2387 }
2388 let mut best: Option<(u16, u64)> = None;
2389 for _ in 0..5 {
2390 let at = pick(map.nodes.len());
2391 if at == 0 {
2392 continue;
2393 }
2394 let node = &map.nodes[usize::from(at)];
2395 if node.ping_sent != 0 || node.flags & (FLAG_HANDSHAKE | FLAG_NOADDR) != 0 {
2396 continue;
2397 }
2398 let quiet = now.saturating_sub(node.pong_recv);
2399 if best.is_none_or(|(_, held)| quiet > held) {
2400 best = Some((at, quiet));
2401 }
2402 }
2403 best.map(|(at, _)| at)
2404}
2405
2406// ------------------------------------------------------- what the commands do
2407
2408impl Server {
2409 /// Start a handshake with a node at an address, which is `CLUSTER MEET`.
2410 ///
2411 /// Nothing is known about them yet, not even their id, so they go into the
2412 /// table under a name this node made up and the next tick opens a link and
2413 /// sends them a MEET. Their answer carries their real id, which replaces the
2414 /// made up one. That is why meeting a node twice is harmless and why meeting
2415 /// one that is already known is a no-op rather than a duplicate.
2416 pub(super) fn cluster_meet(&self, host: &str, port: u16, bus: u16) {
2417 let now = self.now_ms();
2418 let mut map = self.cluster.map.lock();
2419 let known = map
2420 .nodes
2421 .iter()
2422 .any(|node| node.host == host && node.port == port);
2423 if known {
2424 return;
2425 }
2426 let id = yo_alloc::allow(|| String::from_utf8_lossy(&new_id()).into_owned());
2427 let node = yo_alloc::allow(|| {
2428 Node::new(
2429 id,
2430 yo_alloc::allow(|| String::from(host)),
2431 port,
2432 bus,
2433 FLAG_HANDSHAKE | FLAG_MEET,
2434 now,
2435 )
2436 });
2437 yo_alloc::allow(|| map.nodes.push(node));
2438 }
2439
2440 /// Whether an id was forgotten on purpose recently, which is what makes
2441 /// forgetting the same node twice answer OK rather than complain.
2442 pub(super) fn cluster_blacklisted(&self, id: &str) -> bool {
2443 self.cluster.bus.blacklisted(id, self.now_ms())
2444 }
2445
2446 /// Drop a node and tell everybody else to, which is `CLUSTER FORGET`.
2447 ///
2448 /// The telling is the part that matters. Dropping a node on its own would
2449 /// last until the next gossip packet from anybody who still had it, so the
2450 /// id is refused for a minute here and the refusal is passed round in the
2451 /// extension that carries it.
2452 pub(super) fn cluster_forget(&self, at: u16) {
2453 let now = self.now_ms();
2454 let id = {
2455 let mut map = self.cluster.map.lock();
2456 let id = yo_alloc::allow(|| map.nodes[usize::from(at)].id.clone());
2457 map.forget(at);
2458 id
2459 };
2460 self.cluster.bus.blacklist(&id, now);
2461 self.cluster.bus.cut(&id);
2462 let packet = {
2463 let map = self.cluster.map.lock();
2464 let mut p = ping(self, &map, T_PING, None);
2465 // The forgotten node rides on the next ping rather than in a packet
2466 // of its own, which is the reference's design: there is no reliable
2467 // delivery on the bus, so a fact that has to reach everybody is
2468 // repeated rather than sent once.
2469 let mut body = [0u8; NAME_LEN + 8];
2470 body[..NAME_LEN].copy_from_slice(id.as_bytes());
2471 body[NAME_LEN..].copy_from_slice(&BLACKLIST_MS.to_be_bytes());
2472 push_ext(&mut p, X_FORGOTTEN, &body);
2473 let exts = be16(&p, O_EXTENSIONS) + 1;
2474 put16(&mut p, O_EXTENSIONS, exts);
2475 seal(&mut p);
2476 p
2477 };
2478 for link in self.cluster.bus.all() {
2479 link.send(&packet);
2480 }
2481 self.cluster.bus.dirty.store(true, Relaxed);
2482 }
2483
2484 /// Become a replica of another node, which is `CLUSTER REPLICATE`.
2485 pub(super) fn cluster_replicate(self: &Arc<Server>, at: u16) {
2486 // A node that has just been told whose replica it is has no business
2487 // still holding a manual failover open, and if it armed a pause for one
2488 // that pause goes with it.
2489 manual_reset(self);
2490 let (host, port) = {
2491 let mut map = self.cluster.map.lock();
2492 // Whatever slots this node was holding are not its any more, which
2493 // is the reference's rule and is why the command refuses when there
2494 // are keys in them.
2495 for slot in 0..SLOTS {
2496 if map.owner[slot] == Some(0) {
2497 map.owner[slot] = None;
2498 }
2499 }
2500 map.nodes[0].flags &= !(FLAG_MASTER | FLAG_MIGRATE_TO);
2501 map.nodes[0].flags |= FLAG_SLAVE;
2502 map.nodes[0].master = Some(at);
2503 let shard = yo_alloc::allow(|| map.nodes[usize::from(at)].shard.clone());
2504 yo_alloc::allow(|| map.nodes[0].shard = shard);
2505 let node = &map.nodes[usize::from(at)];
2506 (yo_alloc::allow(|| node.host.clone()), node.port)
2507 };
2508 self.recount_coverage();
2509 self.cluster.bus.dirty.store(true, Relaxed);
2510 if !host.is_empty() {
2511 self.follow_master(&host, port);
2512 }
2513 }
2514
2515 /// Send a published message to every other node, which is what makes a
2516 /// subscriber on one node hear a publish on another.
2517 ///
2518 /// Every node gets a copy of an ordinary publish, because an ordinary
2519 /// subscription is not tied to a slot and could be anywhere. A shard publish
2520 /// only needs to reach the shard that owns the slot, but the reference
2521 /// broadcasts it too and lets the far side drop it, so this does the same.
2522 pub(crate) fn cluster_publish(&self, shard: bool, channel: &[u8], body: &[u8]) {
2523 if !self.cluster_enabled() || !self.cluster.bus.on.load(Relaxed) {
2524 return;
2525 }
2526 let packet = {
2527 let map = self.cluster.map.lock();
2528 publish_packet(self, &map, shard, channel, body)
2529 };
2530 for link in self.cluster.bus.all() {
2531 link.send(&packet);
2532 }
2533 }
2534
2535 /// Send everybody a `PONG` right now rather than waiting for the cron.
2536 ///
2537 /// A `PONG` nobody asked for is how the reference tells the cluster about a
2538 /// configuration change it has just made to itself, and the only thing that
2539 /// makes it a `PONG` rather than a `PING` is that nobody is expected to
2540 /// answer it. What the far side actually reads is the header, which carries
2541 /// this node's slots and its config epoch, so one packet is the whole of the
2542 /// announcement.
2543 ///
2544 /// It matters after a slot import because the epoch has just gone up and the
2545 /// rest of the cluster is still pointing clients at the node the slot came
2546 /// from. Waiting the ordinary ping interval would leave every client that
2547 /// asked the wrong node being redirected to a node that no longer owns it.
2548 pub(super) fn cluster_broadcast_pong(&self) {
2549 if !self.cluster_enabled() || !self.cluster.bus.on.load(Relaxed) {
2550 return;
2551 }
2552 let packet = {
2553 let map = self.cluster.map.lock();
2554 ping(self, &map, T_PONG, None)
2555 };
2556 for link in self.cluster.bus.all() {
2557 link.send(&packet);
2558 }
2559 }
2560
2561 /// `CLUSTER LINKS`, which is one map per open link in each direction.
2562 pub(super) fn cluster_links(&self, out: &mut Out) {
2563 let links = self.cluster.bus.all();
2564 let at = out.len();
2565 let mut n = 0;
2566 for link in links {
2567 let node = link.named();
2568 // The reference only lists links it has associated with a node, and
2569 // an inbound link stays unassociated until a packet on it says who
2570 // is sending, so a connection that has said nothing is not a link
2571 // yet as far as this report is concerned.
2572 if node.is_empty() {
2573 continue;
2574 }
2575 out.map(6);
2576 out.bulk(b"direction");
2577 out.bulk(if link.inbound {
2578 b"from".as_slice()
2579 } else {
2580 b"to".as_slice()
2581 });
2582 out.bulk(b"node");
2583 out.bulk(node.as_bytes());
2584 out.bulk(b"create-time");
2585 out.int(link.created as i64);
2586 out.bulk(b"events");
2587 out.bulk(b"r");
2588 out.bulk(b"send-buffer-allocated");
2589 out.int(link.sent.load(Relaxed) as i64);
2590 out.bulk(b"send-buffer-used");
2591 out.int(0);
2592 n += 1;
2593 }
2594 out.close_array(at, n);
2595 }
2596}
2597
2598#[cfg(test)]
2599mod tests {
2600 use super::*;
2601
2602 #[test]
2603 fn a_bitmap_round_trips_through_the_reference_bit_order() {
2604 let mut bitmap = [0u8; BITMAP_LEN];
2605 for slot in [0usize, 1, 7, 8, 1234, 5061, 12182, SLOTS - 1] {
2606 set_bit(&mut bitmap, slot);
2607 }
2608 for slot in 0..SLOTS {
2609 let want = matches!(slot, 0 | 1 | 7 | 8 | 1234 | 5061 | 12182) || slot == SLOTS - 1;
2610 assert_eq!(bit(&bitmap, slot), want, "slot {slot}");
2611 }
2612 // Least significant bit first inside each byte, which is the one detail
2613 // a reader is likely to get backwards and the one the reference will not
2614 // forgive.
2615 assert_eq!(bitmap[0], 0b1000_0011);
2616 assert_eq!(bitmap[1], 0b0000_0001);
2617 }
2618
2619 #[test]
2620 fn an_extension_is_padded_to_the_eight_byte_boundary() {
2621 let mut p = Vec::new();
2622 push_ext(&mut p, X_SHARDID, &[b'a'; 40]);
2623 assert_eq!(p.len(), 48);
2624 assert_eq!(be32(&p, 0), 48);
2625 assert_eq!(be16(&p, 4), X_SHARDID);
2626 // A hostname is not a multiple of eight and has to be rounded up, which
2627 // is what `getAlignedPingExtSize` does.
2628 let mut q = Vec::new();
2629 push_ext(&mut q, X_HOSTNAME, b"node1.example\0");
2630 assert_eq!(q.len(), 8 + 16);
2631 assert_eq!(be32(&q, 0), 24);
2632 }
2633
2634 #[test]
2635 fn a_packet_of_the_wrong_length_is_refused() {
2636 let mut p = vec![0u8; HDR_LEN];
2637 p[0..4].copy_from_slice(SIG);
2638 put16(&mut p, O_VER, PROTO_VER);
2639 put16(&mut p, O_TYPE, T_PING);
2640 put16(&mut p, O_COUNT, 0);
2641 p[O_MFLAGS] = 0;
2642 seal(&mut p);
2643 assert_eq!(expected(&p, T_PING), Some(HDR_LEN));
2644 // One gossip entry claimed and none present is the shape every parser
2645 // bug has, so it has to come out as a length that does not match.
2646 put16(&mut p, O_COUNT, 1);
2647 assert_eq!(expected(&p, T_PING), Some(HDR_LEN + GOSSIP_LEN));
2648 assert_ne!(expected(&p, T_PING), Some(p.len()));
2649 }
2650
2651 /// A node table with a master that is about to fail, one replica of it and
2652 /// two other masters, which is the smallest cluster an election means
2653 /// anything on.
2654 ///
2655 /// Node 0 is this server and is the replica standing for election. Node 1 is
2656 /// its master and owns the first third of the slots, and nodes 2 and 3 own
2657 /// the rest, so the quorum is two and this node is not part of it.
2658 /// A wall clock reading, since every span in an election is measured
2659 /// against one and a node that has just started is not two node timeouts
2660 /// away from the epoch.
2661 const T0: u64 = 1_700_000_000_000;
2662
2663 fn shard() -> Arc<Server> {
2664 let mut server = Server::new();
2665 server.enable_cluster("", 7000);
2666 let server = Arc::new(server);
2667 let master = server.cluster_pretend_node("1".repeat(40).as_str(), "10.0.0.1", 7001);
2668 let other = server.cluster_pretend_node("2".repeat(40).as_str(), "10.0.0.2", 7002);
2669 let third = server.cluster_pretend_node("3".repeat(40).as_str(), "10.0.0.3", 7003);
2670 server.cluster_pretend_follower(master);
2671 {
2672 let mut map = server.cluster.map.lock();
2673 for slot in 0..SLOTS {
2674 map.owner[slot] = Some(match slot {
2675 0..=5460 => master,
2676 5461..=10922 => other,
2677 _ => third,
2678 });
2679 }
2680 }
2681 server.recount_coverage();
2682 server
2683 }
2684
2685 /// An `AUTH_REQUEST` as a replica of node 1 would send it.
2686 fn asking(epoch: u64, config: u64, forced: bool) -> Vec<u8> {
2687 let mut p = vec![0u8; HDR_LEN];
2688 put64(&mut p, O_CURRENT_EPOCH, epoch);
2689 put64(&mut p, O_CONFIG_EPOCH, config);
2690 for slot in 0..=5460 {
2691 set_bit(&mut p[O_SLOTS..O_SLOTS + BITMAP_LEN], slot);
2692 }
2693 p[O_MFLAGS] = if forced { MF_FORCEACK } else { 0 };
2694 p
2695 }
2696
2697 /// A node that cannot be dialled has to start running out of time, or the
2698 /// election it should be losing never happens.
2699 ///
2700 /// Failure detection measures the time since a ping went out, and a node
2701 /// with no link never gets one sent, so the address that stops answering is
2702 /// the one case where the clock has to be started by hand.
2703 #[test]
2704 fn a_node_that_cannot_be_reached_is_treated_as_pinged() {
2705 let server = shard();
2706 let id = "1".repeat(40);
2707 assert_eq!(server.cluster.map.lock().nodes[1].ping_sent, 0);
2708 unreachable(&server, &id);
2709 let first = server.cluster.map.lock().nodes[1].ping_sent;
2710 assert!(first > 0, "the clock is running");
2711 // And the next failed dial leaves it where it is, because the span that
2712 // matters is the one since the node went quiet and not the one since
2713 // the last attempt to reach it.
2714 unreachable(&server, &id);
2715 assert_eq!(server.cluster.map.lock().nodes[1].ping_sent, first);
2716 // A name nobody knows is not an error, it is a node that has been
2717 // forgotten between the decision to dial it and the attempt.
2718 unreachable(&server, &"9".repeat(40));
2719 }
2720
2721 /// Every reason a master has for not answering a replica that wants its
2722 /// master's slots, in the order a real server checks them.
2723 ///
2724 /// The order is the safety rather than a detail of the implementation, so
2725 /// each one is arranged to be the only thing wrong.
2726 #[test]
2727 fn a_vote_is_given_once_and_only_when_every_condition_holds() {
2728 let server = shard();
2729 // Stand this node up as a master serving the last third, and put a
2730 // replica of node 1 in the table for it to be asked about.
2731 {
2732 let mut map = server.cluster.map.lock();
2733 map.nodes[0].flags &= !FLAG_SLAVE;
2734 map.nodes[0].flags |= FLAG_MASTER;
2735 map.nodes[0].master = None;
2736 for slot in 10923..SLOTS {
2737 map.owner[slot] = Some(0);
2738 }
2739 let mut replica = Node::new(
2740 "4".repeat(40),
2741 "10.0.0.4".to_owned(),
2742 7004,
2743 7004 + 10000,
2744 FLAG_SLAVE,
2745 0,
2746 );
2747 replica.master = Some(1);
2748 map.nodes.push(replica);
2749 }
2750 let at = 4u16;
2751 let ask = |server: &Arc<Server>, p: &[u8], now: u64| {
2752 let mut map = server.cluster.map.lock();
2753 vote_if_needed(server, &mut map, at, p, now)
2754 };
2755 // A replica bumps the epoch before it asks and reading the packet pulls
2756 // this node's up to it, so by the time the question is put the two
2757 // agree and neither is nought.
2758 server.cluster.epoch.store(1, Relaxed);
2759
2760 // The master it wants to replace is up and nobody said this was a manual
2761 // failover, so there is nothing to vote about.
2762 assert!(!ask(&server, &asking(1, 0, false), T0));
2763 // A manual failover says so in the packet, and that is the whole
2764 // difference from where the voter is standing.
2765 assert!(ask(&server, &asking(1, 0, true), T0));
2766 // One vote per epoch, and it has gone.
2767 assert!(!ask(&server, &asking(1, 0, true), T0));
2768
2769 // Give up on node 1 and move the epoch on, which is what a real replica
2770 // would have done before asking again.
2771 server.cluster.epoch.store(2, Relaxed);
2772 {
2773 let mut map = server.cluster.map.lock();
2774 map.nodes[1].flags |= FLAG_FAIL;
2775 }
2776 // Not twice about the same master inside two node timeouts, however
2777 // dead it is, because the first replica may still be winning.
2778 assert!(!ask(&server, &asking(2, 0, false), T0 + NODE_TIMEOUT_MS));
2779 let later = T0 + NODE_TIMEOUT_MS * 2 + 1;
2780 // A request that was stale before it arrived.
2781 assert!(!ask(&server, &asking(1, 0, false), later));
2782 // A node that is not a replica has no master to replace.
2783 {
2784 let mut map = server.cluster.map.lock();
2785 map.nodes[4].flags &= !FLAG_SLAVE;
2786 }
2787 assert!(!ask(&server, &asking(2, 0, false), later));
2788 {
2789 let mut map = server.cluster.map.lock();
2790 map.nodes[4].flags |= FLAG_SLAVE;
2791 }
2792 // Slots that have already moved somewhere newer than the epoch the
2793 // replica would claim them under. Voting for that would undo the move.
2794 {
2795 let mut map = server.cluster.map.lock();
2796 map.owner[3000] = Some(2);
2797 map.nodes[2].epoch = 7;
2798 }
2799 assert!(!ask(&server, &asking(2, 6, false), later));
2800 // The same request under an epoch that is not behind is fine.
2801 assert!(ask(&server, &asking(2, 7, false), later));
2802 assert_eq!(server.cluster.vote.given(), 2);
2803
2804 // And a node with no slots of its own is not part of the electorate at
2805 // all, however much it knows about the shard.
2806 server.cluster.epoch.store(3, Relaxed);
2807 {
2808 let mut map = server.cluster.map.lock();
2809 for slot in 0..SLOTS {
2810 if map.owner[slot] == Some(0) {
2811 map.owner[slot] = Some(3);
2812 }
2813 }
2814 }
2815 assert!(!ask(
2816 &server,
2817 &asking(3, 7, false),
2818 later + NODE_TIMEOUT_MS * 3
2819 ));
2820 }
2821
2822 /// A replica of a master the cluster has given up on waits its turn, asks
2823 /// once, and takes the slots over when the quorum is in.
2824 #[test]
2825 fn an_election_waits_then_asks_then_wins() {
2826 let server = shard();
2827 let step = |server: &Arc<Server>, now: u64| {
2828 let mut map = server.cluster.map.lock();
2829 decide(server, &mut map, now)
2830 };
2831
2832 // The master is up, so there is no election to hold.
2833 assert!(matches!(step(&server, T0), Step::Idle));
2834 {
2835 let mut map = server.cluster.map.lock();
2836 map.nodes[1].flags |= FLAG_FAIL;
2837 }
2838 // The first tick after that works out when this node may ask and tells
2839 // the other replicas how far it has got.
2840 assert!(matches!(step(&server, T0), Step::Announce));
2841 let at = server.cluster.vote.at.load(Relaxed);
2842 assert!(
2843 (T0 + 500..=T0 + 1000).contains(&at),
2844 "half a second plus up to half a second more, got {at}"
2845 );
2846 // Until then there is nothing to do.
2847 assert!(matches!(step(&server, at - 1), Step::Idle));
2848
2849 // A replica that turns out to hold more data than this one pushes the
2850 // turn back by a second, and one that falls behind does not pull it
2851 // forward again.
2852 {
2853 let mut map = server.cluster.map.lock();
2854 let mut ahead = Node::new(
2855 "5".repeat(40),
2856 "10.0.0.5".to_owned(),
2857 7005,
2858 7005 + 10000,
2859 FLAG_SLAVE,
2860 0,
2861 );
2862 ahead.master = Some(1);
2863 ahead.offset = 900;
2864 map.nodes.push(ahead);
2865 }
2866 assert!(matches!(step(&server, at), Step::Idle));
2867 assert_eq!(server.cluster.vote.at.load(Relaxed), at + RANK_DELAY_MS);
2868 {
2869 let mut map = server.cluster.map.lock();
2870 map.nodes[4].offset = 0;
2871 }
2872 assert!(matches!(step(&server, at), Step::Idle));
2873 assert_eq!(server.cluster.vote.at.load(Relaxed), at + RANK_DELAY_MS);
2874
2875 // Then it asks, once, under an epoch of its own.
2876 let now = at + RANK_DELAY_MS;
2877 let Step::Ask(packet) = step(&server, now) else {
2878 panic!("the turn has come");
2879 };
2880 assert_eq!(be64(&packet, O_CURRENT_EPOCH), 1);
2881 assert_eq!(server.cluster.vote.epoch.load(Relaxed), 1);
2882 // The slots in the request are the master's, because those are the ones
2883 // the answer is about.
2884 assert!(bit(&packet[O_SLOTS..O_SLOTS + BITMAP_LEN], 5460));
2885 assert!(!bit(&packet[O_SLOTS..O_SLOTS + BITMAP_LEN], 5461));
2886 assert!(matches!(step(&server, now), Step::Idle), "asked already");
2887
2888 // One vote out of the three masters is not a quorum.
2889 server.cluster.vote.count.store(1, Relaxed);
2890 assert!(matches!(step(&server, now), Step::Idle));
2891 server.cluster.vote.count.store(2, Relaxed);
2892 assert!(matches!(step(&server, now), Step::Won));
2893
2894 let map = server.cluster.map.lock();
2895 assert!(map.nodes[0].is_master());
2896 assert_eq!(map.nodes[0].master, None);
2897 assert_eq!(map.nodes[0].epoch, 1, "the epoch it stood under");
2898 assert_eq!(map.owner[0], Some(0));
2899 assert_eq!(map.owner[5460], Some(0));
2900 assert_eq!(map.owner[5461], Some(2), "somebody else's slots are theirs");
2901 }
2902
2903 /// An election this node has no business holding is not held.
2904 #[test]
2905 fn a_replica_that_should_not_stand_does_not() {
2906 let refused = |now: u64, set: fn(&Arc<Server>)| {
2907 let server = shard();
2908 {
2909 let mut map = server.cluster.map.lock();
2910 map.nodes[1].flags |= FLAG_FAIL;
2911 }
2912 set(&server);
2913 let mut map = server.cluster.map.lock();
2914 matches!(decide(&server, &mut map, now), Step::Idle)
2915 };
2916 // A master does not stand for election, whatever has happened to
2917 // anybody else.
2918 assert!(refused(T0, |server| {
2919 let mut map = server.cluster.map.lock();
2920 map.nodes[0].flags &= !FLAG_SLAVE;
2921 map.nodes[0].flags |= FLAG_MASTER;
2922 }));
2923 // A replica that has been told not to.
2924 assert!(refused(T0, |server| {
2925 let mut map = server.cluster.map.lock();
2926 map.nodes[0].flags |= FLAG_NOFAILOVER;
2927 }));
2928 // A master that was serving nothing has nothing to take over.
2929 assert!(refused(T0, |server| {
2930 let mut map = server.cluster.map.lock();
2931 for slot in 0..=5460 {
2932 map.owner[slot] = Some(2);
2933 }
2934 }));
2935 // Data too old to be worth promoting. The link went down long enough
2936 // ago that this node has missed more than a failover is allowed to
2937 // lose, on top of the silence that made the master dead.
2938 let stale = T0 + NODE_TIMEOUT_MS + STALE_DATA_MS + 1;
2939 assert!(refused(stale, |server| {
2940 server.pretend_following("10.0.0.1", 7001, false);
2941 server.pretend_master_down_at(T0);
2942 }));
2943 // A second less and it stands, which is what makes the line above a
2944 // test of the bound rather than of the setup.
2945 assert!(!refused(stale - 1000, |server| {
2946 server.pretend_following("10.0.0.1", 7001, false);
2947 server.pretend_master_down_at(T0);
2948 }));
2949 }
2950
2951 /// The same table the other way round, with this node as the master and
2952 /// node 1 as the replica that is about to ask it to stand down.
2953 fn standing() -> Arc<Server> {
2954 let server = shard();
2955 {
2956 let mut map = server.cluster.map.lock();
2957 map.nodes[0].flags &= !FLAG_SLAVE;
2958 map.nodes[0].flags |= FLAG_MASTER;
2959 map.nodes[0].master = None;
2960 map.nodes[1].flags &= !FLAG_MASTER;
2961 map.nodes[1].flags |= FLAG_SLAVE;
2962 map.nodes[1].master = Some(0);
2963 for slot in 0..=5460 {
2964 map.owner[slot] = Some(0);
2965 }
2966 }
2967 server.recount_coverage();
2968 server
2969 }
2970
2971 /// The master's half of a manual failover, which is to stop taking writes
2972 /// and say where it stopped.
2973 #[test]
2974 fn a_master_asked_to_stand_down_stops_writing_and_says_where() {
2975 let server = standing();
2976 let mut todo = Todo::default();
2977 {
2978 let map = server.cluster.map.lock();
2979 stand_down(&server, &map, 2, T0, &mut todo);
2980 }
2981 assert!(todo.reply.is_empty(), "only a replica of this node may ask");
2982 assert_eq!(server.pause_ends(), 0);
2983
2984 {
2985 let map = server.cluster.map.lock();
2986 stand_down(&server, &map, 1, T0, &mut todo);
2987 }
2988 let reply = todo
2989 .reply
2990 .first()
2991 .expect("answered at once, not by the cron");
2992 assert_eq!(be16(reply, O_TYPE), T_PING);
2993 assert!(
2994 reply[O_MFLAGS] & MF_PAUSED != 0,
2995 "and the answer says the writes have stopped"
2996 );
2997 assert_eq!(be64(reply, O_OFFSET), server.repl_offset());
2998 // Held for twice as long as the failover has to finish in, so that the
2999 // master is still holding them at the moment the replica gives up.
3000 assert_eq!(
3001 server.pause_ends(),
3002 T0 + MANUAL_TIMEOUT_MS * MANUAL_PAUSE_MULT
3003 );
3004 assert_eq!(
3005 server.paused(T0),
3006 Some(false),
3007 "the writes and not the reads"
3008 );
3009
3010 // And lets go on its own when nothing came of it, which is the one
3011 // outcome worth going out of the way to avoid getting wrong.
3012 manual_cron(&server, T0 + MANUAL_TIMEOUT_MS + 1);
3013 assert_eq!(server.cluster.manual.end.load(Relaxed), 0);
3014 assert_eq!(server.pause_ends(), 0);
3015 }
3016
3017 /// The replica's half, which is to wait for the offsets to meet and then go
3018 /// straight to the front of the queue.
3019 #[test]
3020 fn a_manual_failover_waits_for_the_offsets_to_meet() {
3021 let server = shard();
3022 let step = |now: u64| {
3023 let mut map = server.cluster.map.lock();
3024 decide(&server, &mut map, now)
3025 };
3026 let manual = &server.cluster.manual;
3027 manual.end.store(T0 + MANUAL_TIMEOUT_MS, Relaxed);
3028
3029 // The master is up and has not said anything yet, so there is nothing
3030 // to stand for.
3031 assert!(matches!(step(T0), Step::Idle));
3032 manual_cron(&server, T0);
3033 assert!(!manual.can_start.load(Relaxed), "no offset from the master");
3034 manual.offset.store(server.repl_offset() + 1, Relaxed);
3035 manual_cron(&server, T0);
3036 assert!(!manual.can_start.load(Relaxed), "still behind the master");
3037 assert!(matches!(step(T0), Step::Idle));
3038
3039 // Caught up with everything the master wrote before it stopped, which
3040 // is the moment this is safe and the only one.
3041 manual.offset.store(server.repl_offset(), Relaxed);
3042 manual_cron(&server, T0);
3043 assert!(manual.can_start.load(Relaxed));
3044
3045 // No fixed delay, no random delay and no rank, because there is nothing
3046 // to let propagate and nobody else is standing.
3047 assert!(matches!(step(T0), Step::Announce));
3048 assert_eq!(server.cluster.vote.at.load(Relaxed), T0);
3049 assert_eq!(server.cluster.vote.rank.load(Relaxed), 0);
3050 let Step::Ask(packet) = step(T0) else {
3051 panic!("nothing to wait for on this path");
3052 };
3053 assert!(
3054 packet[O_MFLAGS] & MF_FORCEACK != 0,
3055 "the master is up and is in on it, so say so"
3056 );
3057
3058 server.cluster.vote.count.store(2, Relaxed);
3059 assert!(matches!(step(T0), Step::Won));
3060 let map = server.cluster.map.lock();
3061 assert!(map.nodes[0].is_master());
3062 assert_eq!(map.owner[5460], Some(0));
3063 assert_eq!(
3064 map.owner[5461],
3065 Some(2),
3066 "and nothing that was not its master's"
3067 );
3068 }
3069
3070 /// `CLUSTER FAILOVER` refuses where the reference refuses, and each of its
3071 /// three forms does a different amount of asking.
3072 #[test]
3073 fn cluster_failover_refuses_where_the_reference_refuses() {
3074 let ends = |e: Error, want: &str| {
3075 let text = e.to_string();
3076 assert!(text.ends_with(want), "wanted {want}, got {text}");
3077 };
3078 let server = standing();
3079 ends(
3080 manual_failover(&server, false, false).unwrap_err(),
3081 "You should send CLUSTER FAILOVER to a replica",
3082 );
3083 {
3084 let mut map = server.cluster.map.lock();
3085 map.nodes[0].flags &= !FLAG_MASTER;
3086 map.nodes[0].flags |= FLAG_SLAVE;
3087 map.nodes[0].master = None;
3088 }
3089 ends(
3090 manual_failover(&server, false, false).unwrap_err(),
3091 "I'm a replica but my master is unknown to me",
3092 );
3093
3094 // A master with no link to it cannot be asked to hold its clients
3095 // still, so the plain form says which form to use instead.
3096 let server = shard();
3097 server.cluster.map.lock().nodes[1].linked = false;
3098 ends(
3099 manual_failover(&server, false, false).unwrap_err(),
3100 "Master is down or failed, please use CLUSTER FAILOVER FORCE",
3101 );
3102 server.cluster.map.lock().nodes[1].linked = true;
3103 server.cluster.map.lock().nodes[1].flags |= FLAG_FAIL;
3104 ends(
3105 manual_failover(&server, false, false).unwrap_err(),
3106 "Master is down or failed, please use CLUSTER FAILOVER FORCE",
3107 );
3108 server.cluster.map.lock().nodes[1].flags &= !FLAG_FAIL;
3109 manual_failover(&server, false, false).unwrap();
3110 assert_ne!(server.cluster.manual.end.load(Relaxed), 0);
3111 assert!(
3112 !server.cluster.manual.can_start.load(Relaxed),
3113 "the plain form waits for the master to answer"
3114 );
3115 assert!(server.cluster.map.lock().nodes[0].flags & FLAG_SLAVE != 0);
3116
3117 // FORCE does not ask the master, but it does still stand for election.
3118 let server = shard();
3119 manual_failover(&server, true, false).unwrap();
3120 assert!(server.cluster.manual.can_start.load(Relaxed));
3121 assert!(server.cluster.map.lock().nodes[0].flags & FLAG_SLAVE != 0);
3122
3123 // TAKEOVER does not ask anybody at all.
3124 let server = shard();
3125 manual_failover(&server, true, true).unwrap();
3126 assert_eq!(
3127 server.cluster.manual.end.load(Relaxed),
3128 0,
3129 "nothing left to wait for"
3130 );
3131 let map = server.cluster.map.lock();
3132 assert!(map.nodes[0].is_master());
3133 assert_eq!(map.nodes[0].epoch, 1, "under an epoch it made up");
3134 assert_eq!(map.owner[0], Some(0));
3135 assert_eq!(map.owner[5460], Some(0));
3136 assert_eq!(map.owner[5461], Some(2));
3137 }
3138
3139 #[test]
3140 fn a_node_id_has_to_be_forty_hex_characters() {
3141 let mut p = vec![0u8; NAME_LEN * 3];
3142 assert_eq!(node_id(&p, 0), None, "all zeros is the reference's no node");
3143 p[0..NAME_LEN].copy_from_slice(&[b'a'; NAME_LEN]);
3144 assert_eq!(node_id(&p, 0).as_deref(), Some("a".repeat(40).as_str()));
3145 p[5] = b'z';
3146 assert_eq!(node_id(&p, 0), None);
3147 assert_eq!(node_id(&p, NAME_LEN * 3), None, "off the end is not an id");
3148 }
3149}