turbo-persistence: Use AtomicBool for is_empty() to avoid lock contention (#92481)
### What?
Replace the `RwLock`-based `is_empty()` check in `TurboPersistence` with
a lock-free `AtomicBool` that mirrors the emptiness of
`inner.meta_files`.
### Why?
`is_empty()` is called on the hot read path (`lookup_task_candidates`)
as a fast early-return before performing any real work. The previous
implementation acquired a read lock on the inner `RwLock` purely to
check whether `meta_files` is empty — a boolean state that changes
infrequently (only on `load_directory` and `commit`). Taking a lock on
every lookup, even a read lock, adds unnecessary contention and
overhead.
### How?
- Added an `is_empty: AtomicBool` field to `TurboPersistence`,
initialized to `true` (a fresh database is always empty).
- The atomic is updated at the two mutation points that change
`meta_files`:
- `load_directory()` — after reading meta files from disk into
`inner.meta_files`.
- `commit()` — after appending new meta files and retaining/removing old
ones (under the write lock).
- `is_empty()` now does a single `load(Ordering::Relaxed)` instead of
acquiring a read lock.
`Relaxed` ordering is appropriate because `is_empty()` is used as a
performance hint, not a synchronization point. A briefly stale value
only means a redundant hash computation, not a correctness issue.
<!-- NEXT_JS_LLM_PR -->
Co-authored-by: Tobias Koppers <sokra@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>