Skip to content

[Bug](Highest) APPEND_ONLY table stream query can crash BE in VCollectIterator with multi-segment rowsets #65901

Description

@MoanasDaddyXu

Tracking

Search before asking

  • I searched the existing issues and found no issue with the same assertion or iterator-mode conflict.

Version

Reproduced on Doris commit 87d57a84729.

What's Wrong?

Querying an APPEND_ONLY table stream backed by ROW binlog can trigger a fatal assertion in the BE scan path when a data rowset contains multiple segments:

Check failed: !_get_data_by_ref

The BE then receives SIGABRT and exits.

The outer BlockReader sees a NONOVERLAPPING rowset and selects Block-based batch reading. ROW binlog requires stable ordered output, so the inner VCollectIterator selects merge/RowRef reading when the rowset has multiple segments. These independently selected modes conflict: the child iterator remains in by-reference mode while the parent calls the Block interface, causing the assertion.

The assertion prevents the engine from continuing in an inconsistent state that could otherwise produce missing, duplicated, or incorrect rows.

What You Expected?

The table stream query should complete without crashing the BE. BlockReader and all child VCollectIterator instances should use a consistent Block or RowRef mode while preserving ROW binlog ordering semantics.

How to Reproduce?

  1. Create a table with ROW binlog enabled.
  2. Create an APPEND_ONLY table stream on the table.
  3. Write enough data for a data rowset to contain multiple segments, with the rowset classified as NONOVERLAPPING.
  4. Query the table stream.
  5. Observe the BE assertion in VCollectIterator::Level0Iterator::next(Block*) followed by SIGABRT.

The issue does not reproduce when the data rowset has only one segment because the inner iterator does not enter merge/RowRef mode.

be.out

The following excerpt is limited to the relevant, sanitized be.out content:

Check failed: !_get_data_by_ref
*** Current BE git commitID: 87d57a84729 ***
*** SIGABRT received; stack trace: ***
 0# doris::signal::FailureSignalHandler(int, siginfo_t*, void*)
 1# pthread_kill
 2# raise
 3# abort
 4# google::LogMessage::SendToLog()
 5# google::LogMessage::Flush()
 6# google::LogMessageFatal::~LogMessageFatal()
 7# doris::VCollectIterator::Level0Iterator::next(doris::Block*)
 8# doris::VCollectIterator::Level1Iterator::_normal_next(doris::Block*)
 9# doris::VCollectIterator::Level1Iterator::next(doris::Block*)
10# doris::VCollectIterator::next(doris::Block*)
11# doris::BlockReader::_direct_next_block(doris::Block*, bool*)
12# doris::BlockReader::next_block_with_aggregation(doris::Block*, bool*)
13# doris::OlapScanner::_get_block_impl(doris::RuntimeState*, doris::Block*, bool*)
14# doris::Scanner::get_block(doris::RuntimeState*, doris::Block*, bool*)
15# doris::Scanner::get_block_after_projects(doris::RuntimeState*, doris::Block*, bool*)
16# doris::ScannerScheduler::_scanner_scan(...)
17# doris::ScannerSplitRunner::process_for(...)
18# doris::PrioritizedSplitRunner::process()
19# doris::TimeSharingTaskExecutor::_dispatch_thread()
20# doris::Thread::supervise_thread(void*)

Root Cause

ROW binlog is the direct trigger, but the code-level defect is inconsistent mode selection between BlockReader and VCollectIterator. The parent must explicitly propagate whether Block or RowRef output is required, and Block mode must prevent every child iterator from entering by-reference mode.

Are you willing to submit PR?

  • Yes, I am willing to submit a PR!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions