perf(cache): use the quick_cache backend for the session metadata cache - #8013
Merged
Merged
Conversation
Same motivation as the index cache switch (lance-format#7953): moka records every hit into a global read-op channel, which negatively scales with readers. The shard formula already handles metadata capacities: >= 4 GiB per shard, so even the largest entries (manifests of wide many-fragment tables, ~100-200 MB) stay admissible. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
wjones127
approved these changes
Jul 27, 2026
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
#7953 moved the session index cache off moka because moka records every cache hit into a single global read-op channel (
record_read_op: channel length check + housekeeper try-lock CAS + try_send), which negatively scales with concurrent readers. The session metadata cache stayed on moka as a deliberate scope cut. It is the one remaining moka cache on a query-serving path: manifests, file/column metadata, deletion vectors, and row-id sequences are all read during query planning, at a lower rate than the index cache but on every query.Change
Both
Session::newandSession::with_index_cache_backendnow build the metadata cache withQuickCacheBackend::with_capacity(metadata_cache_size)— the same backend and sizing formula as the index cache, with no new configuration.The existing shard formula (
min(cpus / 2, capacity / 4 GiB), floor 1) already fits metadata capacities. Because quick_cache splits its weight budget evenly across shards with no borrowing, and silently refuses entries heavier than a shard's share, the per-shard share is what bounds the largest admissible entry:DEFAULT_METADATA_CACHE_SIZE) → 1 shard, share = full capacityThe largest realistic metadata entries are manifests of wide many-fragment tables (
DataFilecarriesfields+column_indices, ~8 B/column/file → ~100–200 MB pathological), plus whole-datasetRowIdIndex/RowAddrMaskat tens of MB — all far below the ≥ 4 GiB share.Low shard counts are fine here: warm hits in quick_cache take no lock (one atomic CLOCK reference bit), so shard count only affects admission/eviction contention, and the #7953 sweep measured a single-shard quick_cache at 6.1 Mops/s pure-get with 256 readers (10x moka). The metadata cache sees tens of reads per query versus ~2000 for the index cache.
quick_cache's own default shard count (
available_parallelism × 4, 2048 on a 320-core host) is deliberately not used: it would shrink the share to ~18 MiB at 36 GiB capacity and silently refuse ordinary manifests.What stays on moka
The io_uring handle cache (needs TTL for fd lifecycle) and the mem_wal SSTable cache (needs predicate invalidation) keep moka — both depend on moka-only features and have read rates where the read-op channel never contends.
LanceCache::with_capacity's default backend is also unchanged; the two hot session caches select quick_cache explicitly.Tests
cargo check -p lance,cargo test -p lance-core cache(25 passed),cargo test -p lance --lib session::(12 passed). Correctness does not depend on eviction order (entries reload via single-flight), andinvalidate_prefixhas no production call sites.🤖 Generated with Claude Code