mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
> **Note:** This is a **proof of concept** implementation. It is not yet ready for production use. ## Summary Implements memory eviction for the turbo-tasks engine. After a persistence snapshot completes, tasks that are safe to remove are evicted from in-memory storage and transparently restored from disk on next access. ### Eviction levels - **Full eviction**: Entire task removed from the in-memory map (restored from disk on access). Only possible when the task has no meaningful transient state (and other state is already on disk) - **DataAndMeta eviction**: Both data and meta categories cleared, but the task stays in the map to preserve transient state (e.g. `current_session_clean`, aggregated session-clean counts). - **DataOnly eviction**: Only data-category fields cleared; meta (graph structure, output, dirty state) stays in memory. - **MetaOnly eviction**: Only meta-category fields cleared; data stays in memory. Data and meta evictability are computed independently — if one category is modified but the other is clean, the clean category can still be dropped. Eviction is gated behind `BackendOptions::evict_after_snapshot` (off by default), and can be enabled in Next.js via the `TURBO_ENGINE_EVICT_AFTER_SNAPSHOT=1` env var for testing. ## Key changes - **Orthogonal eviction decision tree** (`storage_schema.rs`): Data and meta evictability are computed independently. Full eviction additionally requires no meaningful transient state (session-clean flags, aggregated session-clean counts). Replaces the previous sequential bail-out approach which was too aggressive on full eviction (losing transient session state on leaf tasks) and not aggressive enough on partial eviction (blocking all eviction when only one category was modified). - **`drop_partial()` codegen** (`task_storage_macro.rs`): New generated methods to drop data - **`restore_from_*()` codegen changes** (`task_storage_macro.rs`): New semantics for merging persistent data from the backend with transient data stored in memory. - **`task_cache` moved into `Storage`** (`storage.rs`): The `CachedTaskType → TaskId` deduplication map was previously a separate field on `TurboTasksBackendInner`. It is now owned by `Storage` so eviction can remove entries when a task is fully evicted. Because `task_cache` is a pure performance cache (entries are re-populated by `task_by_type()` on miss once the task type is persisted to backing storage), evicting entries is safe. After bulk eviction the map is shrunk when it is less than half full. - **Parallel shard eviction** (`storage.rs`): Eviction iterates all storage shards in parallel after snapshot, applying the appropriate eviction level per task. Each shard is shrunk after bulk eviction to reclaim slack capacity. - In principle this is O(N) work to scan, but because each pass drops >98% of tasks there isn't wasted work and the logic is fast, taking <100ms for even the largest applications. ## Design notes - **SessionDependent tasks**: SessionDependent tasks can still be evicted but if `current_session_clean` is set we prevent full eviction to avoid rechecking. Within a session the file-watchers are responsible for invalidations after setting `current_session_clean`. ## Known limitations (proof of concept) - No LRU or access-frequency tracking — all eligible tasks are evicted on every snapshot cycle - No memory pressure feedback — eviction runs on a timer, not in response to actual memory pressure - Only runs after snapshotting which tends to be a high point in memory - Future work will explore interleaving this logic with snapshotting to trim the peak <!-- NEXT_JS_LLM_PR -->