@@ -41,7 +41,6 @@ fd_policy_new( void * shmem, ulong dedup_max, ulong peer_max, ulong seed ) {
4141 policy -> peers .pool = fd_peer_pool_new ( peers_pool , peer_max );
4242 policy -> peers .fast = fd_peer_dlist_new ( peers_fast );
4343 policy -> peers .slow = fd_peer_dlist_new ( peers_slow );
44- policy -> iterf .ele_idx = ULONG_MAX ;
4544 policy -> turbine_slot0 = ULONG_MAX ;
4645 policy -> tsreset = 0 ;
4746 policy -> nonce = 1 ;
@@ -165,6 +164,8 @@ fd_policy_peer_select( fd_policy_t * policy ) {
165164 fd_peer_dlist_t * worst_dlist = policy -> peers .slow ;
166165 fd_peer_t * pool = policy -> peers .pool ;
167166
167+ if ( FD_UNLIKELY ( fd_peer_pool_used ( policy -> peers .pool ) == 0 ) ) return NULL ;
168+
168169 fd_peer_dlist_t * dlist = bucket_stages [policy -> peers .select .stage ] == FD_POLICY_LATENCY_FAST ? best_dlist : worst_dlist ;
169170
170171 while ( FD_UNLIKELY ( fd_peer_dlist_iter_done ( policy -> peers .select .iter , dlist , pool ) ) ) {
@@ -202,18 +203,13 @@ fd_policy_next( fd_policy_t * policy, fd_forest_t * forest, fd_repair_t * repair
202203 }
203204 }
204205
205- /* Every so often we'll need to reset the frontier iterator to the
206- head of frontier, because we could end up traversing down a very
207- long tree if we are far behind. */
206+ /**********************/
207+ /* ADVANCE ITERATOR */
208+ /********************* */
208209
209- if ( FD_UNLIKELY ( now_ms - policy -> tsreset > 100UL /* ms */ ||
210- policy -> iterf .frontier_ver != fd_fseq_query ( fd_forest_ver_const ( forest ) ) ) ) {
211- fd_policy_reset ( policy , forest );
212- }
213-
214- fd_forest_blk_t * ele = fd_forest_pool_ele ( pool , policy -> iterf .ele_idx );
215- if ( FD_UNLIKELY ( !ele ) ) {
216- // This happens when we are fully caught up i.e. we have all the shreds of every slot we know about.
210+ fd_forest_iter_next ( forest );
211+ if ( FD_UNLIKELY ( fd_forest_iter_done ( forest ) ) ) {
212+ // This happens when we have already requested all the shreds we know about.
217213 return NULL ;
218214 }
219215
@@ -231,53 +227,34 @@ fd_policy_next( fd_policy_t * policy, fd_forest_t * forest, fd_repair_t * repair
231227 next valid requestable element. */
232228
233229 int req_made = 0 ;
234- while ( !req_made ) {
235- ele = fd_forest_pool_ele ( pool , policy -> iterf .ele_idx );
236-
237- if ( FD_UNLIKELY ( !passes_throttle_threshold ( policy , ele ) ) ) {
238- /* We are not ready to repair this slot yet. But it's possible we
239- have another fork that we need to repair... so we just
240- should skip to the next SLOT in the consumed iterator. The
241- likelihood that this ele is the head of turbine is high, which
242- means that the shred_idx of the iterf is likely to be UINT_MAX,
243- which means calling fd_forest_iter_next will advance the iterf
244- to the next slot. */
245- policy -> iterf .shred_idx = UINT_MAX ; // heinous... i'm sorry
246- policy -> iterf = fd_forest_iter_next ( policy -> iterf , forest );
247- if ( FD_UNLIKELY ( fd_forest_iter_done ( policy -> iterf , forest ) ) ) {
248- policy -> iterf = fd_forest_iter_init ( forest );
249- break ;
250- }
251- continue ;
252- }
253230
254- if ( FD_UNLIKELY ( policy -> iterf .shred_idx == UINT_MAX ) ) {
255- ulong key = fd_policy_dedup_key ( FD_REPAIR_KIND_HIGHEST_SHRED , ele -> slot , 0 );
256- if ( FD_UNLIKELY ( ele -> slot < highest_known_slot && !dedup_next ( policy , key , now ) ) ) {
257- // We'll never know the the highest shred for the current turbine slot, so there's no point in requesting it.
258- out = fd_repair_highest_shred ( repair , fd_policy_peer_select ( policy ), now_ms , policy -> nonce , ele -> slot , 0 );
259- policy -> nonce ++ ;
260- req_made = 1 ;
261- }
262- } else {
263- ulong key = fd_policy_dedup_key ( FD_REPAIR_KIND_SHRED , ele -> slot , policy -> iterf .shred_idx );
264- if ( FD_UNLIKELY ( !dedup_next ( policy , key , now ) ) ) {
265- out = fd_repair_shred ( repair , fd_policy_peer_select ( policy ), now_ms , policy -> nonce , ele -> slot , policy -> iterf .shred_idx );
266- policy -> nonce ++ ;
267- if ( FD_UNLIKELY ( ele -> first_req_ts == 0 ) ) ele -> first_req_ts = fd_tickcount ();
268- req_made = 1 ;
269- }
270- }
271-
272- /* Even if we have a request ready, we need to advance the iterator.
273- Otherwise on the next call of policy_next, we'll try to re-request the
274- same shred and it will get deduped. */
231+ fd_forest_blk_t * ele = fd_forest_pool_ele ( pool , forest -> iter .ele_idx );
232+ if ( FD_UNLIKELY ( !passes_throttle_threshold ( policy , ele ) ) ) {
233+ /* We are not ready to repair this slot yet. But it's possible we
234+ have another fork that we need to repair... so we just
235+ should skip to the next SLOT in the consumed iterator. The
236+ likelihood that this ele is the head of turbine is high, which
237+ means that the shred_idx of the iterf is likely to be UINT_MAX,
238+ which means calling fd_forest_iter_next will advance the iterf
239+ to the next slot. */
240+ forest -> iter .shred_idx = UINT_MAX ;
241+ /* TODO: Heinous... I'm sorry. Easiest way to ensure this slot gets added back to the requests deque.
242+ but maybe there should be an explicit API for it. */
243+ return NULL ;
244+ }
275245
276- policy -> iterf = fd_forest_iter_next ( policy -> iterf , forest );
277- if ( FD_UNLIKELY ( fd_forest_iter_done ( policy -> iterf , forest ) ) ) {
278- policy -> iterf = fd_forest_iter_init ( forest );
279- break ;
246+ if ( FD_UNLIKELY ( forest -> iter .shred_idx == UINT_MAX ) ) {
247+ if ( FD_UNLIKELY ( ele -> slot < highest_known_slot ) ) {
248+ // We'll never know the the highest shred for the current turbine slot, so there's no point in requesting it.
249+ out = fd_repair_highest_shred ( repair , fd_policy_peer_select ( policy ), now_ms , policy -> nonce , ele -> slot , 0 );
250+ policy -> nonce ++ ;
251+ req_made = 1 ;
280252 }
253+ } else {
254+ out = fd_repair_shred ( repair , fd_policy_peer_select ( policy ), now_ms , policy -> nonce , ele -> slot , forest -> iter .shred_idx );
255+ policy -> nonce ++ ;
256+ if ( FD_UNLIKELY ( ele -> first_req_ts == 0 ) ) ele -> first_req_ts = fd_tickcount ();
257+ req_made = 1 ;
281258 }
282259
283260 if ( FD_UNLIKELY ( !req_made ) ) return NULL ;
@@ -325,7 +302,7 @@ fd_policy_peer_remove( fd_policy_t * policy, fd_pubkey_t const * key ) {
325302
326303 if ( FD_UNLIKELY ( policy -> peers .select .iter == fd_peer_pool_idx ( policy -> peers .pool , peer_ele ) ) ) {
327304 /* In general removal during iteration is safe, except when the iterator is on the peer to be removed. */
328- fd_peer_dlist_t * dlist = policy -> peers .select .stage == FD_POLICY_LATENCY_FAST ? policy -> peers .fast : policy -> peers .slow ;
305+ fd_peer_dlist_t * dlist = bucket_stages [ policy -> peers .select .stage ] == FD_POLICY_LATENCY_FAST ? policy -> peers .fast : policy -> peers .slow ;
329306 policy -> peers .select .iter = fd_peer_dlist_iter_fwd_next ( policy -> peers .select .iter , dlist , policy -> peers .pool );
330307 }
331308
@@ -365,12 +342,6 @@ fd_policy_peer_response_update( fd_policy_t * policy, fd_pubkey_t const * to, lo
365342 }
366343}
367344
368- void
369- fd_policy_reset ( fd_policy_t * policy , fd_forest_t * forest ) {
370- policy -> iterf = fd_forest_iter_init ( forest );
371- policy -> tsreset = ts_ms ( fd_log_wallclock () );
372- }
373-
374345void
375346fd_policy_set_turbine_slot0 ( fd_policy_t * policy , ulong slot ) {
376347 policy -> turbine_slot0 = slot ;
0 commit comments