Skip to content

[fix](be) Reset quantile union state for empty window frames - #69964

Draft
mrhhsg wants to merge 2 commits into
apache:masterfrom
mrhhsg:fix/quantile-union-empty-window
Draft

mrhhsg wants to merge 2 commits into
apache:masterfrom
mrhhsg:fix/quantile-union-empty-window

Conversation

@mrhhsg

@mrhhsg mrhhsg commented Nov 2, 2026

Copy link
Copy Markdown
Member

What problem does this PR solve?

Issue Number: N/A

Related PR: N/A

Problem Summary: A bounded ROWS window can become empty after a nonempty frame. The quantile_union reset previously restored only the first-input flag and retained the preceding QuantileState. Without a subsequent value to merge, an empty or NULL-only frame returned the preceding frame's quantiles. Reset both the first-input flag and the stored samples before each frame. The logical reset retains explicit sample-vector capacity for reuse, while clear() preserves its storage-release behavior.

Release note

Fix quantile_union over empty window frames: quantile_percent now returns NaN instead of values from the preceding frame.

Check List (For Author)

  • Test: ASAN BE unit tests (47 passed); ASAN BE+FE build (including FE Checkstyle); three isolated SQL regression suites (1 suite passed each); clang-format, format check, build hygiene, changed-line clang-tidy (no warnings), and diff check. No performance benchmark was run.
  • Behavior changed: Yes (empty window frames no longer inherit the preceding quantile state).
  • Does this need documentation: No.

### What problem does this PR solve?

Issue Number: N/A

Related PR: N/A

Problem Summary: A bounded window can become empty after a nonempty frame. The quantile_union reset only restored the first-input flag while retaining the previous QuantileState, so an empty frame returned the previous frame's quantiles. Clear the stored state on reset while retaining the existing first-input behavior. Unit and SQL regression tests cover empty, null-only, partitioned, and nonempty frames, including all state representations and retained results.

### Release note

Fix quantile_union results for empty window frames; quantile_percent now returns NaN instead of values retained from the preceding frame.

### Check List (For Author)

- Test: ASAN BE unit tests (46 focused cases); isolated SQL regression (new suite plus two existing suites); ASAN BE+FE build with FE Checkstyle; clang-format, header hygiene, clang-tidy, and diff checks.
- Behavior changed: Yes (empty window frames no longer inherit the preceding quantile state).
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: N/A

Related PR: N/A

Problem Summary: Bounded window frames reset the quantile union accumulator for every output row. The empty-frame correctness fix used QuantileState::clear(), which also shrinks its explicit sample vector and makes ordinary nonempty frames allocate it again on every row. Separate logical sample reset from storage release, use the non-releasing reset for aggregate frames, and retain the existing clear() behavior for callers that need to release storage. Cover repeated explicit frames of sizes 2, 3, and 2048, empty results, capacity reuse, and saved result stability.

### Release note

None

### Check List (For Author)

- Test: ASAN BE unit tests (47 passed); ASAN BE and FE build; three isolated SQL regression suites; clang-format, format check, build hygiene, and changed-line clang-tidy.
- Behavior changed: No (preserves the empty-window correctness fix while avoiding repeated allocations).
- Does this need documentation: No.
@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?

@mrhhsg

mrhhsg commented Nov 2, 2026

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41398895740

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

@mrhhsg

mrhhsg commented Nov 2, 2026

Copy link
Copy Markdown
Member Author

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

No new actionable findings in the six-file diff at b78e968c2883bd9dd7c0c1277846cdef9a233bb9. No existing inline findings require carrying forward, and no additional user focus was supplied.

Critical checkpoint conclusions:

  1. Goal and evidence: Reset now clears both the first-input flag and samples. Bounded empty or NULL-only frames therefore publish EMPTY, whose percentiles are NaN. Added unit and SQL tests exercise the trigger.
  2. Scope and clarity: The change is focused: logical reset, reuse from existing clear, aggregate reset, and relevant tests.
  3. Concurrency: Mutation remains local to the aggregate state. No new threads, shared mutable function state, locks, or lock-order changes; existing digest COW/reader locking remains intact.
  4. Lifecycle: Reset releases only the accumulator's digest reference. Published results and inputs retain their own ownership; explicit vectors are independently owned. No static-initialization dependency or ownership cycle is introduced.
  5. Configuration: No configuration changes.
  6. Compatibility: Object layout, existing function contracts, intermediate/result types and serialized encodings are unchanged. EMPTY uses the existing representation; no new libc API or dependency is introduced.
  7. Thrift/protobuf: No definitions changed.
  8. Parallel paths: Nullable/nonnullable aggregation, bounded ROWS/RANGE, partition boundaries and nested reset forwarding use the corrected state reset. Growing windows retain their existing accumulation behavior; grouped/distributed publication remains compatible.
  9. Conditions and comments: No production conditional is added. The reset comment and capacity test comment match the implementation and actual bounded-frame caller.
  10. Test coverage: Inspected initial/trailing empty frames, consecutive resets, SINGLE/EXPLICIT/TDIGEST, subsequent adds, NULL-only input, retained input/results, explicit capacity, multi-value frames and partition reset. No new error behavior requires expected-error tests.
  11. Expected results: Every added SQL result matches its frame boundaries and explicit ordering. For example, FOLLOWING 1..2 over 10/20/30 produces min/median/max 20/25/30, then 30/30/30, then NaN.
  12. Observability: This deterministic local-state correction needs no additional metrics or logging.
  13. Transactions and persistence: No EditLog, failover, visibility-version, delete-bitmap or persistent-storage logic changes.
  14. Data writes and atomicity: No storage write or transaction behavior changes; accumulator lifetime and cleanup remain RAII-managed.
  15. FE/BE passing: No new fields or variables; existing function names and QUANTILE_STATE types remain consistent.
  16. Performance and memory: Logical reset retains explicit capacity; clear retains its storage-release behavior. Previous first-input assignment already replaced digest ownership, so the new reset releases it earlier without introducing another frame traversal or digest construction.
  17. Other issues and limits: All changed files and relevant caller/consumer paths were reviewed. Both initial ownership and capacity risks were dismissed with concrete evidence, and all three reviewers returned NO_NEW_VALUABLE_FINDINGS. No unresolved code candidate or static coverage gap remains.

Static inspection only: no builds, tests, benchmarks, or runtime/ELF validation were performed. Expected results were checked from SQL semantics; their generation provenance was not independently verified.

Review converged after 1 round(s).

@mrhhsg

mrhhsg commented Nov 2, 2026

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17594	5259	5089	5089
q2	2167	349	300	300
q3	10164	1415	839	839
q4	4684	474	340	340
q5	7462	842	550	550
q6	185	186	156	156
q7	755	820	621	621
q8	9289	1395	1162	1162
q9	5488	4236	4277	4236
q10	6850	1304	1040	1040
q11	441	251	228	228
q12	645	400	282	282
q13	18118	3688	3027	3027
q14	278	273	242	242
q15	q16	731	735	654	654
q17	1207	744	591	591
q18	7059	6194	6146	6146
q19	1117	971	627	627
q20	387	351	229	229
q21	5291	2517	2512	2512
q22	390	325	269	269
Total cold run time: 100302 ms
Total hot run time: 29140 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5995	5901	6158	5901
q2	739	597	584	584
q3	5665	5797	5458	5458
q4	2006	2209	1594	1594
q5	5946	5651	5592	5592
q6	237	188	149	149
q7	2263	2010	1791	1791
q8	2975	2740	2714	2714
q9	7869	7538	7500	7500
q10	3638	3565	3178	3178
q11	585	404	389	389
q12	690	654	513	513
q13	3378	3645	3064	3064
q14	286	285	269	269
q15	q16	654	688	621	621
q17	7774	7028	6872	6872
q18	13018	12218	12866	12218
q19	940	832	842	832
q20	2145	2135	1924	1924
q21	5655	4606	4686	4606
q22	482	442	404	404
Total cold run time: 72940 ms
Total hot run time: 66173 ms

@hello-stephen

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

query5	4296	584	439	439
query6	428	217	210	210
query7	4808	447	229	229
query8	323	178	160	160
query9	8771	3152	3157	3152
query10	463	308	255	255
query11	6075	3856	3553	3553
query12	147	88	86	86
query13	1251	459	332	332
query14	6131	3926	3627	3627
query14_1	3402	3365	3372	3365
query15	212	198	181	181
query16	952	429	420	420
query17	860	662	557	557
query18	2428	420	310	310
query19	198	168	132	132
query20	87	85	85	85
query21	213	131	108	108
query22	12971	13048	12845	12845
query23	13565	12897	12495	12495
query23_1	12407	12734	12603	12603
query24	7401	819	459	459
query24_1	473	470	466	466
query25	497	394	335	335
query26	1258	257	139	139
query27	2764	443	273	273
query28	4644	2039	2031	2031
query29	1541	584	439	439
query30	302	229	182	182
query31	1011	929	802	802
query32	160	90	88	88
query33	518	292	221	221
query34	904	870	502	502
query35	731	750	654	654
query36	818	800	738	738
query37	119	93	83	83
query38	1782	1714	1686	1686
query39	789	796	742	742
query39_1	727	730	735	730
query40	223	117	92	92
query41	64	62	61	61
query42	85	85	83	83
query43	344	370	307	307
query44	1309	699	712	699
query45	181	173	169	169
query46	821	970	566	566
query47	2866	2717	2778	2717
query48	296	310	219	219
query49	567	393	290	290
query50	683	271	201	201
query51	10408	10420	10644	10420
query52	76	79	68	68
query53	183	203	150	150
query54	234	199	178	178
query55	74	67	71	67
query56	236	205	200	200
query57	1656	1637	1561	1561
query58	301	267	256	256
query59	2122	2216	2041	2041
query60	280	241	225	225
query61	158	169	170	169
query62	389	346	302	302
query63	190	162	177	162
query64	2907	991	765	765
query65	3322	3281	3277	3277
query66	1765	428	302	302
query67	20278	20375	20059	20059
query68	3084	1012	628	628
query69	383	276	251	251
query70	848	773	815	773
query71	286	225	214	214
query72	2834	2616	2317	2317
query73	508	536	298	298
query74	4640	4491	4346	4346
query75	2343	2295	1926	1926
query76	2326	1002	578	578
query77	355	377	261	261
query78	9723	9697	9156	9156
query79	999	862	548	548
query80	552	417	353	353
query81	558	328	271	271
query82	757	130	104	104
query83	303	192	184	184
query84	322	117	96	96
query85	885	418	364	364
query86	339	236	234	234
query87	2007	1955	1835	1835
query88	3753	2758	2741	2741
query89	338	279	242	242
query90	1863	165	164	164
query91	161	155	132	132
query92	98	88	89	88
query93	1040	1009	576	576
query94	450	317	284	284
query95	574	327	297	297
query96	672	485	238	238
query97	2467	2444	2349	2349
query98	163	152	152	152
query99	770	760	644	644
Total cold run time: 234591 ms
Total hot run time: 151293 ms

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.10	0.04	0.05
query3	0.26	0.09	0.09
query4	1.61	0.10	0.09
query5	0.24	0.24	0.24
query6	1.18	0.69	0.68
query7	0.04	0.01	0.01
query8	0.05	0.04	0.04
query9	0.41	0.36	0.34
query10	0.57	0.59	0.59
query11	0.20	0.15	0.14
query12	0.18	0.15	0.15
query13	0.47	0.50	0.49
query14	1.03	1.02	1.01
query15	0.62	0.60	0.61
query16	0.35	0.36	0.35
query17	1.16	1.17	1.16
query18	0.20	0.20	0.19
query19	2.05	2.02	1.99
query20	0.02	0.01	0.01
query21	15.48	0.19	0.13
query22	4.90	0.06	0.05
query23	16.32	0.33	0.12
query24	2.80	0.47	0.40
query25	0.13	0.05	0.03
query26	1.43	0.22	0.15
query27	0.05	0.04	0.05
query28	4.03	0.73	0.36
query29	12.51	4.16	3.24
query30	0.28	0.14	0.10
query31	2.78	0.55	0.32
query32	3.22	0.59	0.50
query33	3.27	3.15	3.25
query34	15.25	4.00	3.37
query35	3.35	3.33	3.34
query36	0.55	0.45	0.42
query37	0.09	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.04	0.03
query40	0.17	0.15	0.13
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: 97.62 s
Total hot run time: 24.27 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100.00% (4/4) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.70% (35894/46195)
Line Coverage 63.04% (403665/640365)
Region Coverage 59.67% (341876/572909)
Branch Coverage 60.73% (158078/260299)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants