Skip to content

[branch-4.0][fix](load) only load source scanners update load counters#65277

Open
liaoxin01 wants to merge 1 commit into
apache:branch-4.0from
liaoxin01:codex/pick-63781-to-branch-4.0
Open

[branch-4.0][fix](load) only load source scanners update load counters#65277
liaoxin01 wants to merge 1 commit into
apache:branch-4.0from
liaoxin01:codex/pick-63781-to-branch-4.0

Conversation

@liaoxin01

Copy link
Copy Markdown
Contributor

Pick #63781

)

- Gate the load counter update in
`Scanner::_collect_profile_before_close()` on a new virtual
`_should_update_load_counters()`:
- Base `Scanner` reports only when `_is_load` (classic
stream/broker/routine load scanners with src tuple desc).
- `FileScanner` additionally reports for `FILE_STREAM` scans: TVF based
loads (`http_stream`, group commit) plan the load source as a tvf query
scan without src tuple desc (`_is_load` is false), but their WHERE
clause filtered rows must still be reported as `NumberUnselectedRows` /
counted into `NumberTotalRows`.
- Add a deterministic regression case covering INSERT-SELECT / DELETE /
UPDATE whose scans filter out all rows.

For DELETE/UPDATE/INSERT INTO ... SELECT executed through the insert
path, rows filtered by query scan predicates (including runtime filters)
were added to the RuntimeState load counters. When all scanned rows are
filtered, `num_rows_load_success()` (total - filtered - unselected) goes
negative, BE reports a negative `dpp.norm.ALL`, and FE fails the
`insert_max_filter_ratio` check with errors like:

```
Insert has too many filtered data 0/-2 insert_max_filter_ratio is 1.000000
```

This only triggers with `enable_insert_strict=false` and
`insert_max_filter_ratio > 0` (the strict branch only checks
`filteredRows > 0`). The intermittency in the field comes from runtime
filter arrival timing: rows are only counted when the RF arrives in time
to filter inside the scanner.

This was historically gated by `if (!enable_profile && !_is_load)
return;` (already buggy with `enable_profile=true`), and became
unconditional after apache#57314 removed the early return.

Compared to the previous revision of this PR (thrift
`skip_query_scan_load_counters` option set by FE for DELETE/UPDATE):
- No thrift / FE changes needed.
- Also fixes plain INSERT INTO ... SELECT: `AbstractInsertExecutor` sets
`query_type=LOAD` for all insert-path commands, so the query-type based
gate still let OlapScanner predicate-filtered rows pollute the counters
there.
- `FILE_STREAM` is a precise discriminator: only the `http_stream` /
`group_commit` TVFs use it, and they require a backend id on the
ConnectContext (only present for stream-load style HTTP requests), so
they can never appear in a normal query/DELETE/UPDATE.

`FileScanner::_counter.num_rows_filtered` is only accumulated in
`_convert_to_output_block` (load-only path), so for `http_stream` the
`NumberFilteredRows` reported to clients comes from sink validation and
is unaffected by this gate.

- New regression case
`regression-test/suites/load_p0/insert/test_scan_filtered_rows_not_pollute_load_counter.groovy`:
uses value-column predicates on an AGGREGATE KEY table (cannot be pushed
down to storage, evaluated by scanner conjuncts) to deterministically
reproduce; before this fix the INSERT-SELECT/DELETE/UPDATE statements
fail with `0/-10`.
- `test_group_commit_http_stream` semantics preserved: `insert into ...
select from http_stream(...) where ...` still reports
`NumberUnselectedRows`/`NumberTotalRows` (the previous `_is_load`-only
attempt broke this with `expected: <6> but was: <5>`).
Copilot AI review requested due to automatic review settings July 6, 2026 13:12
@liaoxin01 liaoxin01 requested a review from morningman as a code owner July 6, 2026 13:12
@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?

Copilot AI 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.

Pull request overview

This PR fixes incorrect load counter accounting by ensuring only scanners that are actually reading load source data update RuntimeState load counters. This prevents query predicate filtering (e.g., INSERT INTO ... SELECT ... WHERE ...) from being mixed into load counters, which could otherwise make num_rows_load_success() negative and trigger erroneous “too many filtered rows” failures.

Changes:

  • Gate Scanner::_collect_profile_before_close() load-counter updates behind a new virtual _should_update_load_counters() hook.
  • Override _should_update_load_counters() in FileScanner to also treat FILE_STREAM scans as load-source scans (TVF-based load paths where _is_load is false).
  • Add a regression test covering INSERT/DELETE/UPDATE no-op cases where all rows are filtered during scan, ensuring the load counter logic does not cause failures (including with profile enabled).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
regression-test/suites/load_p0/insert/test_scan_filtered_rows_not_pollute_load_counter.groovy New regression suite validating scan-filtered rows don’t corrupt load counters for INSERT/DELETE/UPDATE paths.
regression-test/data/load_p0/insert/test_scan_filtered_rows_not_pollute_load_counter.out Expected outputs for the new regression suite.
be/src/vec/exec/scan/scanner.h Introduces _should_update_load_counters() to control whether a scanner contributes to load counters.
be/src/vec/exec/scan/scanner.cpp Gates load counter updates in _collect_profile_before_close() using _should_update_load_counters().
be/src/vec/exec/scan/file_scanner.h Declares FileScanner override of _should_update_load_counters().
be/src/vec/exec/scan/file_scanner.cpp Implements override to update load counters for _is_load scanners and FILE_STREAM TVF load scanners.

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

@liaoxin01

Copy link
Copy Markdown
Contributor Author

run buildall

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.

3 participants