aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-05 05:46:15 +0100
committertv <tv@krebsco.de>2026-11-05 05:46:15 +0100
commit13476a8cf598770b501cf0b02a26725a6f5ce3d5 (patch)
treec8e067045039f50ce3020add3a7a2aee7d8538ee
parent4e53e152f83ecb88fa162e0a18e6832df5a38fef (diff)
trees as member chose
-rw-r--r--src/simtest/bench.rs10
-rw-r--r--src/swarm/tree.rs25
2 files changed, 29 insertions, 6 deletions
diff --git a/src/simtest/bench.rs b/src/simtest/bench.rs
index 40b413d..39e054e 100644
--- a/src/simtest/bench.rs
+++ b/src/simtest/bench.rs
@@ -600,7 +600,15 @@ async fn trees(out: &mut String, nodes: &[AppState], net: &crate::transport::sim
};
let mut latencies = Vec::new();
for node in nodes {
- latencies.extend(crate::swarm::tree::own_latencies(node, &latency).await);
+ // Each member's parent in this node's tree, as the member chose it.
+ let mut parents = std::collections::HashMap::new();
+ for member in nodes {
+ if member.local_id() != node.local_id() {
+ let chosen = crate::swarm::tree::own_parent(member, node.local_id()).await;
+ parents.insert(member.local_id().to_owned(), chosen);
+ }
+ }
+ latencies.extend(crate::swarm::tree::own_latencies(node, &parents, &latency).await);
}
let members: usize = latencies.iter().map(|l| l.members).sum();
if members == 0 {
diff --git a/src/swarm/tree.rs b/src/swarm/tree.rs
index f04e442..29186d8 100644
--- a/src/swarm/tree.rs
+++ b/src/swarm/tree.rs
@@ -327,7 +327,9 @@ fn shape(
/// How long our writes take to reach the members along our own tree, by link latency
/// alone (the bench's, which knows each link's): the mean over the members it reaches
-/// (and the others do), against two other trees of ours. In one, each member's parent is
+/// (and the others do), against two other trees of ours. Our tree as the members chose
+/// their parents (`parents`, from `own_parent` on each): of members beyond our
+/// neighbours, we don't know the round trips their choice goes by. In one, each member's parent is
/// chosen as now, but among those as close to us and as well placed (`rank`) by the
/// exact latency, not the round-trip bucket it said; in the other, every member takes the fastest path over the links members
/// reach (no tree computed alike everywhere gets below it). In milliseconds, one way.
@@ -340,11 +342,23 @@ pub(crate) struct Latencies {
pub(crate) fastest: f64,
}
+/// Our parent in `writer`'s tree, as we choose it (`parent`, by what we and our
+/// neighbours said); None if we have none, or no tree is known.
+#[cfg(test)]
+pub(crate) async fn own_parent(state: &AppState, writer: &str) -> Option<String> {
+ let (graph, distance) = distances(state, topology::pair_key(writer))?;
+ let known = known_reaches(state, &graph).await;
+ let reached = |by: &str, member: &str| known.reached(by, member);
+ let round_trip = |by: &str, member: &str| known.round_trip(by, member);
+ parent(&graph, &distance, &reached, &round_trip, state.local_id()).map(str::to_owned)
+}
+
/// `Latencies` of our own tree, by `latency(from, to)` in milliseconds; None while the
/// member list isn't known, or we aren't in it, or the tree reaches nobody.
#[cfg(test)]
pub(crate) async fn own_latencies(
state: &AppState,
+ parents: &HashMap<String, Option<String>>,
latency: &(dyn Fn(&str, &str) -> f64 + Sync),
) -> Option<Latencies> {
let me = state.local_id();
@@ -360,10 +374,11 @@ pub(crate) async fn own_latencies(
let now: HashMap<&str, Option<&str>> = members
.iter()
.map(|member| {
- (
- *member,
- parent(&graph, &distance, &reached, &round_trip, member),
- )
+ let chosen = match parents.get(*member) {
+ Some(chosen) => chosen.as_deref(),
+ None => parent(&graph, &distance, &reached, &round_trip, member),
+ };
+ (*member, chosen)
})
.collect();
let faster: HashMap<&str, Option<&str>> = members