summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/swarm/bootstrap.rs29
1 files changed, 22 insertions, 7 deletions
diff --git a/src/swarm/bootstrap.rs b/src/swarm/bootstrap.rs
index b725786..3be462e 100644
--- a/src/swarm/bootstrap.rs
+++ b/src/swarm/bootstrap.rs
@@ -14,6 +14,7 @@
use std::sync::atomic::Ordering;
use std::time::Duration;
+use std::collections::HashSet;
use std::path::Path;
use anyhow::{Context, Result, bail};
@@ -57,7 +58,7 @@ pub(crate) async fn bootstrap(state: &AppState, seeds: &[String], start: Start)
state.mark_ready(swarm_id).await?;
// Members of the swarm still running, if any: they merge with this node, or it
// rejoins them if they moved on to a newer epoch.
- resolve_seeds(state, &mut seeds.to_vec()).await;
+ resolve_seeds(state, &mut seeds.to_vec(), &mut HashSet::new()).await;
return Ok(());
}
if start == Start::Genesis {
@@ -85,7 +86,7 @@ pub(crate) async fn bootstrap(state: &AppState, seeds: &[String], start: Start)
state.initial_sync_done.store(true, Ordering::Release);
state.mark_ready(swarm_id).await?;
// Remembered members, if any, to find those still running.
- resolve_seeds(state, &mut seeds.to_vec()).await;
+ resolve_seeds(state, &mut seeds.to_vec(), &mut HashSet::new()).await;
return Ok(());
}
@@ -98,6 +99,7 @@ pub(crate) async fn bootstrap(state: &AppState, seeds: &[String], start: Start)
}
let mut unresolved: Vec<String> = seeds.to_vec();
+ let mut failing = HashSet::new();
let mut resolve_retry = RESOLVE_RETRY;
let mut next_resolve = Instant::now();
let mut next_report = Instant::now() + BOOTSTRAP_REPORT;
@@ -114,7 +116,7 @@ pub(crate) async fn bootstrap(state: &AppState, seeds: &[String], start: Start)
let now = Instant::now();
if !unresolved.is_empty() && now >= next_resolve {
- resolve_seeds(state, &mut unresolved).await;
+ resolve_seeds(state, &mut unresolved, &mut failing).await;
if !unresolved.is_empty() {
next_resolve = now + resolve_retry;
resolve_retry = (resolve_retry * 2).min(RESOLVE_RETRY_MAX);
@@ -174,20 +176,33 @@ pub(crate) fn load_backup(path: &Path) -> Result<Backup> {
}
/// Resolves the seeds in `unresolved`, says HELLO to each that resolves, and keeps the
-/// rest for later.
-async fn resolve_seeds(state: &AppState, unresolved: &mut Vec<String>) {
+/// rest for later. Warns once per seed that fails (`failing` remembers which), and says
+/// when such a seed resolves after all.
+async fn resolve_seeds(
+ state: &AppState,
+ unresolved: &mut Vec<String>,
+ failing: &mut HashSet<String>,
+) {
let mut still = Vec::new();
for seed in unresolved.drain(..) {
match state.transport.resolve_seed(&seed).await {
Ok(peer) => {
- debug!(seed = %seed, peer = %peer, "Resolved seed");
+ if failing.remove(&seed) {
+ info!(seed = %seed, peer = %peer, "Seed resolves now");
+ } else {
+ debug!(seed = %seed, peer = %peer, "Resolved seed");
+ }
remember_peer(state, &peer).await;
if let Err(error) = send_hello_once(state, &peer).await {
warn!(peer = %peer, error = %format!("{error:#}"), "Initial HELLO failed; will retry");
}
}
Err(error) => {
- warn!(seed = %seed, error = %error, "Seed doesn't resolve; will retry");
+ if failing.insert(seed.clone()) {
+ warn!(seed = %seed, error = %error, "Seed doesn't resolve; trying again until it does");
+ } else {
+ debug!(seed = %seed, error = %error, "Seed still doesn't resolve");
+ }
still.push(seed);
}
}