Checkpoint gather disables eviction for a handle it never opens

XMLWordPrintableJSON

    • Type: Bug
    • Resolution: Fixed
    • Priority: Major - P3
    • WT12.0.0
    • Affects Version/s: None
    • Component/s: Checkpoints
    • None
    • Storage Engines - Transactions
    • 53.111
    • SE Transactions - 2026-09-11
    • 3
    • v9.0, v8.3, v8.0, v7.0

      Background

      Investigating WT-18590 (checkpoint prepare stalling on sweep's dhandle rwlock) turned up a second, independent cost in the same code path: _wt_session_lock_checkpoint unconditionally calls _wt_evict_file_exclusive_on before flushing a checkpoint handle from the cache, for every handle a checkpoint gathers.

      That handle is acquired WT_DHANDLE_EXCLUSIVE | WT_DHANDLE_LOCK_ONLY a few lines above, which never opens the underlying tree. With no open tree there is no root page, so the __wt_evict_file flush that follows returns immediately — the evict_disabled/eviction-off bracket around it protects a call that had nothing to do.

      _wt_evict_file_exclusive_on is not cheap to call speculatively: it takes the connection-wide eviction walk lock, bumps pass_intr to interrupt the eviction server's pass, takes the eviction pass and queue locks, clears the tree from every eviction queue, and spins for btree->evict_busy to drain. Paying that once per handle gathered, for a no-op flush, both slows the checkpoint down directly and holds the same lock other callers need — including the sweep server, which takes it once per handle it closes (sweep_close_dhandle_locked / _wt_conn_dhandle_close).

      Fix (implemented)

      Only call _wt_evict_file_exclusive_on / wt_evict_file_exclusive_off when the handle is actually open (F_ISSET(session->dhandle, WT_DHANDLE_OPEN)). _wt_evict_file already asserts btree->evict_disabled > 0 || !F_ISSET(dhandle, WT_DHANDLE_OPEN), so an unopened handle needs no protection — the assertion is exactly the condition being restored.

      Reproducer results

      15,000 tables, a fan-out thread reopening every table, a rotating dirty set, and a checkpoint every 0.5s; 450s runs from identical fresh databases, unsampled. Isolating this change against the WT-18590 base (before the sweep-direction fix) roughly doubled sweep's close throughput per checkpoint (measured 103→338 and 184→276 handles closed per checkpoint across paired runs) and dropped the resident handle count by ~1,500, consistent with the gather no longer starving sweep of the same lock.

      Related

      • WT-18590 — the sweep/gather walk-direction fix this was found alongside; that ticket covers the acquire-path stall, this one covers the per-handle eviction-gate cost. The two are independent and were split into separate PRs.

            Assignee:
            Chenhao Qu
            Reporter:
            Chenhao Qu
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: