aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-01 13:25:49 +0100
committertv <tv@krebsco.de>2026-11-01 13:25:49 +0100
commit9333940209c48d460a5f61b80ba827db7889f147 (patch)
treec818fcba62b052cd77934d91de66a0ba9539400a
parentd5de69630cf544fd048c8376e1b51cd0e4e7c7fc (diff)
electorate window must be at least 7d
-rw-r--r--src/config/mod.rs9
-rw-r--r--src/swarm/members.rs9
2 files changed, 14 insertions, 4 deletions
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 418c8e3..c5b2dad 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -254,7 +254,7 @@ pub(crate) const OPTIONS: &[OptionSpec] = &[
Kind::Duration,
"DURATION",
Some("7d"),
- "Members that renewed their alive stamp within this time vote on remakes (a majority of them must agree). Matters on the node that coordinates a remake.",
+ "Members that renewed their alive stamp within this time vote on remakes (a majority of them must agree). At least 7h (members renew every seventh of their own window, hourly at most); the same on every node, or a coordinator with a shorter one counts fewer members.",
),
option(
"clock-skew-warn",
@@ -748,8 +748,11 @@ impl Settings {
if !(1024..=4 << 20).contains(&self.blob_chunk) {
bail!("blob-chunk must be between 1KiB and 4MiB");
}
- if self.electorate_window.is_zero() {
- bail!("electorate-window must be longer than 0");
+ // Members renew their alive stamp hourly at most (`members::alive_renewal`): in
+ // a shorter window, live members would drop out between renewals, down to an
+ // electorate of the coordinator alone.
+ if self.electorate_window < crate::swarm::members::MIN_ELECTORATE_WINDOW {
+ bail!("electorate-window must be at least 7h (seven hourly renewals)");
}
if let Some(alias) = &self.alias {
check_alias(alias)?;
diff --git a/src/swarm/members.rs b/src/swarm/members.rs
index 6be523c..098c767 100644
--- a/src/swarm/members.rs
+++ b/src/swarm/members.rs
@@ -229,9 +229,16 @@ pub(crate) fn electorate(doc: &impl ReadDoc, now_ms: u64, window: Duration) -> V
/// drops out of the electorate (a seventh of the window), but at most hourly and at
/// least daily, so idle swarms stay quiet.
fn alive_renewal(window: Duration) -> Duration {
- (window / 7).clamp(Duration::from_secs(3600), Duration::from_secs(24 * 3600))
+ (window / 7).clamp(RENEWAL_MOST_OFTEN, Duration::from_secs(24 * 3600))
}
+const RENEWAL_MOST_OFTEN: Duration = Duration::from_secs(3600);
+
+/// The shortest `--electorate-window`: seven renewals at most often, so a live node
+/// renews within a seventh of it, as with any longer one.
+pub(crate) const MIN_ELECTORATE_WINDOW: Duration =
+ Duration::from_secs(7 * RENEWAL_MOST_OFTEN.as_secs());
+
/// Registers this node if it is ready and its entry is missing, keeps its alias as
/// configured (set, changed or removed after a restart with another `--alias`) and its
/// addresses as the transport gives them, and renews its `alive` stamp now and then