Skip to content

[improvement](fe) Add opt-in spreading for remote external scan splits - #68791

Open
OIiveirra wants to merge 15 commits into
apache:masterfrom
OIiveirra:fix/jira-doris-29500-split-scheduling
Open

OIiveirra wants to merge 15 commits into
apache:masterfrom
OIiveirra:fix/jira-doris-29500-split-scheduling

Conversation

@OIiveirra

@OIiveirra OIiveirra commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

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

    • 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 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.
    • 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?

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: apache#68726

Problem Summary: Repeated independent queries for the same remote external
file split can choose the same backend under consistent hashing. Each policy
starts with zero assigned weight and the original tie rule selects the same
candidate, so increasing the existing candidate count does not remove the
hotspot.

Add an opt-in external_scan_consistent_hash_spread_num session variable.
The default value of 1 preserves the existing scheduler. Values greater than
1 select stable, distinct hash candidates and choose the candidate with the
least policy-assigned weight, breaking ties uniformly at random. Candidate
counts are capped by eligible backends. Local preference and mandatory Host
constraints remain in effect; global redistribution is disabled only in the
new mode to preserve candidate and locality bounds. Each split executes once.

In a local experiment using three backends on one shared physical host,
a one-million-row, single-file workload at concurrency 32 improved pooled
successful QPS by 2.4234x for COUNT and 2.4143x for SUM across three paired
60-second rounds with file caching disabled. All 12 measurements had zero
errors. This does not establish a threefold guarantee or customer result.
The round-robin and COUNT changes in the related PR remain separate.

### Release note

Add an optional external_scan_consistent_hash_spread_num session setting to
spread repeated external scan queries across consistent hash candidates.
The default preserves existing scheduling. With file caching enabled,
spreading can increase warmup reads and cache space on additional backends.

### Check List (For Author)

- Test: Regression test / Unit Test / Manual test
    - Standard FE build and Checkstyle passed.
    - FederationBackendPolicySpreadTest: 19 tests passed.
    - FederationBackendPolicyTest: 9 existing tests passed.
    - VariableMgrTest#testExternalScanConsistentHashSpreadVariable passed.
    - Parameter and S3 TVF regression suites generated and verified through
      the standard regression entry point against the isolated personal cluster.
    - COUNT and SUM: 100 independent queries each, correct results, one split
      and one execution target per query, distributed across three backends.
    - Three paired cache-off capacity rounds for COUNT and SUM passed.
    - Cold file-cache cost sampling: 30 queries per mode passed; spreading
      warmed three backend copies and incurred three times the remote reads.
- Behavior changed: Yes, only when the new setting is greater than 1 and
  the scan uses consistent hashing; default scheduling is unchanged.
- Does this need documentation: Yes, included in
  docs/external-scan-consistent-hash-spread.md.
Copilot AI balanced review requested due to automatic review settings October 8, 2026 13:18
@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.

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

### 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 OIiveirra changed the title [improvement](fe) Spread hot external splits across hash candidates [improvement](fe) Automatically balance remote external scan splits 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.
@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17586	5600	5517	5517
q2	2111	303	255	255
q3	10269	1385	834	834
q4	4684	472	350	350
q5	7424	785	536	536
q6	181	184	157	157
q7	742	793	613	613
q8	9234	1346	1152	1152
q9	5724	4465	4421	4421
q10	6816	1292	1026	1026
q11	434	253	233	233
q12	623	402	285	285
q13	18097	3069	2386	2386
q14	280	276	255	255
q15	q16	723	721	670	670
q17	1155	739	583	583
q18	7021	6196	6140	6140
q19	1100	949	600	600
q20	384	338	226	226
q21	5844	2498	2563	2498
q22	390	341	303	303
Total cold run time: 100822 ms
Total hot run time: 29040 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6504	6459	6434	6434
q2	739	598	572	572
q3	5451	5709	5215	5215
q4	2052	2158	1565	1565
q5	5812	5636	5773	5636
q6	241	193	149	149
q7	2270	2002	1823	1823
q8	3142	2773	2806	2773
q9	8248	8122	7719	7719
q10	3667	3588	3211	3211
q11	611	421	377	377
q12	662	689	491	491
q13	2733	3072	2357	2357
q14	285	281	264	264
q15	q16	689	676	608	608
q17	7821	6970	6833	6833
q18	13104	12274	12934	12274
q19	926	779	775	775
q20	2189	2150	1915	1915
q21	5811	4644	4757	4644
q22	490	472	394	394
Total cold run time: 73447 ms
Total hot run time: 66029 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 151725 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 7e4fb1c549d514a81fc8e5a6e53ab30bed2dd16c, data reload: false

query5	4306	604	479	479
query6	421	213	190	190
query7	4816	467	224	224
query8	313	185	175	175
query9	8735	4032	4014	4014
query10	458	308	242	242
query11	5968	3437	3181	3181
query12	141	87	82	82
query13	1247	442	305	305
query14	6552	4860	4516	4516
query14_1	4283	4261	4259	4259
query15	209	205	181	181
query16	946	440	442	440
query17	857	709	525	525
query18	2408	423	293	293
query19	185	154	126	126
query20	81	77	75	75
query21	206	137	111	111
query22	12914	12966	12783	12783
query23	13148	12443	11976	11976
query23_1	12280	12096	12229	12096
query24	7079	845	452	452
query24_1	459	460	464	460
query25	523	412	337	337
query26	1308	266	141	141
query27	2746	458	261	261
query28	4608	1911	1935	1911
query29	1560	608	435	435
query30	304	226	186	186
query31	902	770	638	638
query32	142	92	90	90
query33	509	301	237	237
query34	915	924	491	491
query35	770	757	632	632
query36	844	824	743	743
query37	131	131	85	85
query38	1797	1719	1689	1689
query39	683	697	688	688
query39_1	668	646	649	646
query40	209	115	96	96
query41	65	66	66	66
query42	88	86	83	83
query43	361	378	333	333
query44	1353	704	695	695
query45	185	174	163	163
query46	945	1014	554	554
query47	2918	3046	2878	2878
query48	292	311	228	228
query49	599	409	292	292
query50	716	283	209	209
query51	10458	10416	10535	10416
query52	78	82	70	70
query53	194	220	155	155
query54	229	204	189	189
query55	80	69	70	69
query56	224	232	193	193
query57	1609	1591	1556	1556
query58	283	259	244	244
query59	2359	2406	2114	2114
query60	301	235	227	227
query61	134	148	142	142
query62	399	347	280	280
query63	204	162	168	162
query64	2718	963	857	857
query65	3420	3367	3376	3367
query66	1765	437	310	310
query67	20230	20184	20282	20184
query68	3000	1011	610	610
query69	386	298	247	247
query70	932	812	828	812
query71	303	240	206	206
query72	2651	2362	2266	2266
query73	525	563	299	299
query74	4579	4446	4288	4288
query75	2454	2318	1994	1994
query76	2306	1123	635	635
query77	369	422	305	305
query78	8880	8871	8450	8450
query79	952	886	521	521
query80	487	431	335	335
query81	510	323	271	271
query82	213	139	112	112
query83	199	196	183	183
query84	291	122	104	104
query85	758	419	365	365
query86	253	240	224	224
query87	2006	1960	1810	1810
query88	3640	2683	2669	2669
query89	342	296	260	260
query90	2127	186	178	178
query91	155	155	121	121
query92	86	88	87	87
query93	1006	1010	562	562
query94	444	303	263	263
query95	591	410	335	335
query96	689	557	233	233
query97	2484	2416	2333	2333
query98	154	152	144	144
query99	767	755	652	652
Total cold run time: 233122 ms
Total hot run time: 151725 ms

@hello-stephen

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

query1	0.01	0.01	0.01
query2	0.10	0.05	0.04
query3	0.26	0.11	0.11
query4	1.60	0.12	0.11
query5	0.24	0.24	0.24
query6	1.18	0.69	0.68
query7	0.03	0.01	0.01
query8	0.05	0.04	0.03
query9	0.42	0.34	0.36
query10	0.57	0.58	0.58
query11	0.21	0.15	0.14
query12	0.18	0.15	0.15
query13	0.48	0.48	0.49
query14	0.99	0.97	0.95
query15	0.65	0.60	0.60
query16	0.35	0.36	0.34
query17	1.10	1.15	1.14
query18	0.24	0.22	0.22
query19	2.04	1.98	1.95
query20	0.02	0.01	0.01
query21	15.49	0.24	0.14
query22	4.54	0.06	0.05
query23	16.27	0.31	0.12
query24	3.05	0.66	0.44
query25	0.13	0.08	0.06
query26	1.47	0.26	0.15
query27	0.06	0.03	0.04
query28	1.90	0.64	0.41
query29	12.54	4.16	3.30
query30	0.28	0.15	0.13
query31	2.77	0.58	0.34
query32	3.22	0.61	0.53
query33	3.31	3.18	3.15
query34	15.62	3.98	3.35
query35	3.32	3.30	3.32
query36	0.54	0.42	0.43
query37	0.09	0.06	0.06
query38	0.04	0.04	0.03
query39	0.04	0.03	0.03
query40	0.17	0.14	0.14
query41	0.09	0.03	0.02
query42	0.04	0.03	0.02
query43	0.04	0.03	0.03
Total cold run time: 95.74 s
Total hot run time: 24.38 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 98.00% (49/50) 🎉
Increment coverage report
Complete coverage report

### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#68726

Problem Summary: Keep the external scan spreading option at 1 by default so existing scheduling, candidate counts and redistribution are preserved. Explain that 1 is a mode rather than a single-backend limit. Automatic spreading remains available with an explicit 0. Update default-value and strategy tests, explicitly enable automatic mode in the external regression, and remove user documentation from the source repository in favor of the separate website documentation change.

### Release note

Preserve original external scan scheduling by default. Enable automatic spreading explicitly with external_scan_consistent_hash_spread_num = 0, or bound hash candidates with a value greater than 1.

### Check List (For Author)

- Test: 33 focused FE unit tests; standard clean FE build and Checkstyle; isolated parameter and external scan regressions. Variable output generated by the regression framework.
- Behavior changed: Yes; restore the default from 0 to 1 compared with the previous PR revision. Explicit spreading algorithms are unchanged.
- Does this need documentation: Yes; English and Chinese website documentation prepared separately, not published yet.
@OIiveirra OIiveirra changed the title [improvement](fe) Automatically balance remote external scan splits [improvement](fe) Add opt-in spreading for remote external scan splits Oct 9, 2026
@OIiveirra

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17602	5686	5580	5580
q2	2142	356	288	288
q3	10185	1415	848	848
q4	4685	485	356	356
q5	7464	814	557	557
q6	191	188	156	156
q7	788	821	619	619
q8	9311	1372	1141	1141
q9	5687	4448	4453	4448
q10	6847	1312	1031	1031
q11	437	258	243	243
q12	635	406	290	290
q13	18046	3048	2387	2387
q14	274	271	250	250
q15	q16	739	743	691	691
q17	1179	752	590	590
q18	7082	6279	6169	6169
q19	1250	957	607	607
q20	412	338	228	228
q21	5823	2554	2576	2554
q22	411	383	306	306
Total cold run time: 101190 ms
Total hot run time: 29339 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6773	6678	6805	6678
q2	749	612	618	612
q3	5664	5620	5308	5308
q4	2032	2145	1550	1550
q5	5773	5601	5822	5601
q6	247	189	148	148
q7	2216	2080	1815	1815
q8	3129	2749	2756	2749
q9	8131	8203	8095	8095
q10	3660	3586	3293	3293
q11	595	399	368	368
q12	663	694	494	494
q13	2753	3079	2388	2388
q14	276	285	266	266
q15	q16	673	678	617	617
q17	7812	6970	6860	6860
q18	13136	12246	13134	12246
q19	923	795	792	792
q20	2193	2163	1936	1936
q21	5781	4698	4738	4698
q22	478	439	418	418
Total cold run time: 73657 ms
Total hot run time: 66932 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 151628 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 813826a7febf0ea08fd99104017247da106e9673, data reload: false

query5	4303	610	453	453
query6	419	209	199	199
query7	4811	445	219	219
query8	316	182	163	163
query9	8778	3935	3958	3935
query10	446	304	255	255
query11	5973	3435	3210	3210
query12	142	88	88	88
query13	1249	433	314	314
query14	6547	4779	4480	4480
query14_1	4228	4225	4224	4224
query15	205	202	181	181
query16	936	438	460	438
query17	848	644	526	526
query18	2428	420	319	319
query19	190	161	136	136
query20	80	79	81	79
query21	220	131	111	111
query22	13004	12994	12801	12801
query23	13103	12555	12189	12189
query23_1	12106	12230	12198	12198
query24	7097	825	456	456
query24_1	468	467	458	458
query25	536	421	362	362
query26	1268	258	140	140
query27	2765	435	269	269
query28	4621	1950	1928	1928
query29	1548	613	449	449
query30	302	215	180	180
query31	889	765	646	646
query32	141	94	96	94
query33	509	300	246	246
query34	902	847	507	507
query35	761	769	647	647
query36	804	799	715	715
query37	126	106	93	93
query38	1791	1756	1667	1667
query39	700	743	699	699
query39_1	657	675	659	659
query40	221	119	99	99
query41	73	71	68	68
query42	89	88	85	85
query43	369	388	325	325
query44	1322	700	702	700
query45	184	173	164	164
query46	884	982	571	571
query47	2955	2941	2963	2941
query48	289	304	214	214
query49	568	392	273	273
query50	690	264	212	212
query51	10538	10706	10378	10378
query52	79	77	70	70
query53	189	209	151	151
query54	231	184	169	169
query55	71	69	64	64
query56	217	210	217	210
query57	1618	1560	1560	1560
query58	264	254	241	241
query59	2336	2382	2145	2145
query60	271	229	217	217
query61	142	138	136	136
query62	405	350	284	284
query63	190	156	161	156
query64	2771	913	751	751
query65	3434	3353	3367	3353
query66	1771	407	302	302
query67	20047	20110	19901	19901
query68	3261	970	603	603
query69	384	288	236	236
query70	961	808	825	808
query71	309	232	207	207
query72	2758	2558	2297	2297
query73	524	528	290	290
query74	4623	4445	4292	4292
query75	2336	2288	1952	1952
query76	2372	1023	603	603
query77	366	387	304	304
query78	9023	9004	8446	8446
query79	933	915	503	503
query80	761	416	334	334
query81	558	326	274	274
query82	576	142	108	108
query83	282	197	177	177
query84	316	115	101	101
query85	987	416	358	358
query86	346	245	231	231
query87	2027	1958	1791	1791
query88	3637	2702	2669	2669
query89	343	290	253	253
query90	1716	183	180	180
query91	156	140	119	119
query92	100	88	87	87
query93	1016	1013	566	566
query94	508	319	292	292
query95	562	343	315	315
query96	657	509	231	231
query97	2452	2438	2343	2343
query98	152	146	141	141
query99	793	761	656	656
Total cold run time: 233987 ms
Total hot run time: 151628 ms

@hello-stephen

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

query1	0.01	0.01	0.01
query2	0.09	0.05	0.05
query3	0.26	0.11	0.11
query4	1.61	0.12	0.13
query5	0.28	0.25	0.25
query6	1.16	0.67	0.68
query7	0.04	0.01	0.01
query8	0.05	0.03	0.04
query9	0.42	0.35	0.36
query10	0.58	0.57	0.60
query11	0.20	0.14	0.13
query12	0.18	0.14	0.14
query13	0.47	0.48	0.50
query14	0.98	0.96	0.96
query15	0.63	0.61	0.61
query16	0.31	0.36	0.36
query17	1.11	1.17	1.14
query18	0.22	0.22	0.21
query19	2.08	2.00	1.96
query20	0.02	0.01	0.01
query21	15.49	0.29	0.15
query22	4.46	0.05	0.06
query23	16.25	0.32	0.12
query24	2.94	0.89	0.43
query25	0.13	0.04	0.05
query26	1.66	0.25	0.16
query27	0.04	0.04	0.03
query28	1.90	0.60	0.40
query29	12.55	4.11	3.23
query30	0.30	0.15	0.13
query31	2.78	0.59	0.33
query32	3.22	0.61	0.52
query33	3.29	3.22	3.15
query34	15.46	4.02	3.40
query35	3.35	3.33	3.31
query36	0.55	0.43	0.42
query37	0.10	0.07	0.06
query38	0.04	0.04	0.03
query39	0.04	0.04	0.03
query40	0.17	0.15	0.15
query41	0.09	0.03	0.03
query42	0.04	0.03	0.03
query43	0.05	0.03	0.03
Total cold run time: 95.6 s
Total hot run time: 24.4 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 39.00% (39/100) 🎉
Increment coverage report
Complete coverage report

924060929
924060929 previously approved these changes Oct 9, 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 head 813826a7febf0ea08fd99104017247da106e9673 after three review rounds and a final sweep of all nine changed files. Five distinct P2 issues are inline. There are no existing inline P0/P1 findings to carry forward. No additional user focus was specified. This was static inspection only: I did not build or run the tests; the author's stated test results were not independently validated here.

Critical checkpoints:

  • Goal and tests: The default value 1 preserves the prior policy. Explicit spread can distribute remote, hostless splits with randomized minimum-weight ties, as the new policy unit tests exercise. The intended behavior fails for host-hinted remote work (inline M2), pathless bounded-hash work (M5), and a forwarded hash-enabled session (M4). The S3 regression fixture can fail before its scan checks (M3).
  • Scope and reuse: The implementation is confined to the FE policy, scan-node policy choice, a session variable, and tests. It reuses the existing hash ring and eligible-backend filtering. No unrelated source edits appear in the nine-file diff.
  • Concurrency and locks: Eager assignment occurs during planning; lazy batches call the policy under SplitAssignment.assignLock, so the query-local weight map is serialized. No new thread or lock order is introduced. Full-ring enumeration under that lock adds avoidable work (M1).
  • Lifecycle and configuration: The policy captures the session setting when a scan node is constructed; later queries construct new policies. The pre-existing cached hash ring owns no new lifetime here. The nonnegative integer checker and session reset are consistent with the variable framework. The count is forwarded, but its enabling hash selector is omitted (M4).
  • Compatibility and parallel paths: No FE–BE Thrift shape or storage format changes. Default scheduling and mixed-mode fallback retain the old policy locally. Eager and lazy file scans share the changed assignment path; metadata and data-generator scans use other placement paths. No cross-language static initialization is added.
  • Conditions and correctness: The 0, 1 and positive bounded modes, backend eligibility, required nonremote hosts, and alternative-host use were traced. Each split remains assigned once; no transaction visibility or version invariant is changed. The soft-locality pass can defeat spreading (M2), and placeholder hash identity can confine distinct ranges (M5). The forwarded setting mismatch is a silent behavior change (M4).
  • Coverage and results: The new Java policy and variable tests and both regression suites and output files were inspected. Their recorded rows and variable outputs match the test SQL, but they do not cover the forwarded flag pair or host-hinted/pathless multi-backend cases. The OUTFILE path-style key is wrong on both exports (M3). No tests were executed in this review.
  • Observability, writes and performance: Existing assigned-weight profile data remains available; no additional metric requirement was established. This changes scheduling, not transactions, data writes or EditLog behavior. The material performance risks are repeated full-ring work (M1) and unused eligible BEs (M2/M5). No other substantiated issue remained after deduplication and the final sweep.

Comment thread fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
### What problem does this PR solve?

Problem Summary: External scan scheduling can hash pathless connector ranges to the same key, and repeated locality hints can keep remote splits on one backend. Add connector-provided split identities and balance spread candidates by assigned weight while preserving the default scheduling behavior.

### Release note

None

### Check List (For Author)

- Test: Connector SPI surface and metadata tests; focused FE UT attempted but blocked by the read-only Maven repository.

- Behavior changed: Yes (opt-in external scan spread scheduling).

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

Problem Summary: Full-ring construction is unnecessary when spread mode already allows every eligible backend, and the external scan regression fixture used an unrecognized path-style property. Use the filtered backend list directly and align both OUTFILE exports with the recognized property.

### Release note

None

### Check List (For Author)

- Test: git diff --check; regression fixture review.

- Behavior changed: No.

- Does this need documentation: No
@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17607	5650	5533	5533
q2	2109	320	258	258
q3	10242	1399	853	853
q4	4681	474	354	354
q5	7435	795	536	536
q6	186	188	153	153
q7	762	795	606	606
q8	9241	1289	1128	1128
q9	5658	4423	4419	4419
q10	6809	1293	1024	1024
q11	433	252	242	242
q12	637	396	295	295
q13	18048	3087	2378	2378
q14	273	274	245	245
q15	q16	729	724	674	674
q17	1191	737	568	568
q18	7164	6222	6157	6157
q19	1115	950	598	598
q20	393	337	223	223
q21	5215	2566	2661	2566
q22	406	344	292	292
Total cold run time: 100334 ms
Total hot run time: 29102 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6698	6652	6791	6652
q2	740	614	576	576
q3	5603	5739	5251	5251
q4	2079	2193	1579	1579
q5	5747	5577	5725	5577
q6	253	193	144	144
q7	2249	2038	1806	1806
q8	3251	2667	2754	2667
q9	8106	8187	8098	8098
q10	3649	3590	3236	3236
q11	604	401	374	374
q12	655	688	502	502
q13	2743	3086	2393	2393
q14	284	282	257	257
q15	q16	669	684	620	620
q17	7757	6923	6801	6801
q18	13087	12243	13077	12243
q19	912	810	789	789
q20	2154	2161	1935	1935
q21	5742	4686	4772	4686
q22	530	467	389	389
Total cold run time: 73512 ms
Total hot run time: 66575 ms

@OIiveirra

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17580	5528	5512	5512
q2	2064	317	264	264
q3	10237	1375	817	817
q4	4690	478	357	357
q5	7433	787	533	533
q6	188	194	159	159
q7	776	795	606	606
q8	9245	1324	1046	1046
q9	5770	4422	4431	4422
q10	6829	1291	1031	1031
q11	441	254	238	238
q12	638	402	286	286
q13	18042	3042	2376	2376
q14	278	267	250	250
q15	q16	732	723	674	674
q17	1173	749	576	576
q18	6954	6215	6170	6170
q19	1097	949	589	589
q20	379	334	224	224
q21	5240	2295	2369	2295
q22	353	318	271	271
Total cold run time: 100139 ms
Total hot run time: 28696 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6172	6136	6140	6136
q2	679	573	566	566
q3	5207	5379	5001	5001
q4	2020	2160	1527	1527
q5	5280	5179	5914	5179
q6	250	197	158	158
q7	2254	2036	1870	1870
q8	3107	2713	2789	2713
q9	8364	8185	8207	8185
q10	3863	3786	3402	3402
q11	675	441	394	394
q12	709	755	538	538
q13	2916	3267	2518	2518
q14	312	309	308	308
q15	q16	701	731	691	691
q17	8402	7453	7334	7334
q18	13238	12299	13118	12299
q19	937	772	774	772
q20	2178	2169	1949	1949
q21	5731	4677	4831	4677
q22	517	445	440	440
Total cold run time: 73512 ms
Total hot run time: 66657 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 151645 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 22d6ebafe16dfdfaa76e25357a106028deab5037, data reload: false

query5	4310	577	489	489
query6	418	204	193	193
query7	4801	438	228	228
query8	322	182	163	163
query9	8748	4036	4032	4032
query10	462	310	258	258
query11	5958	3410	3193	3193
query12	146	89	83	83
query13	1244	429	317	317
query14	6607	4796	4480	4480
query14_1	4253	4270	4256	4256
query15	211	199	188	188
query16	944	458	415	415
query17	850	660	561	561
query18	2426	433	314	314
query19	194	163	134	134
query20	84	88	81	81
query21	214	140	110	110
query22	13063	13030	12781	12781
query23	13255	12536	12094	12094
query23_1	12240	12062	12293	12062
query24	7086	828	473	473
query24_1	467	475	479	475
query25	538	423	369	369
query26	1252	258	138	138
query27	2775	435	270	270
query28	4592	1946	1973	1946
query29	1551	599	487	487
query30	313	206	185	185
query31	874	765	649	649
query32	133	88	94	88
query33	499	298	223	223
query34	865	851	500	500
query35	747	785	641	641
query36	817	790	722	722
query37	131	99	84	84
query38	1774	1759	1677	1677
query39	718	706	684	684
query39_1	685	678	700	678
query40	214	111	95	95
query41	66	69	64	64
query42	85	86	87	86
query43	374	370	328	328
query44	1286	696	701	696
query45	177	180	166	166
query46	831	965	558	558
query47	2944	2971	2905	2905
query48	298	297	222	222
query49	577	380	288	288
query50	659	280	221	221
query51	10666	10451	10380	10380
query52	85	85	71	71
query53	189	201	155	155
query54	233	187	179	179
query55	72	78	62	62
query56	221	218	202	202
query57	1629	1613	1569	1569
query58	282	261	245	245
query59	2373	2351	2134	2134
query60	316	243	222	222
query61	147	145	140	140
query62	388	340	292	292
query63	195	169	170	169
query64	2752	940	766	766
query65	3417	3346	3368	3346
query66	1786	412	299	299
query67	20125	20288	19967	19967
query68	3048	1001	634	634
query69	374	287	245	245
query70	917	836	810	810
query71	285	220	210	210
query72	2621	2571	2241	2241
query73	511	519	292	292
query74	4589	4487	4319	4319
query75	2321	2319	1938	1938
query76	2300	1014	639	639
query77	360	393	308	308
query78	8989	9004	8432	8432
query79	1042	844	520	520
query80	571	435	331	331
query81	524	325	290	290
query82	576	134	108	108
query83	298	195	175	175
query84	306	121	103	103
query85	801	413	372	372
query86	317	239	225	225
query87	2001	1956	1805	1805
query88	3582	2705	2696	2696
query89	338	297	256	256
query90	1919	184	179	179
query91	153	150	121	121
query92	97	87	86	86
query93	989	976	573	573
query94	454	320	272	272
query95	596	405	310	310
query96	662	506	233	233
query97	2447	2446	2299	2299
query98	155	148	146	146
query99	786	758	635	635
Total cold run time: 233647 ms
Total hot run time: 151645 ms

@hello-stephen

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

query1	0.00	0.00	0.00
query2	0.09	0.05	0.05
query3	0.26	0.11	0.12
query4	1.61	0.13	0.13
query5	0.25	0.24	0.25
query6	1.17	0.69	0.69
query7	0.03	0.01	0.00
query8	0.06	0.03	0.03
query9	0.42	0.35	0.36
query10	0.57	0.56	0.58
query11	0.20	0.15	0.14
query12	0.19	0.14	0.14
query13	0.49	0.49	0.50
query14	0.99	0.96	0.96
query15	0.63	0.62	0.62
query16	0.31	0.33	0.33
query17	1.16	1.15	1.18
query18	0.23	0.26	0.21
query19	2.09	2.05	1.98
query20	0.01	0.02	0.01
query21	15.48	0.27	0.15
query22	4.53	0.06	0.06
query23	16.27	0.32	0.12
query24	3.18	0.51	0.45
query25	0.12	0.04	0.05
query26	1.15	0.24	0.15
query27	0.05	0.04	0.04
query28	2.02	0.59	0.43
query29	12.55	4.21	3.34
query30	0.28	0.15	0.14
query31	2.77	0.58	0.35
query32	3.26	0.62	0.53
query33	3.08	3.22	3.16
query34	15.51	4.02	3.39
query35	3.30	3.35	3.38
query36	0.55	0.46	0.42
query37	0.09	0.06	0.06
query38	0.05	0.04	0.03
query39	0.04	0.03	0.03
query40	0.17	0.15	0.15
query41	0.08	0.03	0.02
query42	0.04	0.03	0.02
query43	0.04	0.04	0.03
Total cold run time: 95.37 s
Total hot run time: 24.65 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 69.07% (67/97) 🎉
Increment coverage report
Complete coverage report

@OIiveirra

Copy link
Copy Markdown
Contributor Author

rerun p0

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 69.07% (67/97) 🎉
Increment coverage report
Complete coverage report

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

Complete static review of all 27 changed files at 22d6ebafe16dfdfaa76e25357a106028deab5037, after two rounds. Each round included the main risk scan/validation, normal full-scope aspect reviews, and a separate focused risk scan. All three fresh round-2 reviewers returned NO_NEW_VALUABLE_FINDINGS against the unchanged final comment set; the final changed-file and unresolved-candidate sweep is complete.

Three new P2 findings are inline: M1, MaxCompute read sessions share session-relative scheduling coordinates; M2, Iceberg JNI metadata tasks share a dummy-path identity; M3, singleton streamed batches redundantly rebuild the maintained weight histogram. These concern scan parallelism and FE planning overhead; no wrong-result or crash consequence was substantiated. They are distinct connector instances/triggers from the existing threads.

The earlier P1 connector API-major issue and legacy ring-order issue are fixed at this head, so no existing P0/P1 blocking IDs apply. The earlier forwarding, Fluss lake-tail identity, S3 fixture key, all-candidate ring walk, and overloaded-host-hint concerns are addressed in the code. The original per-hinted-split minimum scan was replaced; M3 covers a distinct rebuild cost introduced by that repair. The existing Remote Doris same-URI/different-ticket P2 still applies and is not reposted.

The reviewed execution chain is:

session settings / forwarded map -> ExternalScanNode(policy snapshot)
 -> eligible compute-group BEs -> eager planner or lazy SplitAssignment(assignLock)
 -> locality / candidate selection -> minimum weight / ties -> scan ranges -> BE
ConnectorScanRange -> PluginDrivenSplit(captured identity,start,length) -> SplitHash

Applicable critical-checkpoint conclusions:

  • Goal and evidence: Opt-in 0/all or N/bounded spreading selects minimum assigned weight with uniform random ties while default1 preserves legacy scheduling. Scheduler unit and S3 regression cases support the intended modes statically; MaxCompute and Iceberg metadata work identities remain incomplete (M1/M2), and the existing Remote Doris gap remains. No test execution is claimed.
  • Scope and abstraction: Generic scheduler/session changes and connector-owned identity hooks keep planning connector-agnostic. Two optimizer-test pattern edits retain their aggregate assertions and affect no production rewrite.
  • Concurrency and lock cost: Eager scheduling is planning-thread-owned. Async partition and streaming producers serialize mutable weights/counts through SplitAssignment.assignLock; range conversion and queue IO run outside it. No new lock order/deadlock found. M3 flags redundant histogram reconstruction inside this lock.
  • Lifecycle, initialization and memory: Each scan owns its policy, cumulative weights and captured immutable identities; cached rings are read-only and keyed by eligible backend membership. No new resource, cleanup cycle, thread or C++ static initializer. Java temporary histogram allocations are the M3 concern; BE memory ownership is unchanged.
  • Dynamic configuration: Added session/global setting defaults to1, accepts0 through Integer.MAX_VALUE, rejects negative/overflow/nonnumeric statement values before mutation, and is read when each scan policy is constructed. SET/UNSET and global/new-session behavior use existing machinery without restart.
  • Compatibility and rolling upgrades: Connector API major14 is propagated to kernel resource, plugin jar manifest and pinned surface test; incompatible plugin majors are rejected. Default1 now retains the original ring order. Renamed engine hook has no stale callers. No new wire/storage layout; older masters cannot implement this new option, while unknown forwarded keys are ignored.
  • Thrift/protobuf definitions: No gensrc/thrift or gensrc/proto change; cross-branch field-ID comparison is not applicable.
  • Parallel execution paths: Eager, singleton streaming, partition-batch, hash/random/round-robin, native/JNI/system-table and cloud/shared-nothing compute-group paths reviewed. M1/M2 cover missing identities in two previously unhandled arms; Remote Doris is already covered by an existing thread.
  • Conditions and error behavior: Mode gates match0/1/N semantics; unavailable required hosts/backends fail; candidate count is capped. Explicit local-preference exception may select outside hash candidates and remain deterministic for a first hinted split; overloaded later hints enter spread. No new silent-error continuation found.
  • Test coverage: Unit cases cover weights across batches, random ties, membership/availability, candidate caps, multiple BE counts, forwarding, defaults and invalid values; connector tests cover distinct work and stable wrapped files. Regression cases cover SQL results and settings. Missing MaxCompute-session and Iceberg-metadata identity cases are part of M1/M2.
  • Changed expected results: Both complete goldens match inspected ordered SQL, five remote-mode repetitions, duplicate rows from two files, SHOW variable values and unchanged values after invalid SET. Generation provenance and runtime success remain unverified; no files were regenerated or tests run.
  • Observability: Existing assignment-weight SummaryProfile, planning timestamps, backend/range EXPLAIN details and debug logs provide scheduling evidence. No new external IO/distributed protocol requiring additional operational counters is introduced.
  • Transactions and persistence: Global session defaults use existing VariableMgr EditLog/checkpoint/replay machinery. No transaction lifecycle, committed-data visibility, visible-version or delete-bitmap code changed.
  • Data writes and atomicity: Production write/commit paths are unchanged; regression fixture inserts/OUTFILE follow existing patterns. No new write atomicity or crash-cleanup mechanism is introduced.
  • FE-to-BE variables: The new option is consumed by FE planning and forwarded between FEs together with the selector/cache flag; BE receives existing assigned scan ranges. No new BE-bound field or scattered transmission path needs updating.
  • Performance: Full-candidate spread avoids hash-ring traversal and unused alternative-host lists; minimum ties use one-pass reservoir sampling. M3 identifies avoidable all-backend histogram work on each streamed range; M1/M2 identify avoidable candidate collapse. No local throughput measurement or validation of author benchmark claims was performed.
  • Other issues and user focus: No additional user focus was supplied. All initial risks and candidate duplicates have concrete dispositions; no extra wrong-result, availability or lifecycle issue was substantiated after full-scope rechecks.

Review was static only. No builds, tests, source changes, golden regeneration or benchmark runs were performed. Author-reported validation is not treated as executed evidence from this review. No additional user focus was supplied. Review analysis is complete; the three inline P2 findings and existing Remote Doris concern remain for the author to address.

…ghts

### What problem does this PR solve?

Related PR: apache#68791

Problem Summary: MaxCompute ranges from different read sessions and Iceberg JNI metadata tasks can share synthetic paths and coordinates. Bounded consistent-hash scheduling then confines distinct work to the same backend candidates. Include the existing read-session or serialized-task identity through the connector hook while preserving native Iceberg file identities. Remove the redundant per-batch weight histogram rebuild because production weight updates already maintain it incrementally. Cover identity separation, ten-backend bounded candidate assignment and histogram consistency across singleton batches.

### Release note

Synthetic MaxCompute and Iceberg JNI metadata scan ranges use work-specific consistent-hash identities. This can change their backend placement, including legacy hash mode. Native Iceberg file identities are unchanged.

### Check List (For Author)

- Test: Unit Test / Manual test
    - 70 targeted FE and connector unit tests passed; standard build.sh --fe and Checkstyle passed; git diff --check passed.
- Behavior changed: Yes, distinguish synthetic work for hash placement and remove redundant histogram rebuilds.
- Does this need documentation: No, existing session-variable semantics are unchanged.
### What problem does this PR solve?

Related PR: apache#68791

Problem Summary: Remote Doris result streams can advertise the same proxy URI with different Flight tickets. Hashing only that URI restricts distinct streams to the same bounded backend candidate set. Capture an immutable identity from the URI and the remaining ticket bytes when the split is created, without consuming the execution ByteBuffer. Add tests for distinct work, stable identity, heap/direct/read-only buffer state, and bounded assignment across eight backends.

### Release note

Remote Doris consistent-hash placement distinguishes different result-stream tickets at the same endpoint.

### Check List (For Author)

- Test: Unit Test / Manual test
    - 82 targeted FE/connector unit tests passed; standard clean FE build with Checkstyle passed; git diff --check passed.
- Behavior changed: Yes, hash placement includes the result-stream ticket; execution parameters are unchanged.
- Does this need documentation: No, existing session-variable semantics are unchanged.
@OIiveirra

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17654	5651	5497	5497
q2	2098	307	265	265
q3	10250	1439	841	841
q4	4688	487	342	342
q5	7438	783	527	527
q6	189	193	158	158
q7	755	799	614	614
q8	9246	1330	1117	1117
q9	5712	4424	4448	4424
q10	6818	1288	1033	1033
q11	436	256	235	235
q12	631	416	286	286
q13	18016	3053	2374	2374
q14	279	262	250	250
q15	q16	731	726	665	665
q17	1180	736	580	580
q18	7111	6203	6150	6150
q19	1110	973	611	611
q20	367	337	227	227
q21	5042	2271	2380	2271
q22	357	329	283	283
Total cold run time: 100108 ms
Total hot run time: 28750 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6139	6083	6097	6083
q2	689	578	526	526
q3	5277	5417	4977	4977
q4	2020	2206	1573	1573
q5	5451	5350	6096	5350
q6	274	196	164	164
q7	2397	2135	1946	1946
q8	3173	2701	2781	2701
q9	8409	8235	8438	8235
q10	3752	3664	3326	3326
q11	643	448	417	417
q12	704	753	563	563
q13	2922	3194	2473	2473
q14	326	301	281	281
q15	q16	718	737	667	667
q17	8361	7503	7552	7503
q18	13117	12273	13129	12273
q19	937	793	799	793
q20	2193	2165	1944	1944
q21	5748	4674	4776	4674
q22	489	457	416	416
Total cold run time: 73739 ms
Total hot run time: 66885 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 151550 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 5d584fce62774c7f02ea7454dc33a8b8a555d4cb, data reload: false

query5	4333	583	450	450
query6	431	223	203	203
query7	4802	456	230	230
query8	316	183	164	164
query9	8774	3927	3939	3927
query10	465	302	252	252
query11	5973	3424	3178	3178
query12	143	87	85	85
query13	1250	444	324	324
query14	6509	4728	4477	4477
query14_1	4276	4228	4217	4217
query15	208	200	188	188
query16	959	454	440	440
query17	858	665	564	564
query18	2428	409	295	295
query19	181	163	134	134
query20	79	76	85	76
query21	219	128	111	111
query22	12995	12968	12796	12796
query23	13211	12476	12010	12010
query23_1	12136	12105	12195	12105
query24	7086	820	444	444
query24_1	476	479	465	465
query25	507	393	345	345
query26	1247	255	136	136
query27	2764	438	265	265
query28	4613	1949	1930	1930
query29	1547	572	429	429
query30	297	213	184	184
query31	877	755	648	648
query32	143	90	91	90
query33	516	302	235	235
query34	900	846	490	490
query35	746	764	649	649
query36	811	822	733	733
query37	138	98	108	98
query38	1796	1760	1707	1707
query39	721	694	681	681
query39_1	652	682	648	648
query40	237	114	98	98
query41	65	68	62	62
query42	83	81	78	78
query43	364	376	324	324
query44	1300	692	699	692
query45	175	177	162	162
query46	835	960	559	559
query47	3015	3014	2962	2962
query48	359	317	211	211
query49	564	400	299	299
query50	673	268	207	207
query51	10468	10363	10733	10363
query52	82	87	70	70
query53	190	213	150	150
query54	231	201	179	179
query55	70	71	68	68
query56	237	220	197	197
query57	1594	1576	1567	1567
query58	278	257	248	248
query59	2344	2365	2109	2109
query60	276	242	224	224
query61	147	149	151	149
query62	391	346	293	293
query63	206	154	160	154
query64	2748	927	803	803
query65	3440	3402	3386	3386
query66	1773	407	297	297
query67	20120	20230	19992	19992
query68	2935	1019	665	665
query69	395	292	251	251
query70	922	819	860	819
query71	299	224	209	209
query72	2710	2543	2288	2288
query73	528	526	301	301
query74	4604	4475	4328	4328
query75	2322	2324	1943	1943
query76	2287	1013	608	608
query77	358	394	296	296
query78	8872	8822	8406	8406
query79	876	858	516	516
query80	468	407	363	363
query81	517	320	274	274
query82	211	132	109	109
query83	195	198	176	176
query84	287	122	102	102
query85	770	406	369	369
query86	251	285	239	239
query87	1989	1970	1856	1856
query88	3568	2710	2678	2678
query89	323	297	253	253
query90	2089	180	174	174
query91	158	150	129	129
query92	98	86	86	86
query93	988	979	583	583
query94	437	301	273	273
query95	581	412	323	323
query96	672	523	236	236
query97	2485	2411	2296	2296
query98	154	148	145	145
query99	770	775	646	646
Total cold run time: 232538 ms
Total hot run time: 151550 ms

@hello-stephen

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

query1	0.01	0.01	0.01
query2	0.10	0.05	0.05
query3	0.27	0.12	0.11
query4	1.61	0.12	0.11
query5	0.27	0.25	0.25
query6	1.17	0.68	0.68
query7	0.04	0.01	0.00
query8	0.05	0.04	0.03
query9	0.41	0.36	0.36
query10	0.60	0.57	0.57
query11	0.21	0.14	0.15
query12	0.18	0.14	0.14
query13	0.49	0.51	0.51
query14	0.97	0.98	0.98
query15	0.62	0.62	0.60
query16	0.35	0.35	0.36
query17	1.13	1.15	1.12
query18	0.23	0.21	0.20
query19	2.06	2.01	1.97
query20	0.02	0.02	0.01
query21	15.48	0.28	0.15
query22	4.32	0.05	0.05
query23	16.25	0.32	0.12
query24	3.14	0.60	0.41
query25	0.10	0.07	0.05
query26	1.51	0.24	0.14
query27	0.05	0.04	0.05
query28	2.36	0.67	0.43
query29	12.49	4.11	3.27
query30	0.29	0.14	0.14
query31	2.77	0.59	0.34
query32	3.22	0.62	0.52
query33	3.15	3.32	3.28
query34	15.45	3.99	3.40
query35	3.34	3.33	3.34
query36	0.54	0.46	0.45
query37	0.10	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.02	0.02
query40	0.18	0.14	0.14
query41	0.09	0.03	0.04
query42	0.04	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 95.79 s
Total hot run time: 24.66 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 98.89% (89/90) 🎉
Increment coverage report
Complete coverage report

### What problem does this PR solve?

Related PR: apache#68791

Problem Summary: Merge the current master while preserving its initialized backend order and narrowed candidate membership alongside incremental split weights. Adapt deterministic selection tests to each policy's randomized order. Repair the attached FE CI failures: assert the complete aggregation keys that remain under outer-join null extension; explicitly request JSON in HTTP forwarding tests; let the test server itself allocate an ephemeral port and shut it down after the suite; exclude embedded multi-release vendor class variants only from Paimon S3 coverage reporting. Production HTTP forwarding, optimizer rules and runtime plugin contents are unchanged. The separate FE coverage job was blocked by the same scheduling merge conflict.

### Release note

None

### Check List (For Author)

- Test: Unit Test / Manual test
    - 76 targeted FE unit tests passed with zero failures, errors or skips.
    - JaCoCo report reproduction failed without exclusions and passed with the coverage-profile exclusions on the same classes and agent-generated exec file.
    - Standard FE build and Checkstyle passed; git diff --check passed.
- Behavior changed: No additional query or runtime plugin behavior change; preserve both scheduling changes during the master merge and repair test/report infrastructure.
- Does this need documentation: No, session-variable semantics are unchanged.
@OIiveirra
OIiveirra requested a review from morningman as a code owner October 13, 2026 12:03
@OIiveirra

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17591	5634	5542	5542
q2	2104	316	282	282
q3	10243	1379	834	834
q4	4679	465	340	340
q5	7426	786	539	539
q6	192	189	157	157
q7	772	795	607	607
q8	9255	1323	1070	1070
q9	5752	4420	4448	4420
q10	6813	1294	1034	1034
q11	423	252	237	237
q12	638	404	283	283
q13	18475	3067	2374	2374
q14	280	265	242	242
q15	q16	745	722	667	667
q17	1173	741	576	576
q18	7051	6212	6150	6150
q19	1098	951	615	615
q20	379	334	226	226
q21	5322	2224	2406	2224
q22	360	311	267	267
Total cold run time: 100771 ms
Total hot run time: 28686 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6159	6137	6133	6133
q2	672	555	549	549
q3	5214	5355	4956	4956
q4	2007	2121	1540	1540
q5	5307	5200	5867	5200
q6	270	205	162	162
q7	2351	2056	1837	1837
q8	3174	2772	2768	2768
q9	8212	8174	8106	8106
q10	3985	3719	3361	3361
q11	637	451	421	421
q12	691	770	528	528
q13	3084	3181	2525	2525
q14	318	313	297	297
q15	q16	722	716	655	655
q17	8350	7487	7327	7327
q18	13170	12252	13128	12252
q19	905	783	777	777
q20	2177	2166	1962	1962
q21	5752	4714	4751	4714
q22	483	459	405	405
Total cold run time: 73640 ms
Total hot run time: 66475 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 152408 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 74c3f7664fc8714f167f334e59c023632afb0db4, data reload: false

query5	4323	590	442	442
query6	423	205	194	194
query7	4792	437	221	221
query8	315	187	164	164
query9	8756	4024	3995	3995
query10	490	311	263	263
query11	5960	3425	3204	3204
query12	145	86	84	84
query13	1252	425	315	315
query14	6538	4825	4509	4509
query14_1	4249	4296	4307	4296
query15	219	206	186	186
query16	937	451	435	435
query17	866	664	516	516
query18	2399	406	302	302
query19	193	171	129	129
query20	79	78	75	75
query21	203	129	107	107
query22	13027	12996	12914	12914
query23	13096	12473	12192	12192
query23_1	12147	12277	12134	12134
query24	7070	821	473	473
query24_1	464	468	466	466
query25	516	389	332	332
query26	1289	250	136	136
query27	2777	444	279	279
query28	4631	1939	1918	1918
query29	1552	579	433	433
query30	307	218	185	185
query31	893	777	644	644
query32	146	89	92	89
query33	502	294	225	225
query34	954	876	493	493
query35	742	751	652	652
query36	812	812	717	717
query37	132	111	91	91
query38	1809	1747	1680	1680
query39	697	709	689	689
query39_1	674	674	676	674
query40	235	119	94	94
query41	67	66	64	64
query42	86	86	83	83
query43	367	373	335	335
query44	1321	722	721	721
query45	226	176	164	164
query46	829	947	564	564
query47	2719	3033	2934	2934
query48	288	298	217	217
query49	561	398	304	304
query50	674	278	215	215
query51	10574	10627	10715	10627
query52	81	81	66	66
query53	186	205	152	152
query54	227	211	193	193
query55	77	71	64	64
query56	246	232	212	212
query57	1632	1590	1597	1590
query58	278	254	250	250
query59	2369	2385	2155	2155
query60	288	234	217	217
query61	137	150	146	146
query62	396	342	284	284
query63	192	170	170	170
query64	2757	937	755	755
query65	3441	3378	3395	3378
query66	1797	430	311	311
query67	20160	20179	20032	20032
query68	2914	1033	630	630
query69	396	305	264	264
query70	943	862	837	837
query71	294	232	217	217
query72	2813	2694	2275	2275
query73	527	538	295	295
query74	4611	4454	4314	4314
query75	2327	2301	1909	1909
query76	2286	1006	616	616
query77	344	402	303	303
query78	8923	8954	8486	8486
query79	1007	842	542	542
query80	514	415	338	338
query81	521	318	275	275
query82	578	139	109	109
query83	291	195	179	179
query84	310	119	107	107
query85	792	418	350	350
query86	324	252	230	230
query87	2003	1960	1810	1810
query88	3636	2771	2711	2711
query89	335	293	254	254
query90	1922	187	187	187
query91	156	149	123	123
query92	98	90	85	85
query93	1021	1003	572	572
query94	445	301	279	279
query95	579	357	319	319
query96	685	526	228	228
query97	2462	2395	2307	2307
query98	151	154	140	140
query99	786	744	654	654
Total cold run time: 233240 ms
Total hot run time: 152408 ms

@hello-stephen

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

query1	0.00	0.00	0.01
query2	0.09	0.05	0.05
query3	0.27	0.12	0.12
query4	1.61	0.13	0.12
query5	0.24	0.25	0.24
query6	1.16	0.70	0.68
query7	0.04	0.01	0.01
query8	0.05	0.04	0.04
query9	0.42	0.34	0.36
query10	0.57	0.57	0.57
query11	0.20	0.15	0.13
query12	0.18	0.15	0.15
query13	0.48	0.51	0.49
query14	0.98	0.95	0.97
query15	0.64	0.61	0.60
query16	0.36	0.34	0.36
query17	1.13	1.12	1.12
query18	0.23	0.21	0.20
query19	2.13	2.06	2.08
query20	0.02	0.01	0.01
query21	15.48	0.24	0.15
query22	4.52	0.05	0.06
query23	16.27	0.32	0.12
query24	2.62	0.65	1.31
query25	0.09	0.07	0.05
query26	1.78	0.24	0.15
query27	0.06	0.05	0.03
query28	3.12	0.63	0.39
query29	12.54	4.21	3.31
query30	0.28	0.13	0.14
query31	2.77	0.57	0.34
query32	3.22	0.62	0.52
query33	3.28	3.29	3.22
query34	15.50	4.04	3.34
query35	3.35	3.32	3.35
query36	0.54	0.46	0.46
query37	0.09	0.06	0.06
query38	0.05	0.05	0.04
query39	0.04	0.03	0.03
query40	0.17	0.14	0.14
query41	0.08	0.04	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.03
Total cold run time: 96.73 s
Total hot run time: 24.81 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 77.78% (70/90) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 98.89% (89/90) 🎉
Increment coverage report
Complete coverage report

@linrrzqqq

Copy link
Copy Markdown
Collaborator

/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.

Reviewed commit 74c3f7664fc8714f167f334e59c023632afb0db4 across all 35 changed files. Review converged after 1 round: both full-scope reviewers and the additional risk reviewer returned NO_NEW_VALUABLE_FINDINGS; every candidate/risk was independently checked and dismissed or deduplicated. No new inline findings and no still-applicable existing P0/P1 findings.

Both earlier P1 concerns are fixed: connector API gating now uses major 14 with the updated surface baseline, and disabled-spread cache affinity retains hash-ring order.

The existing P2 all-candidate ring-walk concern remains partially applicable to TVFs and is recorded as already covered. FileQueryScanNode initializes the TVF policy twice, and the list overload appends backend candidates both times. With 10 distinct eligible BEs, the list has 20 entries; spread=11 therefore asks the ring for 11 unique nodes although only 10 exist, traversing all virtual nodes per split. Automatic spread=0 bypasses this. This is redundant planning work; no wrong-result consequence was established. It is not reposted inline.

Critical checkpoint conclusions:

  • Goal and proof: the code provides opt-in minimum-weight placement with random minimum-weight ties, legacy mode 1, automatic mode 0, and bounded hash candidates above 1. Local host preference remains an explicit exception: independent hinted queries may still prefer the same local BE. Policy, identity and variable tests plus S3 regression suites cover the behavior by inspection.
  • Scope and clarity: scheduling and identity logic remain centralized and connector-agnostic. The additional HTTP fixture, optimizer assertions and coverage configuration broaden the diff; their mechanisms were reviewed independently.
  • Concurrency and locking: eager assignment runs during planning; concurrent partition workers and streamed assignments serialize policy weight/histogram updates under SplitAssignment.assignLock. Connector planning, queue conversion and backpressure remain outside it. No new lock-order cycle was found; the existing TVF ring work remains the performance exception above.
  • Lifecycle and initialization: strategy/spread are captured per scan node; weight history persists across batches. Histogram writes are centralized and incremental. Remote Doris snapshots an immutable identity from a duplicate ticket buffer without consuming the execution buffer. HTTP test teardown closes the server context. No C++ static-initialization change.
  • Dynamic configuration: the nonnegative int variable defaults to 1, validates negatives/non-integers/overflow, and affects subsequent plan construction without restart. Spread, hash selector and cache settings forward to the master; UNSET restores the compiled default. Persisted global values use existing variable machinery and are not reset by the new default.
  • Compatibility: connector API 14 is stamped and checked from the same parent property; incompatible plugin majors are rejected and require matching builds. The new hook is in the frozen surface. No storage format or FE/BE wire change was found; missing session JSON keys retain defaults.
  • Thrift/protobuf IDs: no gensrc definition changes; not applicable.
  • Parallel paths: eager, partition-batch and streamed planning use the common policy. Cache/hash and automatic RANDOM gates, cloud/group eligibility, mandatory nonremote hosts, native/JNI connector arms, and unchanged Hive/Hudi/ES/JDBC peers were traced. Load policies retain their separate round-robin path.
  • Conditions and errors: spread-mode checks distinguish legacy/automatic/bounded modes; overloaded remote hints fall back to spread candidates while mandatory hosts remain exact. Empty eligible/required-host sets fail; assignment arithmetic checks overflow.
  • Test coverage: unit additions cover multiple BE counts, candidate reachability, ties, batch history, eligibility, missing hosts, invalid variables, forwarding, identity distinction and buffer preservation. Regression suites check results across modes. Policy-only tests do not exercise the TVF double initialization, and these suites do not measure live throughput.
  • Changed results: ordered three-row/NULL fixtures, the six-row two-export result, and variable default/change/error/unset goldens match the SQL by inspection. Golden generation was not reproduced.
  • Observability: existing scan backend IDs, planning debug timings and optional assigned-weight profiles remain available. No shared live-load metric is introduced or promised.
  • Transactions and persistence: no visible-version, delete-bitmap, transaction or EditLog schema changes. Global variable save/replay follows existing generic handling; no new master-failover transaction path.
  • Writes and crash atomicity: production data-write semantics are unchanged; OUTFILE is regression fixture setup. No new storage ownership or crash-atomicity mechanism.
  • FE/BE variable passing: spread and selector control FE placement and need FE forwarding only; existing cache options and execution range payloads remain unchanged.
  • Performance: spread omits unused alternative-host lists and global redistribution; all-candidate direct lists avoid ring walks on unique inventories. Minimum lookup uses incremental counts instead of per-batch/per-hint full scans. Remaining TVF work is the existing P2 above; no benchmark was executed here.
  • Further review and core invariants: the review continued through all changes, producer/consumer chains and missed-case sweeps. No new substantiated visibility, memory-ownership, silent-error or correctness finding remained.

No additional user-provided focus was supplied. This was a static review only: no builds, unit/regression tests, golden regeneration or performance experiments were run, and author/CI claims are not executed evidence from this invocation. No unresolved static coverage gap remains; external plugins were assessed through the supplied scan-range contract, not every third-party implementation.

Review converged after 1 round(s).

hello-stephen pushed a commit that referenced this pull request Oct 14, 2026
… at graceful exit (#68942)

Problem Summary:

**In short.** The NonConcurrent regression pipeline fails a few percent
of its runs with `Lsan fail` while every case passes. LeakSanitizer
finds, at the BE's graceful exit, one stream load's `ResourceContext`
that was never released, but its report only shows allocation stacks,
which are the same for every stream load, so nobody can tell which load
it was. This PR makes the BE print, at graceful exit in memleak-check
mode, every `ResourceContext` still alive with its task id, the
references still held, its memory tracker and workload group, and
whether its `QueryContext` is already gone. Nothing changes unless
`enable_graceful_exit_check=true`.

**Background.**
- With `enable_graceful_exit_check=true` (memleak-check mode, used by
the regression pipelines on the ASAN build), `doris_main` stops every
service and runs `ExecEnv::destroy()` instead of `_exit()`, so that
LeakSanitizer checks the heap when the process exits. The NonConcurrent
pipeline greps `be.out` for `detected memory leaks` after `stop_be.sh
--grace` and reports `Lsan fail`.
- Every query or load has a `ResourceContext`: CPU/memory/IO contexts, a
task controller, the query memory tracker and the workload group. The
`QueryContext` owns it, and the components that work for the task (load
channel, memtables, scanner context, `RuntimeQueryStatisticsMgr`,
threads attached to the task, ...) hold references of their own while
they run.

**The problem, and what it cost.**
- `Lsan fail` hits 1–5% of NonConcurrent runs depending on the month
(448 of the last 14000, back to March 2026), on PRs that have nothing to
do with it; authors rerun or skip. Every report TeamCity still keeps (10
runs from 2026-10-05 to 2026-10-12, on #68707, #68281, #68791, #68803,
#68798, #68543, #68901, #68919, #68879) has the same shape, down to the
byte counts, and all of its leaks are indirect:

  | Leaked | Size | Origin |
  |---|---|---|
| one `ResourceContext` with its CPU/memory/IO contexts,
`QueryTaskController` and both trackers (`Load#Id=…`,
`Memtable#Load#Id=…`) | 6.5 KB, 94 objects | an HTTP stream load:
`StreamLoadAction::_process_put` → `StreamLoadExecutor` →
`FragmentMgr::_get_or_create_query_ctx` |
| the `normal` workload group created by
`WorkloadGroupMgr::create_internal_wg()` | 6.1 KB + 4.3 KB | kept alive
by `ResourceContext::_workload_group` |
| the `std::make_shared` block of the load's `QueryContext` | 2.5 KB |
kept allocated by the `weak_ptr` in `QueryTaskController` |

- The `QueryContext` itself was destroyed: in `be.INFO`, each of the
21894 `query_id: … use wg:` lines of the run has its `Query …
deconstructed`. So one reference to the load's `ResourceContext` is
never released, from a place LeakSanitizer does not scan (a bthread
stack, whose memory brpc maps itself) or a count that is never
decremented. LeakSanitizer cannot tell which of these two it is.
- A NonConcurrent run issues about 430 HTTP stream loads (about 380
through the load channel, 150 of them audit-log loads), and the report
cannot say which one leaked: the stacks are identical, and the one thing
that would identify the load, the tracker label with its id, is inside
the leaked memory, which LeakSanitizer does not print. Without the load
there is nothing to follow, so the flake stays unexplained.

**How this PR fixes it.**
- In memleak-check mode each `ResourceContext` registers itself in a
process-wide set when it is constructed and removes itself when it is
destroyed. The set stores the addresses bitwise inverted, so
LeakSanitizer does not take it for a reference and still reports a
leaked context.
- `ResourceContext::describe_live_contexts()` returns one line per
context still alive: address, strong references still held, task id,
finished flag, running time, memory tracker (label, consumption, peak),
workload group and, for a query, whether its `QueryContext` is still
alive.
- `doris_main` calls `ResourceContext::log_live_contexts()` right after
`ExecEnv::destroy()` on the graceful exit path. It writes the
description to `be.WARNING` and to `be.out`, where the LeakSanitizer
report follows once `main()` returns, or one INFO line when no context
is alive. The printed address falls inside one of the `Objects leaked
above` ranges of that report.
- The description is built on a short-lived thread, and the main thread
only handles the resulting text. Describing a context touches it; done
on the main thread, it could leave a pointer to a leaked context in a
dead slot of the main thread's stack, which LeakSanitizer scans at exit
— it would then take the context for referenced and not report it, so
the run that reproduces the leak could pass. The stack of a finished
thread is not scanned.

**Results.** What the next `Lsan fail` will tell, compared with today:

| | Before | After |
|---|---|---|
| Which query or load leaked | unknown | `task_id=…`; its label, table
and test are then in `be.INFO` |
| How many references are left | unknown | `references=N` |
| Whether the `QueryContext` is gone | only by pairing ~20k log lines |
`query_context=destroyed` |
| Where to look | the LeakSanitizer report in `be.out` | the same
`be.out`, just before that report (the build log's `head -n 100 be.out`
shows it) |
| Cost with `enable_graceful_exit_check=false` (default) | — | one
boolean check per `ResourceContext` construction and destruction |

A line looks like this (values made up):

```
1 resource contexts are still alive. LeakSanitizer reports a leaked context as the memory block that holds it, so match the addresses below against the ranges it prints under 'Objects leaked above'.
  0x7c0000001010: references=1, task_id=1eac0c4ec4ec0000-0000000000000003, finished=true, running_ms=7569, mem_tracker=Load#Id=1eac0c4ec4ec0000-0000000000000003 (consumption=0, peak=17.18 MB), workload_group=normal(1), query_context=destroyed
```

**Classes, and how they call each other.**
- `ResourceContext` (`resource_context.{h,cpp}`): registers in the
constructor and unregisters in the destructor when memleak-check mode is
on; `describe_live_contexts()` formats the live ones;
`log_live_contexts()` runs that on its own thread and logs the result.
- `QueryTaskController`: new `is_query_context_alive()`.
- `doris_main`: one call to `log_live_contexts()` after
`ExecEnv::destroy()`.

```
doris_main (graceful exit, enable_graceful_exit_check=true)
  ├─ ExecEnv::destroy()
  └─ ResourceContext::log_live_contexts() ──► be.WARNING + be.out (or one INFO line)
     └─ [short-lived thread] describe_live_contexts(100)
        ├─ registry of disguised addresses ◄── ResourceContext() / ~ResourceContext()
        └─ per live context:
              ├─ TaskController: task id, finished, running time
              ├─ MemoryContext → MemTrackerLimiter: label, consumption, peak
              ├─ WorkloadGroup: name, id
              └─ QueryTaskController::is_query_context_alive()
```

No holder of `ResourceContext` changes, and neither do the LeakSanitizer
options or suppressions. Once the leaked load is known, the fix for the
leak itself will be a separate PR.


---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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