-
Type:
Improvement
-
Resolution: Unresolved
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: Cache and Eviction
-
None
-
Storage Engines - Transactions
-
208.894
-
SE Transactions - 2026-11-06
-
3
Problem
The eviction server walks the data handle list round-robin. A tree that has no bytes of interest for the current eviction mode (typically a tree with only its pinned root page in cache) is only recognised as unwanted inside __evict_walk_tree, after the handle loop has already released the handle list lock and taken evict_walk_lock. The check is in __evict_walk_target: target_pages is 0 and none of the clean (evictable, excluding the root), dirty leaf or update byte counters selected by the current mode is non-zero, so it counts eviction_server_skip_unwanted_tree and returns.
That return happens before the evict_walk_period update at the end of __evict_walk_tree, so these trees never back off. Every pass pays, for each of them, the unlock of dhandle_lock, the trylock of evict_walk_lock, the target computation, and the relock of dhandle_lock at the top of the loop.
With a large handle count this is the dominant cost of the scan. On the WT-18829 reproducer (r27_t32, 96 cores, ~160k open handles) the unwanted-tree exit runs 0.8M to 1.9M times/s against ~15k real tree visits/s, and 29% to 67% of the handle skips are of this kind. In a develop perf profile of the eviction threads (30 s), the code that runs only for handles that pass the period check (__wti_evict_set_saved_walk_tree 15%, __evict_get_target_pages 11.5%, dhandle_lock read lock/unlock about 12%) is about 40% of self time; nearly all of those calls are for unwanted trees. Part of that is the first cache miss on the dhandle and would move to the next access once the check is hoisted, so this is an upper bound, not the expected gain.
On the HELP-101149 primary 18.8% of handles considered in stall seconds take the unwanted exit (99.6k/s), so the reproducer overstates the share.
Measured ceiling
A throw-away hack that skips btrees with no bytes of interest in the handle loop (C0, 8.0, r27_t32, 3 runs per side) gave +64% tree visits and +19% pages queued; the extra visits went to small trees (pages queued per visit -27%), and one run overlapped the base range. So hoisting the check frees server time, but on its own it is not expected to reach the WT-18829 target; it is a low-risk part of a combination with the bounded-wake change (WT-18961).
Proposed change
- Move the no-bytes-of-interest decision into the handle loop, after the existing period check and before the handle list lock is released, so an idle tree costs about the same as a not-useful-before skip.
- Factor the predicate out of __evict_walk_target into one shared inline function used by both the handle loop and __evict_walk_target, so the two cannot drift apart. The predicate keeps its current meaning: clean means evictable bytes excluding the root page, dirty means dirty leaf bytes, updates means update bytes, each considered only when its flag is set in the current mode.
- Keep counting eviction_server_skip_unwanted_tree for each such skip, so the statistic keeps its meaning in FTDC.
- Do not add any back-off for the unwanted exit and do not change evict_walk_period handling.
Open point for the implementation: the clean test reads the root page footprint, and the handle loop does not hold evict_walk_lock, which is what protects the root page against being discarded on handle close. The change must either show that the lock-free read is safe or use a variant that is (for example taking the walk lock with a trylock while the handle list lock is still held).
- related to
-
WT-18829 Eviction candidate supply is capped when dirty content is spread across many trees (high data handle count)
-
- Open
-