Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_o3db_sync/src/dist/peer_set.rs

2.5 KiB, 26 runs

created by r1870400018:11386, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//! The rolling view of known peers.
2//!
3//! A [`PeerSet`] is held by every distributed-Ozone engine and consulted on
4//! every placement decision. The set is updated:
5//!
6//! - at start-up, from the configuration's bootstrap list;
7//! - at runtime, as Kademlia DHT lookups surface new contacts;
8//! - at runtime, as peers are evicted after sustained unresponsiveness.
9//!
10//! Internally the set is a sorted vector keyed by [`NodeId`]. Sorted order
11//! gives deterministic iteration -- two peers with the same membership will
12//! iterate in the same order, which keeps placement decisions byte-identical
13//! across peers for debugging. The insert / remove cost is `O(log n)` for the
14//! search and `O(n)` for the shift, which is appropriate for the expected
15//! peer counts (tens to low thousands, updated infrequently).
16//!
17//! [Written with AI entirely](https://need2know.ai/entirely-ai/code)\
18//! Anthropic Claude
19
20use crate::kademlia::id::NodeId;
21
22
23/// A rolling, sorted, deduplicated view of known peers.
24///
25/// The local peer is always excluded from the set -- distributed Ozone never
26/// asks itself to be a holder via [`placement::holders`][crate::dist::placement].
27#[derive(Clone, Debug, Default)]
28pub struct PeerSet {
29 peers: Vec<NodeId>,
30}
31
32impl PeerSet {
33 pub fn new() -> Self {
34 Self { peers: Vec::new() }
35 }
36
37 /// Excludes the local peer and deduplicates. Runs in `O(n log n)`.
38 pub fn from_bootstrap(
39 local_peer_id: &NodeId,
40 candidates: impl IntoIterator<Item = NodeId>,
41 )
42 -> Self
43 {
44 let mut peers: Vec<NodeId> = candidates.into_iter()
45 .filter(|p| p != local_peer_id)
46 .collect();
47 peers.sort_by(|a, b| a.as_bytes().cmp(b.as_bytes()));
48 peers.dedup();
49 Self { peers }
50 }
51
52 /// Maintains sorted-deduplicated order; false if the peer was already
53 /// present.
54 pub fn insert(&mut self, peer: NodeId) -> bool {
55 match self.peers.binary_search_by(|p| p.as_bytes().cmp(peer.as_bytes())) {
56 Ok(_) => false,
57 Err(idx) => {
58 self.peers.insert(idx, peer);
59 true
60 }
61 }
62 }
63
64 pub fn remove(&mut self, peer: &NodeId) -> bool {
65 match self.peers.binary_search_by(|p| p.as_bytes().cmp(peer.as_bytes())) {
66 Ok(idx) => {
67 self.peers.remove(idx);
68 true
69 }
70 Err(_) => false,
71 }
72 }
73
74 pub fn contains(&self, peer: &NodeId) -> bool {
75 self.peers.binary_search_by(|p| p.as_bytes().cmp(peer.as_bytes())).is_ok()
76 }
77
78 /// Sorted order.
79 pub fn as_slice(&self) -> &[NodeId] {
80 &self.peers
81 }
82
83 pub fn len(&self) -> usize {
84 self.peers.len()
85 }
86
87 pub fn is_empty(&self) -> bool {
88 self.peers.is_empty()
89 }
90}