1use std::io::{Read, Write};
41use std::net::{Shutdown, TcpListener, TcpStream};
42use std::sync::atomic::Ordering::Relaxed;
43use std::sync::atomic::{AtomicBool, AtomicU64};
44use std::sync::{Arc, Mutex};
45use std::time::Duration;
46
47use yo_common::lock::Lock;
48
49use super::super::Server;
50use super::super::pubsub::{self, Kind};
51use super::{
52 FLAG_FAIL, FLAG_HANDSHAKE, FLAG_MASTER, FLAG_MEET, FLAG_MIGRATE_TO, FLAG_MYSELF, FLAG_NOADDR,
53 FLAG_NOFAILOVER, FLAG_PFAIL, FLAG_SLAVE, Map, Node, SLOTS, new_id,
54};
55use crate::reply::Out;
56
57const SIG: &[u8; 4] = b"RCmb";
62
63const PROTO_VER: u16 = 1;
66
67const NAME_LEN: usize = 40;
69
70const IP_LEN: usize = 46;
73
74const BITMAP_LEN: usize = SLOTS / 8;
76
77const HDR_LEN: usize = 2256;
80
81const GOSSIP_LEN: usize = 104;
83
84const MAX_PACKET: usize = 64 * 1024 * 1024;
90
91const O_TOTLEN: usize = 4;
94const O_VER: usize = 8;
95const O_PORT: usize = 10;
96const O_TYPE: usize = 12;
97const O_COUNT: usize = 14;
98const O_CURRENT_EPOCH: usize = 16;
99const O_CONFIG_EPOCH: usize = 24;
100const O_OFFSET: usize = 32;
101const O_SENDER: usize = 40;
102const O_SLOTS: usize = 80;
103const O_SLAVEOF: usize = 2128;
104const O_MYIP: usize = 2168;
105const O_EXTENSIONS: usize = 2214;
106const O_PPORT: usize = 2246;
107const O_CPORT: usize = 2248;
108const O_FLAGS: usize = 2250;
109const O_STATE: usize = 2252;
110const O_MFLAGS: usize = 2253;
111
112const G_NAME: usize = 0;
114const G_PING: usize = 40;
115const G_PONG: usize = 44;
116const G_IP: usize = 48;
117const G_PORT: usize = 94;
118const G_CPORT: usize = 96;
119const G_FLAGS: usize = 98;
120
121const T_PING: u16 = 0;
123const T_PONG: u16 = 1;
124const T_MEET: u16 = 2;
125const T_FAIL: u16 = 3;
126const T_PUBLISH: u16 = 4;
127const T_AUTH_REQUEST: u16 = 5;
128const T_AUTH_ACK: u16 = 6;
129const T_UPDATE: u16 = 7;
130const T_MFSTART: u16 = 8;
131const T_MODULE: u16 = 9;
132const T_PUBLISHSHARD: u16 = 10;
133
134const MF_EXT_DATA: u8 = 4;
137
138const X_HOSTNAME: u16 = 0;
140const X_HUMAN_NAME: u16 = 1;
141const X_FORGOTTEN: u16 = 2;
142const X_SHARDID: u16 = 3;
143const X_SECRET: u16 = 4;
144
145const STATE_OK: u8 = 0;
149const STATE_FAIL: u8 = 1;
150
151const BLACKLIST_MS: u64 = 60_000;
158
159const CRON_MS: u64 = 100;
161
162const PING_MS: u64 = 1000;
166
167const NODE_TIMEOUT_MS: u64 = 15_000;
169
170const CONNECT_TIMEOUT: Duration = Duration::from_millis(500);
173
174fn be16(p: &[u8], at: usize) -> u16 {
181 p.get(at..at + 2)
182 .map_or(0, |b| u16::from_be_bytes([b[0], b[1]]))
183}
184
185fn be32(p: &[u8], at: usize) -> u32 {
186 p.get(at..at + 4)
187 .map_or(0, |b| u32::from_be_bytes([b[0], b[1], b[2], b[3]]))
188}
189
190fn be64(p: &[u8], at: usize) -> u64 {
191 p.get(at..at + 8).map_or(0, |b| {
192 u64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
193 })
194}
195
196fn put16(p: &mut [u8], at: usize, v: u16) {
199 p[at..at + 2].copy_from_slice(&v.to_be_bytes());
200}
201
202fn put64(p: &mut [u8], at: usize, v: u64) {
203 p[at..at + 8].copy_from_slice(&v.to_be_bytes());
204}
205
206fn text(p: &[u8], at: usize, len: usize) -> String {
209 let Some(raw) = p.get(at..at + len) else {
210 return String::new();
211 };
212 let end = raw.iter().position(|b| *b == 0).unwrap_or(len);
213 String::from_utf8_lossy(&raw[..end]).into_owned()
214}
215
216fn node_id(p: &[u8], at: usize) -> Option<String> {
220 let raw = p.get(at..at + NAME_LEN)?;
221 if raw.iter().all(|b| *b == 0) {
222 return None;
223 }
224 if !raw.iter().all(u8::is_ascii_hexdigit) {
225 return None;
226 }
227 Some(String::from_utf8_lossy(raw).into_owned())
228}
229
230fn bit(bitmap: &[u8], slot: usize) -> bool {
233 bitmap
234 .get(slot / 8)
235 .is_some_and(|b| b & (1 << (slot % 8)) != 0)
236}
237
238fn set_bit(bitmap: &mut [u8], slot: usize) {
240 bitmap[slot / 8] |= 1 << (slot % 8);
241}
242
243fn pick(n: usize) -> u16 {
248 let mut raw = [0u8; 8];
249 yo_common::entropy::fill(&mut raw);
250 (u64::from_be_bytes(raw) % n as u64) as u16
251}
252
253pub(super) struct Wire {
264 pub(super) inbound: bool,
267 pub(super) node: Lock<String>,
270 pub(super) created: u64,
272 peer: String,
275 local: String,
277 sock: Mutex<TcpStream>,
281 dead: AtomicBool,
284 sent: AtomicU64,
288}
289
290impl Wire {
291 fn new(sock: TcpStream, inbound: bool, node: &str, now: u64) -> Option<Arc<Wire>> {
293 let peer = sock.peer_addr().ok()?.ip().to_string();
294 let local = sock.local_addr().ok()?.ip().to_string();
295 Some(Arc::new(Wire {
296 inbound,
297 node: Lock::new(String::from(node)),
298 created: now,
299 peer,
300 local,
301 sock: Mutex::new(sock),
302 dead: AtomicBool::new(false),
303 sent: AtomicU64::new(0),
304 }))
305 }
306
307 fn named(&self) -> String {
309 let held = self.node.lock();
310 yo_alloc::allow(|| held.clone())
311 }
312
313 fn name(&self, id: &str) {
316 let mut held = self.node.lock();
317 yo_alloc::allow(|| {
318 held.clear();
319 held.push_str(id);
320 });
321 }
322
323 fn send(&self, packet: &[u8]) {
331 if self.dead.load(Relaxed) {
332 return;
333 }
334 let Ok(mut sock) = self.sock.lock() else {
335 self.dead.store(true, Relaxed);
336 return;
337 };
338 if sock.write_all(packet).is_err() {
339 self.dead.store(true, Relaxed);
340 let _ = sock.shutdown(Shutdown::Both);
341 return;
342 }
343 self.sent.store(packet.len() as u64, Relaxed);
344 }
345
346 fn kill(&self) {
348 self.dead.store(true, Relaxed);
349 if let Ok(sock) = self.sock.lock() {
350 let _ = sock.shutdown(Shutdown::Both);
351 }
352 }
353}
354
355#[derive(Default)]
361pub(super) struct Bus {
362 links: Lock<Vec<Arc<Wire>>>,
364 blacklist: Lock<Vec<(String, u64)>>,
366 pub(super) secret: Lock<String>,
370 on: AtomicBool,
372 dirty: AtomicBool,
374}
375
376impl Bus {
377 fn add(&self, wire: &Arc<Wire>) {
379 let mut links = self.links.lock();
380 yo_alloc::allow(|| {
381 links.retain(|held| !held.dead.load(Relaxed));
382 links.push(Arc::clone(wire));
383 });
384 }
385
386 fn outbound(&self, id: &str) -> Option<Arc<Wire>> {
388 let links = self.links.lock();
389 links
390 .iter()
391 .find(|held| !held.inbound && !held.dead.load(Relaxed) && *held.node.lock() == *id)
392 .map(Arc::clone)
393 }
394
395 fn all(&self) -> Vec<Arc<Wire>> {
397 let links = self.links.lock();
398 yo_alloc::allow(|| {
399 links
400 .iter()
401 .filter(|held| !held.dead.load(Relaxed))
402 .map(Arc::clone)
403 .collect()
404 })
405 }
406
407 fn cut(&self, id: &str) {
410 let mut links = self.links.lock();
411 links.retain(|held| {
412 let theirs = held.node.lock();
413 if *theirs != *id {
414 return true;
415 }
416 drop(theirs);
417 held.kill();
418 false
419 });
420 }
421
422 fn blacklisted(&self, id: &str, now: u64) -> bool {
425 let mut list = self.blacklist.lock();
426 list.retain(|(_, until)| *until > now);
427 list.iter().any(|(held, _)| held == id)
428 }
429
430 fn blacklist(&self, id: &str, now: u64) {
432 let mut list = self.blacklist.lock();
433 yo_alloc::allow(|| {
434 list.retain(|(held, until)| held != id && *until > now);
435 list.push((String::from(id), now + BLACKLIST_MS));
436 });
437 }
438}
439
440impl Server {
443 pub fn start_cluster_bus(self: &Arc<Server>) -> Result<(), String> {
456 if !self.cluster_enabled() || self.cluster.bus.on.swap(true, Relaxed) {
457 return Ok(());
458 }
459 let (port, id) = {
460 let map = self.cluster.map.lock();
461 (
462 map.nodes[0].bus,
463 yo_alloc::allow(|| map.nodes[0].id.clone()),
464 )
465 };
466 let door = TcpListener::bind(("0.0.0.0", port))
467 .map_err(|e| format!("cluster bus port {port} could not be bound: {e}"))?;
468 let _ = id;
469 let accepting = Arc::clone(self);
470 spawn("yo-bus-accept", move || accept(&accepting, &door));
471 let ticking = Arc::clone(self);
472 spawn("yo-bus-cron", move || cron(&ticking));
473 Ok(())
474 }
475}
476
477fn spawn(name: &str, body: impl FnOnce() + Send + 'static) {
479 yo_alloc::allow(|| {
480 let _ = std::thread::Builder::new()
481 .name(String::from(name))
482 .spawn(body);
483 });
484}
485
486fn accept(server: &Arc<Server>, door: &TcpListener) {
488 loop {
489 let Ok((sock, _)) = door.accept() else {
490 std::thread::sleep(Duration::from_millis(CRON_MS));
491 continue;
492 };
493 let _ = sock.set_nodelay(true);
494 let now = server.now_ms();
495 let Some(wire) = Wire::new(sock, true, "", now) else {
496 continue;
497 };
498 server.cluster.bus.add(&wire);
499 let reading = Arc::clone(server);
500 spawn("yo-bus-link", move || pump(&reading, &wire));
501 }
502}
503
504fn dial(server: &Arc<Server>, id: &str, host: &str, bus: u16, meet: bool) -> bool {
510 let Ok(addrs) = std::net::ToSocketAddrs::to_socket_addrs(&(host, bus)) else {
511 return false;
512 };
513 let mut sock = None;
514 for addr in addrs {
515 if let Ok(open) = TcpStream::connect_timeout(&addr, CONNECT_TIMEOUT) {
516 sock = Some(open);
517 break;
518 }
519 }
520 let Some(sock) = sock else {
521 return false;
522 };
523 let _ = sock.set_nodelay(true);
524 let now = server.now_ms();
525 let Some(wire) = Wire::new(sock, false, id, now) else {
526 return false;
527 };
528 server.cluster.bus.add(&wire);
529 let packet = {
533 let mut map = server.cluster.map.lock();
534 let at = map.find(id.as_bytes());
535 if let Some(at) = at {
536 map.nodes[usize::from(at)].linked = true;
537 map.nodes[usize::from(at)].flags &= !FLAG_MEET;
541 if !meet {
542 map.nodes[usize::from(at)].ping_sent = now;
543 }
544 }
545 ping(server, &map, if meet { T_MEET } else { T_PING }, at)
546 };
547 wire.send(&packet);
548 let reading = Arc::clone(server);
549 spawn("yo-bus-link", move || pump(&reading, &wire));
550 true
551}
552
553fn pump(server: &Arc<Server>, wire: &Arc<Wire>) {
555 let sock = {
556 let Ok(held) = wire.sock.lock() else {
557 return;
558 };
559 held.try_clone()
560 };
561 let Ok(mut sock) = sock else {
562 wire.kill();
563 return;
564 };
565 let mut head = [0u8; 8];
566 let mut buf: Vec<u8> = yo_alloc::allow(|| Vec::with_capacity(HDR_LEN * 2));
567 loop {
568 if wire.dead.load(Relaxed) || sock.read_exact(&mut head).is_err() {
569 break;
570 }
571 if &head[0..4] != SIG {
572 break;
573 }
574 let total = u32::from_be_bytes([head[4], head[5], head[6], head[7]]) as usize;
575 if !(16..=MAX_PACKET).contains(&total) {
576 break;
577 }
578 yo_alloc::allow(|| {
579 buf.clear();
580 buf.resize(total, 0);
581 });
582 buf[..8].copy_from_slice(&head);
583 if sock.read_exact(&mut buf[8..]).is_err() {
584 break;
585 }
586 if !process(server, wire, &buf) {
587 break;
588 }
589 }
590 wire.kill();
591 let name = wire.named();
594 if !name.is_empty() && !wire.inbound {
595 let mut map = server.cluster.map.lock();
596 if let Some(at) = map.find(name.as_bytes()) {
597 map.nodes[usize::from(at)].linked = false;
598 }
599 }
600}
601
602fn header(server: &Server, map: &Map, kind: u16) -> Vec<u8> {
606 let mut p = yo_alloc::allow(|| vec![0u8; HDR_LEN]);
607 p[0..4].copy_from_slice(SIG);
608 put16(&mut p, O_VER, PROTO_VER);
609 put16(&mut p, O_TYPE, kind);
610 put16(&mut p, O_PORT, map.nodes[0].port);
611 put16(&mut p, O_CPORT, map.nodes[0].bus);
612 put16(&mut p, O_PPORT, 0);
613 put16(&mut p, O_FLAGS, map.nodes[0].flags);
614 let speaking = map.nodes[0]
618 .master
619 .filter(|_| map.nodes[0].flags & FLAG_SLAVE != 0)
620 .map_or(0, usize::from);
621 put64(&mut p, O_CURRENT_EPOCH, server.cluster.epoch.load(Relaxed));
622 put64(&mut p, O_CONFIG_EPOCH, map.nodes[speaking].epoch);
623 put64(&mut p, O_OFFSET, server.repl_offset());
624 p[O_SENDER..O_SENDER + NAME_LEN].copy_from_slice(map.nodes[0].id.as_bytes());
625 for slot in 0..SLOTS {
626 if map.owner[slot] == Some(speaking as u16) {
627 set_bit(&mut p[O_SLOTS..O_SLOTS + BITMAP_LEN], slot);
628 }
629 }
630 if let Some(master) = map.nodes[0].master {
631 let id = map.nodes[usize::from(master)].id.as_bytes();
632 p[O_SLAVEOF..O_SLAVEOF + NAME_LEN].copy_from_slice(id);
633 }
634 let _ = O_MYIP;
639 p[O_STATE] = if server.cluster_up() {
640 STATE_OK
641 } else {
642 STATE_FAIL
643 };
644 p[O_MFLAGS] = MF_EXT_DATA;
645 p
646}
647
648fn seal(p: &mut [u8]) {
650 let total = p.len() as u32;
651 p[O_TOTLEN..O_TOTLEN + 4].copy_from_slice(&total.to_be_bytes());
652}
653
654fn ping(server: &Server, map: &Map, kind: u16, to: Option<u16>) -> Vec<u8> {
659 let mut p = header(server, map, kind);
660 let now = server.now_ms();
661 let mut want = (map.nodes.len() / 10).max(3);
665 if map.nodes.len() >= 2 {
666 want = want.min(map.nodes.len() - 2);
667 } else {
668 want = 0;
669 }
670 let mut count = 0u16;
671 let mut sent: Vec<u16> = yo_alloc::allow(|| Vec::with_capacity(want + 4));
672 let mut tries = want * 3;
673 while sent.len() < want && tries > 0 {
674 tries -= 1;
675 let at = pick(map.nodes.len());
676 if at == 0 || Some(at) == to || sent.contains(&at) {
677 continue;
678 }
679 let node = &map.nodes[usize::from(at)];
680 if node.flags & (FLAG_HANDSHAKE | FLAG_NOADDR) != 0 {
684 continue;
685 }
686 if !node.linked && map.runs(at).is_empty() {
687 continue;
688 }
689 sent.push(at);
690 }
691 for at in 1..map.nodes.len() as u16 {
695 if map.nodes[usize::from(at)].flags & FLAG_PFAIL != 0 && !sent.contains(&at) {
696 sent.push(at);
697 }
698 }
699 for at in sent {
700 let node = &map.nodes[usize::from(at)];
701 let mut entry = [0u8; GOSSIP_LEN];
702 entry[G_NAME..G_NAME + NAME_LEN].copy_from_slice(node.id.as_bytes());
703 entry[G_PING..G_PING + 4].copy_from_slice(&((node.ping_sent / 1000) as u32).to_be_bytes());
704 entry[G_PONG..G_PONG + 4].copy_from_slice(&((node.pong_recv / 1000) as u32).to_be_bytes());
705 let host = node.host.as_bytes();
706 let take = host.len().min(IP_LEN - 1);
707 entry[G_IP..G_IP + take].copy_from_slice(&host[..take]);
708 entry[G_PORT..G_PORT + 2].copy_from_slice(&node.port.to_be_bytes());
709 entry[G_CPORT..G_CPORT + 2].copy_from_slice(&node.bus.to_be_bytes());
710 entry[G_FLAGS..G_FLAGS + 2].copy_from_slice(&node.flags.to_be_bytes());
711 yo_alloc::allow(|| p.extend_from_slice(&entry));
712 count += 1;
713 }
714 let _ = now;
715 put16(&mut p, O_COUNT, count);
716 let mut exts = 0u16;
717 push_ext(&mut p, X_SHARDID, map.nodes[0].shard.as_bytes());
720 exts += 1;
721 let secret = server.cluster.bus.secret.lock();
722 if secret.len() == NAME_LEN {
723 push_ext(&mut p, X_SECRET, secret.as_bytes());
724 exts += 1;
725 }
726 drop(secret);
727 put16(&mut p, O_EXTENSIONS, exts);
728 seal(&mut p);
729 p
730}
731
732fn push_ext(p: &mut Vec<u8>, kind: u16, data: &[u8]) {
735 let len = 8 + data.len().div_ceil(8) * 8;
736 yo_alloc::allow(|| {
737 p.extend_from_slice(&(len as u32).to_be_bytes());
738 p.extend_from_slice(&kind.to_be_bytes());
739 p.extend_from_slice(&[0, 0]);
740 p.extend_from_slice(data);
741 p.resize(p.len() + (len - 8 - data.len()), 0);
742 });
743}
744
745fn fail_packet(server: &Server, map: &Map, about: &str) -> Vec<u8> {
747 let mut p = header(server, map, T_FAIL);
748 yo_alloc::allow(|| p.extend_from_slice(about.as_bytes()));
749 seal(&mut p);
750 p
751}
752
753fn publish_packet(server: &Server, map: &Map, shard: bool, channel: &[u8], body: &[u8]) -> Vec<u8> {
756 let kind = if shard { T_PUBLISHSHARD } else { T_PUBLISH };
757 let mut p = header(server, map, kind);
758 yo_alloc::allow(|| {
759 p.extend_from_slice(&(channel.len() as u32).to_be_bytes());
760 p.extend_from_slice(&(body.len() as u32).to_be_bytes());
761 p.extend_from_slice(channel);
762 p.extend_from_slice(body);
763 });
764 seal(&mut p);
765 p
766}
767
768fn update_packet(server: &Server, map: &Map, about: u16) -> Vec<u8> {
771 let mut p = header(server, map, T_UPDATE);
772 let node = &map.nodes[usize::from(about)];
773 let mut body = [0u8; 8 + NAME_LEN + BITMAP_LEN];
774 body[0..8].copy_from_slice(&node.epoch.to_be_bytes());
775 body[8..8 + NAME_LEN].copy_from_slice(node.id.as_bytes());
776 for slot in 0..SLOTS {
777 if map.owner[slot] == Some(about) {
778 set_bit(&mut body[8 + NAME_LEN..], slot);
779 }
780 }
781 yo_alloc::allow(|| p.extend_from_slice(&body));
782 seal(&mut p);
783 p
784}
785
786#[derive(Default)]
797struct Todo {
798 reply: Vec<Vec<u8>>,
800 shout: Vec<Vec<u8>>,
802 deliver: Option<(bool, Vec<u8>, Vec<u8>)>,
804 save: bool,
806 recount: bool,
808 close: bool,
810}
811
812fn process(server: &Arc<Server>, wire: &Arc<Wire>, p: &[u8]) -> bool {
814 if be16(p, O_VER) != PROTO_VER {
815 return true;
816 }
817 let kind = be16(p, O_TYPE);
818 let Some(explen) = expected(p, kind) else {
819 return true;
820 };
821 if explen != p.len() {
822 return true;
823 }
824 let now = server.now_ms();
825 let mut todo = Todo::default();
826 {
827 let mut map = server.cluster.map.lock();
828 digest(server, wire, p, kind, now, &mut map, &mut todo);
829 }
830 for packet in &todo.reply {
831 wire.send(packet);
832 }
833 if !todo.shout.is_empty() {
834 for link in server.cluster.bus.all() {
835 for packet in &todo.shout {
836 link.send(packet);
837 }
838 }
839 }
840 if let Some((shard, channel, body)) = todo.deliver
841 && server.anyone_subscribed()
842 {
843 let kind = if shard { Kind::Shard } else { Kind::Channel };
844 pubsub::deliver(server, kind, &channel, &body);
845 }
846 if todo.save {
847 server.cluster.bus.dirty.store(true, Relaxed);
848 }
849 if todo.recount {
850 server.recount_coverage();
851 }
852 !todo.close
853}
854
855fn expected(p: &[u8], kind: u16) -> Option<usize> {
864 match kind {
865 T_PING | T_PONG | T_MEET => {
866 let count = usize::from(be16(p, O_COUNT));
867 let mut len = HDR_LEN.checked_add(count.checked_mul(GOSSIP_LEN)?)?;
868 if p.get(O_MFLAGS).is_some_and(|f| f & MF_EXT_DATA != 0) {
869 let mut left = be16(p, O_EXTENSIONS);
870 let mut at = len;
871 while left > 0 {
872 left -= 1;
873 let extlen = be32(p, at) as usize;
874 if extlen < 8 || !extlen.is_multiple_of(8) || p.len().checked_sub(len)? < extlen
875 {
876 return None;
877 }
878 len += extlen;
879 at += extlen;
880 }
881 }
882 Some(len)
883 }
884 T_FAIL => Some(HDR_LEN + NAME_LEN),
885 T_PUBLISH | T_PUBLISHSHARD => {
886 let channel = be32(p, HDR_LEN) as usize;
887 let body = be32(p, HDR_LEN + 4) as usize;
888 HDR_LEN
889 .checked_add(8)?
890 .checked_add(channel)?
891 .checked_add(body)
892 }
893 T_AUTH_REQUEST | T_AUTH_ACK | T_MFSTART => Some(HDR_LEN),
894 T_UPDATE => Some(HDR_LEN + 8 + NAME_LEN + BITMAP_LEN),
895 _ => Some(p.len()),
899 }
900}
901
902#[allow(clippy::too_many_lines)]
904fn digest(
905 server: &Arc<Server>,
906 wire: &Arc<Wire>,
907 p: &[u8],
908 kind: u16,
909 now: u64,
910 map: &mut Map,
911 todo: &mut Todo,
912) {
913 let flags = be16(p, O_FLAGS);
914 let claimed = node_id(p, O_SENDER);
915 let linked = wire.named();
919 let mut sender = None;
920 if !linked.is_empty()
921 && let Some(at) = map.find(linked.as_bytes())
922 && map.nodes[usize::from(at)].flags & FLAG_HANDSHAKE == 0
923 {
924 sender = Some(at);
925 }
926 if sender.is_none()
927 && let Some(id) = claimed.as_deref()
928 {
929 sender = map.find(id.as_bytes());
930 if sender.is_some() && linked.is_empty() {
931 wire.name(id);
932 }
933 }
934 if let Some(at) = sender {
935 let node = &mut map.nodes[usize::from(at)];
936 if p.get(O_MFLAGS).is_some_and(|f| f & MF_EXT_DATA != 0) {
937 node.flags |= super::FLAG_EXTENSIONS;
938 }
939 node.data_recv = now;
940 }
941 let sender_epoch = be64(p, O_CONFIG_EPOCH);
942 if let Some(at) = sender
943 && map.nodes[usize::from(at)].flags & FLAG_HANDSHAKE == 0
944 {
945 let theirs = be64(p, O_CURRENT_EPOCH);
946 server.cluster.epoch.fetch_max(theirs, Relaxed);
947 let node = &mut map.nodes[usize::from(at)];
948 if sender_epoch > node.epoch {
949 node.epoch = sender_epoch;
950 todo.save = true;
951 }
952 node.offset = be64(p, O_OFFSET);
953 }
954
955 if kind == T_PING || kind == T_MEET {
956 if (kind == T_MEET || map.nodes[0].host.is_empty()) && map.nodes[0].host != wire.local {
962 yo_alloc::allow(|| map.nodes[0].host.clone_from(&wire.local));
963 todo.save = true;
964 }
965 if sender.is_none() && kind == T_MEET {
966 let host = {
971 let announced = text(p, O_MYIP, IP_LEN);
972 if announced.is_empty() {
973 yo_alloc::allow(|| wire.peer.clone())
974 } else {
975 announced
976 }
977 };
978 let id = yo_alloc::allow(|| String::from_utf8_lossy(&new_id()).into_owned());
979 let node = yo_alloc::allow(|| {
980 Node::new(
981 id,
982 host,
983 be16(p, O_PORT),
984 be16(p, O_CPORT),
985 FLAG_HANDSHAKE,
986 now,
987 )
988 });
989 yo_alloc::allow(|| map.nodes.push(node));
990 todo.save = true;
991 gossip(server, p, now, map, todo);
995 }
996 todo.reply.push(ping(server, map, T_PONG, sender));
997 }
998
999 match kind {
1000 T_PING | T_PONG | T_MEET => {}
1001 T_FAIL => {
1002 if sender.is_some()
1003 && let Some(id) = node_id(p, HDR_LEN)
1004 && let Some(at) = map.find(id.as_bytes())
1005 && map.nodes[usize::from(at)].flags & (FLAG_FAIL | FLAG_MYSELF) == 0
1006 {
1007 let node = &mut map.nodes[usize::from(at)];
1008 node.flags |= FLAG_FAIL;
1009 node.flags &= !FLAG_PFAIL;
1010 node.fail_time = now;
1011 todo.save = true;
1012 }
1013 return;
1014 }
1015 T_PUBLISH | T_PUBLISHSHARD => {
1016 if sender.is_none() {
1017 todo.close = true;
1018 return;
1019 }
1020 let channel = be32(p, HDR_LEN) as usize;
1021 let body = be32(p, HDR_LEN + 4) as usize;
1022 let at = HDR_LEN + 8;
1023 todo.deliver = yo_alloc::allow(|| {
1024 Some((
1025 kind == T_PUBLISHSHARD,
1026 p[at..at + channel].to_vec(),
1027 p[at + channel..at + channel + body].to_vec(),
1028 ))
1029 });
1030 return;
1031 }
1032 T_UPDATE => {
1033 if sender.is_none() {
1034 todo.close = true;
1035 return;
1036 }
1037 let epoch = be64(p, HDR_LEN);
1038 let Some(id) = node_id(p, HDR_LEN + 8) else {
1039 return;
1040 };
1041 let Some(about) = map.find(id.as_bytes()) else {
1042 return;
1043 };
1044 if epoch <= map.nodes[usize::from(about)].epoch {
1045 return;
1046 }
1047 map.nodes[usize::from(about)].epoch = epoch;
1048 map.nodes[usize::from(about)].flags &= !FLAG_SLAVE;
1049 map.nodes[usize::from(about)].flags |= FLAG_MASTER;
1050 map.nodes[usize::from(about)].master = None;
1051 claim_slots(
1052 server,
1053 map,
1054 about,
1055 epoch,
1056 &p[HDR_LEN + 8 + NAME_LEN..],
1057 todo,
1058 );
1059 todo.save = true;
1060 return;
1061 }
1062 T_AUTH_REQUEST | T_AUTH_ACK | T_MFSTART | T_MODULE => return,
1066 _ => return,
1067 }
1068
1069 if !wire.inbound {
1072 let held = map.find(linked.as_bytes());
1073 if let Some(at) = held
1074 && map.nodes[usize::from(at)].flags & FLAG_HANDSHAKE != 0
1075 {
1076 match sender {
1077 Some(known) => {
1080 let host = yo_alloc::allow(|| wire.peer.clone());
1081 let node = &mut map.nodes[usize::from(known)];
1082 if node.host != host {
1083 node.host = host;
1084 node.port = be16(p, O_PORT);
1085 node.bus = be16(p, O_CPORT);
1086 }
1087 map.forget(at);
1088 todo.save = true;
1089 todo.close = true;
1090 return;
1091 }
1092 None => {
1095 let Some(id) = claimed.clone() else {
1096 return;
1097 };
1098 wire.name(&id);
1099 let node = &mut map.nodes[usize::from(at)];
1100 yo_alloc::allow(|| node.id = id);
1101 node.flags &= !(FLAG_HANDSHAKE | FLAG_MEET);
1102 node.flags |= flags & (FLAG_MASTER | FLAG_SLAVE);
1103 node.pong_recv = now;
1104 node.ping_sent = 0;
1105 sender = Some(at);
1106 todo.save = true;
1107 }
1108 }
1109 } else if let Some(at) = held
1110 && Some(map.nodes[usize::from(at)].id.as_str()) != claimed.as_deref()
1111 {
1112 let node = &mut map.nodes[usize::from(at)];
1117 node.flags |= FLAG_NOADDR;
1118 node.host.clear();
1119 node.port = 0;
1120 node.bus = 0;
1121 node.linked = false;
1122 todo.save = true;
1123 todo.close = true;
1124 return;
1125 }
1126 }
1127
1128 let Some(at) = sender else {
1129 return;
1130 };
1131 let node = &mut map.nodes[usize::from(at)];
1134 node.flags &= !FLAG_NOFAILOVER;
1135 node.flags |= flags & FLAG_NOFAILOVER;
1136 if kind == T_PING && !wire.inbound {
1137 let host = yo_alloc::allow(|| wire.peer.clone());
1138 if node.host != host {
1139 node.host = host;
1140 node.port = be16(p, O_PORT);
1141 node.bus = be16(p, O_CPORT);
1142 todo.save = true;
1143 }
1144 }
1145 if !wire.inbound && kind == T_PONG {
1146 node.pong_recv = now;
1147 node.ping_sent = 0;
1148 if node.flags & FLAG_PFAIL != 0 {
1149 node.flags &= !FLAG_PFAIL;
1150 todo.save = true;
1151 } else if node.flags & FLAG_FAIL != 0 {
1152 clear_failure(map, at, now);
1153 todo.save = true;
1154 }
1155 }
1156
1157 let follows = node_id(p, O_SLAVEOF);
1160 match follows {
1161 None => {
1162 if map.nodes[usize::from(at)].flags & FLAG_SLAVE != 0 {
1163 let node = &mut map.nodes[usize::from(at)];
1164 node.flags &= !FLAG_SLAVE;
1165 node.flags |= FLAG_MASTER;
1166 node.master = None;
1167 todo.save = true;
1168 }
1169 }
1170 Some(id) => {
1171 let master = map.find(id.as_bytes());
1172 if map.nodes[usize::from(at)].is_master() {
1173 let same_shard = master.is_some_and(|m| {
1179 map.nodes[usize::from(m)].shard == map.nodes[usize::from(at)].shard
1180 });
1181 if same_shard && sender_epoch >= map.nodes[usize::from(at)].epoch {
1182 let m = master.expect("same shard means there is one");
1183 for slot in 0..SLOTS {
1184 if map.owner[slot] == Some(at) {
1185 map.owner[slot] = Some(m);
1186 }
1187 }
1188 let promoted = &mut map.nodes[usize::from(m)];
1189 promoted.flags &= !FLAG_SLAVE;
1190 promoted.flags |= FLAG_MASTER;
1191 promoted.master = None;
1192 promoted.epoch = sender_epoch;
1193 } else if !same_shard {
1194 for slot in 0..SLOTS {
1195 if map.owner[slot] == Some(at) {
1196 map.owner[slot] = None;
1197 }
1198 }
1199 }
1200 let node = &mut map.nodes[usize::from(at)];
1201 node.flags &= !(FLAG_MASTER | FLAG_MIGRATE_TO);
1202 node.flags |= FLAG_SLAVE;
1203 todo.save = true;
1204 }
1205 if let Some(m) = master
1206 && map.nodes[usize::from(at)].master != Some(m)
1207 && m != at
1208 {
1209 map.nodes[usize::from(at)].master = Some(m);
1210 let shard = yo_alloc::allow(|| map.nodes[usize::from(m)].shard.clone());
1211 yo_alloc::allow(|| map.nodes[usize::from(at)].shard = shard);
1212 todo.save = true;
1213 }
1214 }
1215 }
1216
1217 let speaking = if map.nodes[usize::from(at)].is_master() {
1221 Some(at)
1222 } else {
1223 map.nodes[usize::from(at)].master
1224 };
1225 let claim = &p[O_SLOTS..O_SLOTS + BITMAP_LEN];
1226 let dirty = speaking
1227 .is_some_and(|m| (0..SLOTS).any(|slot| bit(claim, slot) != (map.owner[slot] == Some(m))));
1228 if dirty && map.nodes[usize::from(at)].is_master() {
1229 claim_slots(server, map, at, sender_epoch, claim, todo);
1230 }
1231 if dirty {
1232 for slot in 0..SLOTS {
1236 if !bit(claim, slot) {
1237 continue;
1238 }
1239 let Some(owner) = map.owner[slot] else {
1240 continue;
1241 };
1242 if owner == at {
1243 continue;
1244 }
1245 if map.nodes[usize::from(owner)].epoch > sender_epoch {
1246 todo.reply.push(update_packet(server, map, owner));
1247 break;
1248 }
1249 }
1250 }
1251 if map.nodes[0].is_master()
1255 && map.nodes[usize::from(at)].is_master()
1256 && sender_epoch == map.nodes[0].epoch
1257 && map.nodes[0].id < map.nodes[usize::from(at)].id
1258 {
1259 let next = server.cluster.epoch.fetch_add(1, Relaxed) + 1;
1260 map.nodes[0].epoch = next;
1261 todo.save = true;
1262 }
1263 gossip(server, p, now, map, todo);
1264 extensions(server, p, now, map, at, todo);
1265}
1266
1267fn gossip(server: &Arc<Server>, p: &[u8], now: u64, map: &mut Map, todo: &mut Todo) {
1270 let count = usize::from(be16(p, O_COUNT));
1271 let sender_master = node_id(p, O_SENDER)
1272 .and_then(|id| map.find(id.as_bytes()))
1273 .is_none_or(|at| map.nodes[usize::from(at)].is_master());
1274 for entry in 0..count {
1275 let base = HDR_LEN + entry * GOSSIP_LEN;
1276 let Some(id) = node_id(p, base + G_NAME) else {
1277 continue;
1278 };
1279 let flags = be16(p, base + G_FLAGS);
1280 let host = text(p, base + G_IP, IP_LEN);
1281 let port = be16(p, base + G_PORT);
1282 let bus = be16(p, base + G_CPORT);
1283 if let Some(at) = map.find(id.as_bytes()) {
1284 if at == 0 {
1285 continue;
1286 }
1287 if sender_master {
1290 let sender = node_id(p, O_SENDER).unwrap_or_default();
1291 if flags & (FLAG_FAIL | FLAG_PFAIL) != 0 {
1292 report(map, at, &sender, now);
1293 if mark_failing(map, at, now) {
1294 let about = yo_alloc::allow(|| map.nodes[usize::from(at)].id.clone());
1295 todo.shout.push(fail_packet(server, map, &about));
1296 todo.save = true;
1297 }
1298 } else {
1299 unreport(map, at, &sender);
1300 }
1301 }
1302 let node = &mut map.nodes[usize::from(at)];
1303 if node.flags & (FLAG_FAIL | FLAG_PFAIL) == 0
1304 && node.ping_sent == 0
1305 && node.reports.is_empty()
1306 {
1307 let heard = u64::from(be32(p, base + G_PONG)) * 1000;
1311 if heard > node.pong_recv && heard <= now + 500 {
1312 node.pong_recv = heard;
1313 }
1314 } else if node.down()
1315 && flags & (FLAG_FAIL | FLAG_PFAIL | FLAG_NOADDR | FLAG_HANDSHAKE) == 0
1316 && !host.is_empty()
1317 && (node.host != host || node.port != port)
1318 {
1319 yo_alloc::allow(|| node.host = host);
1323 node.port = port;
1324 node.bus = bus;
1325 node.linked = false;
1326 node.flags &= !FLAG_NOADDR;
1327 todo.save = true;
1328 }
1329 continue;
1330 }
1331 if flags & FLAG_NOADDR != 0 {
1342 continue;
1343 }
1344 if server.cluster.bus.blacklisted(&id, now) {
1345 continue;
1346 }
1347 let flags = flags & !(FLAG_MYSELF | FLAG_HANDSHAKE | FLAG_MEET);
1348 let node = yo_alloc::allow(|| Node::new(id, host, port, bus, flags, now));
1349 yo_alloc::allow(|| map.nodes.push(node));
1350 todo.save = true;
1351 }
1352}
1353
1354fn extensions(server: &Arc<Server>, p: &[u8], now: u64, map: &mut Map, at: u16, todo: &mut Todo) {
1356 if !p.get(O_MFLAGS).is_some_and(|f| f & MF_EXT_DATA != 0) {
1357 return;
1358 }
1359 let mut left = be16(p, O_EXTENSIONS);
1360 let mut base = HDR_LEN + usize::from(be16(p, O_COUNT)) * GOSSIP_LEN;
1361 while left > 0 && base + 8 <= p.len() {
1362 left -= 1;
1363 let extlen = be32(p, base) as usize;
1364 if extlen < 8 || base + extlen > p.len() {
1365 return;
1366 }
1367 let kind = be16(p, base + 4);
1368 let data = &p[base + 8..base + extlen];
1369 match kind {
1370 X_SHARDID => {
1371 let id = String::from_utf8_lossy(&data[..NAME_LEN.min(data.len())]);
1372 if id.len() == NAME_LEN && map.nodes[usize::from(at)].shard != id {
1373 yo_alloc::allow(|| map.nodes[usize::from(at)].shard = id.into_owned());
1374 todo.save = true;
1375 }
1376 }
1377 X_SECRET => {
1378 let theirs = String::from_utf8_lossy(&data[..NAME_LEN.min(data.len())]);
1382 let mut mine = server.cluster.bus.secret.lock();
1383 if theirs.len() == NAME_LEN && **mine > *theirs {
1384 yo_alloc::allow(|| *mine = theirs.into_owned());
1385 }
1386 }
1387 X_FORGOTTEN => {
1388 if data.len() < NAME_LEN + 8 {
1392 return;
1393 }
1394 let Some(id) = node_id(data, 0) else {
1395 return;
1396 };
1397 let ttl = be64(data, NAME_LEN);
1398 if map.nodes[0].id == id
1399 || map.nodes[0].master.map(usize::from)
1400 == map.find(id.as_bytes()).map(usize::from)
1401 {
1402 base += extlen;
1403 continue;
1404 }
1405 server.cluster.bus.blacklist(&id, now + ttl);
1406 if let Some(gone) = map.find(id.as_bytes())
1407 && gone != 0
1408 {
1409 server.cluster.bus.cut(&id);
1410 map.forget(gone);
1411 todo.save = true;
1412 }
1413 }
1414 X_HOSTNAME | X_HUMAN_NAME => {}
1418 _ => {}
1419 }
1420 base += extlen;
1421 }
1422}
1423
1424fn report(map: &mut Map, at: u16, from: &str, now: u64) {
1426 if from.is_empty() {
1427 return;
1428 }
1429 let node = &mut map.nodes[usize::from(at)];
1430 if let Some(held) = node.reports.iter_mut().find(|(who, _)| who == from) {
1431 held.1 = now;
1432 return;
1433 }
1434 yo_alloc::allow(|| node.reports.push((String::from(from), now)));
1435}
1436
1437fn unreport(map: &mut Map, at: u16, from: &str) {
1439 map.nodes[usize::from(at)]
1440 .reports
1441 .retain(|(who, _)| who != from);
1442}
1443
1444fn mark_failing(map: &mut Map, at: u16, now: u64) -> bool {
1452 let cutoff = now.saturating_sub(NODE_TIMEOUT_MS * 2);
1453 map.nodes[usize::from(at)]
1454 .reports
1455 .retain(|(_, when)| *when > cutoff);
1456 if map.nodes[usize::from(at)].flags & (FLAG_PFAIL | FLAG_FAIL) == 0 {
1457 return false;
1458 }
1459 if map.nodes[usize::from(at)].flags & FLAG_FAIL != 0 {
1460 return false;
1461 }
1462 let needed = map.voters() / 2 + 1;
1463 let mut votes = map.nodes[usize::from(at)].reports.len();
1464 if map.nodes[0].is_master() && !map.runs(0).is_empty() {
1465 votes += 1;
1466 }
1467 if votes < needed {
1468 return false;
1469 }
1470 let node = &mut map.nodes[usize::from(at)];
1471 node.flags &= !FLAG_PFAIL;
1472 node.flags |= FLAG_FAIL;
1473 node.fail_time = now;
1474 true
1475}
1476
1477fn clear_failure(map: &mut Map, at: u16, now: u64) {
1485 let node = &map.nodes[usize::from(at)];
1486 let replica = !node.is_master();
1487 let empty = map.runs(at).is_empty();
1488 let stale = now.saturating_sub(node.fail_time) > NODE_TIMEOUT_MS * 2;
1489 if replica || empty || stale {
1490 let node = &mut map.nodes[usize::from(at)];
1491 node.flags &= !FLAG_FAIL;
1492 node.fail_time = 0;
1493 }
1494}
1495
1496fn claim_slots(
1508 server: &Arc<Server>,
1509 map: &mut Map,
1510 owner: u16,
1511 epoch: u64,
1512 claim: &[u8],
1513 todo: &mut Todo,
1514) {
1515 let mut lost = 0usize;
1516 for slot in 0..SLOTS {
1517 if !bit(claim, slot) {
1518 continue;
1519 }
1520 if map.owner[slot] == Some(owner) || map.importing[slot].is_some() {
1521 continue;
1522 }
1523 let held = map.owner[slot];
1524 let newer = held.is_none_or(|at| map.nodes[usize::from(at)].epoch <= epoch);
1525 if !newer {
1526 continue;
1527 }
1528 if held == Some(0) {
1529 lost += 1;
1530 }
1531 map.owner[slot] = Some(owner);
1532 map.migrating[slot] = None;
1533 todo.save = true;
1534 }
1535 if lost > 0 && map.runs(0).is_empty() && owner != 0 {
1539 map.nodes[0].flags &= !FLAG_MASTER;
1540 map.nodes[0].flags |= FLAG_SLAVE;
1541 map.nodes[0].master = Some(owner);
1542 let shard = yo_alloc::allow(|| map.nodes[usize::from(owner)].shard.clone());
1543 yo_alloc::allow(|| map.nodes[0].shard = shard);
1544 let (host, port) = {
1545 let node = &map.nodes[usize::from(owner)];
1546 (yo_alloc::allow(|| node.host.clone()), node.port)
1547 };
1548 let following = Arc::clone(server);
1549 spawn("yo-bus-follow", move || {
1550 following.follow_master(&host, port);
1551 });
1552 }
1553 todo.recount = true;
1557}
1558
1559fn cron(server: &Arc<Server>) {
1563 let mut tick = 0u64;
1564 loop {
1565 std::thread::sleep(Duration::from_millis(CRON_MS));
1566 tick += 1;
1567 let now = server.now_ms();
1568 let mut dial_list: Vec<(String, String, u16, bool)> = Vec::new();
1573 let mut ping_list: Vec<(String, Vec<u8>)> = Vec::new();
1574 let mut shout: Vec<Vec<u8>> = Vec::new();
1575 let mut follow: Option<(String, u16)> = None;
1576 let mut save = false;
1577 {
1578 let mut map = server.cluster.map.lock();
1579 let count = map.nodes.len();
1580 for at in 1..count as u16 {
1581 let node = &map.nodes[usize::from(at)];
1582 if node.flags & FLAG_HANDSHAKE != 0
1584 && now.saturating_sub(node.data_recv) > NODE_TIMEOUT_MS.max(1000)
1585 {
1586 map.forget(at);
1587 save = true;
1588 break;
1589 }
1590 if node.flags & FLAG_NOADDR != 0 || node.host.is_empty() {
1591 continue;
1592 }
1593 if !node.linked {
1594 let meet = node.flags & FLAG_MEET != 0;
1599 yo_alloc::allow(|| {
1600 dial_list.push((node.id.clone(), node.host.clone(), node.bus, meet));
1601 });
1602 continue;
1603 }
1604 let quiet = now.saturating_sub(node.pong_recv);
1608 let due = node.ping_sent == 0 && quiet > PING_MS;
1609 if due || (tick.is_multiple_of(10) && oldest_of_five(&map, now) == Some(at)) {
1610 let packet = ping(server, &map, T_PING, Some(at));
1611 let id = yo_alloc::allow(|| map.nodes[usize::from(at)].id.clone());
1612 map.nodes[usize::from(at)].ping_sent = now;
1613 ping_list.push((id, packet));
1614 }
1615 }
1616 for at in 1..map.nodes.len() as u16 {
1620 let node = &map.nodes[usize::from(at)];
1621 if node.flags & (FLAG_HANDSHAKE | FLAG_FAIL | FLAG_PFAIL) != 0 {
1622 continue;
1623 }
1624 let waiting = if node.ping_sent == 0 {
1625 0
1626 } else {
1627 now.saturating_sub(node.ping_sent)
1628 };
1629 let quiet = now.saturating_sub(node.data_recv);
1630 if waiting.min(quiet) > NODE_TIMEOUT_MS {
1631 map.nodes[usize::from(at)].flags |= FLAG_PFAIL;
1632 save = true;
1633 }
1634 if mark_failing(&mut map, at, now) {
1635 let about = yo_alloc::allow(|| map.nodes[usize::from(at)].id.clone());
1636 shout.push(fail_packet(server, &map, &about));
1637 save = true;
1638 }
1639 }
1640 if map.nodes[0].flags & FLAG_SLAVE != 0
1646 && !server.following()
1647 && let Some(master) = map.nodes[0].master
1648 && let Some(node) = map.nodes.get(usize::from(master))
1649 && node.flags & FLAG_NOADDR == 0
1650 && !node.host.is_empty()
1651 {
1652 follow = yo_alloc::allow(|| Some((node.host.clone(), node.port)));
1653 }
1654 }
1655 if let Some((host, port)) = follow {
1659 server.follow_master(&host, port);
1660 }
1661 for (id, host, bus, meet) in dial_list {
1662 if !dial(server, &id, &host, bus, meet) {
1663 continue;
1664 }
1665 let mut map = server.cluster.map.lock();
1666 if let Some(at) = map.find(id.as_bytes()) {
1667 map.nodes[usize::from(at)].linked = true;
1668 }
1669 }
1670 for (id, packet) in ping_list {
1671 if let Some(link) = server.cluster.bus.outbound(&id) {
1672 link.send(&packet);
1673 } else {
1674 let mut map = server.cluster.map.lock();
1675 if let Some(at) = map.find(id.as_bytes()) {
1676 map.nodes[usize::from(at)].linked = false;
1677 map.nodes[usize::from(at)].ping_sent = 0;
1678 }
1679 }
1680 }
1681 if !shout.is_empty() {
1682 for link in server.cluster.bus.all() {
1683 for packet in &shout {
1684 link.send(packet);
1685 }
1686 }
1687 }
1688 if save {
1689 server.cluster.bus.dirty.store(true, Relaxed);
1690 }
1691 server.recount_coverage();
1692 if tick.is_multiple_of(10) && server.cluster.bus.dirty.swap(false, Relaxed) {
1695 let _ = super::save(server);
1696 }
1697 }
1698}
1699
1700fn oldest_of_five(map: &Map, now: u64) -> Option<u16> {
1705 if map.nodes.len() < 2 {
1706 return None;
1707 }
1708 let mut best: Option<(u16, u64)> = None;
1709 for _ in 0..5 {
1710 let at = pick(map.nodes.len());
1711 if at == 0 {
1712 continue;
1713 }
1714 let node = &map.nodes[usize::from(at)];
1715 if node.ping_sent != 0 || node.flags & (FLAG_HANDSHAKE | FLAG_NOADDR) != 0 {
1716 continue;
1717 }
1718 let quiet = now.saturating_sub(node.pong_recv);
1719 if best.is_none_or(|(_, held)| quiet > held) {
1720 best = Some((at, quiet));
1721 }
1722 }
1723 best.map(|(at, _)| at)
1724}
1725
1726impl Server {
1729 pub(super) fn cluster_meet(&self, host: &str, port: u16, bus: u16) {
1737 let now = self.now_ms();
1738 let mut map = self.cluster.map.lock();
1739 let known = map
1740 .nodes
1741 .iter()
1742 .any(|node| node.host == host && node.port == port);
1743 if known {
1744 return;
1745 }
1746 let id = yo_alloc::allow(|| String::from_utf8_lossy(&new_id()).into_owned());
1747 let node = yo_alloc::allow(|| {
1748 Node::new(
1749 id,
1750 yo_alloc::allow(|| String::from(host)),
1751 port,
1752 bus,
1753 FLAG_HANDSHAKE | FLAG_MEET,
1754 now,
1755 )
1756 });
1757 yo_alloc::allow(|| map.nodes.push(node));
1758 }
1759
1760 pub(super) fn cluster_blacklisted(&self, id: &str) -> bool {
1763 self.cluster.bus.blacklisted(id, self.now_ms())
1764 }
1765
1766 pub(super) fn cluster_forget(&self, at: u16) {
1773 let now = self.now_ms();
1774 let id = {
1775 let mut map = self.cluster.map.lock();
1776 let id = yo_alloc::allow(|| map.nodes[usize::from(at)].id.clone());
1777 map.forget(at);
1778 id
1779 };
1780 self.cluster.bus.blacklist(&id, now);
1781 self.cluster.bus.cut(&id);
1782 let packet = {
1783 let map = self.cluster.map.lock();
1784 let mut p = ping(self, &map, T_PING, None);
1785 let mut body = [0u8; NAME_LEN + 8];
1790 body[..NAME_LEN].copy_from_slice(id.as_bytes());
1791 body[NAME_LEN..].copy_from_slice(&BLACKLIST_MS.to_be_bytes());
1792 push_ext(&mut p, X_FORGOTTEN, &body);
1793 let exts = be16(&p, O_EXTENSIONS) + 1;
1794 put16(&mut p, O_EXTENSIONS, exts);
1795 seal(&mut p);
1796 p
1797 };
1798 for link in self.cluster.bus.all() {
1799 link.send(&packet);
1800 }
1801 self.cluster.bus.dirty.store(true, Relaxed);
1802 }
1803
1804 pub(super) fn cluster_replicate(self: &Arc<Server>, at: u16) {
1806 let (host, port) = {
1807 let mut map = self.cluster.map.lock();
1808 for slot in 0..SLOTS {
1812 if map.owner[slot] == Some(0) {
1813 map.owner[slot] = None;
1814 }
1815 }
1816 map.nodes[0].flags &= !(FLAG_MASTER | FLAG_MIGRATE_TO);
1817 map.nodes[0].flags |= FLAG_SLAVE;
1818 map.nodes[0].master = Some(at);
1819 let shard = yo_alloc::allow(|| map.nodes[usize::from(at)].shard.clone());
1820 yo_alloc::allow(|| map.nodes[0].shard = shard);
1821 let node = &map.nodes[usize::from(at)];
1822 (yo_alloc::allow(|| node.host.clone()), node.port)
1823 };
1824 self.recount_coverage();
1825 self.cluster.bus.dirty.store(true, Relaxed);
1826 if !host.is_empty() {
1827 self.follow_master(&host, port);
1828 }
1829 }
1830
1831 pub(crate) fn cluster_publish(&self, shard: bool, channel: &[u8], body: &[u8]) {
1839 if !self.cluster_enabled() || !self.cluster.bus.on.load(Relaxed) {
1840 return;
1841 }
1842 let packet = {
1843 let map = self.cluster.map.lock();
1844 publish_packet(self, &map, shard, channel, body)
1845 };
1846 for link in self.cluster.bus.all() {
1847 link.send(&packet);
1848 }
1849 }
1850
1851 pub(super) fn cluster_broadcast_pong(&self) {
1865 if !self.cluster_enabled() || !self.cluster.bus.on.load(Relaxed) {
1866 return;
1867 }
1868 let packet = {
1869 let map = self.cluster.map.lock();
1870 ping(self, &map, T_PONG, None)
1871 };
1872 for link in self.cluster.bus.all() {
1873 link.send(&packet);
1874 }
1875 }
1876
1877 pub(super) fn cluster_links(&self, out: &mut Out) {
1879 let links = self.cluster.bus.all();
1880 let at = out.len();
1881 let mut n = 0;
1882 for link in links {
1883 let node = link.named();
1884 if node.is_empty() {
1889 continue;
1890 }
1891 out.map(6);
1892 out.bulk(b"direction");
1893 out.bulk(if link.inbound {
1894 b"from".as_slice()
1895 } else {
1896 b"to".as_slice()
1897 });
1898 out.bulk(b"node");
1899 out.bulk(node.as_bytes());
1900 out.bulk(b"create-time");
1901 out.int(link.created as i64);
1902 out.bulk(b"events");
1903 out.bulk(b"r");
1904 out.bulk(b"send-buffer-allocated");
1905 out.int(link.sent.load(Relaxed) as i64);
1906 out.bulk(b"send-buffer-used");
1907 out.int(0);
1908 n += 1;
1909 }
1910 out.close_array(at, n);
1911 }
1912}
1913
1914#[cfg(test)]
1915mod tests {
1916 use super::*;
1917
1918 #[test]
1919 fn a_bitmap_round_trips_through_the_reference_bit_order() {
1920 let mut bitmap = [0u8; BITMAP_LEN];
1921 for slot in [0usize, 1, 7, 8, 1234, 5061, 12182, SLOTS - 1] {
1922 set_bit(&mut bitmap, slot);
1923 }
1924 for slot in 0..SLOTS {
1925 let want = matches!(slot, 0 | 1 | 7 | 8 | 1234 | 5061 | 12182) || slot == SLOTS - 1;
1926 assert_eq!(bit(&bitmap, slot), want, "slot {slot}");
1927 }
1928 assert_eq!(bitmap[0], 0b1000_0011);
1932 assert_eq!(bitmap[1], 0b0000_0001);
1933 }
1934
1935 #[test]
1936 fn an_extension_is_padded_to_the_eight_byte_boundary() {
1937 let mut p = Vec::new();
1938 push_ext(&mut p, X_SHARDID, &[b'a'; 40]);
1939 assert_eq!(p.len(), 48);
1940 assert_eq!(be32(&p, 0), 48);
1941 assert_eq!(be16(&p, 4), X_SHARDID);
1942 let mut q = Vec::new();
1945 push_ext(&mut q, X_HOSTNAME, b"node1.example\0");
1946 assert_eq!(q.len(), 8 + 16);
1947 assert_eq!(be32(&q, 0), 24);
1948 }
1949
1950 #[test]
1951 fn a_packet_of_the_wrong_length_is_refused() {
1952 let mut p = vec![0u8; HDR_LEN];
1953 p[0..4].copy_from_slice(SIG);
1954 put16(&mut p, O_VER, PROTO_VER);
1955 put16(&mut p, O_TYPE, T_PING);
1956 put16(&mut p, O_COUNT, 0);
1957 p[O_MFLAGS] = 0;
1958 seal(&mut p);
1959 assert_eq!(expected(&p, T_PING), Some(HDR_LEN));
1960 put16(&mut p, O_COUNT, 1);
1963 assert_eq!(expected(&p, T_PING), Some(HDR_LEN + GOSSIP_LEN));
1964 assert_ne!(expected(&p, T_PING), Some(p.len()));
1965 }
1966
1967 #[test]
1968 fn a_node_id_has_to_be_forty_hex_characters() {
1969 let mut p = vec![0u8; NAME_LEN * 3];
1970 assert_eq!(node_id(&p, 0), None, "all zeros is the reference's no node");
1971 p[0..NAME_LEN].copy_from_slice(&[b'a'; NAME_LEN]);
1972 assert_eq!(node_id(&p, 0).as_deref(), Some("a".repeat(40).as_str()));
1973 p[5] = b'z';
1974 assert_eq!(node_id(&p, 0), None);
1975 assert_eq!(node_id(&p, NAME_LEN * 3), None, "off the end is not an id");
1976 }
1977}