Skip to content

[fix](be) Return fragment failure status instead of silent eos in memory scratch sink - #67604

Open
Z-SWEI wants to merge 1 commit into
apache:masterfrom
Z-SWEI:fix/result-queue-silent-eos
Open

[fix](be) Return fragment failure status instead of silent eos in memory scratch sink#67604
Z-SWEI wants to merge 1 commit into
apache:masterfrom
Z-SWEI:fix/result-queue-silent-eos

Conversation

@Z-SWEI

@Z-SWEI Z-SWEI commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Problem Summary:

For queries whose results are pumped through MemoryScratchSink into ResultQueueMgr (the external scan context path: BaseBackendService::get_next -> ResultQueueMgr::fetch_result), when the fragment instance fails -- e.g. query timeout or memory limit exceeded -- MemoryScratchSinkLocalState::close() only puts the nullptr eos sentinel into the record batch queue and never propagates the failure status to the ResultQueueMgr.

A fetcher that already passed the queue status check and is blocked in blocking_get() wakes up on the sentinel, treats it as a normal end-of-stream, and returns eos to the caller. The client stops polling once it sees eos, so the query silently returns truncated results instead of the real error (TIMEOUT, MEM_LIMIT_EXCEEDED, ...).

This patch:

  1. Publishes the fragment failure status to the result queue before putting the eos sentinel in MemoryScratchSinkLocalState::close(). It must be done before the sentinel: a fetcher blocked in blocking_get wakes up on the sentinel and re-checks the queue status.
  2. Re-checks the queue status when fetch_result observes the sentinel, so the failure is surfaced on this last fetch instead of a silent truncated eos.
  3. Adds a unit test (fetch_result_failure_before_eos_sentinel) covering the race: a fetch thread blocked in blocking_get while the sink thread publishes the failure status and then puts the sentinel.

Release note

Fix silently truncated query results when a fragment served by MemoryScratchSink fails -- the query now returns the real failure status (e.g. TIMEOUT, MEM_LIMIT_EXCEEDED) instead of an apparent normal end-of-stream.

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
  • Behavior changed:

    • No.
    • Yes. A failed fragment served by MemoryScratchSink now surfaces its real failure status to the caller instead of a silent truncated eos.
  • Does this need documentation?

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

…ory scratch sink

When a fragment instance executed with MemoryScratchSink fails (e.g.
query timeout or memory limit exceeded), MemoryScratchSinkLocalState::close()
only puts the nullptr eos sentinel into the record batch queue and never
propagates the failure status to ResultQueueMgr. A fetcher that already
passed the status check in ResultQueueMgr::fetch_result and is blocked in
blocking_get wakes up on the sentinel, treats it as normal end-of-stream
and returns eos to the client. The client stops polling once it sees eos,
so the query silently returns truncated results instead of the real error.

This patch:
1. Publishes the fragment failure status to the result queue before
   putting the eos sentinel in MemoryScratchSinkLocalState::close().
2. Re-checks the queue status when fetch_result observes the sentinel,
   so the failure is surfaced on the last fetch instead of a silent
   truncated eos.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

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.

2 participants