@@ -1073,13 +1073,13 @@ fd_forest_publish( fd_forest_t * forest, ulong new_root_slot ) {
10731073#define SLOT_INSERT 1
10741074
10751075int
1076- fd_forest_evict ( fd_forest_t * forest , ulong new_slot , ulong parent_slot ) {
1076+ fd_forest_evict ( fd_forest_t * forest , ulong new_slot , ulong parent_slot ) {
10771077 FD_LOG_NOTICE (( "fd_forest_eviction_time" ));
10781078 fd_forest_ancestry_t * ancestry = fd_forest_ancestry ( forest );
10791079 fd_forest_frontier_t * frontier = fd_forest_frontier ( forest );
10801080 fd_forest_subtlist_t * subtlist = fd_forest_subtlist ( forest );
1081+ fd_forest_orphaned_t * orphaned = fd_forest_orphaned ( forest );
10811082 fd_forest_blk_t * pool = fd_forest_pool ( forest );
1082- ulong null = fd_forest_pool_idx_null ( pool );
10831083
10841084
10851085 int has_orphans = !fd_forest_subtlist_is_empty ( subtlist , pool );
@@ -1088,42 +1088,50 @@ fd_forest_evict( fd_forest_t * forest, ulong new_slot, ulong parent_slot ) {
10881088 /* During regular operation there's usually no orphans, but if eviction
10891089 is called then it's likely we have orphans. */
10901090 if ( FD_LIKELY ( has_orphans ) ) {
1091+
10911092 /* We'll keep it if it's older than all of our orphans, or if it's
10921093 parent is part of the main tree. */
1093-
1094- ulong evict_orphan_slot = ULONG_MAX ; /* best orphan candidate for eviction is the newest subtree. */
1094+ fd_forest_blk_t * evict_orphan = NULL ; /* best orphan candidate for eviction is the newest subtree. */
10951095 for ( fd_forest_subtlist_iter_t iter = fd_forest_subtlist_iter_fwd_init ( subtlist , pool );
10961096 !fd_forest_subtlist_iter_done ( iter , subtlist , pool );
10971097 iter = fd_forest_subtlist_iter_fwd_next ( iter , subtlist , pool ) ) {
10981098 fd_forest_blk_t * ele = fd_forest_subtlist_iter_ele ( iter , subtlist , pool );
1099- if ( FD_LIKELY ( evict_orphan_slot == ULONG_MAX ) ) evict_orphan_slot = ele -> slot ;
1100- else evict_orphan_slot = fd_ulong_max ( evict_orphan_slot , ele -> slot );
1099+ if ( FD_LIKELY ( evict_orphan == NULL ) ) evict_orphan = ele ;
1100+ else evict_orphan = fd_ptr_if ( evict_orphan -> slot < ele -> slot , ele , evict_orphan );
1101+ }
11011102
1103+ for ( fd_forest_orphaned_iter_t iter = fd_forest_orphaned_iter_init ( orphaned , pool );
1104+ !fd_forest_orphaned_iter_done ( iter , orphaned , pool );
1105+ iter = fd_forest_orphaned_iter_next ( iter , orphaned , pool ) ) {
1106+ fd_forest_blk_t * ele = fd_forest_orphaned_iter_ele ( iter , orphaned , pool );
1107+ evict_orphan = fd_ptr_if ( evict_orphan -> slot < ele -> slot , ele , evict_orphan );
11021108 }
1103- /* We are connecting to the main tree. Nuke the orphan. */
1109+ /* Now we have the max of all subtrees and orphans. This is our best candidate for eviction. */
1110+
1111+ /* If are connecting to the main tree. Nuke the best candidate orphan. */
11041112 if ( fd_forest_ancestry_ele_query ( ancestry , & parent_slot , NULL , pool ) ||
11051113 fd_forest_frontier_ele_query ( frontier , & parent_slot , NULL , pool ) ) {
1106- // evict_orphan_slot
1107-
1114+ subtrees_orphaned_remove ( forest , evict_orphan -> slot );
1115+ requests_remove ( forest , fd_forest_orphreqs ( forest ), fd_forest_orphlist ( forest ), & forest -> orphiter , fd_forest_pool_idx ( pool , evict_orphan ) );
1116+ fd_forest_pool_ele_release ( pool , evict_orphan );
11081117 return SLOT_INSERT ;
11091118 }
11101119
1111-
1112- /* We ourselves are an orphan. Should we evict something else or just evict ourselves?
1120+ /* The new slot an orphan. Should we evict the candidate orphan or insert ourselves?
11131121 We'll keep it if it's older than all of our orphans */
1114- for ( fd_forest_subtlist_iter_t iter = fd_forest_subtlist_iter_fwd_init ( subtlist , pool );
1115- !fd_forest_subtlist_iter_done ( iter , subtlist , pool );
1116- iter = fd_forest_subtlist_iter_fwd_next ( iter , subtlist , pool ) ) {
1117- fd_forest_blk_t * ele = fd_forest_subtlist_iter_ele ( iter , subtlist , pool );
1118- if ( FD_LIKELY ( new_slot > ele -> slot ) ) {
1119- return SLOT_IGNORE ;
1120- }
1122+
1123+ if ( evict_orphan -> slot < new_slot ) {
1124+ return SLOT_IGNORE ;
1125+ } else {
1126+ subtrees_orphaned_remove ( forest , evict_orphan -> slot );
1127+ requests_remove ( forest , fd_forest_orphreqs ( forest ), fd_forest_orphlist ( forest ), & forest -> orphiter , fd_forest_pool_idx ( pool , evict_orphan ) );
1128+ fd_forest_pool_ele_release ( pool , evict_orphan );
1129+ return SLOT_INSERT ;
11211130 }
11221131
1123- // choose something to evict from orphans
1124- return SLOT_INSERT ;
11251132 } else {
1126- /* Have no orphans. */
1133+ /* Have no orphans. Considering the most extreme case where someone
1134+ has DoSed us with 10000 slots that chain to the root. */
11271135
11281136 if ( FD_LIKELY ( parent_exists ) ) {
11291137 /* Parent exists. This slot chains to the main tree. From oldest to newest,
@@ -1157,18 +1165,16 @@ fd_forest_evict( fd_forest_t * forest, ulong new_slot, ulong parent_slot ) {
11571165 else return SLOT_IGNORE ;
11581166 } else {
11591167 /* evict slot found. EVICT IT. */
1160-
1168+ fd_forest_blk_t * evict_ele = fd_forest_frontier_ele_remove ( frontier , & evict_slot , NULL , pool );
1169+ requests_remove ( forest , fd_forest_requests ( forest ), fd_forest_reqslist ( forest ), & forest -> iter , fd_forest_pool_idx ( pool , evict_ele ) );
1170+ fd_forest_pool_ele_release ( pool , evict_ele );
11611171 return SLOT_INSERT ;
11621172 }
11631173 } else {
11641174 /* Parent does not exist. This new slot would've been added as an orphan. */
11651175 return SLOT_IGNORE ;
11661176 }
11671177 }
1168-
1169-
1170-
1171-
11721178}
11731179
11741180ulong
0 commit comments