diff options
| author | tv <tv@krebsco.de> | 2026-11-03 05:20:59 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-03 05:20:59 +0100 |
| commit | 96d7744dd29a3c783b43a7a6697af7d5d5719a10 (patch) | |
| tree | ddc154200b6086f5f9832237b6a620670ba8b4c3 /src/swarm/topology | |
| parent | 9ee8bae8cd740fc038ac6ca14eae4fad458cda31 (diff) | |
add writer trees
Diffstat (limited to 'src/swarm/topology')
| -rw-r--r-- | src/swarm/topology/mod.rs | 56 |
1 files changed, 55 insertions, 1 deletions
diff --git a/src/swarm/topology/mod.rs b/src/swarm/topology/mod.rs index 1c1a6c4..b876fd0 100644 --- a/src/swarm/topology/mod.rs +++ b/src/swarm/topology/mod.rs @@ -26,6 +26,7 @@ //! transport. With one transport, it is the one graph as before. use std::collections::{BTreeMap, BTreeSet}; +use std::sync::Arc; use tracing::info; @@ -58,6 +59,42 @@ pub(crate) struct NeighbourView { neighbours: BTreeSet<String>, /// Every reachable member is a neighbour. full_mesh: bool, + /// The graph the member list gives, as if every member reached every other + /// (`member_list_graph`): computed when first asked for, kept while the member list + /// stays the same. + whole: std::sync::OnceLock<Arc<BTreeMap<String, BTreeSet<String>>>>, +} + +/// Every member's neighbours as the member list gives them, as if every member reached +/// every other: the same on every node that knows the same member list, whatever each +/// reaches (`swarm::tree` builds writers' trees on it). On each transport among the +/// members on it, all together. None until the view is known. +pub(crate) fn member_list_graph( + state: &AppState, +) -> Option<Arc<BTreeMap<String, BTreeSet<String>>>> { + let view = state.neighbours.read_or_recover(); + let view = view.as_ref()?; + Some(Arc::clone(view.whole.get_or_init(|| { + let mut whole: BTreeMap<String, BTreeSet<String>> = view + .members + .iter() + .map(|member| (member.clone(), BTreeSet::new())) + .collect(); + let transports: BTreeSet<&String> = view.transports.values().flatten().collect(); + for transport in transports { + let on_it: Vec<String> = view + .transports + .iter() + .filter(|(_, on)| on.contains(transport)) + .map(|(member, _)| member.clone()) + .collect(); + let graph = graph(&on_it, view.k, &|_| false, &|m| view.stable.contains(m)); + for (member, neighbours) in graph { + whole.entry(member).or_default().extend(neighbours); + } + } + Arc::new(whole) + }))) } /// Whether the neighbours are computed from the member list yet (before, everyone @@ -342,7 +379,23 @@ pub(crate) async fn refresh(state: &AppState) -> Option<NeighbourChange> { }) { return None; } - view.as_ref().map(|view| view.neighbours.clone()) + view.as_ref().map(|view| { + // The member list's graph stays while the member list does. + let whole = if view.members == current + && view.k == k + && view.stable == stable + && view.transports == transports + { + view.whole.clone() + } else { + Default::default() + }; + (view.neighbours.clone(), whole) + }) + }; + let (previous, whole) = match previous { + Some((previous, whole)) => (Some(previous), whole), + None => (None, Default::default()), }; // Before the first view everyone known counted as a neighbour. @@ -400,6 +453,7 @@ pub(crate) async fn refresh(state: &AppState) -> Option<NeighbourChange> { unlisted, outbound, neighbours: computed, + whole, }); // New neighbours are kept alive and judged. state.peers_due.now(); |
