@@ -137,11 +137,16 @@ struct fd_crds_entry_private {
137137 ulong next ;
138138 } expire ;
139139
140- /* Finally, a core operation on the CRDS is to to query for values by
141- hash, to respond to pull requests. This is done with a treap
142- sorted by hash, which is just the first 8 bytes value_hash. */
140+ /* In order to load balance pull request messages across peers, each
141+ message has a mask value that is mask_bits long. The pull request
142+ is only concerned with CRDS entires with a hash where the first
143+ mask_bits of the hash match the mask value.
144+
145+ We need to be able to quickly iterate over all CRDS table entries
146+ matching a given mask. To do this, we store the first 8 bytes of
147+ the value_hash in a sorted treap. */
143148 struct {
144- ulong hash ;
149+ ulong hash_prefix ;
145150 ulong parent ;
146151 ulong left ;
147152 ulong right ;
@@ -204,18 +209,16 @@ struct fd_crds_entry_private {
204209#define TREAP_NAME hash_treap
205210#define TREAP_T fd_crds_entry_t
206211#define TREAP_QUERY_T ulong
207- #define TREAP_CMP (q ,e ) ((q>e->hash.hash )-(q<e->hash.hash ))
212+ #define TREAP_CMP (q ,e ) ((q>e->hash.hash_prefix )-(q<e->hash.hash_prefix ))
208213#define TREAP_IDX_T ulong
209214#define TREAP_OPTIMIZE_ITERATION 1
210215#define TREAP_NEXT hash.next
211216#define TREAP_PREV hash.prev
212- #define TREAP_LT (e0 ,e1 ) ((e0)->hash.hash<(e1)->hash.hash)
213-
217+ #define TREAP_LT (e0 ,e1 ) ((e0)->hash.hash_prefix<(e1)->hash.hash_prefix)
214218#define TREAP_PARENT hash.parent
215219#define TREAP_LEFT hash.left
216220#define TREAP_RIGHT hash.right
217221#define TREAP_PRIO hash.prio
218-
219222#include "../../../util/tmpl/fd_treap.c"
220223
221224static inline ulong
@@ -280,6 +283,7 @@ struct fd_crds_purged {
280283 /* Similar to fd_crds_entry, we want the ability to query and iterate
281284 through value by hash[:8] to generate pull requests. */
282285 struct {
286+ ulong hash_prefix ;
283287 ulong parent ;
284288 ulong left ;
285289 ulong right ;
@@ -311,17 +315,16 @@ typedef struct fd_crds_purged fd_crds_purged_t;
311315#define TREAP_NAME purged_treap
312316#define TREAP_T fd_crds_purged_t
313317#define TREAP_QUERY_T ulong
314- #define TREAP_CMP (q ,e ) ((q>*(ulong *)(e->hash))-(q<*(ulong *)(e->hash)))
318+ #define TREAP_CMP (q ,e ) ((q>e->treap.hash_prefix)-(q<e->treap.hash_prefix))
319+ #define TREAP_IDX_T ulong
315320#define TREAP_OPTIMIZE_ITERATION 1
316321#define TREAP_NEXT treap.next
317322#define TREAP_PREV treap.prev
318- #define TREAP_LT (e0 ,e1 ) (*(ulong *)((e0)->hash)<*(ulong *)((e1)->hash))
319-
320- #define TREAP_PARENT treap.parent
321- #define TREAP_LEFT treap.left
322- #define TREAP_RIGHT treap.right
323- #define TREAP_PRIO treap.prio
324-
323+ #define TREAP_LT (e0 ,e1 ) ((e0)->treap.hash_prefix<(e1)->treap.hash_prefix)
324+ #define TREAP_PARENT treap.parent
325+ #define TREAP_LEFT treap.left
326+ #define TREAP_RIGHT treap.right
327+ #define TREAP_PRIO treap.prio
325328#include "../../../util/tmpl/fd_treap.c"
326329
327330#define DLIST_NAME failed_inserts_dlist
@@ -756,7 +759,7 @@ crds_entry_init( fd_gossip_view_crds_value_t const * view,
756759 out_value -> stake = stake ;
757760
758761 fd_crds_generate_hash ( sha , payload + view -> value_off , view -> length , out_value -> value_hash );
759- out_value -> hash .hash = fd_ulong_load_8 ( out_value -> value_hash );
762+ out_value -> hash .hash_prefix = fd_ulong_bswap ( fd_ulong_load_8 ( out_value -> value_hash ) );
760763
761764 if ( FD_UNLIKELY ( view -> tag == FD_GOSSIP_VALUE_NODE_INSTANCE ) ) {
762765 out_value -> node_instance .token = view -> node_instance -> token ;
@@ -770,16 +773,19 @@ crds_entry_init( fd_gossip_view_crds_value_t const * view,
770773static inline void
771774purged_init ( fd_crds_purged_t * purged ,
772775 uchar const * hash ,
776+ ulong hash_prefix ,
773777 long now ) {
774778 fd_memcpy ( purged -> hash , hash , 32UL );
779+ purged -> treap .hash_prefix = hash_prefix ;
775780 purged -> expire .wallclock_nanos = now ;
776781}
777782
778783void
779784insert_purged ( fd_crds_t * crds ,
780785 uchar const * hash ,
781786 long now ) {
782- if ( purged_treap_ele_query ( crds -> purged .treap , * (ulong * )hash , crds -> purged .pool ) ) {
787+ ulong hash_prefix = fd_ulong_bswap ( fd_ulong_load_8 ( hash ) );
788+ if ( purged_treap_ele_query ( crds -> purged .treap , hash_prefix , crds -> purged .pool ) ) {
783789 return ;
784790 }
785791 fd_crds_purged_t * purged ;
@@ -795,7 +801,7 @@ insert_purged( fd_crds_t * crds,
795801 crds -> metrics -> purged_cnt ++ ;
796802 }
797803 }
798- purged_init ( purged , hash , now );
804+ purged_init ( purged , hash , hash_prefix , now );
799805 purged_treap_ele_insert ( crds -> purged .treap , purged , crds -> purged .pool );
800806 purged_dlist_ele_push_tail ( crds -> purged .purged_dlist , purged , crds -> purged .pool );
801807}
841847fd_crds_insert_failed_insert ( fd_crds_t * crds ,
842848 uchar const * hash ,
843849 long now ) {
844- if ( purged_treap_ele_query ( crds -> purged .treap , * (ulong * )hash , crds -> purged .pool ) ) {
850+ ulong hash_prefix = fd_ulong_bswap ( fd_ulong_load_8 ( hash ) );
851+ if ( purged_treap_ele_query ( crds -> purged .treap , hash_prefix , crds -> purged .pool ) ) {
845852 return ;
846853 }
847854 fd_crds_purged_t * failed ;
@@ -857,7 +864,7 @@ fd_crds_insert_failed_insert( fd_crds_t * crds,
857864 crds -> metrics -> purged_cnt ++ ;
858865 }
859866 }
860- purged_init ( failed , hash , now );
867+ purged_init ( failed , hash , hash_prefix , now );
861868 purged_treap_ele_insert ( crds -> purged .treap , failed , crds -> purged .pool );
862869 failed_inserts_dlist_ele_push_tail ( crds -> purged .failed_inserts_dlist , failed , crds -> purged .pool );
863870}
@@ -873,7 +880,7 @@ fd_crds_checks_fast( fd_crds_t * crds,
873880
874881 if ( FD_UNLIKELY ( !incumbent ) ) return FD_CRDS_UPSERT_CHECK_UPSERTS ;
875882
876- if ( FD_UNLIKELY ( * ( ulong * ) incumbent -> value_bytes == ( * ( ulong * )( payload + candidate -> value_off ) ) ) ) {
883+ if ( FD_UNLIKELY ( fd_ulong_load_8 ( incumbent -> value_bytes ) == fd_ulong_load_8 ( payload + candidate -> value_off ) ) ) {
877884 /* We have a duplicate, so we return the number of duplicates */
878885 return (int )(++ incumbent -> num_duplicates );
879886 }
@@ -1245,6 +1252,19 @@ fd_crds_bucket_add( fd_crds_t * crds,
12451252 crds -> samplers -> ele_cnt );
12461253}
12471254
1255+ static void
1256+ generate_masks ( ulong mask ,
1257+ uint mask_bits ,
1258+ ulong * start_mask ,
1259+ ulong * end_mask ) {
1260+ /* agave defines the mask as a ulong with the top mask_bits bits
1261+ set to the desired prefix and all other bits set to 1. */
1262+ FD_TEST ( mask_bits < 64U );
1263+ ulong range = fd_ulong_mask ( 0U , (int )(63U - mask_bits ) );
1264+ * start_mask = mask & ~range ;
1265+ * end_mask = mask | range ;
1266+ }
1267+
12481268struct fd_crds_mask_iter_private {
12491269 ulong idx ;
12501270 ulong end_hash ;
@@ -1255,12 +1275,11 @@ fd_crds_mask_iter_init( fd_crds_t const * crds,
12551275 ulong mask ,
12561276 uint mask_bits ,
12571277 uchar iter_mem [ static 16UL ] ) {
1258- fd_crds_mask_iter_t * it = (fd_crds_mask_iter_t * )iter_mem ;
1259- ulong start_hash = 0 ;
1260- if ( FD_LIKELY ( mask_bits > 0 ) ) start_hash = (mask & (~0UL <<(64UL - mask_bits )));
1261-
1262- it -> end_hash = mask ;
1278+ ulong start_hash , end_hash ;
1279+ generate_masks ( mask , mask_bits , & start_hash , & end_hash );
12631280
1281+ fd_crds_mask_iter_t * it = (fd_crds_mask_iter_t * )iter_mem ;
1282+ it -> end_hash = end_hash ;
12641283 it -> idx = hash_treap_idx_ge ( crds -> hash_treap , start_hash , crds -> pool );
12651284 return it ;
12661285}
@@ -1276,7 +1295,7 @@ int
12761295fd_crds_mask_iter_done ( fd_crds_mask_iter_t * it , fd_crds_t const * crds ) {
12771296 fd_crds_entry_t const * val = hash_treap_ele_fast_const ( it -> idx , crds -> pool );
12781297 return hash_treap_idx_is_null ( it -> idx ) ||
1279- (it -> end_hash < val -> hash .hash );
1298+ (it -> end_hash < val -> hash .hash_prefix );
12801299}
12811300
12821301fd_crds_entry_t const *
@@ -1289,11 +1308,11 @@ fd_crds_purged_mask_iter_init( fd_crds_t const * crds,
12891308 ulong mask ,
12901309 uint mask_bits ,
12911310 uchar iter_mem [ static 16UL ] ){
1292- fd_crds_mask_iter_t * it = (fd_crds_mask_iter_t * )iter_mem ;
1293- ulong start_hash = 0 ;
1294- if ( FD_LIKELY ( mask_bits > 0 ) ) start_hash = (mask & (~0UL <<(64UL - mask_bits )));
1295- it -> end_hash = mask ;
1311+ ulong start_hash , end_hash ;
1312+ generate_masks ( mask , mask_bits , & start_hash , & end_hash );
12961313
1314+ fd_crds_mask_iter_t * it = (fd_crds_mask_iter_t * )iter_mem ;
1315+ it -> end_hash = end_hash ;
12971316 it -> idx = purged_treap_idx_ge ( crds -> purged .treap , start_hash , crds -> purged .pool );
12981317 return it ;
12991318}
@@ -1311,7 +1330,7 @@ fd_crds_purged_mask_iter_done( fd_crds_mask_iter_t * it,
13111330 fd_crds_t const * crds ){
13121331 fd_crds_purged_t const * val = purged_treap_ele_fast_const ( it -> idx , crds -> purged .pool );
13131332 return purged_treap_idx_is_null ( it -> idx ) ||
1314- (it -> end_hash < fd_ulong_load_8 ( val -> hash ) );
1333+ (it -> end_hash < val -> treap . hash_prefix );
13151334}
13161335
13171336/* fd_crds_purged_mask_iter_hash returns the hash of the current
0 commit comments