Skip to content

[fix](fe) Deduplicate recursive CTE fragment reset requests - #67738

Open
Mryange wants to merge 1 commit into
apache:masterfrom
Mryange:fix-fe-recursive-cte-reset
Open

[fix](fe) Deduplicate recursive CTE fragment reset requests#67738
Mryange wants to merge 1 commit into
apache:masterfrom
Mryange:fix-fe-recursive-cte-reset

Conversation

@Mryange

@Mryange Mryange commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Recursive CTE queries could fail with Fragment context ... not found during recursive fragment cleanup. The FE collected recursive child fragments through a shared plan tree and could generate duplicate reset entries for the same fragment on the same BE. The first WAIT_FOR_DESTROY request removed the BE fragment context, while the duplicate request then failed to find it. This change deduplicates reset entries by fragment ID and BE address while preserving entries for different BEs.

Release note

None

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
  • Behavior changed:

    • No.
    • Yes.
  • Does this need documentation?

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

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

@Mryange

Mryange commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 0.00% (0/5) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17634	3035	3015	3015
q2	2089	265	234	234
q3	10223	994	517	517
q4	4674	252	200	200
q5	7679	596	384	384
q6	136	114	93	93
q7	529	505	381	381
q8	9237	923	964	923
q9	3466	2404	2379	2379
q10	6507	861	698	698
q11	399	200	184	184
q12	618	265	197	197
q13	18122	1527	1171	1171
q14	168	151	138	138
q15	q16	444	396	366	366
q17	1392	891	805	805
q18	3110	2249	2251	2249
q19	1293	933	785	785
q20	380	288	202	202
q21	5650	1654	1808	1654
q22	320	267	232	232
Total cold run time: 94070 ms
Total hot run time: 16807 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3370	3272	3262	3262
q2	500	398	388	388
q3	2220	2272	2185	2185
q4	1187	1166	878	878
q5	2161	2102	2072	2072
q6	171	117	88	88
q7	1023	943	897	897
q8	1592	1373	1377	1373
q9	3109	3072	3068	3068
q10	1880	1826	1633	1633
q11	358	267	252	252
q12	452	432	339	339
q13	1489	1524	1169	1169
q14	174	169	167	167
q15	q16	400	394	358	358
q17	3577	3298	3160	3160
q18	4832	4433	4745	4433
q19	888	835	926	835
q20	1000	975	866	866
q21	3871	3142	3222	3142
q22	392	372	344	344
Total cold run time: 34646 ms
Total hot run time: 30909 ms

@hello-stephen

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

query5	4252	410	349	349
query6	387	137	135	135
query7	4934	415	228	228
query8	287	129	122	122
query9	8668	2896	2873	2873
query10	408	225	188	188
query11	5391	1036	916	916
query12	128	72	69	69
query13	1204	427	306	306
query14	6095	2241	2093	2093
query14_1	2021	1985	1983	1983
query15	179	124	109	109
query16	915	377	345	345
query17	784	469	366	366
query18	2338	315	240	240
query19	165	142	110	110
query20	72	71	71	71
query21	214	102	89	89
query22	5238	5311	5277	5277
query23	6931	6127	6028	6028
query23_1	5987	6187	6060	6060
query24	7281	1079	768	768
query24_1	803	794	802	794
query25	422	300	251	251
query26	1247	239	132	132
query27	2770	430	261	261
query28	4672	1505	1499	1499
query29	933	456	351	351
query30	243	156	132	132
query31	814	394	330	330
query32	128	73	78	73
query33	484	208	180	180
query34	976	820	474	474
query35	395	398	341	341
query36	566	554	502	502
query37	119	80	69	69
query38	992	840	819	819
query39	492	495	477	477
query39_1	464	468	449	449
query40	203	89	74	74
query41	55	52	50	50
query42	72	75	72	72
query43	242	239	209	209
query44	977	537	545	537
query45	109	111	98	98
query46	770	844	514	514
query47	764	747	722	722
query48	316	309	228	228
query49	542	233	189	189
query50	706	256	193	193
query51	8202	8039	8055	8039
query52	73	69	59	59
query53	204	205	141	141
query54	217	163	150	150
query55	70	66	56	56
query56	195	159	154	154
query57	701	741	607	607
query58	187	189	169	169
query59	1195	1204	1072	1072
query60	242	178	171	171
query61	116	107	110	107
query62	355	209	172	172
query63	177	145	159	145
query64	2776	732	573	573
query65	1595	1626	1600	1600
query66	1903	266	223	223
query67	9773	9718	9602	9602
query68	2782	1198	740	740
query69	329	219	192	192
query70	675	627	656	627
query71	254	165	160	160
query72	2217	1657	1519	1519
query73	641	566	334	334
query74	1576	1233	1133	1133
query75	1165	1106	961	961
query76	2282	718	526	526
query77	255	258	216	216
query78	3983	3647	3211	3211
query79	1290	820	575	575
query80	1186	323	289	289
query81	492	159	133	133
query82	643	143	101	101
query83	295	218	199	199
query84	301	114	96	96
query85	833	367	280	280
query86	382	179	176	176
query87	1105	965	891	891
query88	2769	2103	2082	2082
query89	282	194	176	176
query90	1980	130	133	130
query91	138	118	99	99
query92	80	69	72	69
query93	1317	1082	693	693
query94	619	254	236	236
query95	534	246	297	246
query96	804	561	286	286
query97	1076	1083	1042	1042
query98	149	136	126	126
query99	419	348	311	311
Total cold run time: 175429 ms
Total hot run time: 81873 ms

@hello-stephen

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

query1	0.01	0.00	0.00
query2	0.08	0.04	0.04
query3	0.25	0.11	0.11
query4	1.60	0.10	0.10
query5	0.17	0.15	0.16
query6	1.27	0.69	0.68
query7	0.04	0.01	0.00
query8	0.05	0.04	0.03
query9	0.28	0.21	0.21
query10	0.36	0.35	0.34
query11	0.17	0.11	0.12
query12	0.15	0.12	0.12
query13	0.31	0.32	0.31
query14	0.45	0.45	0.45
query15	0.35	0.37	0.34
query16	0.22	0.24	0.21
query17	0.73	0.70	0.75
query18	0.19	0.18	0.18
query19	1.14	1.16	1.17
query20	0.02	0.01	0.00
query21	15.45	0.17	0.11
query22	5.08	0.04	0.04
query23	16.16	0.25	0.10
query24	3.10	0.30	0.26
query25	0.10	0.05	0.04
query26	0.71	0.15	0.13
query27	0.05	0.03	0.03
query28	3.61	0.51	0.29
query29	12.54	3.21	2.55
query30	0.25	0.11	0.12
query31	2.75	0.39	0.17
query32	3.51	0.31	0.24
query33	1.38	1.55	1.54
query34	15.40	2.16	1.74
query35	1.76	1.72	1.72
query36	0.45	0.33	0.28
query37	0.06	0.05	0.04
query38	0.03	0.03	0.03
query39	0.03	0.02	0.02
query40	0.12	0.08	0.07
query41	0.08	0.02	0.03
query42	0.04	0.03	0.03
query43	0.03	0.03	0.03
Total cold run time: 90.53 s
Total hot run time: 14.83 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 100.00% (5/5) 🎉
Increment coverage report
Complete coverage report

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

LGTM

@HappenLee

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 status: complete after two review rounds converged. One blocking lifecycle issue remains.

Critical checkpoint conclusions:

  • Goal and proof: The change correctly removes repeated reset entries within a single recursive CTE controller. The new regression deterministically materializes the shared CTE, executes multiple recursion rounds, and exercises the duplicate-suppression branch; exact-head P0, FE, compile, and CheckStyle checks pass, and FE regression coverage reports all five changed Java lines covered.
  • Scope and clarity: The patch is small and clear for the covered topology, but its per-node set lifetime is narrower than the BE lifecycle ownership domain described in the inline finding.
  • Concurrency and lifecycle: FE construction is local/single-threaded. BE lifecycle state is singular per (query_id, fragment_id) on each addressed BE and assumes one serial controller; independent recursive sibling controllers can share that state without an owner, refcount, or round barrier. This is the blocking issue.
  • Configuration and compatibility: No configuration, Thrift/protocol field, storage format, persistence schema, or rolling-upgrade contract changes. Same-BE local instances are correctly collapsed and distinct BE addresses remain distinct.
  • Parallel paths and conditions: Targets are already consumed once per scan fragment and notify-close uses a fragment-id set. Multi-BE and local-shuffle behavior is preserved. The missing parallel path is two independent recursive controllers sharing one transitive materialized fragment.
  • Tests and results: The ordered golden output is correct and the suite is included in P0. A two-controller regression is still needed for the blocking topology. No local build was run because this review environment prohibits builds; the cited exact-head CI and coverage results were inspected.
  • Error handling, observability, transactions, writes, FE/BE variables, memory, and performance: Status propagation and existing query/fragment identifiers remain adequate. The PR adds no transaction/data-write path, transmitted variable, static lifecycle, or significant allocation. No additional issue was found.
  • User focus: No additional user-provided focus was specified; the complete PR was reviewed.

Because the valid multi-controller topology can still reproduce Fragment context ... not found or mix recursion rounds, I am requesting changes.

List<TRecCTETarget> targets = new ArrayList<>();
// reset infos for all instances of child fragments (used to reset state)
List<TRecCTEResetInfo> fragmentsToReset = new ArrayList<>();
Set<String> resetFragmentKeys = new HashSet<>();

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.

[P1] Keep one owner for a shared fragment's recursive lifecycle

This set is recreated for every RecursiveCteNode, so it removes duplicates only within one controller. A valid reduced plan is:

CTEProducer(base) -> Fbase
Join
|-- RecCTE r1
|   `-- recursive side -> inlined edges -> CTEConsumer(base) x2
`-- RecCTE r2
    `-- recursive side -> inlined edges -> CTEConsumer(base) x2

BindRelation marks the directly referenced edges CTE must-inline, but not its nested base; because base has two consumers and the default threshold is one, it remains materialized. Deep-copying edges retains the lower CTE id, and physical translation returns the same MultiCastPlanFragment, so both fresh sets retain the same (Fbase, BE). Each source then independently sends WAIT/REBUILD/SUBMIT/FINAL_CLOSE, while FragmentMgr owns only one context for that key. For example, R1 can WAIT/REBUILD PFC1, R2 can WAIT and remove PFC1, and R1's SUBMIT then returns NotFound; full sequential execution still fails after the first controller's FINAL_CLOSE removes state. Please clone/inline the transitive fragment per controller or add explicit shared lifecycle ownership/round coordination (a query-wide drop from one list is insufficient), and add a two-controller regression.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants