Skip to content

perf(fts): cache residual posting segments - #8821

Closed
BubbleCal wants to merge 11 commits into
yang/fts-unindexed-exact-hybridfrom
yang/oss-2133-cache-residual-fts-segments
Closed

perf(fts): cache residual posting segments#8821
BubbleCal wants to merge 11 commits into
yang/fts-unindexed-exact-hybridfrom
yang/oss-2133-cache-residual-fts-segments

Conversation

@BubbleCal

Copy link
Copy Markdown
Contributor

Performance issue

After #8818, an exact same-column compound query can scan and tokenize a small append-only tail once per query instead of once per leaf. Repeated queries still rebuild the same query-local residual postings, so tokenization and immutable posting construction remain on every-query latency.

This is stacked on #8818 and implements OSS-2133. Review the branch diff against yang/fts-unindexed-exact-hybrid for this layer.

Change

Cache immutable per-fragment residual FTS segments after the same eligible residual group is seen again. The first use retains the query-local path; the second use builds and publishes the complete group; later queries reuse the posting-backed segments with the committed index under one logical-corpus scorer.

The cache identity includes the dataset store namespace, committed index UUID and version, serialized fragment metadata, field identity and type, and full tokenizer/index parameters. Admission also inherits #8818's append-only physical-source proof, including resolved data-base bindings, and uses normalized physical posting details so legacy V1 or unknown formats fail closed.

Resource controls include:

  • at most 16 residual fragments and 1,000,000 residual rows;
  • 256 MiB working reservation per fragment builder and at most two builders;
  • 1 GiB serialized cap per fragment and 2 GiB aggregate resident cap per group;
  • one owner for identical or overlapping fragment groups, with all-or-nothing publication;
  • structured cancellation for index workers and posting producers;
  • claim and permit retention through non-cancellable CPU work, multipart completion, and detached upload abort;
  • conservative accounting for multipart full-copy peaks, copies, renames, cached baseline entries, and concurrent builders.

Tests cover exact Boolean, Boost, Phrase, MultiMatch, MUST_NOT, and tie behavior; cold/second-use/warm lifecycle metrics; cache eviction and identity invalidation; V1 rejection; physical rewrites and base rebinding; group overlap and aggregate admission; write-stage cancellation/error; multipart completion and detached abort lifetime; and disabled/undersized cache fallback.

Benchmark

Comparable final-head measurements are not available yet, so this PR does not claim a measured speedup. The shared VM is currently running the preceding Layer 2 benchmark under the serial lock. This exact head will be queued afterward using the same 10M indexed plus 100k unindexed fixture, c4-highmem-16 VM, query manifest, cache settings, and exact oracle.

The Layer 3 protocol will measure cold first use, second-use build, warm reuse, and repeated-query break-even. No other benchmark will overlap it.

Scenario / metric (lower is better) #8818 This PR Benefit
Cold first-use latency Not yet measured Not yet measured Not yet verified
Second-use build latency Not applicable Not yet measured Not yet verified
Warm repeated-query latency Not yet measured Not yet measured Not yet verified
Repetitions to break even Not applicable Not yet measured Not yet verified

Validation

  • cargo fmt --all
  • git diff --check
  • Independent exact-head and post-rebase static reviews found no remaining P0 or P1 issue
  • Rust tests, clippy, and full checks: delegated to CI as requested

@github-actions github-actions Bot added A-index Vector index, linalg, tokenizer performance labels Aug 27, 2026
@BubbleCal
BubbleCal force-pushed the yang/oss-2133-cache-residual-fts-segments branch from dca07d7 to 5212397 Compare August 27, 2026 07:44

@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: request changes.

Warm residual entries need to remain bound to the physical files they index. A registered-base rebind currently preserves the key and can make bounded compound search return rows that the exact fallback no longer matches. This layer also does not compile because its new object-store call is missing the extension trait import.

Because this is stacked on #8818, land a buildable, safe version of that prerequisite and rebase before revalidating this layer.

}

async fn reserve_source(&self, source: &Path) -> OsResult<()> {
let source_size = self.inner.head(source).await?.size;

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.

This call does not compile against object_store 0.13: head is provided by ObjectStoreExt, but only ObjectStore as OsObjectStore is imported. On the unmodified head, cargo check -p lance --lib fails here with E0599, so lance cannot build. Import object_store::ObjectStoreExt (or use the trait-qualified equivalent).

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.

Fixed in 3483b77: importing ObjectStoreExt makes the new InMemory::head call compile; cargo check -p lance --lib now succeeds.

index_uuid: index.uuid,
index_version: index.index_version,
fragment_id: fragment.id,
fragment_fingerprint: fragment_fingerprint(fragment)?,

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.

The cache key omits the registered base’s resolved physical binding. fragment_fingerprint serializes only the DataFile’s base_id/relative path, while store_identity names the primary dataset store; UpdateBases can therefore map the same ID to another physical path without changing this key, and the session cache survives the new Dataset handle.

Reproducer run on this head

I indexed a primary row, appended residual text oldtoken alpha through base ID 1, then ran a bounded OR(alpha, oldtoken) query three times until residual_cache_reuse_or_coalesced=1. I wrote newtoken beta at the same relative path in base B, rebound ID 1 with add_bases, and verified that the fragment metadata stayed identical. The next bounded query again reported cache reuse and returned row IDs [4294967296, 0]; the unbounded exact fallback returned [0]. The regression failed the required equality assertion.

Include every contributing file’s resolved physical base identity (including path and dataset-root semantics) in the cache key, or reject registered-base residual fragments.

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Aug 27, 2026
@BubbleCal
BubbleCal force-pushed the yang/oss-2133-cache-residual-fts-segments branch from 5212397 to d2c6142 Compare August 27, 2026 12:39
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Aug 27, 2026
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 27, 2026
@BubbleCal
BubbleCal force-pushed the yang/oss-2133-cache-residual-fts-segments branch from d2c6142 to 9c33e0f Compare August 27, 2026 15:14
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Aug 27, 2026
@BubbleCal
BubbleCal force-pushed the yang/oss-2133-cache-residual-fts-segments branch 2 times, most recently from 1a3f512 to 3483b77 Compare August 27, 2026 15:26
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 27, 2026
@BubbleCal
BubbleCal force-pushed the yang/oss-2133-cache-residual-fts-segments branch from 3483b77 to 3ca01ee Compare August 27, 2026 16:24
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Aug 27, 2026
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 27, 2026
@BubbleCal
BubbleCal force-pushed the yang/oss-2133-cache-residual-fts-segments branch from 3ca01ee to 58a51f4 Compare August 27, 2026 16:49
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Aug 27, 2026
@BubbleCal
BubbleCal force-pushed the yang/oss-2133-cache-residual-fts-segments branch from 58a51f4 to 031cab5 Compare August 27, 2026 16:52

@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: request changes.

The registered-base cache identity defect remains reproducible: after warming the residual cache and rebinding the same base ID to a different physical file, the bounded query returns [4294967296, 0] while the exact fallback returns [0]. The existing finding still identifies the missing resolved-base identity.

This revision also expands each segment-group tuple without updating the cross-column destructures, so cargo check -p lance --lib fails with E0308 (inline finding). Bind cached residuals to the resolved base path and dataset-root semantics, and restore compilation. This layer remains stacked on open #8818; land the prerequisite and rebase before revalidating.

segments,
unindexed_fragments,
residual_spec,
use_query_local_residual,

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.

Expanding this tuple to five fields leaves the cross-column branch below destructuring only three. On the unmodified head, cargo check -p lance --lib fails with E0308 at lines 4659 and 4666, so lance does not compile. Update both patterns for the expanded tuple.

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Aug 27, 2026
@BubbleCal
BubbleCal force-pushed the yang/oss-2133-cache-residual-fts-segments branch from 031cab5 to 0906de4 Compare August 28, 2026 04:24
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Aug 28, 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: request changes.

This restack leaves both acceptance blockers unchanged: the segment-group tuple expansion still prevents lance from compiling, and registered-base rebinding still aliases the residual cache, so a warm query can return postings from the prior physical file.

Update both cross-column tuple patterns, and either scope residual entries to a dataset snapshot or include every contributing file’s resolved base path and dataset-root semantics in the cache identity. This layer remains stacked on open #8818; land that prerequisite and rebase before revalidating.

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Aug 28, 2026
@BubbleCal

Copy link
Copy Markdown
Contributor Author

Closing this optimization because WAL-maintained FTS indexes are the intended path for fresh rows. A query-time residual posting cache duplicates write-time indexing and adds invalidation complexity. #8818 remains as the non-WAL partial-coverage fallback and will be re-benchmarked with a 10K unindexed tail.

@BubbleCal BubbleCal closed this Aug 30, 2026
An error occurred while trying to automatically change base from yang/fts-unindexed-exact-hybrid to main August 31, 2026 09:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-index Vector index, linalg, tokenizer K-changes Latest Gatekeeper recommendation requests changes. performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant