aboutsummaryrefslogtreecommitdiffstats
path: root/src/swarm/peer
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-04 05:14:12 +0100
committertv <tv@krebsco.de>2026-11-04 05:14:12 +0100
commit40073ebf9570464a69a928eba9c51b4dad6e699a (patch)
treef82fdd38ed24603be5c66740af39a786f213cd1a /src/swarm/peer
parente8d1cbddcaec18f79f54cad671f15bbaa189673b (diff)
announcements answered when lacking
A neighbour now answers an announcement only if it lacks some of the announced heads. Heads that merely differ are no longer enough, since they do while writes go on. The check reads the document, so it runs off the message consumer, as the pull check already does.
Diffstat (limited to 'src/swarm/peer')
-rw-r--r--src/swarm/peer/inbound.rs24
-rw-r--r--src/swarm/peer/keepalive.rs4
2 files changed, 23 insertions, 5 deletions
diff --git a/src/swarm/peer/inbound.rs b/src/swarm/peer/inbound.rs
index 1454c3e..28066cb 100644
--- a/src/swarm/peer/inbound.rs
+++ b/src/swarm/peer/inbound.rs
@@ -143,13 +143,31 @@ pub(crate) async fn handle_message(
crate::swarm::blob::handle(state, &peer, blob).await;
}
transport::ParsedMessage::Status(remote) => {
- // An announcement is no keepalive; it is answered only if our heads differ,
- // so the announcer learns what we have that it lacks.
+ // An announcement is no keepalive; it is answered only if we lack some of the
+ // heads it announced (`relay::lacks`), so the announcer learns what we have
+ // that it lacks while we pull. Having all of them, we are as far or further,
+ // and what we have further we announced ourselves; differing heads alone are
+ // no reason, as changes on their way to us make them differ while writes go on.
if !remote.announcing {
status_received(state, &peer).await;
}
let local = on_status(state, &peer, &remote, reactivated).await;
- if remote.announcing && local.heads == remote.heads {
+ if remote.announcing {
+ if local.heads != remote.heads {
+ // Off the consumer: telling which heads we lack takes the document's
+ // lock.
+ let (state, peer) = (state.clone(), peer.clone());
+ tokio::spawn(async move {
+ if crate::swarm::relay::lacks(&state, &remote.heads).await
+ && let Err(error) = state
+ .transport
+ .send_message(&peer, &ParsedMessage::StatusReply(local))
+ .await
+ {
+ debug!(peer = %peer, error = %format!("{error:#}"), "STATUS_REPLY failed");
+ }
+ });
+ }
return Ok(());
}
if let Err(error) = state
diff --git a/src/swarm/peer/keepalive.rs b/src/swarm/peer/keepalive.rs
index 8362d73..f4e961f 100644
--- a/src/swarm/peer/keepalive.rs
+++ b/src/swarm/peer/keepalive.rs
@@ -33,8 +33,8 @@ pub(crate) async fn send_status(state: &AppState, peer: &str) -> Result<()> {
}
/// Sends `peer` a STATUS announcing our new heads (`swarm::relay`): no keepalive, so it
-/// leaves the keepalives' schedule as it is, and it is answered only if the peer's heads
-/// differ (`Status::announcing`). Whom we reach only `with_reaches` (`swarm::reach`):
+/// leaves the keepalives' schedule as it is, and it is answered only if the peer lacks
+/// some of our heads (`Status::announcing`). Whom we reach only `with_reaches` (`swarm::reach`):
/// announcements of heads go often.
pub(crate) async fn announce_heads(state: &AppState, peer: &str, with_reaches: bool) -> Result<()> {
let local = local_status(state, peer).await;