summaryrefslogtreecommitdiffstats
path: root/src/remake/switch.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/remake/switch.rs')
-rw-r--r--src/remake/switch.rs23
1 files changed, 22 insertions, 1 deletions
diff --git a/src/remake/switch.rs b/src/remake/switch.rs
index e9f49ee..cf5ea75 100644
--- a/src/remake/switch.rs
+++ b/src/remake/switch.rs
@@ -26,6 +26,8 @@ use tracing::{error, info, warn};
use super::Host;
use super::catchup;
+use super::content;
+use super::coordinator;
use super::delta::{self, ReplayStats};
use super::kind::Translator;
use super::local::LocalStatus;
@@ -82,7 +84,16 @@ async fn check<H: Host>(host: &H) {
vote::cast(host).await;
let all = host.read_doc(records::load_all).await;
+ content::prune(
+ host,
+ &all,
+ unix_millis(),
+ host.dormant_after().as_millis() as u64,
+ );
let local_record = EpochRecord::from(local);
+ if host.is_node_ready().await {
+ coordinator::resume(host, &local_record, &all);
+ }
let committed: Vec<(String, Record)> = all
.into_iter()
@@ -94,6 +105,10 @@ async fn check<H: Host>(host: &H) {
let (id, record) = match committed.as_slice() {
// Nothing committed here; maybe peers moved on without us.
[] => return catchup::check(host).await,
+ [(id, record)] if record.contested => {
+ error!(remake = %id, "Decisions on this remake disagree; not switching on my own");
+ return catchup::check(host).await;
+ }
[(id, record)] => (id.clone(), record.clone()),
several => {
// Majority voting prevents this; never guess which one is right. Peers
@@ -157,10 +172,16 @@ async fn switch<H: Host>(
id: &str,
record: &Record,
) -> Result<(ReplayStats, Option<String>), String> {
- let (Some(expected), Some(request)) = (record.committed_epoch(), record.snapshot_request(id))
+ let (Some(expected), Some(mut request)) =
+ (record.committed_epoch(), record.snapshot_request(id))
else {
return Err("unreadable remake record".to_owned());
};
+ // Voters fetched it already; a node that didn't vote fetches it now. Without it the
+ // switch fails, and the node rejoins (downloading the snapshot instead).
+ if let Some(reference) = &record.proposal.content {
+ request.content = Some(content::ensure(host, reference).await?);
+ }
let translator = request
.translator()
.ok_or_else(|| format!("unknown remake kind {:?}", request.kind))?;