aboutsummaryrefslogtreecommitdiffstats
path: root/src/state/timing.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/state/timing.rs')
-rw-r--r--src/state/timing.rs44
1 files changed, 30 insertions, 14 deletions
diff --git a/src/state/timing.rs b/src/state/timing.rs
index 9055ed6..af5c0c0 100644
--- a/src/state/timing.rs
+++ b/src/state/timing.rs
@@ -4,15 +4,18 @@ use std::time::Duration;
use crate::backoff::Backoff;
-/// First wait for a sync answer; generous, since a transport may take a while with large
-/// messages (Mycelium sends them in many small packets).
-const SYNC_REPLY_TIMEOUT: Duration = Duration::from_secs(10);
+/// First wait for a sync answer, unless a transport needs longer
+/// (`Transport::sync_reply_timeout`); generous, since a transport may take a while with
+/// large messages (Mycelium sends them in many small packets).
+pub(crate) const SYNC_REPLY_TIMEOUT: Duration = Duration::from_secs(10);
/// Upper bound, as a multiple of the first wait: 5 minutes, about as long as a transport
/// tries to deliver a message (`Transport::delivery_limit`).
const SYNC_REPLY_TIMEOUT_MAX_FACTOR: u32 = 30;
/// Upper bound on the wait between probes of an unreachable peer, as a multiple of
-/// `dormant_probe`: an hour at the default keepalive (1m). A returning node HELLOs its own
-/// neighbours, so this only bounds how long one we never hear from stays out.
+/// `dormant_probe`, unless `--dormant-probe-max` says otherwise: an hour at the default
+/// keepalive (1m). A returning node HELLOs its own neighbours, and once one pair across
+/// a partition meets, the rest are probed at once (`handshake::probe_now`), so this
+/// bounds how long one we never hear from stays out.
const PROBE_MAX_FACTOR: u32 = 6;
#[derive(Clone, Copy, Debug)]
@@ -25,6 +28,8 @@ pub(crate) struct Timing {
pub(crate) dormant_after: Duration,
pub(crate) resync_after: Duration,
pub(crate) dormant_probe: Duration,
+ /// The longest wait between probes (`probe_backoff`).
+ pub(crate) probe_max: Duration,
/// While catching up: send the source a STATUS after this much silence (`swarm::source`).
pub(crate) catch_up_probe: Duration,
/// First wait for an answer to a sync message before sending again; doubles while
@@ -43,6 +48,12 @@ impl Timing {
self.keepalive * 5
}
+ /// [`new`](Self::new) with the default first sync reply timeout.
+ #[cfg(test)]
+ pub(crate) fn from_keepalive(keepalive: Duration, delivery_limit: Duration) -> Self {
+ Self::new(keepalive, SYNC_REPLY_TIMEOUT, delivery_limit)
+ }
+
/// The timings for `--keepalive`.
///
/// Each node keeps about `k` neighbours (`--neighbours`) whatever the swarm's size,
@@ -59,13 +70,9 @@ impl Timing {
/// | LAN, servers | 15–30 s | a returning or silent peer is noticed within a minute or two |
/// | WAN, mobile, metered (the default, 1m) | 60–120 s | about 0.4 messages per second per node at `k` = 12 and 1m |
///
- /// `delivery_limit`: the transport's (`Transport::delivery_limit`).
- pub(crate) fn from_keepalive(keepalive: Duration, delivery_limit: Duration) -> Self {
- Self::new(keepalive, SYNC_REPLY_TIMEOUT, delivery_limit)
- }
-
- /// [`from_keepalive`](Self::from_keepalive) with another first sync reply timeout:
- /// for tests, whose messages don't travel for seconds.
+ /// `sync_reply_timeout`: the transports' (`Transport::sync_reply_timeout`), or for
+ /// tests, whose messages don't travel for seconds, a shorter one. `delivery_limit`:
+ /// the transports' (`Transport::delivery_limit`).
pub(crate) fn new(
keepalive: Duration,
sync_reply_timeout: Duration,
@@ -81,6 +88,7 @@ impl Timing {
// the first sync reply timeout, so a lost message's sender resends it first.
resync_after: (keepalive * 2).max(sync_reply_timeout * 2),
dormant_probe: keepalive * 10, // >= 10*: dormant peers cost almost nothing, but still rejoin within minutes
+ probe_max: keepalive * 10 * PROBE_MAX_FACTOR,
// Seconds, not a keepalive interval: a dead source should cost little time.
// Only the source gets these, and only while catching up.
catch_up_probe: (keepalive / 30).clamp(Duration::from_secs(1), Duration::from_secs(5)),
@@ -89,10 +97,18 @@ impl Timing {
}
}
+ /// `--dormant-probe-max`, if given: the longest wait between probes.
+ pub(crate) fn with_probe_max(mut self, max: Option<Duration>) -> Self {
+ if let Some(max) = max {
+ self.probe_max = max;
+ }
+ self
+ }
+
/// Waits between probes of an unreachable peer: `dormant_probe`, doubling up to
- /// `PROBE_MAX_FACTOR` times as much.
+ /// `probe_max` (all of them `probe_max` if that is shorter).
pub(crate) fn probe_backoff(&self) -> Backoff {
- Backoff::new(self.dormant_probe, self.dormant_probe * PROBE_MAX_FACTOR)
+ Backoff::new(self.dormant_probe.min(self.probe_max), self.probe_max)
}
/// Waits for sync answers: `sync_reply_timeout`, doubling up to 30 times as much.