diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/document/sync.rs | 17 | ||||
| -rw-r--r-- | src/simtest/bench.rs | 4 | ||||
| -rw-r--r-- | src/swarm/stats.rs | 9 | ||||
| -rw-r--r-- | src/swarm/sync.rs | 9 |
4 files changed, 36 insertions, 3 deletions
diff --git a/src/document/sync.rs b/src/document/sync.rs index f9f0295..179df78 100644 --- a/src/document/sync.rs +++ b/src/document/sync.rs @@ -700,6 +700,23 @@ impl SyncSession { } } + /// Whether the peer, as the message just applied says, is behind us: all its heads + /// in our history, and not all of ours. Asked before `answered_as_delivered`: a + /// message taken as delivered from a peer behind us is answered with what it lacks + /// (a node that got its writer's changes before its parent did, by another way). + pub(crate) fn peer_behind( + &self, + doc: &Document, + heads: &[crate::document::ChangeHash], + ) -> bool { + self.state.their_heads.as_ref().is_some_and(|theirs| { + theirs + .iter() + .all(|hash| doc.get_change_by_hash(hash).is_some()) + && heads.iter().any(|hash| !theirs.contains(hash)) + }) + } + /// We applied a message its sender took as delivered (`assume_delivered`, /// `SyncEnvelope::delivered`) to `doc`: if we hold exactly its sender's heads now, /// Automerge's answer, our heads, would tell it nothing. So none goes: we count as diff --git a/src/simtest/bench.rs b/src/simtest/bench.rs index 80c8858..1498317 100644 --- a/src/simtest/bench.rs +++ b/src/simtest/bench.rs @@ -346,6 +346,7 @@ impl Totals { relay.new_changes += stats.relay.new_changes; relay.asked_known_lately += stats.relay.asked_known_lately; relay.asked_known_later += stats.relay.asked_known_later; + relay.answering_behind += stats.relay.answering_behind; relay.nothing_new_change_bytes += stats.relay.nothing_new_change_bytes; relay.waiting += stats.relay.waiting; relay.off_tree += stats.relay.off_tree; @@ -782,8 +783,9 @@ fn report( ); let _ = writeln!( out, - " asked for, though counted as the asker's (another parent brings them): {:.2} per write ({lately} within 2 s, {later} later)", + " asked for, though counted as the asker's (another parent brings them): {:.2} per write ({lately} within 2 s, {later} later); {:.2} per write taken as delivered by a sender behind the receiver, answered", (lately + later) as f64 / writes, + (r1.answering_behind - r0.answering_behind) as f64 / writes, ); let (i0, i1) = (during.0.incidents, during.1.incidents); let _ = writeln!( diff --git a/src/swarm/stats.rs b/src/swarm/stats.rs index 02ccad5..218d5e8 100644 --- a/src/swarm/stats.rs +++ b/src/swarm/stats.rs @@ -166,6 +166,10 @@ pub(crate) struct Relay { /// counting them so (so they weren't what we passed on built on), and later. pub(crate) asked_known_lately: u64, pub(crate) asked_known_later: u64, + /// Messages taken as delivered by their sender, which was behind us: answered with + /// what it lacks (it got changes we had along its tree late, or we got them early by + /// another way). + pub(crate) answering_behind: u64, /// Changes from elsewhere that came not along a writer's tree (pulled, with an /// answer, sent again, fetched as a delta), and their delays summed (as `Propagation`). pub(crate) off_tree: u64, @@ -312,6 +316,11 @@ impl NodeStats { inner.relay.nothing_new_change_bytes += change_bytes as u64; } + /// A message taken as delivered came from a peer behind us (`Relay::answering_behind`). + pub(crate) fn answering_behind(&self) { + self.lock().relay.answering_behind += 1; + } + /// A sync message carried changes that wait for predecessors (`Relay::waiting`). pub(crate) fn waiting(&self) { self.lock().relay.waiting += 1; diff --git a/src/swarm/sync.rs b/src/swarm/sync.rs index c969678..5100b98 100644 --- a/src/swarm/sync.rs +++ b/src/swarm/sync.rs @@ -603,10 +603,15 @@ pub(crate) async fn handle_sync( let heads_after = replica.heads().to_vec(); if delivered { // Level with the sender now, which takes the message as delivered: - // nothing to answer (`SyncSession::answered_as_delivered`). - peer_state + // nothing to answer (`SyncSession::answered_as_delivered`). Unless it is + // behind us: then the answer brings it what it lacks. + let behind = peer_state.sync.peer_behind(&replica.doc, &heads_after); + let answered = peer_state .sync .answered_as_delivered(&replica.doc, &heads_after); + if behind && !answered { + stats.answering_behind(); + } } stats.heads_seen(heads_after.len()); let changed = heads_after != heads_before; |
