@@ -115,6 +115,9 @@ pub(crate) struct CrdsDataStats {
115115pub ( crate ) struct CrdsStats {
116116 pub ( crate ) pull : CrdsDataStats ,
117117 pub ( crate ) push : CrdsDataStats ,
118+ /// number of times a message was first received via a PullResponse
119+ /// and that message was later received via a PushMessage
120+ pub ( crate ) num_redundant_pull_responses : u64 ,
118121}
119122
120123/// This structure stores some local metadata associated with the CrdsValue
@@ -127,8 +130,10 @@ pub struct VersionedCrdsValue {
127130 pub ( crate ) local_timestamp : u64 ,
128131 /// value hash
129132 pub ( crate ) value_hash : Hash ,
130- /// Number of times duplicates of this value are recevied from gossip push.
131- num_push_dups : u8 ,
133+ /// None -> value upserted by GossipRoute::{LocalMessage,PullRequest}
134+ /// Some(0) -> value upserted by GossipRoute::PullResponse
135+ /// Some(k) if k > 0 -> value upserted by GossipRoute::PushMessage w/ k - 1 push duplicates
136+ num_push_recv : Option < u8 > ,
132137}
133138
134139#[ derive( Clone , Copy , Default ) ]
@@ -147,14 +152,21 @@ impl Cursor {
147152}
148153
149154impl VersionedCrdsValue {
150- fn new ( value : CrdsValue , cursor : Cursor , local_timestamp : u64 ) -> Self {
155+ fn new ( value : CrdsValue , cursor : Cursor , local_timestamp : u64 , route : GossipRoute ) -> Self {
151156 let value_hash = hash ( & serialize ( & value) . unwrap ( ) ) ;
157+ let num_push_recv = match route {
158+ GossipRoute :: LocalMessage => None ,
159+ GossipRoute :: PullRequest => None ,
160+ GossipRoute :: PullResponse => Some ( 0 ) ,
161+ GossipRoute :: PushMessage ( _) => Some ( 1 ) ,
162+ } ;
163+
152164 VersionedCrdsValue {
153165 ordinal : cursor. ordinal ( ) ,
154166 value,
155167 local_timestamp,
156168 value_hash,
157- num_push_dups : 0u8 ,
169+ num_push_recv ,
158170 }
159171 }
160172}
@@ -222,7 +234,7 @@ impl Crds {
222234 ) -> Result < ( ) , CrdsError > {
223235 let label = value. label ( ) ;
224236 let pubkey = value. pubkey ( ) ;
225- let value = VersionedCrdsValue :: new ( value, self . cursor , now) ;
237+ let value = VersionedCrdsValue :: new ( value, self . cursor , now, route ) ;
226238 match self . table . entry ( label) {
227239 Entry :: Vacant ( entry) => {
228240 self . stats . lock ( ) . unwrap ( ) . record_insert ( & value, route) ;
@@ -303,8 +315,12 @@ impl Crds {
303315 Err ( CrdsError :: InsertFailed )
304316 } else if matches ! ( route, GossipRoute :: PushMessage ( _) ) {
305317 let entry = entry. get_mut ( ) ;
306- entry. num_push_dups = entry. num_push_dups . saturating_add ( 1 ) ;
307- Err ( CrdsError :: DuplicatePush ( entry. num_push_dups ) )
318+ if entry. num_push_recv == Some ( 0 ) {
319+ self . stats . lock ( ) . unwrap ( ) . num_redundant_pull_responses += 1 ;
320+ }
321+ let num_push_dups = entry. num_push_recv . unwrap_or_default ( ) ;
322+ entry. num_push_recv = Some ( num_push_dups. saturating_add ( 1 ) ) ;
323+ Err ( CrdsError :: DuplicatePush ( num_push_dups) )
308324 } else {
309325 Err ( CrdsError :: InsertFailed )
310326 }
@@ -1450,8 +1466,9 @@ mod tests {
14501466 #[ allow( clippy:: neg_cmp_op_on_partial_ord) ]
14511467 fn test_equal ( ) {
14521468 let val = CrdsValue :: new_unsigned ( CrdsData :: LegacyContactInfo ( ContactInfo :: default ( ) ) ) ;
1453- let v1 = VersionedCrdsValue :: new ( val. clone ( ) , Cursor :: default ( ) , 1 ) ;
1454- let v2 = VersionedCrdsValue :: new ( val, Cursor :: default ( ) , 1 ) ;
1469+ let v1 =
1470+ VersionedCrdsValue :: new ( val. clone ( ) , Cursor :: default ( ) , 1 , GossipRoute :: LocalMessage ) ;
1471+ let v2 = VersionedCrdsValue :: new ( val, Cursor :: default ( ) , 1 , GossipRoute :: LocalMessage ) ;
14551472 assert_eq ! ( v1, v2) ;
14561473 assert ! ( !( v1 != v2) ) ;
14571474 assert ! ( !overrides( & v1. value, & v2) ) ;
@@ -1467,6 +1484,7 @@ mod tests {
14671484 ) ) ) ,
14681485 Cursor :: default ( ) ,
14691486 1 , // local_timestamp
1487+ GossipRoute :: LocalMessage ,
14701488 ) ;
14711489 let v2 = VersionedCrdsValue :: new (
14721490 {
@@ -1476,6 +1494,7 @@ mod tests {
14761494 } ,
14771495 Cursor :: default ( ) ,
14781496 1 , // local_timestamp
1497+ GossipRoute :: LocalMessage ,
14791498 ) ;
14801499
14811500 assert_eq ! ( v1. value. label( ) , v2. value. label( ) ) ;
@@ -1501,6 +1520,7 @@ mod tests {
15011520 ) ) ) ,
15021521 Cursor :: default ( ) ,
15031522 1 , // local_timestamp
1523+ GossipRoute :: LocalMessage ,
15041524 ) ;
15051525 let v2 = VersionedCrdsValue :: new (
15061526 CrdsValue :: new_unsigned ( CrdsData :: LegacyContactInfo ( ContactInfo :: new_localhost (
@@ -1509,6 +1529,7 @@ mod tests {
15091529 ) ) ) ,
15101530 Cursor :: default ( ) ,
15111531 1 , // local_timestamp
1532+ GossipRoute :: LocalMessage ,
15121533 ) ;
15131534 assert_eq ! ( v1. value. label( ) , v2. value. label( ) ) ;
15141535 assert ! ( overrides( & v1. value, & v2) ) ;
@@ -1527,6 +1548,7 @@ mod tests {
15271548 ) ) ) ,
15281549 Cursor :: default ( ) ,
15291550 1 , // local_timestamp
1551+ GossipRoute :: LocalMessage ,
15301552 ) ;
15311553 let v2 = VersionedCrdsValue :: new (
15321554 CrdsValue :: new_unsigned ( CrdsData :: LegacyContactInfo ( ContactInfo :: new_localhost (
@@ -1535,6 +1557,7 @@ mod tests {
15351557 ) ) ) ,
15361558 Cursor :: default ( ) ,
15371559 1 , // local_timestamp
1560+ GossipRoute :: LocalMessage ,
15381561 ) ;
15391562 assert_ne ! ( v1, v2) ;
15401563 assert ! ( !( v1 == v2) ) ;
0 commit comments