aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/simtest/bench.rs53
1 files changed, 48 insertions, 5 deletions
diff --git a/src/simtest/bench.rs b/src/simtest/bench.rs
index 09cd82c..9b18b2c 100644
--- a/src/simtest/bench.rs
+++ b/src/simtest/bench.rs
@@ -57,6 +57,12 @@ struct Scenario {
/// 10 s, not long enough to be held dormant (four keepalives, 20 s), so what a node
/// that is gone costs before the others notice.
away: Option<usize>,
+ /// Nodes that join during each workload, one at a time, evenly spread (of
+ /// `nodes`: they start with `nodes` less twice as many), and so what members joining
+ /// cost while writes go on: member lists differ between nodes until the newcomer's
+ /// registration reached them, and their trees with them. Their catching up counts
+ /// in the messages, but not in the delays (`swarm::stats`: not until caught up).
+ joining: usize,
}
fn sim_only(_: usize) -> &'static [&'static str] {
@@ -107,6 +113,7 @@ const SCENARIOS: &[Scenario] = &[
net: clean,
writer: 1,
away: None,
+ joining: 0,
},
Scenario {
name: "writer behind NAT (one link), 13 nodes",
@@ -115,6 +122,7 @@ const SCENARIOS: &[Scenario] = &[
net: writer_behind_nat,
writer: 1,
away: None,
+ joining: 0,
},
Scenario {
name: "two transports, 3 bridges, 30 nodes",
@@ -123,6 +131,7 @@ const SCENARIOS: &[Scenario] = &[
net: clean,
writer: 5,
away: None,
+ joining: 0,
},
Scenario {
name: "partial mesh, 50 nodes",
@@ -131,6 +140,7 @@ const SCENARIOS: &[Scenario] = &[
net: clean,
writer: 1,
away: None,
+ joining: 0,
},
Scenario {
name: "partial mesh, lossy and slow links, 50 nodes",
@@ -139,6 +149,7 @@ const SCENARIOS: &[Scenario] = &[
net: lossy,
writer: 1,
away: None,
+ joining: 0,
},
Scenario {
name: "partial mesh, 100 nodes",
@@ -147,6 +158,7 @@ const SCENARIOS: &[Scenario] = &[
net: clean,
writer: 1,
away: None,
+ joining: 0,
},
Scenario {
name: "partial mesh, a member away for 10 s, 50 nodes",
@@ -155,6 +167,16 @@ const SCENARIOS: &[Scenario] = &[
net: clean,
writer: 1,
away: Some(3),
+ joining: 0,
+ },
+ Scenario {
+ name: "partial mesh, 5 members joining during each workload, 50 nodes",
+ nodes: 50,
+ on: sim_only,
+ net: clean,
+ writer: 1,
+ away: None,
+ joining: 5,
},
];
@@ -327,7 +349,9 @@ async fn run(seed: u64, scenario: &'static Scenario) -> String {
config.neighbours_k = 12;
};
let mut nodes = vec![sim.start_on_with(&ids[0], (scenario.on)(0), &[], Start::Genesis, timing)];
- for (i, id) in ids.iter().enumerate().skip(1) {
+ // Those there from the start; the others join during the workloads.
+ let initial = scenario.nodes - 2 * scenario.joining;
+ for (i, id) in ids.iter().enumerate().take(initial).skip(1) {
// The writer behind NAT reaches node 2 alone.
let seed = if i == 1 {
ids[2].as_str()
@@ -339,7 +363,7 @@ async fn run(seed: u64, scenario: &'static Scenario) -> String {
let all: Vec<&AppState> = nodes.iter().collect();
let all = all.as_slice();
sim.wait_ready(all, SETTLE).await;
- let count = scenario.nodes;
+ let count = initial;
sim.wait_until(
"every node knows every member",
SETTLE,
@@ -378,6 +402,7 @@ async fn run(seed: u64, scenario: &'static Scenario) -> String {
WRITES,
1000 / WRITE_EVERY.as_millis()
);
+ let mut joined = initial;
for (w, (workload, writer)) in [
("one writer", Some(scenario.writer)),
("writers in turn", None),
@@ -386,7 +411,22 @@ async fn run(seed: u64, scenario: &'static Scenario) -> String {
.enumerate()
{
let start = Totals::of(&nodes).await;
+ // Before which writes the members joining in this workload start.
+ let joins: Vec<usize> = (1..=scenario.joining)
+ .map(|k| WRITES * k / (scenario.joining + 1))
+ .collect();
for i in 0..WRITES {
+ if joins.contains(&i) {
+ let id = &ids[joined];
+ nodes.push(sim.start_on_with(
+ id,
+ (scenario.on)(joined),
+ &[ids[0].as_str()],
+ Start::Join,
+ timing,
+ ));
+ joined += 1;
+ }
// The middle half, the node that goes away is gone (writing nothing).
if let Some(away) = scenario.away {
if i == WRITES / 4 {
@@ -396,20 +436,23 @@ async fn run(seed: u64, scenario: &'static Scenario) -> String {
}
}
let gone = scenario.away.is_some_and(|away| {
- (WRITES / 4..WRITES * 3 / 4).contains(&i) && away == i % nodes.len()
+ (WRITES / 4..WRITES * 3 / 4).contains(&i) && away == i % initial
});
if writer.is_none() && gone {
tokio::time::sleep(WRITE_EVERY).await;
continue;
}
- let node = &nodes[writer.unwrap_or(i % nodes.len())];
+ // In turn, those there from the start: one that just joined may not be
+ // ready yet.
+ let node = &nodes[writer.unwrap_or(i % initial)];
// A path of each workload's own: writing what is there already changes
// nothing, and nothing would pass.
write(node, &format!("bench/{w}/{i}"), json!(i)).await;
tokio::time::sleep(WRITE_EVERY).await;
}
let written = Instant::now();
- sim.wait_converged(all, SETTLE).await;
+ let all: Vec<&AppState> = nodes.iter().collect();
+ sim.wait_converged(&all, SETTLE).await;
let converged = written.elapsed();
report(
&mut out,