Skip to content

perf(scan): memoize FlatReader decoded array (filter+projection decode once)#66

Merged
lukekim merged 2 commits into
spiceai-53from
lukim/flat-reader-memo
Jun 13, 2026
Merged

perf(scan): memoize FlatReader decoded array (filter+projection decode once)#66
lukekim merged 2 commits into
spiceai-53from
lukim/flat-reader-memo

Conversation

@lukekim

@lukekim lukekim commented Jun 12, 2026

Copy link
Copy Markdown

Why

A column referenced by BOTH the WHERE filter and the SELECT projection — the common filtered-scan-returning-the-filter-column case — goes through FlatReader::array_future() twice, decoding the chunk twice.

What

Memoize the shared decode in a OnceLock<SharedArrayFuture> (mirroring DictReader::values_array), so the column decodes once. The segment is still re-requested on every call so the segment reader keeps prioritization visibility — only the decode is cached. Bounded by the reader's lifetime (readers held via Weak in the opener), so it does not reintroduce the unbounded retention that prompted removing the prior flat-reader cache.

Companion to the intra-file split (#62) and the per-ExecutionCtx kernel cache already on spiceai-53. cargo check/clippy -p vortex-layout clean; flat-reader tests pass; e2e validation in spiceai's 3-node CH-benCH.

…e once)

A column referenced by BOTH the filter (WHERE) and the projection (SELECT) — the
common filtered-scan-returning-the-filter-column case — went through
array_future() twice, decoding the chunk twice. Memoize the shared decode in a
OnceLock<SharedArrayFuture> (mirroring DictReader::values_array) so it decodes
once. The segment is still re-requested on every call so the segment reader
keeps prioritization visibility; only the decode is cached. Bounded by the
reader's lifetime (readers are held via Weak in the opener), so it does not
reintroduce the unbounded retention that prompted removing the prior cache.
Copilot AI review requested due to automatic review settings June 12, 2026 23:25
@lukekim lukekim self-assigned this Jun 12, 2026
@lukekim lukekim added the enhancement New feature or request label Jun 12, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR targets a hot-path performance issue in FlatReader where the same column can be decoded twice when it is referenced by both the filter (WHERE) and the projection (SELECT). It introduces memoization so the decoded array future can be shared across those call sites.

Changes:

  • Add a OnceLock<SharedArrayFuture> to FlatReader to memoize the decoded array.
  • Update array_future() to use OnceLock::get_or_init(...) so filter and projection can share the same decode.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +71 to 75
// We create the segment_fut here to ensure we give the segment reader visibility into how
// to prioritize this segment, even if the `array` future has already been initialized (it
// is, on the second of a filter+projection pair over the same column). This is gross... see
// the function's TODO for a maybe better solution?
let segment_fut = self.segment_source.request(self.layout.segment_id());
Comment on lines +46 to +49
/// so it happens once. The segment is still re-requested on every
/// `array_future()` call so the segment reader keeps prioritization
/// visibility (see there). Bounded by the reader's lifetime — readers are
/// held via `Weak` in the opener, mirroring `DictReader`'s `values_array`.
…decode once)

array_future_memoizes_the_decode: the decode cache (OnceLock) starts empty, is
populated after the first array_future() (the WHERE-filter touch), and the second
touch (the SELECT projection of the same column) reuses it — so a column feeding
both filter and projection decodes once. Mirrors the existing flat-reader test
harness (TestSegments + FlatLayoutStrategy).
@lukekim
lukekim merged commit 31c6537 into spiceai-53 Jun 13, 2026
31 of 61 checks passed
@lukekim
lukekim deleted the lukim/flat-reader-memo branch June 13, 2026 02:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants