diff options
Diffstat (limited to 'src/swarm/bootstrap.rs')
| -rw-r--r-- | src/swarm/bootstrap.rs | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/src/swarm/bootstrap.rs b/src/swarm/bootstrap.rs index a9ab1b2..4f6c072 100644 --- a/src/swarm/bootstrap.rs +++ b/src/swarm/bootstrap.rs @@ -18,7 +18,6 @@ use std::collections::HashSet; use std::path::Path; use anyhow::{Context, Result, bail}; -use automerge::{ActorId, AutoCommit}; use serde_json::Value as JsonValue; use tokio::time::Instant; use tracing::{debug, info, warn}; @@ -28,13 +27,13 @@ use crate::document; use crate::document::meta::{self, SWARM}; use crate::document::replica::Epoch; use crate::document::store; +use crate::document::{ActorId, Document}; use crate::files::{FileKind, Files}; use crate::force::Force; use crate::remake::snapshot; use crate::state::AppState; use crate::swarm::peer::{remember_peer, send_hello_once}; -const BOOTSTRAP_POLL: Duration = Duration::from_millis(500); /// How often a node that is still joining says why. const BOOTSTRAP_REPORT: Duration = Duration::from_secs(300); /// Retrying seeds that didn't resolve: first after this, doubling up to the maximum. @@ -112,6 +111,7 @@ pub(crate) async fn bootstrap(state: &AppState, seeds: &[String], start: Start) let mut resolve_retry = RESOLVE_RETRY; let mut next_resolve = Instant::now(); let mut next_report = Instant::now() + BOOTSTRAP_REPORT; + state.transport.on_seeds_found(state.join_progress.clone()); loop { if let Some(swarm_id) = state.swarm_id().await { // A node joining a compacted swarm rejoins the newer epoch first; it is @@ -147,7 +147,19 @@ pub(crate) async fn bootstrap(state: &AppState, seeds: &[String], start: Start) next_report = now + BOOTSTRAP_REPORT; report_joining(state, seeds, &unresolved).await; } - tokio::time::sleep(BOOTSTRAP_POLL).await; + // Until something changes (`join_progress`), or it's time to resolve or report. + let resolving = async { + if unresolved.is_empty() { + std::future::pending().await + } else { + tokio::time::sleep_until(next_resolve).await + } + }; + tokio::select! { + () = state.join_progress.notified() => {} + () = resolving => {} + () = tokio::time::sleep_until(next_report) => {} + } } } @@ -156,7 +168,7 @@ fn swarm_id_path() -> Vec<String> { } /// The swarm ID the document names, if any. -fn read_swarm_id(doc: &AutoCommit) -> Option<String> { +fn read_swarm_id(doc: &Document) -> Option<String> { match store::read_path(doc, &swarm_id_path()) { Ok(Some(JsonValue::String(id))) if !id.is_empty() => Some(id), _ => None, @@ -184,7 +196,7 @@ impl Origin { /// A document the node starts from, ready at once: on the swarm and epoch it names. pub(crate) struct StartingDocument { /// Under a fresh actor. - pub(crate) doc: AutoCommit, + pub(crate) doc: Document, pub(crate) epoch: Epoch, pub(crate) swarm_id: String, pub(crate) origin: Origin, @@ -281,7 +293,7 @@ pub(crate) fn starting_document( /// The swarm and epoch `doc` is on. fn identify( - mut doc: AutoCommit, + doc: Document, origin: Origin, earlier_actors: Vec<ActorId>, ) -> Result<StartingDocument> { @@ -289,8 +301,7 @@ fn identify( let Some(swarm_id) = read_swarm_id(&doc) else { bail!("{what} names no swarm (no _continuum/swarm); it predates swarm IDs in documents"); }; - let epoch = - snapshot::epoch_of(&mut doc).map_err(|reason| anyhow::anyhow!("{what}: {reason}"))?; + let epoch = snapshot::epoch_of(&doc).map_err(|reason| anyhow::anyhow!("{what}: {reason}"))?; Ok(StartingDocument { doc, epoch, @@ -300,15 +311,13 @@ fn identify( }) } -/// A backup to recover from, as `GET /admin/document` saves it, under a fresh actor. -fn load_backup(path: &Path, files: &Files) -> Result<AutoCommit> { +/// A backup to recover from, as `GET /admin/document` saves it (`document::load`). +fn load_backup(path: &Path, files: &Files) -> Result<Document> { let bytes = files .read(FileKind::Backup, path) .with_context(|| format!("Reading the backup {}", path.display()))? .with_context(|| format!("The backup {} doesn't exist", path.display()))?; - Ok(AutoCommit::load(&bytes) - .with_context(|| format!("Loading the backup {}", path.display()))? - .with_actor(ActorId::random())) + crate::document::load(&bytes).with_context(|| format!("Loading the backup {}", path.display())) } /// Resolves the seeds in `unresolved`, says HELLO to each that resolves, and keeps the |
