Skip to content

Commit 3f06cf9

Browse files
committed
gossip: stake maps for fd_gossip and gossvf
1 parent bede639 commit 3f06cf9

File tree

4 files changed

+112
-47
lines changed

4 files changed

+112
-47
lines changed

src/discof/gossip/fd_gossvf_tile.c

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "../../disco/keyguard/fd_keyswitch.h"
55
#include "../../disco/keyguard/fd_keyload.h"
66
#include "../../disco/metrics/fd_metrics.h"
7+
#include "../../disco/shred/fd_stake_ci.h"
78
#include "../../flamenco/gossip/fd_gossip_private.h"
89
#include "../../flamenco/gossip/fd_ping_tracker.h"
910
#include "../../flamenco/leaders/fd_leaders_base.h"
@@ -114,6 +115,7 @@ typedef struct stake stake_t;
114115
#define MAP_NEXT map.next
115116
#define MAP_KEY_EQ(k0,k1) fd_pubkey_eq( k0, k1 )
116117
#define MAP_KEY_HASH(key,seed) (seed^fd_ulong_load_8( (key)->uc ))
118+
#define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
117119
#include "../../util/tmpl/fd_map_chain.c"
118120

119121
struct fd_gossvf_tile_ctx {
@@ -139,8 +141,12 @@ struct fd_gossvf_tile_ctx {
139141
ping_t * pings;
140142
ping_map_t * ping_map;
141143

142-
stake_t * stakes;
143-
stake_map_t * stake_map;
144+
struct {
145+
ulong count;
146+
stake_t * pool;
147+
stake_map_t * map;
148+
uchar msg_buf[ FD_STAKE_CI_STAKE_MSG_SZ ];
149+
} stake;
144150

145151
uchar payload[ FD_NET_MTU ];
146152
ulong payload_sz;
@@ -298,7 +304,7 @@ during_frag( fd_gossvf_tile_ctx_t * ctx,
298304
break;
299305
}
300306
case IN_KIND_REPLAY:
301-
/* TODO: Update stakes map */
307+
fd_memcpy( ctx->stake.msg_buf, fd_chunk_to_laddr_const( ctx->in[ in_idx ].mem, chunk ), sz );
302308
break;
303309
case IN_KIND_PINGS: {
304310
fd_memcpy( ctx->_ping_update, fd_chunk_to_laddr( ctx->in[ in_idx ].mem, chunk ), sz );
@@ -312,6 +318,26 @@ during_frag( fd_gossvf_tile_ctx_t * ctx,
312318
}
313319
}
314320

321+
static inline void
322+
handle_stakes( fd_gossvf_tile_ctx_t * ctx,
323+
fd_stake_weight_msg_t const * msg ) {
324+
fd_stake_weight_t stake_weights[ MAX_STAKED_LEADERS ];
325+
ulong new_stakes_cnt = compute_id_weights_from_vote_weights( stake_weights, msg->weights, msg->staked_cnt );
326+
327+
for( ulong i=0Ul; i<ctx->stake.count; i++ ) {
328+
stake_map_idx_remove_fast( ctx->stake.map, i, ctx->stake.pool );
329+
}
330+
331+
for( ulong i=0UL; i<new_stakes_cnt; i++ ) {
332+
stake_t * entry = stake_pool_ele( ctx->stake.pool, i );
333+
fd_memcpy( entry->pubkey.uc, stake_weights[i].key.uc, 32UL );
334+
entry->stake = stake_weights[i].stake;
335+
336+
stake_map_idx_insert( ctx->stake.map, i, ctx->stake.pool );
337+
}
338+
ctx->stake.count = new_stakes_cnt;
339+
}
340+
315341
static int
316342
verify_prune( fd_gossip_view_prune_t const * view,
317343
uchar const * payload,
@@ -595,7 +621,7 @@ is_ping_active( fd_gossvf_tile_ctx_t * ctx,
595621
if( FD_UNLIKELY( is_entrypoint( ctx, rpc_addr ) ) ) return 1;
596622

597623
/* 2. If the node has more than 1 sol staked, it is active */
598-
stake_t const * stake = stake_map_ele_query_const( ctx->stake_map, (fd_pubkey_t*)(payload+value->pubkey_off), NULL, ctx->stakes );
624+
stake_t const * stake = stake_map_ele_query_const( ctx->stake.map, (fd_pubkey_t*)(payload+value->pubkey_off), NULL, ctx->stake.pool );
599625
if( FD_LIKELY( stake && stake->stake>=1000000000UL ) ) return 1;
600626

601627
/* 3. If the node has actively ponged a ping, it is active */
@@ -971,11 +997,12 @@ unprivileged_init( fd_topo_t * topo,
971997
ctx->ping_map = ping_map_join( ping_map_new( _ping_map, 2UL*FD_PING_TRACKER_MAX, ctx->seed ) );
972998
FD_TEST( ctx->ping_map );
973999

974-
ctx->stakes = stake_pool_join( stake_pool_new( _stake_pool, MAX_STAKED_LEADERS ) );
975-
FD_TEST( ctx->stakes );
1000+
ctx->stake.count = 0UL;
1001+
ctx->stake.pool = stake_pool_join( stake_pool_new( _stake_pool, MAX_STAKED_LEADERS ) );
1002+
FD_TEST( ctx->stake.pool );
9761003

977-
ctx->stake_map = stake_map_join( stake_map_new( _stake_map, fd_ulong_pow2_up( MAX_STAKED_LEADERS ), ctx->seed ) );
978-
FD_TEST( ctx->stake_map );
1004+
ctx->stake.map = stake_map_join( stake_map_new( _stake_map, fd_ulong_pow2_up( MAX_STAKED_LEADERS ), ctx->seed ) );
1005+
FD_TEST( ctx->stake.map );
9791006

9801007
ctx->round_robin_cnt = fd_topo_tile_name_cnt( topo, tile->name );
9811008
ctx->round_robin_idx = tile->kind_id;

src/flamenco/gossip/crds/fd_crds.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,20 +1024,30 @@ fd_crds_insert( fd_crds_t * crds,
10241024
crds->metrics->peer_visible_stake -= incumbent->stake;
10251025
}
10261026

1027-
evict_treap_ele_remove( crds->evict_treap, incumbent, crds->pool );
10281027
if( FD_LIKELY( incumbent->stake ) ) {
10291028
staked_expire_dlist_ele_remove( crds->staked_expire_dlist, incumbent, crds->pool );
10301029
} else {
10311030
unstaked_expire_dlist_ele_remove( crds->unstaked_expire_dlist, incumbent, crds->pool );
10321031
}
1032+
evict_treap_ele_remove( crds->evict_treap, incumbent, crds->pool );
10331033
hash_treap_ele_remove( crds->hash_treap, incumbent, crds->pool );
10341034
lookup_map_ele_remove( crds->lookup_map, &incumbent->key, NULL, crds->pool );
10351035
fd_crds_release( crds, incumbent );
10361036
} else if( candidate->key.tag==FD_GOSSIP_VALUE_CONTACT_INFO ) {
10371037
if( FD_UNLIKELY( !crds_contact_info_pool_free( crds->contact_info.pool ) ) ) {
1038-
fd_crds_entry_t * evict = crds_contact_info_evict_dlist_ele_pop_head( crds->contact_info.evict_dlist, crds->pool );
1038+
fd_crds_entry_t * evict = crds_contact_info_evict_dlist_ele_peek_head( crds->contact_info.evict_dlist, crds->pool );
10391039
remove_contact_info( crds, evict, now, stem );
1040+
if( FD_LIKELY( evict->stake ) ) {
1041+
staked_expire_dlist_ele_remove( crds->staked_expire_dlist, evict, crds->pool );
1042+
} else {
1043+
unstaked_expire_dlist_ele_remove( crds->unstaked_expire_dlist, evict, crds->pool );
1044+
}
1045+
evict_treap_ele_remove( crds->evict_treap, evict, crds->pool );
1046+
hash_treap_ele_remove( crds->hash_treap, evict, crds->pool );
1047+
lookup_map_ele_remove( crds->lookup_map, &evict->key, NULL, crds->pool );
1048+
fd_crds_release( crds, evict );
10401049
crds->metrics->peer_evicted_cnt++;
1050+
crds->metrics->evicted_cnt++;
10411051
}
10421052

10431053
candidate->contact_info.ci = crds_contact_info_pool_ele_acquire( crds->contact_info.pool );

src/flamenco/gossip/crds/fd_crds.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ typedef struct fd_crds_mask_iter_private fd_crds_mask_iter_t;
2222
#define FD_CRDS_UPSERT_CHECK_UPSERTS ( 0)
2323
#define FD_CRDS_UPSERT_CHECK_FAILS (-1)
2424

25-
#define CRDS_MAX_CONTACT_INFO_LG (15)
26-
#define CRDS_MAX_CONTACT_INFO (1<<CRDS_MAX_CONTACT_INFO_LG) /* 32768 */
25+
#define CRDS_MAX_CONTACT_INFO (1<<15) /* 32768 */
2726

2827
struct fd_crds_metrics {
2928
ulong count[ FD_METRICS_ENUM_CRDS_VALUE_CNT ];
@@ -104,7 +103,7 @@ fd_crds_len( fd_crds_t const * crds );
104103
expiry windows.
105104
106105
- purged, kept for 60s
107-
106+
108107
A CRDS value is roughly considered "purged" when it is removed
109108
from the gossip table due to an incoming CRDS value replacing it.
110109

src/flamenco/gossip/fd_gossip.c

Lines changed: 63 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,43 @@ FD_STATIC_ASSERT( FD_METRICS_ENUM_CRDS_VALUE_CNT==FD_GOSSIP_VALUE_LAST+1UL,
1818
#define BLOOM_FALSE_POSITIVE_RATE (0.1)
1919
#define BLOOM_NUM_KEYS (8.0)
2020

21-
struct stake_weight {
22-
fd_pubkey_t key;
21+
struct stake {
22+
fd_pubkey_t pubkey;
2323
ulong stake;
24-
ulong hash;
24+
25+
struct {
26+
ulong prev;
27+
ulong next;
28+
} map;
29+
30+
struct {
31+
ulong next;
32+
} pool;
2533
};
2634

27-
typedef struct stake_weight stake_weight_entry_t;
35+
typedef struct stake stake_t;
2836

29-
fd_pubkey_t pubkey_null = { .ul = {0UL,0UL,0UL,0UL} };
37+
/* NOTE: Since the staked count is known at the time we populate
38+
the map, we can treat the pool as an array instead. This means we
39+
can bypass the acquire/release model and quickly iterate through the
40+
pool when we repopulate the map on every fd_gossip_stakes_update
41+
iteration. */
42+
#define POOL_NAME stake_pool
43+
#define POOL_T stake_t
44+
#define POOL_IDX_T ulong
45+
#define POOL_NEXT pool.next
46+
#include "../../util/tmpl/fd_pool.c"
3047

3148
#define MAP_NAME stake_map
32-
#define MAP_T stake_weight_entry_t
49+
#define MAP_KEY pubkey
50+
#define MAP_ELE_T stake_t
3351
#define MAP_KEY_T fd_pubkey_t
34-
#define MAP_HASH_T ulong
35-
#define MAP_KEY_NULL pubkey_null
36-
#define MAP_KEY_EQUAL(k0,k1) (!(memcmp((k0).key,(k1).key,sizeof(fd_pubkey_t))))
37-
#define MAP_KEY_INVAL(k) (MAP_KEY_EQUAL((k),MAP_KEY_NULL))
38-
#define MAP_KEY_HASH(key) ((key).ui[3])
39-
#define MAP_KEY_MOVE(k0,k1) (fd_memcpy((k0).key,(k1).key,sizeof(fd_pubkey_t) ))
40-
#define MAP_KEY_EQUAL_IS_SLOW 1
41-
#define MAP_LG_SLOT_CNT CRDS_MAX_CONTACT_INFO_LG
42-
43-
#include "../../util/tmpl/fd_map.c"
52+
#define MAP_PREV map.prev
53+
#define MAP_NEXT map.next
54+
#define MAP_KEY_EQ(k0,k1) fd_pubkey_eq( k0, k1 )
55+
#define MAP_KEY_HASH(key,seed) (seed^fd_ulong_load_8( (key)->uc ))
56+
#define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
57+
#include "../../util/tmpl/fd_map_chain.c"
4458

4559
#include "fd_push_set_private.c"
4660

@@ -62,7 +76,11 @@ struct fd_gossip_private {
6276

6377
fd_rng_t * rng;
6478

65-
stake_weight_entry_t * stake_weights;
79+
struct {
80+
ulong count;
81+
stake_t * pool;
82+
stake_map_t * map;
83+
} stake;
6684

6785
struct {
6886
long next_pull_request;
@@ -104,12 +122,13 @@ fd_gossip_footprint( ulong max_values,
104122
ulong entrypoints_len ) {
105123
ulong l;
106124
l = FD_LAYOUT_INIT;
107-
l = FD_LAYOUT_APPEND( l, alignof(fd_gossip_t), sizeof(fd_gossip_t) );
108-
l = FD_LAYOUT_APPEND( l, fd_crds_align(), fd_crds_footprint( max_values, max_values ) );
109-
l = FD_LAYOUT_APPEND( l, fd_active_set_align(), fd_active_set_footprint() );
110-
l = FD_LAYOUT_APPEND( l, fd_ping_tracker_align(), fd_ping_tracker_footprint( entrypoints_len ) );
111-
l = FD_LAYOUT_APPEND( l, stake_map_align(), stake_map_footprint() );
112-
l = FD_LAYOUT_APPEND( l, push_set_align(), push_set_footprint( FD_ACTIVE_SET_MAX_PEERS ) );
125+
l = FD_LAYOUT_APPEND( l, alignof(fd_gossip_t), sizeof(fd_gossip_t) );
126+
l = FD_LAYOUT_APPEND( l, fd_crds_align(), fd_crds_footprint( max_values, max_values ) );
127+
l = FD_LAYOUT_APPEND( l, fd_active_set_align(), fd_active_set_footprint() );
128+
l = FD_LAYOUT_APPEND( l, fd_ping_tracker_align(), fd_ping_tracker_footprint( entrypoints_len ) );
129+
l = FD_LAYOUT_APPEND( l, stake_pool_align(), stake_pool_footprint( CRDS_MAX_CONTACT_INFO ) );
130+
l = FD_LAYOUT_APPEND( l, stake_map_align(), stake_map_footprint( stake_map_chain_cnt_est( CRDS_MAX_CONTACT_INFO ) ) );
131+
l = FD_LAYOUT_APPEND( l, push_set_align(), push_set_footprint( FD_ACTIVE_SET_MAX_PEERS ) );
113132
l = FD_LAYOUT_FINI( l, fd_gossip_align() );
114133
return l;
115134
}
@@ -167,13 +186,15 @@ fd_gossip_new( void * shmem,
167186
FD_LOG_WARNING(( "max_values must be a power of 2" ));
168187
return NULL;
169188
}
189+
ulong stake_map_chain_cnt = stake_map_chain_cnt_est( max_values );
170190

171191
FD_SCRATCH_ALLOC_INIT( l, shmem );
172192
fd_gossip_t * gossip = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_gossip_t), sizeof(fd_gossip_t) );
173-
void * crds = FD_SCRATCH_ALLOC_APPEND( l, fd_crds_align(), fd_crds_footprint( max_values, max_values ) );
193+
void * crds = FD_SCRATCH_ALLOC_APPEND( l, fd_crds_align(), fd_crds_footprint( max_values, max_values ) );
174194
void * active_set = FD_SCRATCH_ALLOC_APPEND( l, fd_active_set_align(), fd_active_set_footprint() );
175195
void * ping_tracker = FD_SCRATCH_ALLOC_APPEND( l, fd_ping_tracker_align(), fd_ping_tracker_footprint( entrypoints_cnt ) );
176-
void * stake_weights = FD_SCRATCH_ALLOC_APPEND( l, stake_map_align(), stake_map_footprint() );
196+
void * stake_pool = FD_SCRATCH_ALLOC_APPEND( l, stake_pool_align(), stake_pool_footprint( CRDS_MAX_CONTACT_INFO ) );
197+
void * stake_weights = FD_SCRATCH_ALLOC_APPEND( l, stake_map_align(), stake_map_footprint( stake_map_chain_cnt ) );
177198
void * active_ps = FD_SCRATCH_ALLOC_APPEND( l, push_set_align(), push_set_footprint( FD_ACTIVE_SET_MAX_PEERS ) );
178199

179200
gossip->gossip_net_out = gossip_net_out;
@@ -190,8 +211,12 @@ fd_gossip_new( void * shmem,
190211
gossip->ping_tracker = fd_ping_tracker_join( fd_ping_tracker_new( ping_tracker, rng, gossip->entrypoints_cnt, gossip->entrypoints, ping_tracker_change, gossip ) );
191212
FD_TEST( gossip->ping_tracker );
192213

193-
gossip->stake_weights = stake_map_join( stake_map_new( stake_weights ) );
194-
FD_TEST( gossip->stake_weights );
214+
gossip->stake.count = 0UL;
215+
gossip->stake.pool = stake_pool_join( stake_pool_new( stake_pool, CRDS_MAX_CONTACT_INFO ) );
216+
FD_TEST( gossip->stake.pool );
217+
218+
gossip->stake.map = stake_map_join( stake_map_new( stake_weights, stake_map_chain_cnt, fd_rng_ulong( rng ) ) );
219+
FD_TEST( gossip->stake.map );
195220

196221
gossip->active_pset = push_set_join( push_set_new( active_ps, FD_ACTIVE_SET_MAX_PEERS ) );
197222
FD_TEST( gossip->active_pset );
@@ -380,9 +405,8 @@ fd_gossip_set_my_contact_info( fd_gossip_t * gossip,
380405
ulong
381406
get_stake( fd_gossip_t const * gossip,
382407
uchar const * pubkey ) {
383-
stake_weight_entry_t const * entry = stake_map_query_const( gossip->stake_weights, *(fd_pubkey_t const *)pubkey, NULL );
408+
stake_t const * entry = stake_map_ele_query_const( gossip->stake.map, (fd_pubkey_t const *)pubkey, NULL, gossip->stake.pool );
384409
if( FD_UNLIKELY( !entry ) ) return 0UL;
385-
386410
return entry->stake;
387411
}
388412

@@ -394,17 +418,22 @@ fd_gossip_stakes_update( fd_gossip_t * gossip,
394418
FD_LOG_ERR(( "stake_weights_cnt %lu exceeds maximum of %d", stake_weights_cnt, CRDS_MAX_CONTACT_INFO ));
395419
}
396420

397-
stake_map_clear( gossip->stake_weights );
421+
/* Clear the map, this requires us to iterate through all elements and
422+
individually call map remove. */
423+
for( ulong i=0UL; i<gossip->stake.count; i++ ) {
424+
stake_map_idx_remove_fast( gossip->stake.map, i, gossip->stake.pool );
425+
}
398426

399427
for( ulong i=0UL; i<stake_weights_cnt; i++ ) {
400-
stake_weight_entry_t * entry = stake_map_insert( gossip->stake_weights, stake_weights[i].key );
401-
if( FD_UNLIKELY( !entry ) ) {
402-
FD_LOG_ERR(( "Failed to insert stake weight" ));
403-
}
428+
stake_t * entry = stake_pool_ele( gossip->stake.pool, i );
429+
fd_memcpy( entry->pubkey.uc, stake_weights[i].key.uc, 32UL );
404430
entry->stake = stake_weights[i].stake;
431+
432+
stake_map_idx_insert( gossip->stake.map, i, gossip->stake.pool );
405433
}
406434
/* Update the identity stake */
407435
gossip->identity_stake = get_stake( gossip, gossip->identity_pubkey );
436+
gossip->stake.count = stake_weights_cnt;
408437
}
409438

410439
static void

0 commit comments

Comments
 (0)