Skip to content

[fix](stream) Mark streams stale when base tables are dropped - #66287

Open
seawinde wants to merge 7 commits into
apache:masterfrom
seawinde:fix-table-stream-stale-on-base-table-drop
Open

[fix](stream) Mark streams stale when base tables are dropped#66287
seawinde wants to merge 7 commits into
apache:masterfrom
seawinde:fix-table-stream-stale-on-base-table-drop

Conversation

@seawinde

@seawinde seawinde commented Jul 30, 2026

Copy link
Copy Markdown
Member

What problem does this PR solve?

Issue Number: #64518

Related PR: #61382

Problem Summary:
Dropping a stream base table left the stream enabled and non-stale in
information_schema.table_streams. Recoverable drops could also keep using
the cached dropped table instead of resolving the persisted base table
identity.

Root cause: BaseTableStream.getBaseTableNullable() retained a cached
Table after it was marked dropped, while isDisabled(), isStale(), and
getStaleReason() only returned their persisted flags.

Change Summary:

File Change Description
BaseTableStream.java Invalidate dropped cached tables and derive availability and stale status from base table resolution.
TableStreamManager.java Preserve base table qualifiers when the table is unavailable and report its type as N/A.
TableStreamBaseTableInfo.java Log expected unavailable base table resolution at debug level.
DropTableStreamTest.java Cover recoverable drop, recovery, force drop, and same-name table recreation.
Regression test Cover direct stream state and readability before base table drop and after recovery. Skip Cloud because ROW binlog is unsupported there.
stateDiagram-v2
    [*] --> Available
    Available --> Stale: drop base table
    Stale --> Available: recover original table ID
    Stale --> Stale: create same-name table with new ID
Loading

Release note

Streams whose base tables are unavailable are now reported disabled and
stale.

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

    Local verification:

    • ./run-fe-ut.sh --run org.apache.doris.catalog.DropTableStreamTest (4 tests)
    • env DISABLE_BUILD_UI=ON ./build.sh --fe
    • Regression coverage is included; buildall is requested for cluster validation.
  • Behavior changed:

    • No.
    • Yes. Streams are disabled and stale while their base tables are unavailable, and recover when the original table ID returns.
  • 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?

@seawinde

Copy link
Copy Markdown
Member Author

run buildall

@morrySnow

Copy link
Copy Markdown
Contributor

/review

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17673	4064	4084	4064
q2	1996	317	198	198
q3	10312	1382	818	818
q4	4681	470	347	347
q5	7509	863	549	549
q6	189	173	141	141
q7	771	846	613	613
q8	9592	1648	1637	1637
q9	6208	4378	4377	4377
q10	6880	1722	1479	1479
q11	504	359	322	322
q12	732	589	471	471
q13	18142	3402	2794	2794
q14	262	260	254	254
q15	q16	791	785	712	712
q17	1023	1060	1043	1043
q18	7190	5760	5526	5526
q19	1338	1249	1026	1026
q20	808	686	578	578
q21	5976	2653	2440	2440
q22	437	371	304	304
Total cold run time: 103014 ms
Total hot run time: 29693 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4615	4460	4357	4357
q2	303	317	222	222
q3	4542	4920	4381	4381
q4	2034	2164	1355	1355
q5	4362	4260	4304	4260
q6	230	179	131	131
q7	2100	1979	1611	1611
q8	2477	2239	2116	2116
q9	7800	7793	7672	7672
q10	4694	4620	4197	4197
q11	592	406	543	406
q12	760	765	552	552
q13	3214	3570	3041	3041
q14	299	301	296	296
q15	q16	721	736	625	625
q17	1353	1363	1371	1363
q18	8071	7383	6790	6790
q19	1108	1069	1093	1069
q20	2219	2223	1947	1947
q21	5270	4548	4486	4486
q22	520	462	399	399
Total cold run time: 57284 ms
Total hot run time: 51276 ms

@hello-stephen

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

query5	4336	623	494	494
query6	464	228	203	203
query7	5014	619	350	350
query8	347	190	170	170
query9	8766	4167	4178	4167
query10	477	365	317	317
query11	5912	2331	2104	2104
query12	147	101	102	101
query13	1252	604	423	423
query14	6252	5212	4933	4933
query14_1	4275	4203	4229	4203
query15	210	197	178	178
query16	988	492	454	454
query17	1033	729	581	581
query18	2428	474	354	354
query19	213	212	152	152
query20	112	104	107	104
query21	231	160	137	137
query22	13606	13510	13370	13370
query23	17496	16518	16122	16122
query23_1	16183	16273	16309	16273
query24	7478	1767	1297	1297
query24_1	1326	1308	1305	1305
query25	570	443	395	395
query26	1374	364	211	211
query27	2561	601	389	389
query28	4471	2050	2019	2019
query29	1098	641	529	529
query30	344	280	241	241
query31	1120	1106	982	982
query32	118	64	66	64
query33	571	324	267	267
query34	1187	1135	672	672
query35	767	781	675	675
query36	1013	1044	876	876
query37	155	105	128	105
query38	1873	1690	1636	1636
query39	887	860	845	845
query39_1	829	832	840	832
query40	248	161	139	139
query41	66	61	63	61
query42	92	91	88	88
query43	328	333	288	288
query44	1499	800	782	782
query45	194	182	173	173
query46	1065	1228	758	758
query47	2105	2108	1985	1985
query48	418	428	291	291
query49	577	419	330	330
query50	1060	427	349	349
query51	10570	10470	10669	10470
query52	87	89	76	76
query53	268	282	214	214
query54	276	241	239	239
query55	77	70	64	64
query56	320	288	300	288
query57	1348	1294	1198	1198
query58	324	270	254	254
query59	1625	1727	1505	1505
query60	339	273	251	251
query61	158	152	147	147
query62	540	495	430	430
query63	249	206	205	205
query64	2818	1038	836	836
query65	4718	4633	4606	4606
query66	1821	500	386	386
query67	29511	29249	28965	28965
query68	2972	1493	964	964
query69	413	304	264	264
query70	915	814	819	814
query71	372	334	318	318
query72	3047	2717	2408	2408
query73	826	780	472	472
query74	5060	4896	4732	4732
query75	2532	2497	2128	2128
query76	2335	1178	812	812
query77	365	376	294	294
query78	11836	11892	11292	11292
query79	1420	1141	772	772
query80	1350	600	503	503
query81	527	344	298	298
query82	592	161	122	122
query83	394	337	309	309
query84	318	169	139	139
query85	1017	607	502	502
query86	420	254	232	232
query87	1843	1836	1744	1744
query88	3885	2891	2865	2865
query89	447	382	334	334
query90	1933	201	201	201
query91	207	195	164	164
query92	65	60	56	56
query93	1697	1584	1036	1036
query94	746	355	305	305
query95	792	494	461	461
query96	1074	852	359	359
query97	2612	2614	2481	2481
query98	210	204	200	200
query99	1099	1117	971	971
Total cold run time: 263822 ms
Total hot run time: 177743 ms

@hello-stephen

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

query1	0.01	0.01	0.01
query2	0.10	0.05	0.04
query3	0.25	0.13	0.13
query4	1.61	0.14	0.14
query5	0.25	0.22	0.23
query6	1.15	0.83	0.80
query7	0.03	0.01	0.01
query8	0.06	0.04	0.04
query9	0.38	0.32	0.32
query10	0.53	0.58	0.57
query11	0.19	0.13	0.14
query12	0.18	0.15	0.14
query13	0.47	0.48	0.47
query14	1.02	1.01	1.00
query15	0.62	0.59	0.60
query16	0.33	0.33	0.34
query17	1.09	1.14	1.09
query18	0.24	0.22	0.23
query19	2.02	1.97	1.92
query20	0.02	0.01	0.02
query21	15.42	0.22	0.13
query22	4.76	0.05	0.05
query23	16.12	0.31	0.14
query24	3.00	0.42	0.33
query25	0.11	0.05	0.04
query26	0.72	0.20	0.14
query27	0.05	0.06	0.03
query28	3.51	0.90	0.55
query29	12.55	4.16	3.30
query30	0.27	0.15	0.16
query31	2.77	0.59	0.32
query32	3.22	0.59	0.50
query33	3.28	3.21	3.33
query34	15.58	4.27	3.55
query35	3.49	3.48	3.51
query36	0.56	0.43	0.42
query37	0.09	0.07	0.06
query38	0.04	0.03	0.03
query39	0.03	0.03	0.03
query40	0.19	0.15	0.14
query41	0.08	0.03	0.04
query42	0.04	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 96.47 s
Total hot run time: 24.87 s

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

Request changes: the drop/recovery behavior is largely implemented, but two correctness issues remain: concurrent readers can null-dereference the volatile cached base table, and available streams report stale qualifiers after supported same-ID rename operations.

Review checkpoints

  • Goal and proof: derived disabled/stale state fixes ordinary recoverable drop, original-ID recovery, force drop, and same-name/new-ID recreation. The added unit and IVM regression coverage exercise those paths, but rename coverage would expose MAIN-001.
  • Scope and clarity: the change is focused on stream lifecycle state and metadata; no unrelated source changes were found.
  • Concurrency: drop/recovery publication and all getter callers were traced. MAIN-002 is a reachable shared-reader race; no separate persistent cleanup/planner race was substantiated.
  • Lifecycle: the runtime cache, Table.isDropped, database registration, recycle-bin recovery, checkpoint load, and journal replay were reviewed. ID-based recovery is sound apart from the accepted issues.
  • Configuration and compatibility: no configuration, storage-format, function-symbol, schema-column, or FE-BE protocol change is introduced.
  • Parallel paths and conditions: table drop, force drop, database drop/recovery, table/database rename, renamed recovery, planner binding, cleanup, metadata, and SHOW CREATE STREAM were checked. Rename paths produce MAIN-001.
  • Tests and results: test SQL ordering/output conventions are correct and the new result file is marked generated. This runner is review-only, so I did not execute builds or tests.
  • Observability: the missing-table state is visible through table_streams and planner errors; lowering repeated missing-resolution logging to debug is acceptable.
  • Persistence, transactions, and data writes: explicit flags and base-table IDs remain serialized; no new transaction, EditLog schema, data-write, or master-failover issue was found.
  • Performance and other concerns: repeated missing-table resolution is bounded to metadata/cleanup lookups; no additional material performance, memory, or static-initialization issue was found.
  • User focus: no additional user-provided review focus was supplied; the full PR was reviewed.

Review completion: complete for the frozen head after the required bounded subagent convergence and final live-state verification.


public TableIf getBaseTableNullable() {
if (baseTable instanceof Table && ((Table) baseTable).isDropped) {
baseTable = null;

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] Snapshot the volatile base table before dereferencing it

The two baseTable occurrences in this condition are separate volatile reads. After a drop marks the cached table dropped, two concurrent readers can both pass the instanceof; one can then execute baseTable = null before the other evaluates ((Table) baseTable).isDropped, causing that reader to dereference null. Concurrent table_streams requests are sufficient because the stream read lock admits multiple readers. Copy the field to one local snapshot, inspect that snapshot, and resolve/publish the replacement once.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6baebd9e78a. getBaseTableNullable() now snapshots the volatile field into cachedBaseTable and uses that local for the dropped check and return path. Clearing the shared cache can no longer change the value being dereferenced by another reader.

// STREAM_COMMENT
trow.addToColumnValue(new TCell().setStringVal(stream.getComment()));
List<String> baseTableQualifiers = stream.getBaseTableFullQualifiers();
// BASE_TABLE_NAME

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] Use live qualifiers while the base table is available

TableStreamBaseTableInfo keeps the creation-time names but resolves internal tables by ID. After a supported same-ID rename (ALTER TABLE old RENAME new or RECOVER TABLE old AS new), this line still emits old even though the stream resolves successfully and is reported enabled; SHOW CREATE STREAM emits new, and callers filtering table_streams by the current base name miss the stream. Resolve baseTable first and use baseTable.getFullQualifiers() when it is non-null, falling back to the stored qualifiers only for the unavailable-table case.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6baebd9e78a. table_streams now resolves the base table first and uses baseTable.getFullQualifiers() while it is available. Stored qualifiers are only the final fallback when neither the live table nor a same-ID recycle-bin entry is available. The unit test covers ALTER TABLE ... RENAME and RECOVER TABLE ... AS.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

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

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 41.67% (5/12) 🎉
Increment coverage report
Complete coverage report

@seawinde
seawinde force-pushed the fix-table-stream-stale-on-base-table-drop branch from 2d14096 to bf0a7de Compare July 30, 2026 13:27
@seawinde

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17738	3982	3954	3954
q2	2434	310	210	210
q3	10967	1347	793	793
q4	4700	463	335	335
q5	7733	852	558	558
q6	176	166	134	134
q7	771	828	605	605
q8	9853	1508	1534	1508
q9	7009	4340	4303	4303
q10	7090	1704	1435	1435
q11	839	356	337	337
q12	787	587	447	447
q13	18112	3332	2737	2737
q14	263	262	236	236
q15	q16	786	763	710	710
q17	1042	991	931	931
q18	7189	6018	5510	5510
q19	1202	1249	949	949
q20	789	677	598	598
q21	5710	2576	2351	2351
q22	424	370	298	298
Total cold run time: 105614 ms
Total hot run time: 28939 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4364	4274	4255	4255
q2	280	307	209	209
q3	4572	5047	4334	4334
q4	2048	2132	1363	1363
q5	4328	4249	4556	4249
q6	233	174	130	130
q7	1841	1741	1442	1442
q8	2255	1995	1956	1956
q9	7532	7588	7758	7588
q10	4723	4611	4101	4101
q11	560	400	380	380
q12	749	744	543	543
q13	3181	3587	2870	2870
q14	293	295	269	269
q15	q16	735	739	630	630
q17	1302	1430	1249	1249
q18	7288	6955	7079	6955
q19	1214	1172	1109	1109
q20	2236	2275	1955	1955
q21	5391	4789	4634	4634
q22	538	481	407	407
Total cold run time: 55663 ms
Total hot run time: 50628 ms

@hello-stephen

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

query5	4315	632	488	488
query6	500	213	217	213
query7	4993	572	357	357
query8	343	187	167	167
query9	9334	4239	4241	4239
query10	454	365	321	321
query11	5867	2344	2168	2168
query12	173	103	116	103
query13	1287	603	454	454
query14	6293	5176	4886	4886
query14_1	4257	4251	4215	4215
query15	207	204	175	175
query16	3405	480	441	441
query17	1116	686	554	554
query18	2381	457	334	334
query19	224	187	148	148
query20	110	107	105	105
query21	620	156	133	133
query22	13504	13430	13292	13292
query23	17325	16800	16331	16331
query23_1	16324	16372	16389	16372
query24	8179	1835	1370	1370
query24_1	1351	1338	1353	1338
query25	568	442	410	410
query26	1537	341	206	206
query27	2450	611	387	387
query28	4420	1997	1992	1992
query29	1045	588	485	485
query30	348	254	217	217
query31	1104	1111	970	970
query32	105	56	55	55
query33	503	293	240	240
query34	1225	1117	653	653
query35	757	760	651	651
query36	1015	999	875	875
query37	154	99	86	86
query38	1866	1704	1645	1645
query39	872	874	844	844
query39_1	824	838	883	838
query40	237	156	135	135
query41	63	64	58	58
query42	90	89	96	89
query43	336	320	284	284
query44	1417	772	792	772
query45	185	175	176	175
query46	1050	1180	743	743
query47	2111	2107	1958	1958
query48	404	419	298	298
query49	564	412	299	299
query50	1135	416	380	380
query51	10984	10902	10908	10902
query52	82	83	72	72
query53	255	279	200	200
query54	297	235	213	213
query55	72	68	63	63
query56	277	302	275	275
query57	1341	1294	1203	1203
query58	286	251	270	251
query59	1558	1621	1483	1483
query60	307	267	251	251
query61	153	148	148	148
query62	561	486	443	443
query63	242	197	196	196
query64	2390	995	981	981
query65	4751	4643	4673	4643
query66	1734	507	391	391
query67	29133	29258	29059	29059
query68	3270	1599	954	954
query69	443	309	271	271
query70	920	844	837	837
query71	372	323	344	323
query72	3247	2861	2523	2523
query73	855	774	457	457
query74	5112	4899	4685	4685
query75	2532	2502	2141	2141
query76	1933	1144	762	762
query77	351	387	329	329
query78	11872	11913	11333	11333
query79	2283	1219	753	753
query80	1394	548	457	457
query81	521	318	281	281
query82	630	155	118	118
query83	374	321	294	294
query84	270	162	128	128
query85	997	617	528	528
query86	438	242	237	237
query87	1824	1820	1755	1755
query88	3760	2854	2818	2818
query89	429	365	329	329
query90	1910	194	198	194
query91	207	190	161	161
query92	62	59	51	51
query93	1817	1530	980	980
query94	709	314	279	279
query95	763	599	474	474
query96	1065	775	378	378
query97	2646	2594	2479	2479
query98	208	205	194	194
query99	1079	1110	974	974
Total cold run time: 268412 ms
Total hot run time: 178423 ms

@seawinde
seawinde force-pushed the fix-table-stream-stale-on-base-table-drop branch from bf0a7de to 8a8eec2 Compare July 30, 2026 14:25
@seawinde

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.10	0.05	0.05
query3	0.26	0.13	0.13
query4	1.61	0.14	0.14
query5	0.24	0.23	0.22
query6	1.17	0.84	0.78
query7	0.04	0.01	0.01
query8	0.06	0.04	0.04
query9	0.40	0.31	0.31
query10	0.54	0.53	0.54
query11	0.20	0.13	0.14
query12	0.24	0.14	0.14
query13	0.47	0.47	0.46
query14	1.03	1.01	1.02
query15	0.63	0.58	0.59
query16	0.31	0.33	0.33
query17	1.12	1.13	1.16
query18	0.26	0.20	0.21
query19	2.03	1.91	1.96
query20	0.02	0.01	0.01
query21	15.52	0.18	0.14
query22	4.94	0.05	0.06
query23	16.13	0.31	0.12
query24	3.42	0.40	0.32
query25	0.12	0.07	0.05
query26	0.79	0.20	0.16
query27	0.05	0.03	0.04
query28	3.58	0.89	0.52
query29	12.61	4.09	3.26
query30	0.28	0.16	0.17
query31	2.77	0.63	0.31
query32	3.21	0.59	0.48
query33	3.19	3.15	3.27
query34	15.63	4.26	3.53
query35	3.58	3.54	3.56
query36	0.66	0.43	0.43
query37	0.10	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.19	0.17	0.15
query41	0.09	0.04	0.03
query42	0.04	0.03	0.02
query43	0.05	0.04	0.04
Total cold run time: 97.78 s
Total hot run time: 24.73 s

@seawinde

Copy link
Copy Markdown
Member Author

/review

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17663	4106	4035	4035
q2	2075	312	195	195
q3	10248	1355	784	784
q4	4679	466	333	333
q5	7479	842	554	554
q6	187	175	136	136
q7	752	815	630	630
q8	9336	1583	1589	1583
q9	6035	4334	4303	4303
q10	6788	1693	1459	1459
q11	515	344	312	312
q12	720	581	469	469
q13	18122	3314	2800	2800
q14	261	255	243	243
q15	q16	781	783	707	707
q17	974	943	936	936
q18	6757	5679	5553	5553
q19	1338	1252	1033	1033
q20	817	648	585	585
q21	5882	2641	2356	2356
q22	430	354	304	304
Total cold run time: 101839 ms
Total hot run time: 29310 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4526	4495	4460	4460
q2	290	329	208	208
q3	4599	4931	4418	4418
q4	2118	2124	1356	1356
q5	4497	4298	4256	4256
q6	232	177	129	129
q7	1757	1912	1726	1726
q8	2577	2248	2156	2156
q9	7878	7864	7686	7686
q10	4660	4647	4140	4140
q11	556	416	377	377
q12	757	739	535	535
q13	3519	3620	2910	2910
q14	313	336	295	295
q15	q16	707	743	639	639
q17	1442	1351	1356	1351
q18	8014	7191	7204	7191
q19	1119	1058	1104	1058
q20	2226	2218	1939	1939
q21	5353	4583	4471	4471
q22	526	462	416	416
Total cold run time: 57666 ms
Total hot run time: 51717 ms

@hello-stephen

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

query5	4323	645	470	470
query6	471	224	198	198
query7	4861	606	333	333
query8	347	183	169	169
query9	8778	4025	4040	4025
query10	484	361	294	294
query11	5912	2330	2140	2140
query12	150	104	103	103
query13	1268	602	451	451
query14	6252	5188	4873	4873
query14_1	4201	4196	4182	4182
query15	212	201	176	176
query16	1031	455	429	429
query17	1098	718	537	537
query18	2634	444	328	328
query19	200	184	139	139
query20	111	105	104	104
query21	242	155	136	136
query22	13587	13540	13421	13421
query23	17240	16521	16044	16044
query23_1	16226	16128	16234	16128
query24	7523	1766	1267	1267
query24_1	1288	1279	1273	1273
query25	547	465	388	388
query26	1334	352	216	216
query27	3170	627	401	401
query28	4563	2132	2095	2095
query29	1082	645	518	518
query30	346	270	243	243
query31	1131	1125	1002	1002
query32	119	67	64	64
query33	527	332	262	262
query34	1191	1180	660	660
query35	759	785	675	675
query36	1047	1006	888	888
query37	160	103	99	99
query38	1876	1705	1627	1627
query39	883	870	840	840
query39_1	827	845	837	837
query40	262	165	146	146
query41	71	72	69	69
query42	96	97	91	91
query43	326	328	283	283
query44	1434	804	772	772
query45	203	194	172	172
query46	1033	1211	739	739
query47	2114	2058	1968	1968
query48	420	441	272	272
query49	609	460	316	316
query50	1058	419	336	336
query51	10848	11049	11082	11049
query52	89	88	74	74
query53	259	274	204	204
query54	303	252	226	226
query55	75	71	67	67
query56	332	296	301	296
query57	1323	1261	1202	1202
query58	286	275	263	263
query59	1543	1663	1457	1457
query60	310	285	264	264
query61	176	172	174	172
query62	541	499	431	431
query63	242	205	203	203
query64	2936	1040	860	860
query65	4723	4631	4646	4631
query66	1776	486	382	382
query67	29384	29312	29163	29163
query68	3066	1596	1033	1033
query69	415	316	258	258
query70	910	818	823	818
query71	370	339	323	323
query72	3068	2824	2094	2094
query73	826	798	434	434
query74	5109	4892	4722	4722
query75	2540	2490	2135	2135
query76	2356	1144	786	786
query77	361	383	275	275
query78	11807	11714	11356	11356
query79	1447	1151	790	790
query80	1304	558	472	472
query81	517	337	293	293
query82	681	156	120	120
query83	363	318	295	295
query84	286	162	132	132
query85	982	610	526	526
query86	412	242	233	233
query87	1830	1813	1738	1738
query88	3798	2840	2802	2802
query89	439	382	321	321
query90	1957	208	189	189
query91	204	189	163	163
query92	61	58	55	55
query93	1669	1496	1005	1005
query94	720	351	295	295
query95	804	491	466	466
query96	1165	844	364	364
query97	2646	2635	2503	2503
query98	229	211	204	204
query99	1105	1116	970	970
Total cold run time: 264640 ms
Total hot run time: 177733 ms

@hello-stephen

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

query1	0.00	0.00	0.01
query2	0.09	0.05	0.05
query3	0.26	0.14	0.14
query4	1.60	0.14	0.14
query5	0.23	0.22	0.22
query6	1.16	0.83	0.84
query7	0.04	0.01	0.00
query8	0.06	0.04	0.04
query9	0.37	0.32	0.31
query10	0.56	0.57	0.54
query11	0.20	0.14	0.13
query12	0.18	0.14	0.14
query13	0.48	0.48	0.49
query14	1.02	1.01	1.02
query15	0.62	0.61	0.60
query16	0.33	0.32	0.31
query17	1.09	1.15	1.10
query18	0.23	0.20	0.20
query19	2.05	1.95	1.90
query20	0.02	0.02	0.01
query21	15.43	0.22	0.13
query22	4.86	0.05	0.06
query23	16.10	0.30	0.12
query24	2.99	0.41	0.32
query25	0.10	0.07	0.03
query26	0.72	0.22	0.15
query27	0.04	0.03	0.04
query28	3.50	0.92	0.51
query29	12.47	4.09	3.28
query30	0.26	0.14	0.15
query31	2.77	0.60	0.31
query32	3.22	0.58	0.47
query33	3.12	3.26	3.26
query34	15.89	4.24	3.49
query35	3.53	3.49	3.54
query36	0.56	0.43	0.40
query37	0.08	0.07	0.06
query38	0.05	0.04	0.03
query39	0.04	0.03	0.03
query40	0.18	0.16	0.15
query41	0.08	0.03	0.03
query42	0.04	0.03	0.02
query43	0.04	0.04	0.04
Total cold run time: 96.66 s
Total hot run time: 24.69 s

@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: You've hit your usage limit. Visit https://chatgpt.com/codex/settings/usage to purchase more credits or try again at Aug 5th, 2026 4:32 AM.
Workflow run: https://github.com/apache/doris/actions/runs/30552265895

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

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 83.33% (10/12) 🎉
Increment coverage report
Complete coverage report

@seawinde

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.

Request changes: the sequential drop/recovery path works, but the current head still has the two existing P1 blockers and two additional metadata/DDL consistency issues: one table_streams row can mix availability snapshots during concurrent DDL, and SHOW CREATE STREAM loses the latest same-ID base identity while the table is recoverably absent.

Review checkpoints

  • Goal and proof: ordinary drop, same-name recovery, force drop, and same-name/new-ID recreation derive the intended state. The added unit/regression tests and green FE/P0 CI prove those sequential paths, but not the accepted concurrent-row or SHOW CREATE cases.
  • Scope and clarity: the source change is focused on stream availability, metadata, logging, and tests.
  • Concurrency: the stream cache, database/table publication, metadata readers, planner binding, and cleanup locks were traced. Existing thread r3682055286 covers the shared-reader NPE; MAIN-001 covers the distinct single-row snapshot race. No deadlock or further lock-order issue was found.
  • Lifecycle: dropped-cache invalidation, force drop, original-ID recovery, rename/recover-as and subsequent re-drop, image load, and replay were reviewed. MAIN-002 is the newly exposed unavailable-state DDL regression; the remaining ID-based reattachment is sound.
  • Configuration and compatibility: no new config, storage format, function symbol, schema column, or FE-BE protocol is introduced; no rolling-upgrade incompatibility was found.
  • Parallel paths and conditions: metadata, SHOW CREATE, Nereids collection/binding, cleanup, leader/replay, force-drop, and rename paths were checked. Existing thread r3682055289 covers the live-qualifier path; the pre-existing Nereids creation-name lookup was not charged to this diff.
  • Tests and results: ordering/output conventions are correct. Current CI reports FE UT, P0 regression, checkstyle, compile, and the other completed checks green. This review runner forbids local builds/tests, so none were run here; latch-controlled concurrency plus unavailable SHOW CREATE coverage for simple drop and rename/recover-as followed by re-drop are still needed.
  • Observability: lowering expected missing-table resolution to debug and exposing stale state are appropriate; no additional metric is needed.
  • Persistence, transactions, and data writes: IDs and explicit flags remain serialized, transient availability is correctly derived, and no EditLog schema, data-write atomicity, master-failover, or transaction-path issue was found.
  • Performance and remaining concerns: repeated missing-table lookups are limited to metadata/cleanup paths; no material CPU, memory, static-initialization, or FE-BE propagation issue was found beyond the reported findings.
  • User focus: no additional user-provided focus was supplied; the whole PR was reviewed.

Review completion: complete for the frozen head after required bounded subagent convergence and final live-state verification.

// BASE_TABLE_TYPE
trow.addToColumnValue(new TCell().setStringVal(baseTable.getType().name()));
}
trow.addToColumnValue(new TCell().setStringVal(

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.

[P2] Derive the row from one availability snapshot

baseTable is reused only for BASE_TABLE_TYPE; isDisabled(), isStale(), and getStaleReason() each resolve it again. Because base-table drop/recovery uses different locks from this stream read lock, a recovery after the type lookup can emit N/A with enabled/non-stale state, while a drop can emit OLAP with disabled/stale state. Resolve availability once per row and derive all four fields from that snapshot while still combining the persisted flags; a latch-controlled DDL test would cover the interleaving.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6baebd9e78a. fillTableStreamValuesMetadataResult() resolves baseTable once per TRow and passes that snapshot to the qualifier, disabled, stale, and stale-reason calculations. The overloads still combine the snapshot with the persisted disabled/stale flags, so one row can no longer mix pre-drop/post-drop or pre-recovery/post-recovery availability.

}

public TableIf getBaseTableNullable() {
if (baseTable instanceof Table && ((Table) baseTable).isDropped) {

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.

[P2] Preserve the latest base identity before clearing it

Once this branch clears the dropped table, getBaseTableNullable() returns null and Env.getDdlStmt() emits ON TABLE UNKNOWN, making SHOW CREATE STREAM non-round-trippable during a recoverable drop. Falling back directly to TableStreamBaseTableInfo is not enough after old is renamed/recovered as new and dropped again: that descriptor still says old, while the recycle bin can recover only new. Preserve the latest same-ID live qualifiers in replay-equivalent state before clearing them (or resolve that recycle entry by ID), and cover both a simple drop and rename/recover-as followed by re-drop.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6baebd9e78a. For an unavailable internal base table, display qualifiers are resolved from the recycle bin by (dbId, tableId) before falling back to creation-time qualifiers. SHOW CREATE STREAM now uses those qualifiers instead of UNKNOWN. Coverage includes a simple recoverable drop, rename then drop, Gson deserialization as a replay/restart-equivalent path, RECOVER TABLE ... AS, and a second drop retaining the recovered name.

trow.addToColumnValue(new TCell().setStringVal(stream.getScanTypeString()));
// STREAM_COMMENT
trow.addToColumnValue(new TCell().setStringVal(stream.getComment()));
List<String> baseTableQualifiers = stream.getBaseTableFullQualifiers();

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] 基表同 ID 重命名后,table_streams 仍返回旧名称
getBaseTableFullQualifiers() 永远返回创建 stream 时保存的名称(基于basetable info)。

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6baebd9e78a. getBaseTableFullQualifiers() no longer always returns the creation-time qualifiers from baseTableInfo: when the same-ID base table is available, it returns the live table qualifiers, so table_streams reflects ALTER TABLE ... RENAME; when the table is recoverably dropped, it resolves the same-ID recycle-bin entry; only if neither can be resolved does it fall back to the creation-time qualifiers. table_streams also resolves the base table once per row and passes that snapshot into the qualifier calculation. Unit coverage includes ALTER TABLE ... RENAME and RECOVER TABLE ... AS.

@seawinde

seawinde commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

run buildall

@seawinde

seawinde commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

/review

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17661	3986	4048	3986
q2	2022	327	198	198
q3	10286	1375	794	794
q4	4681	468	337	337
q5	7496	853	556	556
q6	181	171	134	134
q7	755	788	595	595
q8	9343	1589	1615	1589
q9	5300	4095	4119	4095
q10	6767	1613	1377	1377
q11	502	347	316	316
q12	731	574	448	448
q13	18116	3317	2750	2750
q14	262	258	246	246
q15	q16	733	729	670	670
q17	1052	1020	1073	1020
q18	6630	5617	5566	5566
q19	1324	1287	1110	1110
q20	808	706	568	568
q21	6128	2624	2452	2452
q22	433	343	293	293
Total cold run time: 101211 ms
Total hot run time: 29100 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4271	4167	4201	4167
q2	278	315	207	207
q3	4539	4994	4365	4365
q4	2405	2299	1404	1404
q5	4233	4108	4108	4108
q6	220	172	126	126
q7	1701	1576	1409	1409
q8	2987	2137	2080	2080
q9	7486	7498	7506	7498
q10	4371	4296	3923	3923
q11	609	397	372	372
q12	713	720	517	517
q13	3223	3522	2931	2931
q14	293	294	280	280
q15	q16	697	710	638	638
q17	1293	1288	1287	1287
q18	12083	11060	11756	11060
q19	1149	1207	1140	1140
q20	2248	2202	1934	1934
q21	5727	4859	4813	4813
q22	540	485	427	427
Total cold run time: 61066 ms
Total hot run time: 54686 ms

@hello-stephen

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

query5	4299	598	446	446
query6	470	218	207	207
query7	4890	587	338	338
query8	317	157	159	157
query9	8776	4041	4055	4041
query10	460	350	284	284
query11	5829	2201	1938	1938
query12	149	107	106	106
query13	1264	596	453	453
query14	6104	4301	3962	3962
query14_1	3794	3776	3771	3771
query15	201	201	177	177
query16	1006	485	442	442
query17	959	717	561	561
query18	2480	462	341	341
query19	204	180	144	144
query20	102	97	107	97
query21	249	153	133	133
query22	13129	12904	12942	12904
query23	15797	14967	14684	14684
query23_1	15422	15138	15004	15004
query24	7694	1697	1224	1224
query24_1	1231	1218	1204	1204
query25	512	417	348	348
query26	1309	351	221	221
query27	2599	593	396	396
query28	4571	1986	2019	1986
query29	1063	608	463	463
query30	326	257	218	218
query31	1175	1113	1029	1029
query32	109	59	56	56
query33	507	299	229	229
query34	1193	1189	639	639
query35	722	755	628	628
query36	767	769	696	696
query37	152	102	87	87
query38	1832	1751	1714	1714
query39	835	803	824	803
query39_1	766	793	770	770
query40	241	166	140	140
query41	63	61	61	61
query42	94	90	88	88
query43	316	328	275	275
query44	1410	745	770	745
query45	177	169	164	164
query46	1070	1159	716	716
query47	1577	1539	1456	1456
query48	407	408	293	293
query49	585	397	283	283
query50	1125	424	355	355
query51	10385	10583	10456	10456
query52	83	89	74	74
query53	267	270	199	199
query54	295	242	236	236
query55	77	75	72	72
query56	352	294	282	282
query57	1025	1015	903	903
query58	311	269	262	262
query59	1562	1609	1356	1356
query60	311	291	265	265
query61	170	172	174	172
query62	412	332	271	271
query63	246	194	196	194
query64	2949	1010	860	860
query65	3867	3780	3794	3780
query66	1833	476	349	349
query67	28287	28179	27957	27957
query68	3423	1546	961	961
query69	414	286	263	263
query70	844	772	771	771
query71	363	354	325	325
query72	3058	2695	2512	2512
query73	836	782	426	426
query74	4642	4492	4267	4267
query75	2379	2331	1997	1997
query76	2411	1149	750	750
query77	350	355	259	259
query78	10879	11146	10460	10460
query79	1142	1089	748	748
query80	616	544	448	448
query81	452	326	282	282
query82	291	171	132	132
query83	315	338	293	293
query84	308	156	132	132
query85	896	653	546	546
query86	280	229	209	209
query87	1971	1946	1845	1845
query88	3649	2815	2767	2767
query89	364	318	285	285
query90	2172	199	202	199
query91	202	189	163	163
query92	62	57	53	53
query93	1548	1500	1041	1041
query94	549	351	336	336
query95	816	594	467	467
query96	1141	750	360	360
query97	2441	2450	2319	2319
query98	193	188	186	186
query99	741	730	610	610
Total cold run time: 252631 ms
Total hot run time: 166374 ms

@hello-stephen

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

query1	0.00	0.00	0.00
query2	0.10	0.05	0.05
query3	0.26	0.14	0.13
query4	1.60	0.14	0.14
query5	0.23	0.22	0.22
query6	1.16	0.80	0.82
query7	0.04	0.01	0.01
query8	0.06	0.03	0.04
query9	0.38	0.32	0.30
query10	0.54	0.57	0.54
query11	0.20	0.14	0.14
query12	0.19	0.14	0.15
query13	0.46	0.46	0.47
query14	1.01	0.99	0.98
query15	0.60	0.58	0.60
query16	0.30	0.34	0.32
query17	1.09	1.13	1.10
query18	0.20	0.19	0.20
query19	2.08	1.97	1.88
query20	0.01	0.01	0.02
query21	15.45	0.19	0.13
query22	5.04	0.05	0.05
query23	16.15	0.32	0.12
query24	2.89	0.41	0.33
query25	0.10	0.06	0.04
query26	0.73	0.20	0.15
query27	0.05	0.03	0.03
query28	3.59	0.81	0.34
query29	12.46	4.09	3.25
query30	0.30	0.14	0.15
query31	2.76	0.54	0.32
query32	3.23	0.59	0.48
query33	3.18	3.24	3.19
query34	15.54	3.90	3.28
query35	3.23	3.20	3.23
query36	0.54	0.43	0.43
query37	0.08	0.07	0.06
query38	0.05	0.04	0.04
query39	0.03	0.04	0.03
query40	0.18	0.15	0.14
query41	0.09	0.03	0.03
query42	0.04	0.03	0.03
query43	0.05	0.04	0.04
Total cold run time: 96.27 s
Total hot run time: 23.87 s

@seawinde

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.

Request changes: the stable-ID drop and recovery lifecycle is largely correct, but planner collection has one P1 correctness bug: an implicit stream-base lock dependency can overwrite an explicitly resolved relation in the shared name cache.

Review checkpoints

  • Goal and proof: The patch dynamically reports the stream disabled/stale while its stable-ID base is unavailable and resumes the same base object after recovery. The FE tests cover the sequential lifecycle and the regression proves a real post-recovery scan. The concurrent planner fence described inline remains incorrect.
  • Scope and clarity: The production changes are focused, except that the qualifier-to-relation resolver map is also used as an implicit lock-resource set, which causes the accepted finding.
  • Concurrency and locking: I traced query collection/binding against table and database drop, rename, and recovery, plus metadata, recycle, and cleanup actors. Post-lock ID-ordered acquisition has no new deadlock or reverse lock order; the pre-lock unconditional cache overwrite is the P1 issue.
  • Lifecycle, persistence, and compatibility: Stable-ID invalidation, same-object recovery, Gson/edit-log/replay, cleanup, and consumption paths are consistent on ordinary schedules. The patch adds no configuration, FE/BE protocol, storage-format, serialized availability field, or rolling-upgrade concern.
  • Parallel and conditional paths: QUERY and INSERT_TARGET paths, view/CTE/subquery recursion, wrapper construction, metadata, SHOW CREATE, consumption, and cleanup were checked. A detached-base qualifier dereference is another manifestation of the accepted cache/resource abstraction bug; other name-durability concerns duplicate existing review threads.
  • Tests and results: The changed expected output is deterministic, and the current head's FE unit, P0 regression, compile, and style checks are green. Per the review-only instructions, I did not run local builds or tests. A latch-controlled rename/collision test is still needed for the inline finding.
  • Observability, performance, and data writes: Metadata exposes state and reason, expected absence logging avoids warning spam, and the added ordinary-path work is constant time. No distinct transaction, data-write, master-failover, or material performance issue survived review.
  • User focus: No additional focus was supplied, so the full PR was reviewed.
  • Completion: Converged after two complete rounds, each with two normal full-scope reviews and one separate risk-focused review. One new distinct inline finding survived live duplicate suppression.

default:
throw new AnalysisException("Unknown table from " + tableFrom);
}
tables.put(baseTable.getFullQualifiers(), baseTable);

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 stream lock dependencies out of the relation cache

Reduced plan:

Join
  UnboundRelation(db.b)  // table B
  UnboundRelation(db.s)  // stream base A, currently named a

If collection first caches db.b -> B, another session can rename B: b -> c and A: a -> b before the collector visits s. This unconditional put then replaces the already-resolved db.b entry with A. StatementContext.lock() omits B, and BindRelation.getAndCacheTable(db.b, ...) returns A, so the bound tree scans A for both branches and can silently return the wrong rows. This is distinct from the existing replacement-table thread: the stream base is resolved by the correct stable ID here, but the new write corrupts an explicit relation already fenced in the cache. Please keep implicit base lock resources in a separate ID/object-keyed collection consumed by lock(), and cover this pre-lock rename interleaving with a latch-controlled test.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in a7850adc43a.

CollectRelation now only validates that the stream base resolves by its persisted stable ID; it no longer writes the implicit base object into the qualifier-to-relation cache. StatementContext.lock() expands each collected BaseTableStream into its stable-ID base table only in the existing local ID-ordered lock queue. This keeps tables[db.b] -> B intact while still locking both the explicit table B and stream base A. No additional statement-level dependency collection was introduced. The external-metadata preload guard also recognizes the implicit stream-base plan lock.

Added coverage for:

  • a latch-controlled pre-lock interleaving that collects B, renames B: b -> c and A: a -> b, then verifies tables[db.b] remains B while the stream still resolves A by stable ID;
  • locking both the explicit relation and stream base without locking the stream object or replacing the relation cache entry;
  • recognizing the stream base lock in external metadata preload.

Rebased onto the latest master and verified with:
./run-fe-ut.sh --run org.apache.doris.catalog.DropTableStreamTest,org.apache.doris.nereids.StatementContextTest,org.apache.doris.nereids.trees.plans.ExplainTableStreamPlanTest

Result: 40 tests run, 0 failures, 0 errors, and the FE reactor finished with BUILD SUCCESS.

Issue Number: N/A

Related PR: yujun777#29

Problem Summary: Dropping a stream base table left the stream enabled
and non-stale because its runtime cache continued returning the dropped
table. Derive stream availability from the persisted base table identity,
preserve diagnostic qualifiers when the table is unavailable, and allow
recovery only when the original table ID returns. Add unit and regression
coverage for drop, recover, and force-drop behavior.

Streams whose base tables are unavailable are now reported disabled and
stale.

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.catalog.DropTableStreamTest
      (4 tests)
    - env DISABLE_BUILD_UI=ON ./build.sh --fe
- Behavior changed: Yes. Streams become disabled and stale while their
  base tables are unavailable.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#61382

Problem Summary: Stream metadata could dereference a concurrently cleared base table, mix availability states within one table_streams row, and keep creation-time base table names after same-ID rename or recovery. Resolve the base table once per metadata row, use live qualifiers when available, and recover the latest dropped-table identity from the recycle bin for SHOW CREATE without adding persistent state.

### Release note

Stream metadata and SHOW CREATE STREAM now preserve consistent, current base table identity across rename, drop, and recovery.

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.catalog.DropTableStreamTest (5 tests passed before the final SHOW CREATE assertion; the final source and test compilation passed, but rerunning was blocked by an external IntelliJ JPS error-stub class in target/test-classes)
    - env DISABLE_BUILD_UI=ON ./build.sh --fe --clean (passed with 0 checkstyle violations before the external JPS process began overwriting target classes)
- Behavior changed: Yes. Stream metadata uses one base-table availability snapshot and preserves the latest same-ID base table qualifiers.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#66287

Problem Summary: A recycled base table retained its pre-rename database name. Resolving full qualifiers through that detached table could dereference a missing database after the database was renamed. Resolve internal database qualifiers by stable database ID and read only the table name from live or recycled table metadata, with persisted names as fallback.

### Release note

Streams with recycled base tables continue to expose valid qualifiers after database rename.

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.catalog.DropTableStreamTest
- Behavior changed: Yes. Stream metadata uses the current internal database name after database rename.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66287

Problem Summary: Stream relation collection previously re-resolved a renamed or recovered base table by display name, which could cache and lock a same-name replacement while binding later resolved the original table by stable ID. Cache the ID-resolved base table directly so the planner locks the object used during stream binding, while preserving the existing missing-table error message.

### Release note

None

### Check List (For Author)

- Test: FE unit test

    - ./run-fe-ut.sh --run org.apache.doris.catalog.DropTableStreamTest

- Behavior changed: No

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

Issue Number: close apache#65418

Related PR: apache#66287

Problem Summary: The previous stable-ID locking fix cached a stream base table under its current name qualifier. A pre-lock rename could therefore overwrite an explicit relation already resolved under the same qualifier and make binding scan the wrong table. Keep the relation cache limited to SQL relations and expand each stream base table by stable ID only when constructing the existing ordered lock queue.

### Release note

None

### Check List (For Author)

- Test: FE unit test and FE build
    - ./run-fe-ut.sh --run org.apache.doris.nereids.StatementContextTest,org.apache.doris.nereids.trees.plans.ExplainTableStreamPlanTest
    - ./run-fe-ut.sh --run org.apache.doris.catalog.DropTableStreamTest
    - env DISABLE_BUILD_UI=ON ./build.sh --fe
- Behavior changed: Yes. Explicit relation bindings are preserved while stream base tables are locked by stable ID.
- Does this need documentation: No
@seawinde
seawinde force-pushed the fix-table-stream-stale-on-base-table-drop branch from a0238b2 to a7850ad Compare August 11, 2026 03:31
@seawinde

Copy link
Copy Markdown
Member Author

run buildall

@seawinde

Copy link
Copy Markdown
Member Author

/review

### What problem does this PR solve?

Issue Number: close apache#65418

Related PR: apache#66287

Problem Summary: Document why stream base tables are validated by stable ID without entering the qualifier relation cache, and why implicit base dependencies are expanded only in the local ID-ordered planner lock queue. The comments preserve the concurrency invariant behind the relation-cache collision fix.

### Release note

None

### Check List (For Author)

- Test: FE unit test
    - ./run-fe-ut.sh --run org.apache.doris.nereids.StatementContextTest,org.apache.doris.nereids.trees.plans.ExplainTableStreamPlanTest
- Behavior changed: No
- Does this need documentation: No
@seawinde

Copy link
Copy Markdown
Member Author

run buildall

@seawinde

Copy link
Copy Markdown
Member Author

/review

@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Codex completed, but no new pull request review was submitted for the current head SHA.
Workflow run: https://github.com/apache/doris/actions/runs/31456168401

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

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

Requesting changes: the sequential drop/recover behavior works, but three correctness and concurrency gaps remain. Recovery can expose a still-dropped table as available, MTMVs over streams lose the actual OLAP dependency and can remain stale, and a drop/recover race can bypass external-metadata preload and perform remote work under an internal table lock.

Critical checkpoint conclusions

  • Goal and proof: the code makes streams disabled/stale while their stable-ID base is unavailable and restores them when that ID returns; the unit and regression additions prove the sequential path, but not the three inline scenarios.
  • Scope: the 12-file FE/test change is focused on stream availability, qualifiers, planner dependencies, and coverage; no unrelated production change was found.
  • Concurrency: metadata readers, recovery DDL, and planner threads access the volatile base cache under different database/table/recycle/stream locks. ID-ordered planner acquisition and release accounting are otherwise sound, but the publication and preload phase races remain.
  • Lifecycle: normal/force/replay drop, recovery/replay recovery, rename, recycle erasure, Gson reload, and wrapper binding were traced. Stable IDs fence same-name replacements, and no lock-order cycle, static-initialization issue, or leaked lifecycle was found.
  • Configuration: no configuration item was added or changed.
  • Compatibility: no FE-BE symbol, thrift field, storage format, or new persisted field was introduced; existing image and replay state remains compatible.
  • Parallel paths: query, insert-target, and MTMV maps all reach the ID-ordered lock expansion. Non-lock dependency consumers do not receive the implicit base, producing the MTMV issue called out inline; audit/view-dependency effects share that root cause.
  • Conditions and error handling: missing bases fail planning and expected missing-base logging is appropriately DEBUG, but a cache-miss lookup does not apply the same dropped-state condition as the cached path.
  • Test coverage: JUnit 5 and ordered regression coverage exercise sequential drop/recover, rename, force drop, reload, metadata, and lock-cache behavior. The accepted findings need an MTMV refresh case and latch-controlled recovery/preload races.
  • Test results: the added .out rows are ordered and consistent with the SQL. This review runner performed no build or test, as required by the review instructions, so author/CI results were not independently reproduced here.
  • Observability: table_streams exposes the new state and DEBUG logging avoids expected warning noise; no additional metric is required for this metadata path.
  • Transaction and persistence: no transaction protocol or EditLog schema changed; persisted stream identity and replay-equivalent paths were checked.
  • Data writes: the production change does not add a data-write path; the MTMV finding affects refresh/freshness correctness after writes to the base.
  • FE-BE variables and nullable handling: no new FE-BE variable or BE nullable path is involved.
  • Performance: no general hot-path regression was found; the accepted preload race can move connector metadata I/O back under an internal table lock.
  • Other issues: existing qualifier and relation-cache threads were duplicate-fenced, including the SHOW CREATE residual. No security-sensitive behavior was requested or reviewed, and no further non-duplicate issue remained.

User focus: review_focus.txt supplied no additional focus, so the entire PR and all required checkpoints were reviewed.

Review completion: converged after Round 2; both normal full-review subagents and the independent risk challenger returned NO_NEW_VALUABLE_FINDINGS, and every ledger candidate is accepted, dismissed, or duplicate-fenced.

return null;
}
if (cachedBaseTable == null) {
cachedBaseTable = baseTableInfo.getTableNullable();

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.

[P2] Recheck dropped state after resolving a cache miss

During RECOVER TABLE, innerRecoverTable() holds A's write lock, but Database.registerTable() publishes A in the ID/name maps before calling unmarkDropped(). An unlocked table_streams request can therefore reach this cache-miss branch while A.isDropped is still true. Because the looked-up value is cached and returned without the dropped check applied to the initial snapshot, that row reports OLAP/enabled/non-stale before recovery has made the table available. Please make publication atomic to unlocked readers or apply the same dropped-state check to the resolved candidate, and add a latch test paused between map publication and unmarkDropped().

// we need to collect stream table's base table as well
if (table instanceof BaseTableStream) {
collectFromTableStream((BaseTableStream) table, cascadesContext, tableFrom, unboundRelation);
collectFromTableStream((BaseTableStream) table);

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] Preserve the stream base in MTMV dependency tracking

Reduced plan:

MTMV M
  UnboundRelation(S)  // stream over OLAP table T

This change validates T but leaves StatementContext.tables containing only S; T is reintroduced only in the local lock queue. Both MTMV creation and every refresh build MTMVRelation from getTables().values(), so T is absent. Since S is not MTMVRelatedTableIf, isSyncWithBaseTable() treats it as synchronized and snapshot generation skips it, allowing a commit to T to leave M considered fresh and absent from T's invalidation relation. Keep the stable base in a separate ID/object-keyed dependency collection consumed by locking and MTMV relation/snapshot tracking (without putting it back in the qualifier cache), and add an async-MV-over-stream refresh test.

}
if (tableIf instanceof BaseTableStream) {
// Mirror addTablesToLock(): a stream needs no plan lock itself, but its stable-ID base may need one.
TableIf baseTable = ((BaseTableStream) tableIf).getBaseTableNullable();

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.

[P2] Use one stream-base snapshot for preload and locking

For Join(S on internal A, external E), collection can validate A, A can be dropped before this preload gate (so the preload result is memoized as skipped), and A can recover before lock() resolves it again and acquires A's read lock. Binding E then still loads its snapshot/schema while that internal lock is held, defeating the preload boundary that keeps remote metadata work outside table locks. Freeze the stable stream-base dependency during collection and use the same set for both preload gating and ID-ordered locking (or conservatively treat a collected stream as a possible lock dependency), with a latch-controlled drop/gate/recover/lock test.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 91.38% (53/58) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17599	4077	3949	3949
q2	2033	327	223	223
q3	10265	1383	798	798
q4	4679	470	334	334
q5	7537	846	561	561
q6	183	169	132	132
q7	753	800	603	603
q8	9336	1482	1484	1482
q9	5277	4078	4045	4045
q10	6722	1612	1351	1351
q11	502	345	322	322
q12	737	594	458	458
q13	18106	3268	2757	2757
q14	262	267	248	248
q15	q16	739	723	656	656
q17	1024	1093	958	958
q18	6624	5615	5538	5538
q19	1218	1221	1159	1159
q20	803	683	596	596
q21	5691	2529	2373	2373
q22	448	356	301	301
Total cold run time: 100538 ms
Total hot run time: 28844 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4294	4193	4197	4193
q2	274	319	205	205
q3	4544	4939	4373	4373
q4	2173	2283	1422	1422
q5	4221	4122	4150	4122
q6	226	175	127	127
q7	1673	1595	1357	1357
q8	2569	2265	2114	2114
q9	7370	7420	7485	7420
q10	4371	4253	3846	3846
q11	553	418	361	361
q12	706	754	519	519
q13	3164	3487	3008	3008
q14	312	312	293	293
q15	q16	749	703	627	627
q17	1304	1297	1275	1275
q18	12194	11015	11787	11015
q19	1156	1224	1124	1124
q20	2223	2203	1935	1935
q21	5639	4917	4818	4818
q22	557	469	414	414
Total cold run time: 60272 ms
Total hot run time: 54568 ms

@hello-stephen

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

query5	4348	594	449	449
query6	484	230	196	196
query7	4874	552	315	315
query8	325	173	147	147
query9	8770	4009	3993	3993
query10	504	362	289	289
query11	5719	2247	2028	2028
query12	155	99	94	94
query13	1243	590	413	413
query14	6032	4246	3958	3958
query14_1	3749	3753	3748	3748
query15	204	196	174	174
query16	983	514	463	463
query17	919	695	548	548
query18	2423	479	346	346
query19	210	191	153	153
query20	103	101	103	101
query21	229	158	133	133
query22	12971	12962	12805	12805
query23	15803	15175	14550	14550
query23_1	15226	15096	15028	15028
query24	8092	1747	1244	1244
query24_1	1212	1231	1245	1231
query25	555	423	348	348
query26	1310	369	215	215
query27	2596	590	371	371
query28	4522	2016	2009	2009
query29	1046	588	472	472
query30	351	253	221	221
query31	1185	1112	1040	1040
query32	86	59	55	55
query33	507	307	240	240
query34	1172	1150	610	610
query35	752	755	626	626
query36	767	753	684	684
query37	153	105	86	86
query38	1827	1777	1695	1695
query39	829	833	779	779
query39_1	788	801	787	787
query40	244	155	141	141
query41	64	61	60	60
query42	91	88	90	88
query43	316	316	277	277
query44	1502	761	749	749
query45	179	171	162	162
query46	1072	1186	741	741
query47	1584	1588	1512	1512
query48	409	409	296	296
query49	581	405	282	282
query50	1109	412	366	366
query51	10745	10417	10587	10417
query52	85	87	75	75
query53	270	281	194	194
query54	279	226	211	211
query55	74	70	65	65
query56	303	303	300	300
query57	1030	1018	932	932
query58	292	301	259	259
query59	1558	1624	1394	1394
query60	313	313	264	264
query61	172	173	168	168
query62	412	341	271	271
query63	239	195	203	195
query64	2981	1113	971	971
query65	3875	3818	3812	3812
query66	1825	500	363	363
query67	20038	20014	20059	20014
query68	3205	1525	1037	1037
query69	422	316	278	278
query70	886	800	764	764
query71	372	345	333	333
query72	3149	2649	2369	2369
query73	892	814	441	441
query74	4640	4522	4285	4285
query75	2462	2401	1979	1979
query76	2353	1173	761	761
query77	341	383	273	273
query78	11187	11196	10581	10581
query79	1395	1172	773	773
query80	1249	563	454	454
query81	522	333	283	283
query82	648	172	137	137
query83	409	326	291	291
query84	326	165	132	132
query85	1017	629	515	515
query86	405	231	228	228
query87	1990	1957	1825	1825
query88	3774	2780	2808	2780
query89	393	320	286	286
query90	1918	204	196	196
query91	202	196	164	164
query92	65	64	58	58
query93	1572	1563	984	984
query94	720	355	336	336
query95	797	591	477	477
query96	1026	836	349	349
query97	2493	2466	2375	2375
query98	200	189	185	185
query99	755	723	611	611
Total cold run time: 246617 ms
Total hot run time: 158345 ms

@hello-stephen

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

query1	0.00	0.00	0.01
query2	0.09	0.04	0.04
query3	0.25	0.13	0.13
query4	1.60	0.13	0.14
query5	0.23	0.22	0.21
query6	1.16	0.79	0.84
query7	0.04	0.01	0.00
query8	0.06	0.04	0.04
query9	0.38	0.30	0.30
query10	0.53	0.54	0.51
query11	0.19	0.14	0.13
query12	0.17	0.14	0.14
query13	0.47	0.46	0.46
query14	1.00	0.98	0.98
query15	0.59	0.58	0.58
query16	0.32	0.32	0.31
query17	1.07	1.06	1.09
query18	0.22	0.20	0.20
query19	2.08	1.93	2.00
query20	0.02	0.01	0.01
query21	15.44	0.21	0.14
query22	4.90	0.05	0.05
query23	16.15	0.31	0.12
query24	2.96	0.39	0.31
query25	0.10	0.05	0.04
query26	0.74	0.21	0.16
query27	0.04	0.03	0.03
query28	3.52	0.82	0.33
query29	12.48	4.05	3.16
query30	0.30	0.15	0.15
query31	2.77	0.54	0.34
query32	3.22	0.59	0.49
query33	3.13	3.18	3.29
query34	15.59	3.93	3.27
query35	3.24	3.22	3.23
query36	0.55	0.43	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.15	0.15
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.05	0.03	0.04
Total cold run time: 96.11 s
Total hot run time: 23.73 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 68.85% (42/61) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 50.60% (42/83) 🎉
Increment coverage report
Complete coverage report

### What problem does this PR solve?

Issue Number: close apache#65418

Related PR: apache#66287

Problem Summary: Stream base tables are implicit planning dependencies resolved by stable table ID. Keeping them in the qualifier-keyed relation cache can overwrite an explicitly resolved relation after concurrent renames, while resolving them again during preload or locking can select a different object snapshot. MTMV relation generation also omitted the underlying stream base after it was removed from the relation cache. Store exact implicit dependency objects separately, reuse them for preload and locking, include them in all-level MTMV dependencies, and reject dropped tables during cache-miss recovery resolution.

### Release note

Streams continue to track and lock their original base tables by stable identity without corrupting explicit relation bindings.

### Check List (For Author)

- Test: Unit Test
    - 43 FE tests passed across DropTableStreamTest, StatementContextTest, ExplainTableStreamPlanTest, and MTMVRelationTest
    - StatementContextTest rerun: 11 tests passed
    - Java compilation and Checkstyle passed
- Behavior changed: Yes. Stream base dependencies use a stable per-statement object snapshot for planning locks and MTMV dependency tracking.
- Does this need documentation: No
@seawinde

Copy link
Copy Markdown
Member Author

run buildall

@seawinde

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.

Requesting changes for two correctness gaps that remain on 25d0c27f52c20efa8496732fcb0ab457e21e9377:

  • P1 — persisted MTMV compatibility: newly analyzed creation/refresh now tracks the stable stream base, but load compatibility does not repair an already persisted malformed relation. The base can remain absent from commit routing and freshness snapshots, allowing stale rewrite results after upgrade.
  • P2 — database recovery lifecycle: the cached-base check observes only Table.isDropped. RECOVER DATABASE clears that flag before the owning database is published, so a cross-database stream can expose the detached base during recovery and potentially after a failed publication attempt.

Critical-checkpoint conclusions:

  • Goal and proof: the patch correctly makes direct table drop/recover affect stream state and repairs stable dependency capture for current planning. The unit/regression additions cover direct table lifecycle, identity capture, locking/preload reuse, and current MTMV relation construction, but they do not prove cross-database recovery or old-image migration; those are the two blocking gaps above.
  • Focus: production changes are otherwise focused on stream availability, stable planner dependencies, and their metadata consumers. No extra user focus was supplied.
  • Concurrency: collection, preload, and locking now reuse one identity-stable dependency snapshot and table locks remain ID-ordered. The remaining race is the database-recovery publication ordering described inline; no additional lock-order cycle was found.
  • Lifecycle: cached stream bases, recycle state, drop/recover-as, force-drop/replacement, replay/load, and erase paths were traced. The table-only lifecycle fence is incomplete for an unpublished owning database.
  • Configuration: no production configuration or dynamic-update contract is added. Test-only flags are isolated by FE Surefire's per-class JVM behavior.
  • Compatibility: there is no FE/BE protocol, symbol, or storage-format change. Catalog rolling-upgrade compatibility is incomplete for an existing MTMV relation that omits the stable stream base.
  • Parallel paths and conditions: both RECOVER TABLE and RECOVER DATABASE, cache-hit/cache-miss resolution, creation/refresh, nested views, preload/locking, invalidation, freshness, and rewrite discovery were checked. The changed dropped-table condition fixes the reported table-recovery path but misses database recovery.
  • Tests and results: the changed tests and ordered .out expectations were inspected for fidelity and determinism. No builds or tests were run because the authoritative review task prohibited execution. Missing async-MTMV coverage already requested in an existing thread was not duplicated.
  • Observability: existing identifiers and log levels are sufficient for the new normal paths; no separate metrics issue was found. The recycle lookup's downgrade to DEBUG did not hide a distinct actionable failure.
  • Persistence and transactions: no data-write transaction path changes. MTMV relation/snapshot persistence and registration were reviewed; the old-relation migration gap is the persistence finding above. Edit-log/replay changes otherwise remain equivalent.
  • Data writes and FE/BE variables: no new data-write atomicity surface or FE-to-BE variable is introduced.
  • Performance: identity deduplication avoids double locking, and no material new CPU, memory, or redundant-work issue was found.
  • Other issues: all 14 changed files, direct consumers, and existing review threads were rechecked. A second full-review round with a separate risk pass converged with no additional valuable findings.

baseTable = baseTableInfo.getTableNullable();
TableIf cachedBaseTable = baseTable;
if (cachedBaseTable != null) {
if (cachedBaseTable instanceof Table && ((Table) cachedBaseTable).isDropped) {

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.

[P2] Keep cached bases unavailable until their database recovers

A stream can live in ds while its base A lives in db. During RECOVER DATABASE db, recoverAllTables() calls Database.registerTable(A) and clears A.isDropped before InternalCatalog.recoverDatabase() republishes and unmarks db. If the stream retained its pre-drop cached pointer (because it was not read while db was dropped), this branch returns A in that gap, so metadata and planning expose it while its owning database is unavailable; if the later catalog lock/name check fails, that exposure can outlive the recovery attempt because the recycle entries were already removed. This is distinct from the existing RECOVER TABLE cache-miss thread because here the table flag already passes. Please fence on the owning database lifecycle as well (or defer clearing member-table dropped flags), and cover cross-database recovery with a latch test.

return Pair.of(Sets.newHashSet(ctx.getStatementContext().getTables().values()),
Set<TableIf> baseTables = Sets.newHashSet(ctx.getStatementContext().getTables().values());
// Implicit dependencies are all-level tables, not relations written at the first query level.
baseTables.addAll(ctx.getStatementContext().getImplicitTableDependencies());

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] Migrate persisted stream dependencies on upgrade

These additions repair newly analyzed creation and refresh, but an MTMV image can already contain stream S without stable base T: old dependency collection could name-resolve replacement B while the stream wrapper still scanned its cached T, then persist a successful refresh as {S, B} with no T snapshot. On load, MTMVRelation.compatible() only normalizes stored entries and MTMV.compatible() re-registers them unchanged. T therefore has no commit-event edge or recorded snapshot, while freshness treats S as synchronous; the MTMV can remain rewrite-eligible with stale rows until a later refresh succeeds. Please expand persisted stream dependencies before registration (or conservatively invalidate them) and add an old-image upgrade test.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 88.41% (61/69) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 72.46% (50/69) 🎉
Increment coverage report
Complete coverage report

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.

4 participants