@@ -2892,21 +2892,33 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
28922892 // Evict persisted tasks from memory to reclaim space.
28932893 // Like compaction, this runs after snapshot_and_persist
28942894 // as a separate concern.
2895+ //
2896+ // TODO: improve eviction policy — current approach is a full sweep
2897+ // after every snapshot. Better strategies to consider:
2898+ // - Memory pressure signals: only evict when RSS exceeds a threshold
2899+ // rather than unconditionally.
2900+ // - Recency data: track last-access time per task and evict
2901+ // least-recently-used entries first rather than all at once.
2902+ // - Eviction intensity: partial sweeps (evict a fraction of eligible
2903+ // tasks per cycle) to reduce latency spikes.
2904+ // Polls the idle-end event without blocking. Returns
2905+ // `true` and refreshes the listener if idle has ended,
2906+ // `false` if we are still idle.
2907+ macro_rules! check_idle_ended {
2908+ ( ) => { {
2909+ tokio:: select! {
2910+ biased;
2911+ _ = & mut idle_end_listener => {
2912+ idle_end_listener = self . idle_end_event. listen( ) ;
2913+ true
2914+ } ,
2915+ _ = std:: future:: ready( ( ) ) => false ,
2916+ }
2917+ } } ;
2918+ }
28952919
2896- // TODO: should we only run if we stored new data? syncing data to disk
2897- // implies that some of it is eligible for eviction, but if nothing was
2898- // stored then that isn't true. on the other hand pre-fetching might
2899- // bring unused data into the heap.
2900- if this. should_evict ( ) && new_data {
2901- let idle_ended = tokio:: select! {
2902- biased;
2903- _ = & mut idle_end_listener => {
2904- idle_end_listener = self . idle_end_event. listen( ) ;
2905- true
2906- } ,
2907- _ = std:: future:: ready( ( ) ) => false ,
2908- } ;
2909- if !idle_ended {
2920+ if this. should_evict ( ) {
2921+ if !check_idle_ended ! ( ) {
29102922 let evict_span = tracing:: info_span!(
29112923 parent: background_span. id( ) ,
29122924 "evict tasks" ,
@@ -2932,15 +2944,7 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
29322944 // suspends at the `select!` await below.
29332945 const MAX_IDLE_COMPACTION_PASSES : usize = 10 ;
29342946 for _ in 0 ..MAX_IDLE_COMPACTION_PASSES {
2935- let idle_ended = tokio:: select! {
2936- biased;
2937- _ = & mut idle_end_listener => {
2938- idle_end_listener = self . idle_end_event. listen( ) ;
2939- true
2940- } ,
2941- _ = std:: future:: ready( ( ) ) => false ,
2942- } ;
2943- if idle_ended {
2947+ if check_idle_ended ! ( ) {
29442948 break ;
29452949 }
29462950 // Enter the span only around the synchronous
0 commit comments