Skip to content

[improvement](fe) Optimize external file COUNT scan scheduling - #68726

Merged
Gabriel39 merged 9 commits into
apache:masterfrom
OIiveirra:fix/jira-doris-29500
Oct 13, 2026
Merged

Gabriel39 merged 9 commits into
apache:masterfrom
OIiveirra:fix/jira-doris-29500

Conversation

@OIiveirra

@OIiveirra OIiveirra commented Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

What problem does this PR solve?

Issue Number: N/A

Related PR: #68964

Problem Summary:

Repeated queries against a single remotely accessible file split can repeatedly select the same backend when external file caching and consistent-hash scheduling are disabled. The round-robin scheduler reconstructed its candidate list from a host map, discarding the query-local randomized order selected during initialization. This change preserves that order for round-robin assignment and keeps local scheduling and split redistribution inside the active backend candidates.

For unfiltered, ungrouped COUNT(*) and COUNT(1) over File, HDFS, HTTP, Local, and S3 TVFs, the existing file COUNT pushdown is now used under the existing session switches. The instance reduction is limited to a file TVF row-count scan with exactly one assigned static physical split. Dynamic split_source entries, multiple physical splits in one range envelope, and existing external-table COUNT paths retain their original parallelism. DISTINCT, grouped aggregates, filtered plans, merge stages, and stream/ingest TVFs remain outside this path.

The single-split CSV COUNT benchmark improved median QPS from 169.600 to 543.733 (3.206x) under the conditions below. Dynamic batch scans retain baseline fragment-instance parallelism.

Stream Load schema-version locking has been removed from this PR: a differential unit test reproduces the race on the pre-optimization baseline. It is handled separately in #68964, including HTTP transaction cleanup on table-lock timeout. This PR retains the external scan scheduling and file TVF COUNT changes.

Release note

Improve round-robin scheduling for external file scans and reduce execution overhead for unfiltered file TVF row-count queries with a single assigned static physical split.

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:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason

    Validation performed:

    • After separating the independent Stream Load schema-lock fix, the standard focused FE UT reactor passed 33 tests: FederationBackendPolicyTest (12), FileTvfCountPushDownTest (5), UnassignedScanSingleRemoteTableJobTest (7), and the upstream StreamLoadHandlerTest (9). Maven Checkstyle passed. This is functional validation of head 0afd4837804; the benchmark numbers below are from the earlier measured revision.
    • Standard full FE packaging and Checkstyle passed. Standard focused FE UT reactor passed: FederationBackendPolicyTest (12), FileTvfCountPushDownTest (4), and UnassignedScanSingleRemoteTableJobTest (7), 23 tests total, zero failures/errors. Parallelism tests cover dynamic split sources, multiple physical splits in a single range envelope, external-table exclusion, and actual local-shuffle instance assignment.
    • New test_file_tvf_count_pushdown passed both framework snapshot generation and normal comparison (1 suite, zero failures/fatal scripts). It exercises CSV, JSON, Parquet, and ORC with scanner V1/V2 and pushdown enabled/disabled, including COUNT star/one/nullable/DISTINCT, filters, grouping, empty inputs, multiple files, and CSV headers/blank records/no final newline. Zero-byte JSON is included alongside nonempty files because standalone schema inference is unavailable.
    • test_s3_tvf_compression passed against the personal MinIO equivalent using the same public compression fixtures (1 suite, zero failures/fatal scripts). The standard Aliyun OSS profile remains unvalidated because valid credentials are unavailable; community CI should rerun it with its configured credentials.
    • Full Release BE build passed. Both FE versions were tested with identical newly built BE binaries; the new four-format and compressed TVF suites were also repeated successfully on this runtime.
    • Single static split CSV (COUNT(*), 1,000,000 rows, 64 clients): three baseline QPS values were 165.533 / 170.800 / 169.600; candidate values were 449.133 / 544.967 / 543.733. Median QPS increased from 169.600 to 543.733 (3.206x). This measures the combined scheduling and COUNT changes for this workload; it does not establish a scheduling-only multiplier.
    • Real dynamic Iceberg batch (COUNT(value), 64 data files, 1,000,000 rows, expected count 500,000, 16 clients): baseline QPS 29.533 / 30.367 / 28.233, candidate 30.167 / 29.767 / 29.267; medians 29.533 / 29.767 (1.008x). Distributed plans assigned 192 scan fragment instances, 64 per BE, for both versions in all rounds, confirming dynamic sources keep their baseline instance parallelism. These are assigned fragment instances, not active scanner-thread counts. This throughput comparison is limited to the tested fixture and its observed variability.
    • All twelve measurements had verified COUNT results, zero errors, and 3/3 post-measurement backend health. Final artifact inspection found ten connector/dependency JARs with an older API-version manifest because size/mtime-based synchronization skipped them. ZIP entry comparisons confirmed identical classes/resources; the Iceberg provider JAR itself and FE core matched the intended builds. API gating reads the provider's defining JAR, so the differing SPI dependency manifest is outside this check. The measurements are therefore a comparison of the tested workload paths, not a claim of identical complete FE packaging. Unrelated ADBC/ES/Hudi/Trino providers were rejected during startup. A subsequent checksum deployment matched all 2,213 FE artifact hashes and all three BE binaries to the frozen build manifest. All previously rejected providers and Iceberg loaded successfully; static COUNT=1,000,000, dynamic nullable COUNT=500,000, and 3/3 health passed. This deployment smoke did not rerun the performance measurements.
    • Manual benchmark procedure: alternate baseline/candidate FE builds in three rounds (B/C, C/B, B/C), restart all three isolated BEs after each FE switch, require 3/3 health and the expected COUNT result, warm up for 10 seconds, then measure verified successful queries over 30 seconds. Use identical Release BE binaries and session settings (parallel_pipeline_task_num=64, file cache/consistent hash/SQL cache/query cache disabled, COUNT pushdown and scanner V2 enabled). Use 64 clients for the single-split CSV and 16 for the dynamic Iceberg batch; keep profiling disabled during measurement. All measurements require zero errors. The three-BE restart prevents stale cached FE RPC connections after version swaps; startup failures are excluded before measurement.
    • Benchmarks use three BEs on one shared host and report only the tested workload; no equivalent multiplier is claimed for all queries or customer deployments.
  • Behavior changed:

    • No.
    • Yes. Round-robin assignment preserves initialized candidate order; preferred load subsets are honored by local scheduling and redistribution; eligible file TVF COUNT scans use pushdown and one instance per worker when that worker has exactly one static physical split; dynamic sources and existing external-table COUNT parallelism remain unchanged.
  • 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

### What problem does this PR solve?

Issue Number: N/A

Related PR: N/A

Problem Summary:

Repeated queries against a single remotely accessible file split can repeatedly select the same backend when external file caching and consistent-hash scheduling are disabled. The round-robin scheduler reconstructs its candidate list from a host map, losing the query-local candidate order chosen during initialization.

This change preserves that order for round-robin assignment. It also keeps local scheduling and split redistribution within the active backend candidates when load selection retains a preferred subset. Replacing the order is restricted to round-robin policies.

For unfiltered, ungrouped `COUNT(*)` and `COUNT(1)` over File, HDFS, HTTP, Local, and S3 TVFs, this change enables the existing file COUNT pushdown under the existing session switches. DISTINCT, grouped aggregates, filtered plans, merge stages, and stream/ingest TVFs are excluded. A worker with exactly one assigned COUNT scan range uses one instance instead of creating empty local-shuffle instances. Workers with multiple ranges retain the existing parallelism rules.

Previously saved performance measurements on master baseline `0dcd2a31a7b`, using three BEs on one host, a single-split CSV containing 1,000,000 rows, concurrency 64, a 10-second warmup, and a 30-second measurement window, recorded median QPS of 179.900 before and 561.000 after (3.118x). All six rounds reported zero errors. These measurements predate the final review fixes and are workload-specific; the final PR revision has not been benchmarked again. This result does not establish the same improvement for other queries or customer deployments.

### Release note

Improve round-robin scheduling for external file scans and reduce execution overhead for unfiltered file TVF row-count queries with a single assigned scan range.

### Check List (For Author)

- Test
    - [ ] Regression test
    - [x] Unit Test
    - [x] Manual test (add detailed scripts or steps below)
    - [ ] No need to test or manual test. Explain why:
        - [ ] This is a refactor/code format and no logic has been changed.
        - [ ] Previous test can cover this change.
        - [ ] No code files have been changed.
        - [ ] Other reason

  Validation performed:
  - 19 focused JUnit tests passed across `FederationBackendPolicyTest`, `FileTvfCountPushDownTest`, and `UnassignedScanSingleRemoteTableJobTest`. They were executed using a standalone JUnit Launcher with an explicit Byte Buddy agent and available FE compiled dependencies. The modified scheduling class and its test were compiled from the final sources. This is not a successful standard `run-fe-ut.sh` reactor run; that run remains pending because the shared FE build artifacts were inconsistent.
  - FE Checkstyle passed with `mvn -o -pl fe-core -am -DskipTests validate`.
  - `git diff --check` passed.
  - The S3 compression regression includes new COUNT cases, but execution and framework-generated `.out` entries are still pending. This PR is a draft until those results and final-version validation are available.

- Behavior changed:
    - [ ] No.
    - [x] Yes. Round-robin assignment preserves initialized candidate order; preferred load subsets are honored by local scheduling and redistribution; eligible file TVF COUNT scans use pushdown and one instance per worker when that worker has one assigned range.

- Does this need documentation?
    - [x] No.
    - [ ] Yes.

### Check List (For Reviewer who merge this PR)

- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label
@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?

@OIiveirra
OIiveirra marked this pull request as ready for review October 4, 2026 17:13
Copilot AI balanced review requested due to automatic review settings October 4, 2026 17:13

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@OIiveirra

Copy link
Copy Markdown
Collaborator Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 28623 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 6ab06fceef96b3fe5c670344d4481b73ee4587bf, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17578	5503	5463	5463
q2	2073	314	275	275
q3	10233	1383	831	831
q4	4673	472	352	352
q5	7447	788	547	547
q6	184	186	154	154
q7	761	790	602	602
q8	9234	1271	1074	1074
q9	5670	4452	4434	4434
q10	6822	1303	1002	1002
q11	439	251	226	226
q12	626	402	289	289
q13	18046	3067	2374	2374
q14	278	268	242	242
q15	q16	736	727	672	672
q17	1178	734	563	563
q18	7139	6232	6209	6209
q19	1104	950	591	591
q20	403	334	226	226
q21	5348	2232	2402	2232
q22	351	309	265	265
Total cold run time: 100323 ms
Total hot run time: 28623 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6166	6126	6094	6094
q2	686	574	557	557
q3	5234	5389	5002	5002
q4	2015	2121	1553	1553
q5	5283	5239	5806	5239
q6	257	204	158	158
q7	2330	2088	1863	1863
q8	3133	2838	2825	2825
q9	8327	8288	8158	8158
q10	3880	3710	3388	3388
q11	652	491	413	413
q12	723	741	529	529
q13	2965	3281	2568	2568
q14	334	315	294	294
q15	q16	736	733	644	644
q17	8494	7550	7553	7550
q18	13197	12281	13146	12281
q19	931	812	812	812
q20	2204	2171	1954	1954
q21	5881	4761	4809	4761
q22	502	457	408	408
Total cold run time: 73930 ms
Total hot run time: 67051 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 153174 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 6ab06fceef96b3fe5c670344d4481b73ee4587bf, data reload: false

query5	4312	573	473	473
query6	424	215	188	188
query7	4797	443	224	224
query8	320	192	170	170
query9	8776	4153	4043	4043
query10	459	328	266	266
query11	5933	3423	3186	3186
query12	146	90	86	86
query13	1281	469	333	333
query14	6547	4804	4546	4546
query14_1	4258	4300	4245	4245
query15	211	204	181	181
query16	946	446	433	433
query17	854	662	561	561
query18	2419	428	333	333
query19	219	168	137	137
query20	84	80	78	78
query21	220	172	116	116
query22	12949	12988	12781	12781
query23	13188	12567	12255	12255
query23_1	12261	12151	12266	12151
query24	7086	824	457	457
query24_1	461	475	473	473
query25	506	387	338	338
query26	1247	255	134	134
query27	2752	438	270	270
query28	4593	2075	2114	2075
query29	1529	594	459	459
query30	299	236	185	185
query31	883	770	642	642
query32	146	87	90	87
query33	502	294	232	232
query34	888	842	522	522
query35	748	754	646	646
query36	820	854	741	741
query37	130	114	91	91
query38	1819	1736	1688	1688
query39	694	721	717	717
query39_1	680	667	674	667
query40	215	119	99	99
query41	66	64	63	63
query42	87	83	85	83
query43	372	376	359	359
query44	1349	723	711	711
query45	181	177	163	163
query46	852	965	589	589
query47	3001	2919	2917	2917
query48	311	307	224	224
query49	572	394	289	289
query50	693	290	228	228
query51	10278	10589	10466	10466
query52	83	82	71	71
query53	190	216	151	151
query54	249	203	190	190
query55	82	75	67	67
query56	253	244	231	231
query57	1607	1616	1567	1567
query58	284	263	261	261
query59	2373	2396	2146	2146
query60	306	251	246	246
query61	168	176	168	168
query62	394	356	290	290
query63	206	171	171	171
query64	2871	1063	901	901
query65	3426	3376	3402	3376
query66	1804	440	324	324
query67	20215	20309	20317	20309
query68	3023	999	610	610
query69	393	294	248	248
query70	950	843	828	828
query71	307	230	214	214
query72	2790	2586	2065	2065
query73	519	521	308	308
query74	4610	4455	4282	4282
query75	2325	2291	1960	1960
query76	2310	1021	644	644
query77	352	394	298	298
query78	9178	9030	8546	8546
query79	977	902	520	520
query80	665	421	360	360
query81	545	319	284	284
query82	583	138	114	114
query83	262	194	185	185
query84	316	129	110	110
query85	838	430	365	365
query86	316	236	233	233
query87	2010	1964	1840	1840
query88	3627	2715	2715	2715
query89	336	297	256	256
query90	1856	184	181	181
query91	168	149	124	124
query92	101	88	86	86
query93	998	989	561	561
query94	441	305	281	281
query95	592	354	396	354
query96	668	517	242	242
query97	2441	2444	2361	2361
query98	163	148	144	144
query99	784	775	636	636
Total cold run time: 233919 ms
Total hot run time: 153174 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.47 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 6ab06fceef96b3fe5c670344d4481b73ee4587bf, data reload: false

query1	0.00	0.00	0.00
query2	0.11	0.06	0.05
query3	0.26	0.12	0.12
query4	1.61	0.12	0.12
query5	0.28	0.25	0.21
query6	1.17	0.69	0.70
query7	0.04	0.01	0.00
query8	0.05	0.04	0.04
query9	0.43	0.35	0.36
query10	0.61	0.56	0.57
query11	0.21	0.14	0.14
query12	0.19	0.15	0.15
query13	0.51	0.50	0.49
query14	0.99	0.96	0.97
query15	0.62	0.63	0.61
query16	0.33	0.36	0.36
query17	1.11	1.13	1.10
query18	0.22	0.21	0.21
query19	2.14	1.98	2.00
query20	0.01	0.01	0.02
query21	15.50	0.27	0.14
query22	4.58	0.05	0.05
query23	16.24	0.32	0.12
query24	3.22	0.61	0.35
query25	0.10	0.05	0.04
query26	1.05	0.28	0.15
query27	0.05	0.04	0.03
query28	1.57	0.62	0.40
query29	12.52	4.23	3.30
query30	0.29	0.14	0.13
query31	2.78	0.59	0.33
query32	3.24	0.61	0.52
query33	3.19	3.21	3.27
query34	15.47	4.01	3.39
query35	3.32	3.34	3.32
query36	0.57	0.47	0.46
query37	0.10	0.07	0.07
query38	0.05	0.05	0.04
query39	0.04	0.03	0.03
query40	0.17	0.15	0.14
query41	0.09	0.03	0.03
query42	0.03	0.03	0.03
query43	0.04	0.04	0.04
Total cold run time: 95.1 s
Total hot run time: 24.47 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 71.79% (28/39) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 71.79% (28/39) 🎉
Increment coverage report
Complete coverage report

@Gabriel39

Copy link
Copy Markdown
Contributor

Review notes for 6ab06fceef96b3fe5c670344d4481b73ee4587bf: the main concern is the scope of the new single-instance rule. The points below identify code-level boundaries and missing validation; I have not reproduced a wrong-result bug or measured a performance regression.

  1. One assigned scan-range entry does not necessarily mean one physical split.

    The new rule in UnassignedScanSingleRemoteTableJob.degreeOfParallelism() checks only COUNT && maxParallel == 1. However, DefaultScanSource.maxParallel() counts scan-range entries. In batch mode, each BE receives a split_source entry that can supply many physical splits. A COUNT-marked scan using that representation can therefore satisfy this condition even with substantial scan work. This reduces fragment-instance parallelism; it does not necessarily serialize all scanner threads, so the throughput impact needs measurement.

    Please exclude dynamic split_source ranges from this shortcut, or explicitly validate that path. If the intent is a single-file-split optimization, check the actual assigned split representation rather than only the number of range envelopes. Add a test where one range entry represents multiple fetched splits.

  2. The single-instance rule is broader than the new TVF row-count optimization.

    This is a shared external-scan job, and the condition does not require a file TVF or distinguish COUNT(*)/COUNT(1) from existing COUNT(col) pushdown paths. Consequently, the change can also affect existing external-table plans outside the newly added TVF matcher.

    The accompanying comment that the scanner already produces the complete scalar result is also too strong: CSV COUNT still reads records, while CountReader emits batches representing rows for the upper aggregation, rather than a single final count row.

    Please initially scope this shortcut to the intended file TVF row-count plans with one actual assigned split. If broader external-table coverage is intentional, document it and validate those paths separately, including COUNT arguments and batch scans. Update the comment to describe the actual reduction in instance overhead.

  3. Add execution-level coverage for the expanded COUNT path.

    The added end-to-end regression covers gzip CSV COUNT, while the translator tests primarily exercise mocked plan matching. Please supplement them with pushdown-on/off result comparisons for representative CSV, Parquet, ORC, and JSON inputs, under supported scanner V1/V2 paths. Include empty inputs, multiple files/splits, CSV headers/empty records, and real SQL plans with filters, grouping, DISTINCT, and COUNT(nullable_col) to verify the new TVF matcher does not apply incorrectly. For the parallelism change, include a large batch scan and verify both instance counts and throughput against the baseline.

I did not identify a concrete blocking issue in preserving the initialized round-robin candidate order. The existing behavior where cache/consistent-hash scheduling can keep a hot split on the same BE is unchanged and is not a regression introduced by this PR.

OIiveirra added a commit to OIiveirra/doris that referenced this pull request Oct 8, 2026
### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#68726

Problem Summary: Independently planned queries for one remote split can keep
selecting one backend. Enable automatic external scan spreading by default
with value 0, using all eligible backends in the current compute group and
minimum assigned weight with random ties. Preserve locality and single split
execution. Value 1 restores original scheduling; explicit N retains bounded
hash candidates. Other backend policy consumers remain unchanged.

In a shared-host three-BE cache/hash-off SUM experiment at concurrency 64,
three completed alternating pairs increased QPS from 13.867 to 40.506 (2.9211x).
The first attempt at pair three had a gRPC keepalive failure in original mode;
its one-error 6.10 QPS group is retained separately and the complete pair was
repeated after recovery. This is not customer or physical three-host validation.
No COUNT, DOP or CPU-routing optimization is added.

### Release note

Remote external scans automatically spread across eligible backends by default.
Set external_scan_consistent_hash_spread_num to 1 to restore original scheduling.
Automatic file-cache scans can increase cache copies and warmup reads.
Persisted global settings are retained on upgrade.

### Check List (For Author)

- Test: Unit Test / Regression test / Manual test
  - Standard FE build and Checkstyle; 32 focused FE tests passed.
  - Two targeted regression suites framework-generated and verified.
  - 400 correct SUM query profiles verified one split and one target.
  - Three completed paired C64 SUM measurements; interruption disclosed above.
- Behavior changed: Yes, default automatic external scheduling with explicit rollback.
- Does this need documentation: Yes, docs/external-scan-consistent-hash-spread.md included.
OIiveirra added a commit to OIiveirra/doris that referenced this pull request Oct 8, 2026
### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#68726

Problem Summary: Spread scheduling disables global split redistribution, but
still builds and retains alternative Host lists for every split. The only
consumer of these lists is redistribution. Automatic mode considers all
eligible backends, so these unused lists retain O(split count * backend count)
Host references and allocate unnecessary temporary candidate copies.

Build alternative Host lists only for the original scheduling mode. Preserve
candidate selection, assigned weights, locality and split execution unchanged.
Add tests for multiple automatic hash/random splits without retained lists
and an original-mode control that still retains its alternative Host.

### Release note

None

### Check List (For Author)

- Test: Unit Test / Regression test
  - 33 focused FE unit tests passed (23 spread policy, 9 original policy, 1 variable).
  - Standard FE build and Checkstyle passed.
  - Parameter and external scan regression suites verified on the rebuilt FE.
- Behavior changed: No, remove unused allocation without changing scheduling.
- Does this need documentation: No, scheduling and parameter semantics are unchanged.
### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#68726

Problem Summary: The single-instance COUNT rule counted assigned range envelopes,
which can represent many physical splits in dynamic batch scans, and could apply
to existing external-table COUNT paths. Inspect each worker's assigned scan source
and restrict the shortcut to file TVF row-count scans with one static physical
split. Preserve parallelism for dynamic split sources, multiple physical splits,
and external tables, and clarify that upper aggregation still computes COUNT.
Add four-format execution coverage and tests for the parallelism boundaries.

### Release note

Limit single-instance file TVF COUNT execution to one assigned static physical
split and preserve existing external-table and dynamic batch scan parallelism.

### Check List (For Author)

- Test: Standard FE build and Checkstyle; 23 focused FE unit tests; CSV, JSON,
  Parquet and ORC file TVF regression suite; compressed S3 TVF regression with
  equivalent MinIO fixtures; isolated three-BE baseline/candidate manual tests.
  The standard Aliyun OSS profile requires valid credentials and was not validated.
- Behavior changed: Yes. Dynamic and non-TVF COUNT scans retain their original
  parallelism; one static file TVF row-count split reduces fragment instances.
- Does this need documentation: No
@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 28931 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 02425fb222ba8924dba3bbbc6cb30e62540fbcf0, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17580	5674	5522	5522
q2	2131	309	254	254
q3	10234	1383	818	818
q4	4685	471	345	345
q5	7429	801	522	522
q6	180	184	154	154
q7	742	792	609	609
q8	9241	1319	1054	1054
q9	5632	4440	4393	4393
q10	6822	1300	1032	1032
q11	430	253	234	234
q12	621	398	286	286
q13	18081	3057	2373	2373
q14	267	268	245	245
q15	q16	756	734	683	683
q17	1174	741	567	567
q18	7038	6273	6192	6192
q19	1209	967	587	587
q20	383	328	223	223
q21	5879	2547	2542	2542
q22	390	338	296	296
Total cold run time: 100904 ms
Total hot run time: 28931 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6657	6568	6664	6568
q2	785	603	573	573
q3	5542	5693	5251	5251
q4	2052	2153	1572	1572
q5	5847	5637	5692	5637
q6	238	186	151	151
q7	2303	2011	1760	1760
q8	3087	2667	2731	2667
q9	8299	8154	8096	8096
q10	3652	3581	3219	3219
q11	609	408	371	371
q12	662	697	495	495
q13	2722	3117	2380	2380
q14	291	282	256	256
q15	q16	655	684	633	633
q17	7654	7001	6882	6882
q18	13011	12188	13090	12188
q19	910	779	775	775
q20	2187	2175	1931	1931
q21	5765	4702	4749	4702
q22	498	442	413	413
Total cold run time: 73426 ms
Total hot run time: 66520 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 151509 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 02425fb222ba8924dba3bbbc6cb30e62540fbcf0, data reload: false

query5	4296	564	451	451
query6	423	202	203	202
query7	4800	435	227	227
query8	317	170	169	169
query9	8753	3900	3889	3889
query10	449	312	250	250
query11	5950	3397	3184	3184
query12	142	84	81	81
query13	1239	430	314	314
query14	6502	4696	4476	4476
query14_1	4219	4223	4209	4209
query15	205	190	193	190
query16	953	433	423	423
query17	858	645	527	527
query18	2412	419	320	320
query19	199	165	135	135
query20	80	80	81	80
query21	207	134	110	110
query22	12938	13009	12881	12881
query23	13175	12483	12117	12117
query23_1	12327	12260	12285	12260
query24	7109	815	463	463
query24_1	475	466	464	464
query25	535	421	367	367
query26	1251	257	138	138
query27	2751	439	270	270
query28	4646	1904	1914	1904
query29	1564	596	439	439
query30	290	215	178	178
query31	894	759	635	635
query32	140	91	94	91
query33	512	303	242	242
query34	971	849	485	485
query35	773	786	650	650
query36	862	807	736	736
query37	131	103	87	87
query38	1791	1754	1690	1690
query39	704	733	662	662
query39_1	676	671	670	670
query40	222	122	100	100
query41	71	67	68	67
query42	89	89	86	86
query43	363	377	326	326
query44	1281	690	674	674
query45	184	188	171	171
query46	827	954	574	574
query47	2896	3062	2975	2975
query48	302	304	222	222
query49	573	400	329	329
query50	667	282	206	206
query51	10189	10218	10155	10155
query52	78	80	67	67
query53	182	208	152	152
query54	230	198	192	192
query55	69	66	65	65
query56	214	201	199	199
query57	1600	1583	1577	1577
query58	277	260	245	245
query59	2357	2360	2124	2124
query60	283	228	225	225
query61	143	143	147	143
query62	388	335	285	285
query63	197	155	156	155
query64	2722	957	770	770
query65	3420	3347	3398	3347
query66	1789	422	293	293
query67	20182	19941	20201	19941
query68	2948	991	600	600
query69	388	292	239	239
query70	937	834	832	832
query71	274	235	206	206
query72	2680	2550	2294	2294
query73	517	513	292	292
query74	4553	4449	4301	4301
query75	2334	2298	1945	1945
query76	2288	1012	591	591
query77	358	380	294	294
query78	9128	8996	8534	8534
query79	948	904	516	516
query80	735	413	349	349
query81	542	326	277	277
query82	578	136	107	107
query83	272	197	175	175
query84	307	120	106	106
query85	888	425	358	358
query86	335	236	236	236
query87	2020	1933	1843	1843
query88	3559	2680	2657	2657
query89	340	302	252	252
query90	1798	179	176	176
query91	162	149	121	121
query92	92	77	87	77
query93	982	977	552	552
query94	472	313	275	275
query95	570	392	313	313
query96	666	520	236	236
query97	2459	2422	2308	2308
query98	157	148	144	144
query99	771	764	658	658
Total cold run time: 233031 ms
Total hot run time: 151509 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.67 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 02425fb222ba8924dba3bbbc6cb30e62540fbcf0, data reload: false

query1	0.00	0.00	0.00
query2	0.11	0.06	0.05
query3	0.28	0.13	0.12
query4	1.60	0.12	0.13
query5	0.25	0.26	0.25
query6	1.17	0.68	0.68
query7	0.03	0.01	0.00
query8	0.06	0.05	0.03
query9	0.43	0.35	0.37
query10	0.60	0.60	0.59
query11	0.20	0.14	0.14
query12	0.19	0.15	0.14
query13	0.48	0.50	0.48
query14	0.97	0.97	0.97
query15	0.64	0.60	0.63
query16	0.36	0.36	0.36
query17	1.19	1.12	1.16
query18	0.23	0.22	0.21
query19	2.04	2.02	2.01
query20	0.02	0.01	0.02
query21	15.51	0.27	0.15
query22	4.35	0.06	0.06
query23	16.28	0.32	0.12
query24	3.22	0.57	0.40
query25	0.11	0.04	0.07
query26	1.04	0.26	0.15
query27	0.05	0.05	0.03
query28	1.45	0.61	0.43
query29	12.48	4.18	3.30
query30	0.31	0.16	0.15
query31	2.78	0.59	0.35
query32	3.23	0.63	0.52
query33	3.12	3.26	3.20
query34	15.65	4.03	3.40
query35	3.33	3.35	3.34
query36	0.57	0.43	0.43
query37	0.11	0.06	0.07
query38	0.05	0.04	0.04
query39	0.04	0.03	0.04
query40	0.18	0.16	0.14
query41	0.08	0.03	0.04
query42	0.04	0.03	0.03
query43	0.05	0.04	0.04
Total cold run time: 94.88 s
Total hot run time: 24.67 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 73.33% (33/45) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 75.56% (34/45) 🎉
Increment coverage report
Complete coverage report

### What problem does this PR solve?

Issue Number: N/A

Problem Summary: Stream load reads the base schema version without a table
read lock. A concurrent schema change can remove the old base index metadata
before replacing the base index ID, causing a null pointer exception. Use the
existing timed read lock pattern around the returned table metadata and
release it in finally. Add a deterministic test using the real table locks to
reproduce the index replacement window.

### Release note

Fix stream load failures caused by concurrent base index replacement.

### Check List (For Author)

- Test: Unit Test: StreamLoadHandlerTest (4 tests passed). The new concurrency
  test reproduces the original null pointer exception before the fix.
- Behavior changed: Yes. Metadata reads wait for concurrent schema changes,
  using the existing stream load table lock timeout.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: N/A

Problem Summary: The cloud rowset property test repeats the same SELECT while
checking BE capture counters. CI audit logs show that the query after setting
the user property hits SQL cache with zero scanned rows, so the expected BE
counter does not increase. Disable SQL cache in the test connection so each
query reaches the BE. Keep all existing assertions unchanged.

### Release note

None

### Check List (For Author)

- Test: Manual test: Correlated the failing assertion with CI query audit
  records. The standard regression dry run discovered this suite; it exited
  with errors in unrelated cloud scripts. Cloud execution is pending CI;
  the personal environment is not a Cloud cluster.
- Behavior changed: No
- Does this need documentation: No
@OIiveirra
OIiveirra requested a review from liaoxin01 as a code owner October 9, 2026 02:24
924060929
924060929 previously approved these changes Oct 10, 2026
@Gabriel39

Copy link
Copy Markdown
Contributor

/review

@github-actions github-actions Bot 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.

Review complete for PR #68726 at 0be73f90a5f79ea36fdfdef63c910b30a57b8624 after two convergence rounds. I found two new P2 issues, attached inline. The existing P2 Project-expression thread (4228580328) is fixed at this head by the direct and multilayer NoneMovableFunction checks and is not repeated. No existing P0/P1 inline finding still applies. There was no additional user-provided focus.

Critical checkpoint conclusions:

  • Goal and proof: The changes preserve initialized round-robin candidate order, enable existing file-reader COUNT handling for eligible file TVFs, reduce one-static-split instance overhead, and protect the regular stream-load schema-version read. FE unit and regression cases cover the main accepted and rejected COUNT shapes. The two inline findings limit the quality and completeness of the implementation.
  • Scope and clarity: The execution changes are locally understandable. Reconstructing the host map in every assignment adds avoidable work; the schema-version lock should cover the parallel load_sql result path.
  • Concurrency and locks: SplitAssignment.addToQueue holds assignLock while invoking backend assignment, so the new per-split map construction runs under that lock. The regular stream-load read lock uses the existing timed pattern and releases in finally; no new lock-order or deadlock was established. The HTTP stream-load result still reads base-index metadata after its planning locks are released and can race schema change.
  • Lifecycle and ownership: Static/dynamic file split sources, empty-scan fallback, V1 reader ownership, and V2 metadata-count fallback were traced. No new lifetime leak, circular reference, or static-initialization dependency was found.
  • Configuration: No new configuration item is introduced. COUNT uses the existing session switches; dynamic split sources retain their prior parallelism.
  • Compatibility and FE/BE contract: The TVF scan uses existing thrift COUNT fields and sends an explicit empty argument-slot list for COUNT(*)/COUNT(1). V1/V2 readers either count range-scoped rows or fall back to record reads. No new storage format, function symbol, or persistence encoding is introduced.
  • Parallel paths and conditions: The matcher excludes grouped, distinct, filtered, nullable-column, buffer-consuming, and retained nonmovable-expression plans. The one-instance shortcut excludes dynamic and multi-range sources. The parallel HTTP load_sql schema-version path remains the exception raised inline.
  • Tests and expected results: The FE tests and local TVF regression matrix cover scanner V1/V2, pushdown enabled/disabled, empty and multiple files, and assertion behavior. All 132 named TVF snapshots match the suite, and text-fixture counts are consistent. The remote S3 object and binary fixture row contents were not independently executed or decoded. This review ran no builds or tests, as required by the review prompt.
  • Observability: Existing user errors and FE logs cover the changed failure paths; no separate metric or logging defect was established.
  • Transactions, persistence, and writes: The PR changes no EditLog, transaction protocol, or data-write implementation. The new read lock protects only one metadata snapshot; the distinct HTTP result snapshot remains exposed as described inline.
  • Performance and other issues: The intended COUNT and single-instance savings are plausible from the code, but runtime speedups were not measured in this review. The additional host-map traversal and allocations on one-split streaming scans are reported inline. No other substantiated issue remained after the full changed-file sweep.

### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#68726

Problem Summary: Streamed split assignment rebuilt the backend host map for every split. Cache the map and refresh it on initialization and candidate replacement. The load_sql stream load result also read schema version without a table lock during concurrent base index replacement. Read its table properties under the existing timed read lock pattern and release in finally.

### Release note

Avoid repeated host map allocation during streamed scans and protect HTTP stream load metadata reads during schema change.

### Check List (For Author)

- Test: Standard FE UT: FederationBackendPolicyTest, StreamLoadHandlerTest and HttpStreamLoadTablePropertiesTest, 18 tests passed. Maven Checkstyle and git diff --check passed.

- Behavior changed: Yes. HTTP stream load table property reads wait for concurrent schema changes using the request RPC lock timeout.

- Does this need documentation: No
### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#68726

Problem Summary: Merge upstream master e0f2ebb into the published PR branch. Resolve translator conflicts by retaining the COUNT pushdown and retained-expression guard alongside the upstream condition-cache initialization, and remove the obsolete Udf import.

### Release note

None

### Check List (For Author)

- Test: Standard FE UT: 42 tests passed across COUNT pushdown, condition cache, runtime-filter translation, backend scheduling and stream load suites. Maven Checkstyle passed; PR diff against upstream master passes git diff --check.

- Behavior changed: No additional behavior change from the conflict resolution.

- Does this need documentation: No
@OIiveirra

Copy link
Copy Markdown
Collaborator Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 28967 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 9fd223963b5f6da009282f1704ca046e870f096d, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17580	5624	5506	5506
q2	2119	301	275	275
q3	10229	1395	828	828
q4	4669	473	354	354
q5	7441	788	534	534
q6	189	190	159	159
q7	763	801	601	601
q8	9244	1331	1120	1120
q9	5768	4449	4428	4428
q10	6815	1304	1014	1014
q11	434	257	233	233
q12	630	407	286	286
q13	18114	3086	2390	2390
q14	279	263	243	243
q15	q16	740	729	671	671
q17	1171	747	584	584
q18	7015	6219	6190	6190
q19	1100	978	576	576
q20	379	328	227	227
q21	5306	2462	2489	2462
q22	381	362	286	286
Total cold run time: 100366 ms
Total hot run time: 28967 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6514	6440	6466	6440
q2	710	605	576	576
q3	5555	5659	5328	5328
q4	2010	2118	1569	1569
q5	5857	5815	5685	5685
q6	240	189	151	151
q7	2333	1985	1876	1876
q8	3120	2676	2781	2676
q9	8321	8073	7801	7801
q10	3665	3590	3227	3227
q11	592	408	388	388
q12	663	686	493	493
q13	2743	3078	2365	2365
q14	283	293	265	265
q15	q16	652	712	625	625
q17	7764	6962	6859	6859
q18	13187	12341	13052	12341
q19	916	790	797	790
q20	2183	2164	1956	1956
q21	5711	4672	4768	4672
q22	497	454	408	408
Total cold run time: 73516 ms
Total hot run time: 66491 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 151728 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 9fd223963b5f6da009282f1704ca046e870f096d, data reload: false

query5	4305	576	450	450
query6	423	215	191	191
query7	4797	439	215	215
query8	318	191	163	163
query9	8765	3921	3944	3921
query10	470	327	271	271
query11	6020	3423	3190	3190
query12	143	91	83	83
query13	1253	444	319	319
query14	6509	4788	4519	4519
query14_1	4233	4226	4239	4226
query15	203	197	185	185
query16	935	445	418	418
query17	863	652	548	548
query18	2423	419	308	308
query19	200	171	137	137
query20	80	80	80	80
query21	209	135	110	110
query22	12931	12991	12835	12835
query23	13217	12551	12061	12061
query23_1	12243	12211	12346	12211
query24	7132	835	453	453
query24_1	465	478	463	463
query25	532	446	363	363
query26	1317	259	135	135
query27	2781	441	269	269
query28	4591	1912	1890	1890
query29	1567	593	455	455
query30	314	219	182	182
query31	869	763	651	651
query32	140	92	89	89
query33	513	313	255	255
query34	887	848	495	495
query35	756	746	664	664
query36	849	827	711	711
query37	133	108	90	90
query38	1778	1759	1686	1686
query39	685	730	682	682
query39_1	694	666	654	654
query40	222	127	103	103
query41	72	68	68	68
query42	90	87	86	86
query43	361	381	332	332
query44	1315	684	699	684
query45	179	184	161	161
query46	869	958	565	565
query47	2941	2976	2949	2949
query48	290	298	219	219
query49	563	391	301	301
query50	669	284	200	200
query51	10252	10411	10357	10357
query52	78	77	69	69
query53	187	203	147	147
query54	229	198	172	172
query55	77	72	64	64
query56	224	209	224	209
query57	1622	1600	1564	1564
query58	272	254	264	254
query59	2326	2352	2131	2131
query60	271	238	216	216
query61	145	166	145	145
query62	390	337	284	284
query63	190	165	166	165
query64	2738	936	753	753
query65	3425	3366	3382	3366
query66	1766	412	297	297
query67	20111	20129	20071	20071
query68	3112	981	588	588
query69	430	291	243	243
query70	906	838	815	815
query71	286	219	217	217
query72	2637	2591	2314	2314
query73	503	517	291	291
query74	4569	4461	4334	4334
query75	2324	2295	1938	1938
query76	2290	1007	606	606
query77	342	404	292	292
query78	9135	9089	8522	8522
query79	947	886	507	507
query80	530	439	322	322
query81	520	331	273	273
query82	571	132	110	110
query83	302	190	170	170
query84	310	122	96	96
query85	795	413	357	357
query86	312	235	232	232
query87	2022	1980	1804	1804
query88	3572	2702	2645	2645
query89	344	297	258	258
query90	1890	184	178	178
query91	169	148	121	121
query92	94	77	93	77
query93	989	978	569	569
query94	443	308	287	287
query95	590	397	329	329
query96	678	517	233	233
query97	2451	2431	2369	2369
query98	156	147	139	139
query99	773	763	654	654
Total cold run time: 233215 ms
Total hot run time: 151728 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.41 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 9fd223963b5f6da009282f1704ca046e870f096d, data reload: false

query1	0.01	0.01	0.01
query2	0.11	0.05	0.05
query3	0.26	0.10	0.13
query4	1.61	0.13	0.13
query5	0.25	0.22	0.25
query6	1.19	0.70	0.67
query7	0.04	0.01	0.00
query8	0.06	0.04	0.04
query9	0.42	0.35	0.35
query10	0.60	0.57	0.60
query11	0.20	0.14	0.13
query12	0.18	0.14	0.14
query13	0.48	0.49	0.51
query14	0.98	0.96	0.95
query15	0.64	0.62	0.62
query16	0.35	0.35	0.35
query17	1.15	1.18	1.15
query18	0.22	0.21	0.22
query19	2.09	1.98	1.98
query20	0.02	0.01	0.01
query21	15.48	0.27	0.15
query22	4.53	0.06	0.05
query23	16.24	0.33	0.13
query24	3.04	0.71	0.38
query25	0.12	0.06	0.06
query26	1.38	0.27	0.15
query27	0.04	0.05	0.03
query28	1.78	0.59	0.37
query29	12.47	4.09	3.24
query30	0.28	0.15	0.13
query31	2.78	0.57	0.34
query32	3.22	0.62	0.53
query33	3.16	3.30	3.18
query34	15.42	4.04	3.37
query35	3.36	3.38	3.36
query36	0.56	0.44	0.42
query37	0.10	0.06	0.06
query38	0.05	0.03	0.04
query39	0.04	0.03	0.03
query40	0.18	0.15	0.14
query41	0.09	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 95.26 s
Total hot run time: 24.41 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 6.54% (55/841) 🎉
Increment coverage report
Complete coverage report

924060929
924060929 previously approved these changes Oct 12, 2026
@Gabriel39

Copy link
Copy Markdown
Contributor

/review

@github-actions github-actions Bot 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.

Review complete at head 9fd223963b5f6da009282f1704ca046e870f096d. This is a static-only review: the review contract prohibited builds and tests, so inspected tests and their expected outputs are not runtime validation. I found one new P2 issue in the HTTP load_sql transaction cleanup path. No previously reported P0/P1 inline finding still applies; existing_blocking_comment_ids is empty. There was no additional user-provided review focus.

Critical checkpoints:

  • Goal and tests: The changes target file-TVF COUNT pushdown, one-range scan scheduling, active backend selection, and schema-version reads during stream load. The planner, scheduling, and metadata reads follow the intended call paths, but the new HTTP lock timeout leaves a transaction open as described inline. FE unit tests and TVF/stream-load regressions cover the intended positive and negative cases in source; none was run here.
  • Scope and clarity: The production changes are confined to those paths. The added lock helper keeps the property reads together; the missed transaction cleanup is the one focused correctness issue.
  • Concurrency and locks: The FE stream-load RPC races with schema-change work that takes the same OlapTable write lock. The new read locks protect lightweight metadata getters and release in finally; I found no new nested-lock inversion. InsertIntoTableCommand.initPlan releases its read lock after starting the HTTP transaction, however, so a writer can occupy the interval before the new timed read lock and trigger M1. Streamed split assignment remains serialized by its existing lock.
  • Lifecycle: Normal HTTP load_sql starts an FE transaction before result metadata assembly. Neither the FE exception path nor the BE failed-plan path aborts it on the new timeout. There is no new static initializer or ownership cycle. Ordinary stream load already gives the BE rollback ownership; group-commit HTTP skips the FE begin.
  • Configuration: No new configuration item is defined. The COUNT session gates and the request-provided thrift RPC timeout or existing default were checked in their callers; no dynamic-config propagation issue was substantiated.
  • Compatibility and definitions: No function symbol, storage format, or gensrc/thrift/gensrc/proto definition changes. COUNT translation uses existing FE-to-BE fields, and the inspected BE readers retain normal-scan fallback for unsupported count paths. No distinct rolling-upgrade issue was substantiated statically.
  • Parallel paths and conditions: Direct/projected COUNT, V1/V2 readers, zero/multiple/static/dynamic splits, backend locality and redistribution, ordinary versus HTTP stream load, and group commit were traced separately. The project NoneMovableFunction guard and count eligibility conditions exclude the previously reported synthetic-value case; the existing backend host-map issue is also fixed at this head. No other conditional branch produced a distinct finding.
  • Coverage and expected results: The FE tests cover translator shapes, one-range scheduling, backend order, and lock ownership/release. The new TVF suite has four scanner/pushdown modes with 33 golden cases each; fixture cardinalities and the changed S3/cloud assertions were checked. The missing negative test is a forced post-begin HTTP lock timeout followed by an explicit-label retry, as noted inline. Golden files were inspected, not generated or executed in this review.
  • Observability: Existing FE timeout status/logging and BE plan-error logging identify the failed request, while the transaction remains unclosed; no separate logging or metric finding was substantiated.
  • Transactions, persistence, writes, and crashes: No new EditLog or replay format is introduced and no new data-writing operation is added. M1 leaves a PREPARE transaction after the new error path, blocking same-label retry until transaction-manager timeout. I found no separate data-visibility, failover, or crash-specific issue in the changed paths.
  • FE-BE variables and performance: No new transmitted variable is introduced. The backend map is cached after candidate replacement, and the one-range COUNT path reduces local-shuffle instances; no independent performance regression was substantiated. The remaining supported COUNT readers still emit bounded batches for the existing upper aggregate.
  • Other findings: The earlier inline P2 concerns were treated as duplicate fences and checked against this head. The final sweep of all 29 changed paths and the candidate ledger left only the new P2 finding below.

### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#68726

Problem Summary: Baseline testing reproduces the stream load schema-version race before the COUNT optimization. Remove the independent table read-lock changes and their tests from this PR so they can be fixed separately, including HTTP transaction cleanup on lock failure. Preserve the active backend host map and all COUNT scheduling changes.

### Release note

None

### Check List (For Author)

- Test: Standard FE UT, 33 tests passed across FederationBackendPolicyTest, FileTvfCountPushDownTest, UnassignedScanSingleRemoteTableJobTest and StreamLoadHandlerTest. Maven Checkstyle and git diff --check passed.
- Behavior changed: Yes. Restore upstream stream load metadata-read behavior pending a separate fix.
- Does this need documentation: No
@OIiveirra

Copy link
Copy Markdown
Collaborator Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29356 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 0afd483780456addc248d30ed4efb09266be8b24, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17577	5683	5588	5588
q2	2108	316	250	250
q3	10247	1406	841	841
q4	4673	472	352	352
q5	7450	794	548	548
q6	187	186	157	157
q7	784	808	609	609
q8	9235	1353	1147	1147
q9	5740	4474	4455	4455
q10	6806	1298	1034	1034
q11	432	251	247	247
q12	638	411	296	296
q13	18032	3088	2410	2410
q14	270	272	239	239
q15	q16	738	732	676	676
q17	1191	760	570	570
q18	7196	6276	6194	6194
q19	1103	959	617	617
q20	410	338	240	240
q21	5911	2588	2677	2588
q22	401	366	298	298
Total cold run time: 101129 ms
Total hot run time: 29356 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6679	6700	6801	6700
q2	792	621	563	563
q3	5644	5733	5341	5341
q4	2080	2145	1581	1581
q5	5684	5642	5852	5642
q6	236	187	143	143
q7	2329	2058	1856	1856
q8	3142	2739	2792	2739
q9	8227	8173	8051	8051
q10	3686	3605	3248	3248
q11	606	407	381	381
q12	679	718	506	506
q13	2794	3093	2396	2396
q14	283	282	264	264
q15	q16	685	691	616	616
q17	7792	7035	6874	6874
q18	13121	12323	13136	12323
q19	905	816	785	785
q20	2186	2178	1952	1952
q21	5832	4754	4860	4754
q22	510	446	413	413
Total cold run time: 73892 ms
Total hot run time: 67128 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 155054 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 0afd483780456addc248d30ed4efb09266be8b24, data reload: false

query5	4344	620	501	501
query6	455	246	225	225
query7	4816	460	242	242
query8	342	208	186	186
query9	8853	4116	4098	4098
query10	503	335	273	273
query11	5994	3497	3243	3243
query12	152	95	91	91
query13	1288	481	370	370
query14	6593	4915	4573	4573
query14_1	4338	4325	4301	4301
query15	216	212	192	192
query16	985	507	478	478
query17	922	705	601	601
query18	2452	462	351	351
query19	223	186	156	156
query20	88	90	86	86
query21	221	142	121	121
query22	13066	13005	12938	12938
query23	13299	12690	12164	12164
query23_1	12255	12236	12390	12236
query24	7099	849	487	487
query24_1	491	496	501	496
query25	614	496	423	423
query26	1274	266	153	153
query27	2738	460	288	288
query28	4579	1991	1996	1991
query29	1602	646	510	510
query30	305	232	201	201
query31	919	785	678	678
query32	168	100	97	97
query33	542	335	316	316
query34	920	851	514	514
query35	766	775	661	661
query36	827	801	758	758
query37	132	107	101	101
query38	1807	1741	1712	1712
query39	730	747	674	674
query39_1	721	692	691	691
query40	226	121	107	107
query41	77	75	74	74
query42	91	85	88	85
query43	370	388	337	337
query44	1307	702	715	702
query45	184	183	170	170
query46	873	978	570	570
query47	3030	2999	2884	2884
query48	311	322	229	229
query49	593	423	324	324
query50	689	295	221	221
query51	10524	10460	10443	10443
query52	86	84	76	76
query53	191	208	160	160
query54	258	207	208	207
query55	78	75	66	66
query56	253	244	231	231
query57	1638	1608	1569	1569
query58	305	273	270	270
query59	2377	2415	2182	2182
query60	304	265	250	250
query61	189	179	189	179
query62	402	349	301	301
query63	199	167	172	167
query64	2961	1150	1015	1015
query65	3428	3403	3420	3403
query66	1845	448	338	338
query67	20477	20392	20097	20097
query68	3254	1013	625	625
query69	407	300	262	262
query70	946	808	835	808
query71	306	221	217	217
query72	3082	2859	2518	2518
query73	544	529	310	310
query74	4649	4523	4324	4324
query75	2382	2354	1966	1966
query76	2400	1026	614	614
query77	385	410	314	314
query78	8937	9050	8585	8585
query79	894	923	535	535
query80	556	468	380	380
query81	535	322	281	281
query82	806	146	118	118
query83	316	215	195	195
query84	327	131	113	113
query85	945	535	472	472
query86	320	243	234	234
query87	2033	1991	1853	1853
query88	3640	2752	2731	2731
query89	348	308	264	264
query90	1911	194	193	193
query91	189	174	150	150
query92	100	95	97	95
query93	1015	1002	576	576
query94	466	318	291	291
query95	619	366	418	366
query96	674	525	235	235
query97	2451	2460	2341	2341
query98	165	167	154	154
query99	795	784	667	667
Total cold run time: 237106 ms
Total hot run time: 155054 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.62 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 0afd483780456addc248d30ed4efb09266be8b24, data reload: false

query1	0.01	0.01	0.00
query2	0.09	0.05	0.05
query3	0.26	0.11	0.11
query4	1.61	0.11	0.11
query5	0.27	0.25	0.25
query6	1.16	0.68	0.68
query7	0.03	0.01	0.00
query8	0.06	0.04	0.04
query9	0.41	0.36	0.35
query10	0.58	0.60	0.55
query11	0.19	0.14	0.14
query12	0.19	0.15	0.14
query13	0.49	0.50	0.49
query14	0.99	0.98	0.96
query15	0.64	0.64	0.63
query16	0.34	0.35	0.36
query17	1.14	1.14	1.15
query18	0.24	0.21	0.21
query19	2.10	1.95	1.95
query20	0.02	0.01	0.01
query21	15.48	0.28	0.13
query22	4.42	0.06	0.05
query23	16.27	0.33	0.14
query24	2.56	0.66	0.49
query25	0.10	0.05	0.06
query26	1.78	0.24	0.15
query27	0.05	0.04	0.03
query28	2.47	0.63	0.39
query29	12.51	4.14	3.33
query30	0.29	0.14	0.13
query31	2.77	0.59	0.34
query32	3.23	0.61	0.52
query33	3.20	3.22	3.18
query34	15.43	4.05	3.40
query35	3.34	3.36	3.34
query36	0.55	0.48	0.43
query37	0.10	0.06	0.07
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.17	0.15	0.14
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.05	0.04	0.03
Total cold run time: 95.8 s
Total hot run time: 24.62 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 78.85% (41/52) 🎉
Increment coverage report
Complete coverage report

@Gabriel39

Copy link
Copy Markdown
Contributor

/review

@Gabriel39
Gabriel39 merged commit 1ff8aba into apache:master Oct 13, 2026
53 of 54 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Review recovery stopped: PR base/head or open state changed; refusing to resume stale context
Workflow run: https://github.com/apache/doris/actions/runs/38356395547

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

Gabriel39 pushed a commit that referenced this pull request Oct 15, 2026
### What problem does this PR solve?

Issue Number: N/A

Related PR: #68726

Problem Summary:

Stream Load reads the base schema version from table metadata outside
the planning lock. Concurrent schema change removes the old base-index
metadata before switching the base index ID under the table write lock.
An unlocked read in that interval can dereference missing metadata and
fail the load. A deterministic unit test reproduces the null dereference
on the pre-optimization baseline.

For regular Stream Load, populate the response database ID, table ID,
and base schema version inside the existing `generatePlan(OlapTable)`
read-lock scope. Populate them only for the first planned table when a
response is present, preserving multi-table behavior. Planning and
response metadata use the same lock scope without an additional lock
acquisition.

For HTTP `load_sql`, obtain the response table ID and base schema
version from the generated `OlapTableSink`. These values were already
captured during planning under the existing table lock. Keep the other
table-property reads as before. This removes the second metadata-lock
acquisition and the transaction-abort branch introduced solely for its
timeout. Existing transaction handling and Thrift fields are preserved.

This fix is separate from the scheduling and file TVF COUNT optimization
in #68726.

### Release note

Prevent Stream Load response schema-version reads from racing with
schema change by reusing the existing planning lock and planned sink
metadata.

### Check List (For Author)

- Test
    - [x] Regression test
    - [x] Unit Test
    - [ ] Manual test (add detailed scripts or steps below)
    - [ ] No need to test or manual test. Explain why:
- [ ] This is a refactor/code format and no logic has been changed.
        - [ ] Previous test can cover this change.
        - [ ] No code files have been changed.
        - [ ] Other reason

  Validation performed:
- Standard focused FE UT reactor passed `StreamLoadHandlerTest` (14) and
`HttpStreamLoadTablePropertiesTest` (2): 16 tests, zero failures/errors.
Maven Checkstyle passed.
- Unit coverage includes real concurrent base-index replacement with one
read-lock acquisition, metadata read-lock ownership and exceptional
release, the existing planning timeout, first-table response semantics,
and planning without a response. HTTP tests verify planned metadata is
used even when current base-index metadata is absent, for both regular
loads and Group Commit, without another read-lock acquisition.
- Standard ASAN FE/BE build, deployment, and health checks passed in the
personal shared-nothing single-BE environment. P0
`load_p0/http_stream/test_stream_load_schema_metadata` and
`load_p0/http_stream/test_http_stream_properties` passed with zero
failed suites/fatal scripts. Existing regression snapshots were compared
without regeneration or manual edits.
- P0 `schema_change_p0/test_schema_change_unique_mow` also passed: one
suite, zero failed suites/fatal scripts. All three targeted suites used
the binaries built from this revised implementation. Source changes pass
`git diff --check`.
- The concurrency unit test controls the race window; SQL regression
exercises compatibility and does not guarantee it hits that exact
window. This local shared-nothing single-BE environment is not complete
TeamCity or Cloud coverage.

- Behavior changed:
    - [ ] No.
- [x] Yes. Response metadata comes from the existing protected planning
scope or the completed HTTP plan, avoiding an unlocked base-index lookup
and additional lock waiting. Multi-table first-table behavior and
protocol fields are preserved.

- Does this need documentation?
    - [x] No.
    - [ ] Yes.

### Check List (For Reviewer who merge this PR)

- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label
Gabriel39 pushed a commit that referenced this pull request Oct 15, 2026
#68791)

### What problem does this PR solve?

Issue Number: N/A

Related PR: #68726

Problem Summary:

Repeated independently planned queries for a single remotely accessible
external file split can select the same backend under consistent
hashing. The candidate order is stable, each query starts with zero
assigned weight, and the existing minimum-weight tie rule repeatedly
selects the same candidate. Increasing the configured candidate count
alone does not remove this hotspot.

Add the session variable `external_scan_consistent_hash_spread_num` with
default **1**, preserving existing scheduling:

| Value | Behavior |
| --- | --- |
| `1` (default) | Preserve the original strategy, configured candidate
counts, tie rule and global redistribution. This is a mode, not a
one-backend limit. |
| `0` | Enable automatic spreading across all eligible BEs in the
query's compute group. Use the hash strategy when file cache or
consistent hashing is enabled; otherwise use the random strategy. |
| `N > 1` | Spread within at most N distinct hash candidates when file
cache or consistent hashing is enabled; otherwise retain original
round-robin scheduling. |

In spread mode, select the candidate with the least query-local assigned
split weight and break ties uniformly at random. Assign each split once,
retain weight history across batches, and honor compute-group
eligibility, local preference and mandatory Host constraints. Candidate
counts are capped by the eligible BE count; the implementation is not
specific to three BEs.

Disable global split redistribution only in spread mode so it cannot
move a split outside its candidate or locality constraints. Do not
allocate unused alternative-host lists in this mode. With many splits,
balancing is limited to each split's candidates and can be less even
than the original global redistribution.

This PR adds no live CPU monitoring, shared query counter, COUNT
pushdown, DOP adjustment or BE cache protocol. It is independent of
#68726 and does not include that PR's commits. The existing round-robin
path remains available; when #68726 is merged, its round-robin fix also
remains in effect for original-mode callers.

The variable does not enable file caching. With caching enabled,
automatic mode can warm copies on every eligible BE and increase remote
warmup reads and cache storage. Persisted global values survive
upgrades; restoring the compiled default to 1 does not reset an already
saved global 0. `UNSET VARIABLE` restores the compiled session default
1.

Manual performance evidence, collected on scheduling revision
`7e4fb1c549d` before this final default-value adjustment: the same
independent FE binary, three unchanged BEs on one shared physical host
with distinct logical Hosts and disjoint nonexclusive four-core
affinities; one million-row single-file CSV SUM; file cache and
consistent hashing enabled; all candidate caches warmed; concurrency 64;
10-second warmup and 60-second measurement window; three alternating
pairs changing only `spread=1` versus `spread=0`.

| Mode | Mean successful QPS |
| --- | ---: |
| Original (`1`) | 13.3944 |
| Automatic (`0`) | 39.2778 |

The pooled ratio was **2.9324x**, with paired ratios 2.8782x–2.9603x.
All six groups had zero query errors. QPS counts correct completions
within the fixed window; late completions are excluded, all workers are
joined, and latency includes the tail of queries started within the
window. The original hot BE used 97.5%–98.7% of its four-core capacity;
automatic mode used 87.2%–97.7% across the three BEs. Whole-invocation
remote and peer read increments were zero.

This evidence applies to the measured warm-cache shared-host workload.
It is not a new benchmark of final revision `813826a7feb`, a cold-start
result, a strict >=3x guarantee, a three-physical-host acceptance result
or customer validation. The final adjustment changes the default and
documentation, not the explicit spread-selection algorithm; spreading
must now be explicitly enabled to seek this benefit. No throughput from
the related COUNT optimization is attributed to this PR.

### Release note

Add opt-in spreading for remote external file scan splits.
`external_scan_consistent_hash_spread_num` defaults to 1 and preserves
original scheduling. Set it to 0 to spread across all eligible BEs, or a
value above 1 to bound hash candidates when file cache or consistent
hashing is enabled. Spreading can increase cache copies and warmup
costs. Persisted global values are retained on upgrade.

### Check List (For Author)

- Test
    - [x] Regression test
    - [x] Unit Test
    - [x] Manual test (add detailed scripts or steps below)
    - [ ] No need to test or manual test. Explain why:
- [ ] This is a refactor/code format and no logic has been changed.
        - [ ] Previous test can cover this change.
        - [ ] No code files have been changed.
        - [ ] Other reason

  Validation performed on the final revision:
- Standard `run-fe-ut.sh --run
'FederationBackendPolicySpreadTest,VariableMgrTest#testExternalScanConsistentHashSpreadVariable,FederationBackendPolicyTest'`:
33 tests passed, zero failed/error/skipped. Coverage includes 1/2/3/5
BEs, random ties, multiple batches, locality, bounds, forwarding,
original-mode compatibility, default 1 and explicit 0 strategy
selection.
- Standard `build.sh --fe --clean -j16` and integrated Checkstyle
passed. An earlier production build failed with incomplete class/type
errors; its evidence was retained and the clean build succeeded without
unrelated source edits.
- Standard `run-regression-test.sh` with an isolated personal
configuration:
- `-g p0 -d query_p0/ddl/set_and_unset_commands -s
test_external_scan_consistent_hash_spread_variable`; output generated by
the framework using `-forceGenOut`, then verified normally.
- `-g external -d external_table_p0/tvf -s
test_external_scan_consistent_hash_spread`; explicitly enables 0 for
automatic-path coverage.
- Both suites passed with zero failed/fatal/skipped suites. The fixture
is generated by the suite in personal MinIO.
- Isolated FE/BE health checks passed; BE process IDs and binary hashes
were unchanged. No environment configuration or work log is included.
- Separate manual warm-cache experiment on revision `7e4fb1c549d`,
described above. Each mode was also certified by 100 query-owned
profiles: correct result, one source split/range, one positive execution
target, one million rows read, local-cache reads and no remote reads.
Original mode selected one BE; automatic mode selected all three.
- Standards and specification reviews of the implementation and final
default adjustment found no remaining actionable issues.
- Targeted local validation does not claim full TeamCity success on the
updated head. No BE source changed, so no new BE build or BE UT run was
required for this adjustment.

- Behavior changed:
    - [ ] No.
- [x] Yes, when explicitly enabled. Default 1 preserves the existing
strategy. Values 0 and N>1 enable random minimum-weight ties and disable
global redistribution in their applicable paths; caching can require
more copies.

- Does this need documentation?
    - [ ] No.
    - [x] Yes. apache/doris-website#4199

### Check List (For Reviewer who merge this PR)

- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label
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.

6 participants