aboutsummaryrefslogtreecommitdiffstats
path: root/src/state/peer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/state/peer.rs')
-rw-r--r--src/state/peer.rs39
1 files changed, 38 insertions, 1 deletions
diff --git a/src/state/peer.rs b/src/state/peer.rs
index 99f912b..f6e8786 100644
--- a/src/state/peer.rs
+++ b/src/state/peer.rs
@@ -137,6 +137,10 @@ pub(crate) struct PeerState {
/// How many heads its most recent keepalive listed (None if it sent a digest).
pub(crate) reported_heads: Option<usize>,
+ /// It said farewell (`say_farewell`): what else that run of it still sends while it
+ /// stops doesn't make it active again; a message from another run does (`returned`).
+ pub(crate) left: bool,
+
/// HELLOs sent in the current handshake attempt without hearing anything back.
pub(crate) hello_attempts: u32,
/// Since when we consider the peer unreachable (three unanswered HELLOs, or
@@ -212,6 +216,7 @@ impl PeerState {
reports_ready: None,
syncs_with_us: None,
reported_heads: None,
+ left: false,
hello_attempts: 0,
unreachable_since: None,
incidents: Incidents::default(),
@@ -244,9 +249,13 @@ impl PeerState {
now.saturating_duration_since(self.last_seen.unwrap_or(self.added_at))
}
- /// Records inbound activity. Returns true if the peer was dormant.
+ /// Records inbound activity. Returns true if the peer was dormant. From a peer that
+ /// said farewell (`left`), only that it was heard from.
pub(crate) fn mark_seen(&mut self, now: Instant) -> bool {
self.last_seen = Some(now);
+ if self.left {
+ return false;
+ }
self.hello_attempts = 0;
self.unreachable_since = None;
self.probe_backoff.reset();
@@ -333,6 +342,7 @@ impl PeerState {
/// The peer said farewell (it is shutting down): Dormant now, without waiting for
/// its silence, and not counted as an incident. Returns true on the transition.
pub(crate) fn say_farewell(&mut self, now: Instant) -> bool {
+ self.left = true;
if self.liveness.is_dormant() {
return false;
}
@@ -340,6 +350,14 @@ impl PeerState {
true
}
+ /// A message from `run` of the peer (a HELLO's or HELLO_REPLY's): a run other than
+ /// the one that said farewell is back (`left`).
+ pub(crate) fn returned(&mut self, run: crate::transport::RunId) {
+ if self.run_id != Some(run) {
+ self.left = false;
+ }
+ }
+
fn go_dormant(&mut self, now: Instant) {
self.liveness = Liveness::Dormant { since: now };
self.unreachable_since.get_or_insert(now);
@@ -488,6 +506,25 @@ mod tests {
assert!(silent.liveness.is_dormant());
}
+ /// After its farewell, a peer stays dormant whatever its stopping run still sends;
+ /// its next run makes it active again.
+ #[test]
+ fn dormant_after_farewell_until_back() {
+ let timing = Timing::from_keepalive(Duration::from_secs(60), Duration::from_secs(300));
+ let mut peer = PeerState::new(true, &timing);
+ let now = peer.added_at;
+ peer.run_id = Some([1; 16]);
+ peer.mark_seen(now);
+ assert!(peer.say_farewell(now));
+ assert!(!peer.mark_seen(now), "a straggler from the same run");
+ assert!(peer.liveness.is_dormant() && peer.is_unreachable());
+ peer.returned([1; 16]);
+ assert!(!peer.mark_seen(now), "the same run again");
+ peer.returned([2; 16]);
+ assert!(peer.mark_seen(now), "its next run");
+ assert!(!peer.liveness.is_dormant() && !peer.is_unreachable());
+ }
+
/// The two sides of a pair take turns: each sends every other interval.
#[test]
fn keepalives_take_turns() {