diff options
Diffstat (limited to 'src/swarm/hyparview.rs')
| -rw-r--r-- | src/swarm/hyparview.rs | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/src/swarm/hyparview.rs b/src/swarm/hyparview.rs index 17d36b8..004f528 100644 --- a/src/swarm/hyparview.rs +++ b/src/swarm/hyparview.rs @@ -7,7 +7,9 @@ //! link both ends agreed to (NEIGHBOUR, answered by NEIGHBOUR_REPLY), not one every //! node computes alike. A node with fewer asks others from its passive view, one at a //! time per missing neighbour; one that has none asks with high priority, and is taken -//! even where that means dropping another (told so: DISCONNECT). A neighbour that fails +//! even where that means dropping another (told so: DISCONNECT). One left with none +//! (dropped so itself) while its asks are low ones has one of them, or another, made +//! high at once, even of a member that refused before. A neighbour that fails //! (judged unreachable: unanswered HELLOs, dormant, not alive lately) leaves the active //! view, and another is asked. Every neighbour is asked again now and then whether it //! still is (`REAFFIRM_EVERY`): the paper's links are TCP connections, whose ends know @@ -282,6 +284,40 @@ impl Topology for HyParView { changed = true; } } + // No neighbour, and no ask that would make room for us (those sent while + // we had some, low, refused by full members, each refused for a while): + // one high, an ask not sent yet made so, or another, whoever refused before + // if nobody else is left. + if views.active.is_empty() && !views.asking.values().any(|asking| asking.high) { + let unsent = views + .asking + .iter() + .find(|(_, asking)| !asking.sent) + .map(|(member, _)| member.clone()); + let member = unsent.or_else(|| { + let passive = Self::passive_view(&views, &reachable); + let anyone: Vec<String> = if passive.is_empty() { + reachable + .iter() + .filter(|member| !views.asking.contains_key(*member)) + .cloned() + .collect() + } else { + passive + }; + some_of(anyone, 1).pop() + }); + if let Some(member) = member { + views.refused.remove(&member); + let asking = views.asking.entry(member).or_insert(Asking { + since: now, + high: true, + sent: false, + }); + asking.high = true; + changed = true; + } + } let mut to_ask: Vec<(String, bool)> = views .asking .iter() |
