Skip to content

[VL] Fix ValueStream empty-batch and finished-split handling#12563

Draft
malinjawi wants to merge 2 commits into
apache:mainfrom
malinjawi:fix/valuestream-empty-batch
Draft

[VL] Fix ValueStream empty-batch and finished-split handling#12563
malinjawi wants to merge 2 commits into
apache:mainfrom
malinjawi:fix/valuestream-empty-batch

Conversation

@malinjawi

Copy link
Copy Markdown
Contributor

What changes are proposed in this pull request?

Three fixes in the ValueStream scan path:

  1. Unbounded recursion on empty batches. ValueStreamDataSource::next() retried by calling itself — an exhausted iterator, a null batch, or a batch fully eliminated by a dynamic filter each recursed, so a long run of filtered-out batches could grow the native stack without bound. The retry is now a loop.
  2. Finished-split signaling. When no iterators remain, return an explicit engaged-null RowVectorPtr so TableScan reads it as "current split finished", instead of relying on the implicit conversion of nullptr into the std::optional return type.
  3. Null/zero-row batch normalization. RowVectorStream::next() converted every batch unconditionally: a null batch from the upstream iterator would crash the conversion (latent today, given the iterator's peek-and-cache contract), and zero-row batches cost an extra scan round-trip each. Both are now normalized to nullptr and skipped by the data-source loop.

Also adds the stream-index bounds check to constructValueStreamNode() that constructValuesNode() and constructCudfValueStreamNode() already perform (skipped in validation mode, where no input iterators are attached).

How was this patch tested?

New cases in ValueStreamDynamicFilterTest cover consecutive fully-filtered batches, finished-split signaling, and a filter/project pipeline over a value stream; they ride the existing velox_operators_test target.

Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Code (reviewed and tested before submission)

@github-actions github-actions Bot added the VELOX label Jul 19, 2026
ValueStreamDataSource::next() had three defects:

1. Unbounded recursion: each exhausted iterator, null batch, or
   fully-filtered batch retried by calling next() recursively, so a
   long run of empty batches (e.g. a dynamic filter eliminating every
   row of consecutive batches) could grow the native stack without
   bound. The retry logic is now an iterative loop.

2. Finished-split signaling: when no iterators remain, return an
   explicit engaged null RowVectorPtr so TableScan reads the result as
   "current split finished" instead of relying on the implicit
   conversion of nullptr into the std::optional return type.

3. Null/zero-row batch normalization: RowVectorStream::next()
   converted every batch unconditionally, so a null batch from the
   upstream iterator would crash the conversion (a latent path given
   the iterator's peek-and-cache contract), and zero-row batches cost
   an extra scan round-trip apiece. Null and zero-row batches are now
   normalized to nullptr and skipped by the data source loop.
@malinjawi
malinjawi force-pushed the fix/valuestream-empty-batch branch from b1878ec to 30fda50 Compare July 19, 2026 11:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant