diff options
| author | tv <tv@krebsco.de> | 2026-11-05 03:40:09 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-05 03:40:09 +0100 |
| commit | 11d098477cfc76da0bc4385635e4c4b7124a9259 (patch) | |
| tree | 941640ead4d8e80b291780f708a56f8be53a0fe1 /src/swarm/relay.rs | |
| parent | 9f9015a35b591043ebaf6e306f967ffc62cd07f5 (diff) | |
announce only to those behind
Diffstat (limited to 'src/swarm/relay.rs')
| -rw-r--r-- | src/swarm/relay.rs | 40 |
1 files changed, 28 insertions, 12 deletions
diff --git a/src/swarm/relay.rs b/src/swarm/relay.rs index e049846..31df0d3 100644 --- a/src/swarm/relay.rs +++ b/src/swarm/relay.rs @@ -251,8 +251,11 @@ async fn announce_now(state: &AppState, pending: &Pending, slow: bool) { /// The neighbours to tell of the changes `senders` sent us. The peer whose changes we /// announce has them already, so with a single sender it is skipped; with several, each /// lacks the others' changes. So is a neighbour whose latest heads (its STATUS, an -/// announcement of its own, or its STATUS_REPLY) are ours now: it has all we have; and -/// one `sent` the changes along a writer's tree, which has them already. +/// announcement of its own, its STATUS_REPLY, or its latest sync message) are ours, or +/// have all of ours in their history: it has all we have; and one `sent` the changes +/// along a writer's tree, which has them already. Only what the neighbour said counts, +/// not what we sent it: a message along a tree may be lost, which is what the slow +/// round is for. async fn unreached( state: &AppState, senders: &HashSet<String>, @@ -262,11 +265,13 @@ async fn unreached( 1 => senders.iter().next().cloned(), _ => None, }; - let ours = { + let (epoch, heads) = { let stamp = state.stamp.borrow(); - (stamp.epoch, HeadsSummary::of(stamp.heads.to_vec())) + (stamp.epoch, stamp.heads.to_vec()) }; - let mut unreached = Vec::new(); + let ours = HeadsSummary::of(heads.clone()); + // What each neighbour said it has. + let mut said = Vec::new(); for (peer, peer_state) in state.peers_snapshot().await { if skip.as_deref() == Some(peer.as_str()) || sent.contains(&peer) @@ -274,17 +279,28 @@ async fn unreached( { continue; } - let has_ours = peer_state + let last = peer_state .lock() .await .last_heads - .as_ref() - .is_some_and(|(epoch, heads)| *epoch == ours.0 && *heads == ours.1); - if !has_ours { - unreached.push(peer); - } + .clone() + .filter(|(theirs, _)| *theirs == epoch) + .map(|(_, heads)| heads); + said.push((peer, last)); + } + let replica = state.doc.read().await; + if replica.epoch != epoch { + return said.into_iter().map(|(peer, _)| peer).collect(); } - unreached + said.into_iter() + .filter(|(_, last)| { + !last.as_ref().is_some_and(|theirs| { + *theirs == ours + || crate::document::changes::covers(&replica.doc, theirs.listed(), &heads) + }) + }) + .map(|(peer, _)| peer) + .collect() } /// Pulls in progress: one neighbour at a time, so each change arrives about once. The |
