Skip to content

[rust] Return decoded scan batches before later errors - #4606

Open
spoon-lz wants to merge 4 commits into
apache:mainfrom
spoon-lz:codex/scan-partial-results-20261012
Open

spoon-lz wants to merge 4 commits into
apache:mainfrom
spoon-lz:codex/scan-partial-results-20261012

Conversation

@spoon-lz

@spoon-lz spoon-lz commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

Fixes #4605.

Preserve successfully decoded Arrow batches when a later batch fails to decode during the same poll.

This aligns the partial-result delivery policy with Java's Arrow batch scanner and prevents subscription offsets from advancing past successful data that was never delivered to the caller.

Brief change log

  • Retain a decoding error after collecting successful batches and report it on the next poll.
  • Preserve partial results both within one completed fetch and across completed fetches.
  • Report errors immediately when no successful batches are available.
  • Use existing subscription and offset checks to discard stale deferred errors.
  • Document the batch poll behavior and add regression tests.

Tests

  • The same collector regression fails on the community baseline with an Arrow parse error and passes with this change.
  • Rust workspace unit-test gate: 855 tests passed.
  • Two final regression tests passed after test refactoring; the collector test covers 18 scenarios.
  • Workspace Clippy and Rustdoc with warnings denied: passed.
  • Formatting and diff checks: passed.

Coverage includes immediate errors, multiple successful batches, same-fetch and cross-fetch failures, empty fetches, offset continuity, recovery, unsubscribe, and subscription offset changes.

No live Fluss-cluster, OSS, or Python/C++ runtime integration tests were run.

API and Format

No public API signature, configuration, protocol, or storage-format changes.

Arrow batch poll error ordering changes: successfully decoded batches are returned before a later decoding error. Fetch-response initialization and authorization errors remain outside this change.

Documentation

Updated the Rust RecordBatchLogScanner::poll API comment to describe partial-result delivery and deferred errors.

Generative AI disclosure

Yes — Codex was used to prepare the implementation, tests, and documentation.

Preserve successfully decoded Arrow batches when a later batch fails, both
within a completed fetch and across completed fetches. Retain the read error
for the next poll and advance offsets only for successfully returned data.

Discard deferred errors after an offset change or unsubscribe through the
existing stale-fetch checks. Document the batch poll behavior and cover error
ordering, empty fetches, recovery, and subscription changes.
@loserwang1024
loserwang1024 self-requested a review October 12, 2026 09:07

@naivedogger naivedogger 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.

Thanks @spoon-lz for this PR. Left some comments, PTAL.

{
Ok(fetch_result) => fetch_result,
Err(error) if !result.is_empty() => {
next_fetch.defer_error(error);

@naivedogger naivedogger Oct 15, 2026 •

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.

If a valid batch from bucket A is followed by an authorization error from bucket B, the initialize_fetch() error branch returns an error after A's offset has advanced, without delivering A's batch. Could we return the collected batches first, retain the error for the next poll, and add a regression test for this path?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. Collected batches are now returned first, with the initialization error deferred to the next poll. Added a cross-bucket authorization-error regression test.

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.

Thanks for the update. There seems to be one remaining case: remote download failures are wrapped with offset -1 in LogFetchBuffer::try_complete(). If deferred after valid batches, the error is discarded on the next poll because fetch_batches_from_fetch() treats the offset mismatch as a stale response.

Could we preserve the original fetch offset for these failures and add a regression test with valid data followed by a failed pending fetch?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed by preserving the original fetch offset when a pending fetch fails. Added regression tests verifying that valid batches are returned first and the download error is reported on the next poll.

offset,
0,
);
fetch.set_initialized();

@naivedogger naivedogger Oct 15, 2026 •

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.

Could we also test an uninitialized fetch with an authorization error and no preceding data? The result.is_empty() && size_in_bytes == 0 check currently discards the error and returns an empty result. Please propagate the error immediately; calling set_initialized() here bypasses that path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. Zero-byte authorization errors are now propagated immediately when no data is available. Added a regression using an uninitialized fetch, without calling set_initialized().

liuzhuo added 2 commits October 16, 2026 15:11
Return collected batches before later fetch initialization errors and propagate zero-byte authorization errors when no data is available. Return buffered batches before requesting more data to avoid losing results on metadata refresh errors or cancellation. Add regressions for initialization errors and the public poll path.

@naivedogger naivedogger 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.

LGTM. Thanks @spoon-lz for the updates. cc @loserwang1024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[rust]Preserve decoded Arrow batches when a later batch fails to decode

2 participants