Skip to content

perf: stop listing the entire _versions directory for limited version queries - #8679

Open
LuQQiu wants to merge 3 commits into
lance-format:mainfrom
LuQQiu:lu/fix
Open

perf: stop listing the entire _versions directory for limited version queries#8679
LuQQiu wants to merge 3 commits into
lance-format:mainfrom
LuQQiu:lu/fix

Conversation

@LuQQiu

@LuQQiu LuQQiu commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Problem

DirectoryNamespace::list_versions_under always collects every object under the table's _versions/ prefix (read_dir_all(...).try_collect()) before sorting and applying the caller's limit. On object stores this paginates the entire directory even when the caller only wants the latest version (descending=true, limit=1) — which is exactly what get_latest_version does on every dataset resolution through the namespace commit path.

For a table with ~340k versions on S3 this is ~344 sequential ListObjectsV2 pages per resolution: ~25s of pure I/O wait (idle≈26s / busy≈1s per span), paid by every open_table/describe/merge_insert that resolves the latest version. The equivalent non-namespace path (resolve_version_from_listing) already resolves the latest V2 manifest from roughly one list page.

Fix

On lexically-ordered stores the V2 manifest naming scheme (u64::MAX - version, zero-padded) already yields newest-first listings. When the requested order matches the stream's natural order, consume the stream and stop after limit entries instead of collecting everything:

  • descending + limit on an ordered store with V2 naming → stream is already in the right order → stop after limit entries (the get_latest_version hot path becomes a single list page).
  • Everything else (unordered stores, mismatched order, no limit) keeps the existing collect-then-sort behavior.

Also fixes a latent edge: the first stream entry is read for naming-scheme detection, so the limit is re-enforced afterward (covers limit=0).

Measured

Against a real ~340k-version table on S3 (list_table_versions with descending=true, limit=1, same binary, 3 runs):

elapsed S3 LIST requests
before ~25s 344 (full pagination)
after 0.20–0.23s 1 page

Tests

  • New test_list_versions_under_ordering_and_limit covers both paths (memory:// ordered → early-stop; local fs unordered → collect-then-sort) for every descending/limit combination including limit=0 and over-limit.
  • cargo test -p lance-namespace-impls --lib: 299 passed, 0 failed.
  • cargo clippy --no-deps -p lance-namespace-impls --all-targets -- -D warnings clean.

🤖 Generated with Claude Code

… queries

DirectoryNamespace::list_versions_under always collected every object under
the table's _versions/ prefix before sorting and applying the caller's limit.
On object stores this means paginating the whole directory even when the
caller only wants the latest version (descending, limit=1), which is exactly
what get_latest_version does on every dataset resolution. For a table with
hundreds of thousands of versions on S3 this is ~340 sequential LIST pages
(~25s of pure I/O wait) per resolution.

On lexically-ordered stores the V2 manifest naming scheme (u64::MAX - version,
zero-padded) already yields newest-first listings, so when the requested order
matches the stream's natural order we can stop consuming the stream after
`limit` entries instead of collecting everything. Measured against a real
~340k-version table on S3, resolving the latest version drops from ~25s
(344 paginated LIST requests) to ~0.2s (a single page).

Stores without lexical ordering guarantees and mismatched-order requests keep
the existing collect-then-sort behavior.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Aug 20, 2026
LuQQiu and others added 2 commits August 20, 2026 16:10
…first raw entry

The commit protocol retains staging blobs ({manifest}-<uuid>) in
_versions/ after ambiguous publish failures, and their inverted keys sort
ahead of the newest committed V2 manifest on lexically-ordered stores.
Detecting the naming scheme from the first raw entry misclassified such a
stream as non-V2 and silently disabled the early-stop, degrading the
latest-version hot path back to a full directory listing. Detect from the
first entry that parses as a committed manifest instead, and prove the
bound with an entry-consumption-counting regression (staging entry plus
one manifest).

Also ignore negative limits instead of clamping them to 0, matching
apply_pagination (the old code effectively ignored them via the usize
cast wrap).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Aug 20, 2026

@lance-gatekeeper lance-gatekeeper Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gate recommendation: approve.

The retained-staging case is fixed: ordered V2 latest-version lookup now detects its naming scheme from the first committed manifest and remains bounded after skipping retained non-manifest entries. No Gate blocker remains.

@lance-gatekeeper lance-gatekeeper Bot added the K-approved Latest Gatekeeper recommendation permits acceptance. label Aug 20, 2026
@westonpace

Copy link
Copy Markdown
Member

What happens on non-ordered stores like S3 express? Does it just fall back to the old behavior?

@lance-gatekeeper lance-gatekeeper Bot added K-approved Latest Gatekeeper recommendation permits acceptance. and removed K-approved Latest Gatekeeper recommendation permits acceptance. labels Aug 21, 2026
@codecov

codecov Bot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@LuQQiu

LuQQiu commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

What happens on non-ordered stores like S3 express? Does it just fall back to the old behavior?

yep,,, Like S3 express, it's still the old behavior, still reading all the version pages

@lance-gatekeeper lance-gatekeeper Bot added K-approved Latest Gatekeeper recommendation permits acceptance. and removed K-approved Latest Gatekeeper recommendation permits acceptance. labels Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-namespace Namespace impls K-approved Latest Gatekeeper recommendation permits acceptance. performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants