diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/remake/catchup.rs | 4 | ||||
| -rw-r--r-- | src/remake/mod.rs | 20 | ||||
| -rw-r--r-- | src/state.rs | 8 |
3 files changed, 29 insertions, 3 deletions
diff --git a/src/remake/catchup.rs b/src/remake/catchup.rs index 39b9550..56aeee1 100644 --- a/src/remake/catchup.rs +++ b/src/remake/catchup.rs @@ -71,11 +71,13 @@ pub(super) async fn check<H: Host>(host: &H) { } let local = host.current_epoch(); + // Only ready members count: a rejoining peer advertises an epoch it doesn't hold + // yet, and a node of another swarm (or a stranger) advertises one that isn't ours. let mut ahead: Vec<(String, Epoch)> = host .peer_summaries() .await .into_iter() - .filter(|peer| peer.active) + .filter(|peer| peer.serves()) .filter_map(|peer| peer.epoch.map(|epoch| (peer.id, epoch))) .filter(|(_, epoch)| epoch.generation > local.generation) .collect(); diff --git a/src/remake/mod.rs b/src/remake/mod.rs index dacd1db..ca17956 100644 --- a/src/remake/mod.rs +++ b/src/remake/mod.rs @@ -141,10 +141,30 @@ pub(crate) struct PeerSummary { pub(crate) id: String, /// Not dormant. pub(crate) active: bool, + /// Completed the handshake and belongs to our swarm. A peer that merely sent us + /// something (a node of another swarm on the same network, a stranger before + /// admission) is not one, and nothing it advertises is followed. + pub(crate) member: bool, + /// What it last said about being ready; None before it said anything. + pub(crate) ready: Option<bool>, /// The epoch the peer last advertised. pub(crate) epoch: Option<Epoch>, } +impl PeerSummary { + /// A peer whose epoch can be followed and downloaded from: an active member that + /// holds the document it advertises. A rejoining peer advertises its target epoch + /// with an empty document and `ready: false`. + pub(crate) fn serves_epoch(&self, epoch: Epoch) -> bool { + self.serves() && self.epoch == Some(epoch) + } + + /// An active, ready member. + pub(crate) fn serves(&self) -> bool { + self.active && self.member && self.ready == Some(true) + } +} + /// Admin routes. Merged into the authenticated part of the node's router. /// Largest remake request (bytes). The proposal carries the new document to every /// node in one sync message, which Mycelium must deliver within its deadline, so diff --git a/src/state.rs b/src/state.rs index c51446f..9383c89 100644 --- a/src/state.rs +++ b/src/state.rs @@ -643,13 +643,14 @@ impl AppState { self.transport.local_id() } - /// Peers that are active and last said they are on our epoch. + /// Peers that can serve our epoch's data: active, ready members on our epoch + /// (`PeerSummary::serves_epoch`). pub(crate) async fn active_peers_on_local_epoch(&self) -> Vec<String> { let epoch = self.local_epoch(); self.peer_summaries() .await .into_iter() - .filter(|peer| peer.active && peer.epoch == Some(epoch)) + .filter(|peer| peer.serves_epoch(epoch)) .map(|peer| peer.id) .collect() } @@ -1090,6 +1091,9 @@ impl Host for AppState { summaries.push(PeerSummary { id, active: peer.liveness == Liveness::Active, + member: matches!(peer.standing, Standing::Member { .. }) + && peer.hello_state == HelloState::Established, + ready: peer.reports_ready, epoch: peer.epoch, }); } |
