Skip to content

[feature](ivm) Add the per-partition refresh state and its journal channel - #68193

Merged
gavinchou merged 2 commits into
apache:masterfrom
yujun777:ivm-pr2-upstream-master
Sep 21, 2026
Merged

gavinchou merged 2 commits into
apache:masterfrom
yujun777:ivm-pr2-upstream-master

Conversation

@yujun777

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Trace issue: #65418

This PR adds no behaviour of its own. It adds the state that the following PRs need, and the channel
that persists it, so that they can be reviewed as logic alone.

An IVM materialized view has to invalidate the MV partitions that a base-table change really affected.
A partition drop / truncate / replace / recover changes the base table through metadata and emits no
row binlog, so the affected MV partitions must be rebuilt; today the only answer the MV has is "rebuild
all of them", which throws away partitions that are still correct.

Deciding per partition needs a per-partition answer to two questions:

  • which generation of data does this MV partition currently hold?
  • which generation must it hold?

That pair is MTMVPartitionState { refreshEpoch, latestEpoch }, one entry per MV partition, keyed by
partition name. latestEpoch is the requirement, refreshEpoch is the reality, and a partition whose
requirement is ahead of its reality is dirty: it holds rows read before a change that left no binlog,
so it can no longer be maintained incrementally and has to be rebuilt. The requirement has to survive a
restart, because an invalidation that only lives in memory is lost the moment the FE restarts, and a
partition that is then refreshed incrementally keeps the stale rows forever with no error anywhere.

So this PR adds

  1. the state itself (MTMVPartitionState, plus a copy helper for taking a detached snapshot), and
  2. the channel that carries it into the journal and back: a field on the MV, its own field on the alter
    record, a dedicated alter op with its replay branch, and the replay handling of the task result.

Nothing in the FE decides anything from the state yet, and nothing but a replay ever writes it, so every
MV behaves exactly as before. That is deliberate: it makes this step independently mergeable and
independently testable, which is what the PR that starts using the state needs underneath it.

Scope

Adds MTMVPartitionState, the partitionStates field, the alter record field, the new alter op and its replay branch
Does not touch any criterion, routing or invalidation decision; IvmInfo; the refresh path
Field is shared, behaviour is not the field sits on the MV, so both kinds of MV carry it; only an IVM MV ever populates it, and the journal of a non-IVM MV stays byte-for-byte what it was
Compatibility an image written before this PR has no such field and loads as an empty map; an ADD_TASK journal written before it applies nothing on replay instead of clearing what is there

The state is on the MV rather than inside IvmInfo, and the alter op is its own rather than riding on
ALTER_IVM_INFO, whose branch only swaps the IvmInfo object. Both are structural: the same state is
meant to serve a non-IVM MV later, and its journal payload must not be reconstructed as a side effect of
replaying some other op.

Key changes

  • Add MTMVPartitionState, a persisted refreshEpoch / latestEpoch pair keyed by MV partition name, and MTMVPartitionState.copyOf for taking a detached snapshot of a state map. A partition gets a new id on every refresh, so the name is the only identity it can have.
  • Add MTMV.partitionStates with its getter and its replay setter; gsonPostProcess initializes it, so an image written before the field existed and a non-IVM MV both load as an empty map.
  • Carry the state in the ADD_TASK payload under the same condition as ivmInfo, which keeps the journal of a non-IVM MV byte-for-byte unchanged, and apply it on replay only when the field is present, so an old journal applies nothing rather than clearing the state.
  • Add MTMVAlterOpType.ALTER_PARTITION_STATES and its Alter.processAlterMTMV branch.

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

    • No.
  • Does this need documentation?

    • No.

🤖 Generated with Claude Code

…annel

Rebuilding only the MV partitions that a silent base-table change really invalidated needs a
per-partition state: which generation of data the partition holds and which generation it must hold,
persisted so that it survives a restart. This adds that state and the journal channel that carries
it. Nothing decides anything from it yet and nothing but a replay writes it, so the behaviour of
every MV is unchanged.

Key changes:
- Add MTMVPartitionState, a persisted refreshEpoch / latestEpoch pair keyed by MV partition name, and MTMVPartitionState.copyOf for taking a detached snapshot of a state map
- Add MTMV.partitionStates with its getter and its replay setter; gsonPostProcess initializes it, so an image written before the field existed and a non-IVM MV both load as an empty map
- Carry the state in the ADD_TASK payload under the same condition as ivmInfo, which keeps the journal of a non-IVM MV byte-for-byte what it was, and apply it on replay only when the field is present
- Add MTMVAlterOpType.ALTER_PARTITION_STATES and its Alter.processAlterMTMV branch, so a live state change has an op of its own instead of riding on ALTER_IVM_INFO, whose branch only swaps the IvmInfo object

Unit Test:
- MTMVTest: an image round trip of a state, an image without the field, the getter before any state exists, the detached journal payload, the ADD_TASK carry for an IVM MV and its absence for a non-IVM MV, and both replay directions
- AlterMTMVTest: replay of ALTER_PARTITION_STATES through Alter.processAlterMTMV on a real MV
@yujun777
yujun777 marked this pull request as draft September 18, 2026 09:36
@yujun777
yujun777 marked this pull request as ready for review September 18, 2026 09:36
@yujun777
yujun777 marked this pull request as draft September 18, 2026 09:37
@yujun777

Copy link
Copy Markdown
Contributor Author

run buildall

@yujun777

Copy link
Copy Markdown
Contributor Author

/review

@yujun777
yujun777 marked this pull request as ready for review September 18, 2026 09:37
@yujun777

Copy link
Copy Markdown
Contributor Author

run buildall

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

Static review conclusion: request changes for two P2 issues: the new partition-state API exposes mutable owned state after releasing its lock, and the new journal channel is not tested across its actual AlterMTMV.write/read representation.

Critical checkpoint conclusions:

  • Goal and proof: the change is focused on adding inert per-partition epoch state plus image, ADD_TASK, and dedicated alter replay channels. The production serialization path is structurally present, but the journal wire/restart contract lacks a round-trip oracle.
  • Scope and clarity: the seven changed FE files are cohesive and do not add refresh/invalidation policy. The additive DTO and replay branches are otherwise small and clear.
  • Concurrency and locking: task completion snapshots and enqueues under mvRwLock, the FIFO edit-log queue preserves order, and await() is correctly outside the lock. No new lock-order or deadlock issue was found. However, getPartitionStates() returns the live map and mutable values after unlocking, bypassing that ownership invariant for the follow-up callers this API is meant to support.
  • Lifecycle: old images initialize the missing field to empty; old ADD_TASK records with no member preserve current state; an explicit empty map clears it; replay applies detached copies. INSERT OVERWRITE keeps the formal partition name while changing its id, and no current production logic populates or consumes the map. Future sync drop/add logic must own state removal/reinitialization atomically.
  • Configuration and initialization: no configuration item, static-initialization dependency, or new thread is introduced.
  • Compatibility: the image and ADD_TASK fields are additive Gson members; non-IVM ADD_TASK payloads remain unchanged; the dedicated enum operation is not emitted by live code in this PR. No FE-BE protocol or storage-format change applies.
  • Parallel paths and conditions: IVM/non-IVM, image, ADD_TASK success/failure replay, and dedicated alter replay were traced. The IVM-only live carry condition is consistent with this PR's stated scope.
  • Tests and results: the added unit tests cover image compatibility, detached copies, absent ADD_TASK state, IVM/non-IVM carry, and in-memory replay, but not the actual alter-journal bytes or the absent-versus-empty distinction after deserialization. No result files changed. Per the runner instruction, this review was static-only: I did not run builds or tests. CheckStyle had passed externally; FE UT and compile were still pending when inspected, so they are not treated as independent validation here.
  • Observability: because the state is intentionally inert in this PR, no new logging or metric is required yet.
  • Persistence/failover and data correctness: detached copying before asynchronous serialization, fatal edit-log failure behavior, dispatch, and replay ordering are otherwise correct. There is no direct user-data write or transaction-protocol change.
  • Performance: full-map copying is linear but currently empty/inert and is necessary for a detached payload; no separate confirmed performance defect was found.
  • User focus and completion: no additional user focus was supplied. Two complete review rounds were performed; all normal and risk-focused reviewers returned NO_NEW_VALUABLE_FINDINGS in the convergence round, and every candidate was accepted, deduplicated, or dismissed with evidence.

Comment thread fe/fe-core/src/main/java/org/apache/doris/catalog/MTMV.java Outdated
Comment thread fe/fe-core/src/test/java/org/apache/doris/mtmv/AlterMTMVTest.java Outdated
@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17718	4202	4177	4177
q2	2291	336	289	289
q3	10004	1460	830	830
q4	4680	487	350	350
q5	7491	849	573	573
q6	192	179	143	143
q7	834	839	626	626
q8	9322	1688	1576	1576
q9	5500	4241	4223	4223
q10	6749	1668	1351	1351
q11	436	280	256	256
q12	642	425	308	308
q13	18113	2631	2009	2009
q14	270	273	242	242
q15	q16	728	724	669	669
q17	1829	1206	1094	1094
q18	6476	5635	5527	5527
q19	1381	1351	1110	1110
q20	477	407	276	276
q21	5838	2587	2382	2382
q22	420	357	298	298
Total cold run time: 101391 ms
Total hot run time: 28309 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4312	4226	4295	4226
q2	785	614	588	588
q3	4531	4888	4415	4415
q4	2296	2362	1483	1483
q5	4285	4148	4194	4148
q6	233	185	137	137
q7	1706	1630	1781	1630
q8	2763	2217	2208	2208
q9	7656	7705	7655	7655
q10	4310	4339	3957	3957
q11	603	428	396	396
q12	744	777	549	549
q13	2438	2809	2171	2171
q14	296	312	264	264
q15	q16	709	730	635	635
q17	7949	7228	7367	7228
q18	11897	11048	11814	11048
q19	1157	1076	1081	1076
q20	2274	2246	1923	1923
q21	5987	5047	5113	5047
q22	562	494	410	410
Total cold run time: 67493 ms
Total hot run time: 61194 ms

@hello-stephen

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

query5	4328	641	473	473
query6	436	189	171	171
query7	4859	543	301	301
query8	319	183	173	173
query9	8817	4024	4012	4012
query10	449	320	259	259
query11	5656	2198	2052	2052
query12	175	101	95	95
query13	1246	560	409	409
query14	6535	4621	4262	4262
query14_1	4048	4018	3989	3989
query15	204	198	176	176
query16	997	458	437	437
query17	906	679	514	514
query18	2421	450	326	326
query19	193	179	135	135
query20	101	99	102	99
query21	213	138	118	118
query22	13110	13110	12795	12795
query23	15674	14607	13884	13884
query23_1	14097	14065	14015	14015
query24	7603	1753	1237	1237
query24_1	1231	1237	1240	1237
query25	532	413	344	344
query26	1270	316	162	162
query27	2688	534	338	338
query28	4542	1960	2004	1960
query29	1035	597	471	471
query30	311	239	205	205
query31	907	792	648	648
query32	143	110	94	94
query33	521	340	248	248
query34	1164	1142	638	638
query35	756	784	663	663
query36	806	824	723	723
query37	164	120	94	94
query38	1848	1780	1718	1718
query39	710	706	653	653
query39_1	687	643	669	643
query40	235	140	105	105
query41	75	70	68	68
query42	94	93	91	91
query43	360	359	318	318
query44	1419	682	702	682
query45	192	174	174	174
query46	1105	1236	688	688
query47	1482	1496	1388	1388
query48	390	429	292	292
query49	597	432	300	300
query50	1014	362	241	241
query51	10560	10507	10411	10411
query52	88	91	77	77
query53	253	262	179	179
query54	303	216	196	196
query55	76	78	68	68
query56	225	218	204	204
query57	1375	1392	1422	1392
query58	255	219	208	208
query59	2023	2094	1789	1789
query60	279	249	225	225
query61	145	138	147	138
query62	410	325	289	289
query63	217	182	173	173
query64	2832	996	813	813
query65	4011	3979	3936	3936
query66	1830	445	321	321
query67	20158	20036	20087	20036
query68	3578	1525	869	869
query69	411	306	271	271
query70	996	883	870	870
query71	300	239	209	209
query72	3132	2539	2186	2186
query73	850	748	418	418
query74	4629	4480	4307	4307
query75	2384	2315	1926	1926
query76	2388	1138	735	735
query77	368	400	304	304
query78	9324	9030	8541	8541
query79	1222	1161	737	737
query80	525	457	356	356
query81	471	285	235	235
query82	266	167	126	126
query83	270	273	246	246
query84	296	145	113	113
query85	789	457	376	376
query86	303	243	243	243
query87	2001	1981	1838	1838
query88	3685	2714	2698	2698
query89	332	291	245	245
query90	2123	180	179	179
query91	165	151	122	122
query92	102	82	86	82
query93	1567	1506	862	862
query94	527	339	292	292
query95	671	380	334	334
query96	1112	780	329	329
query97	2468	2416	2310	2310
query98	199	186	185	185
query99	734	727	612	612
Total cold run time: 241941 ms
Total hot run time: 153758 ms

@hello-stephen

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

query1	0.00	0.00	0.01
query2	0.08	0.05	0.05
query3	0.27	0.13	0.14
query4	1.60	0.14	0.13
query5	0.23	0.22	0.23
query6	1.15	0.92	0.92
query7	0.04	0.01	0.00
query8	0.05	0.03	0.04
query9	0.40	0.34	0.34
query10	0.57	0.58	0.59
query11	0.20	0.14	0.14
query12	0.18	0.15	0.15
query13	0.46	0.47	0.46
query14	0.98	0.93	0.95
query15	0.60	0.58	0.58
query16	0.31	0.32	0.33
query17	1.12	1.07	1.12
query18	0.21	0.20	0.20
query19	2.08	2.00	1.95
query20	0.02	0.02	0.01
query21	15.50	0.21	0.13
query22	4.83	0.06	0.05
query23	16.15	0.29	0.12
query24	2.88	0.40	0.32
query25	0.11	0.05	0.04
query26	0.73	0.20	0.14
query27	0.05	0.03	0.02
query28	3.57	0.76	0.35
query29	12.51	4.05	3.24
query30	0.28	0.16	0.15
query31	2.77	0.57	0.31
query32	3.24	0.59	0.49
query33	3.15	3.12	3.23
query34	15.59	3.96	3.29
query35	3.20	3.22	3.22
query36	0.56	0.43	0.43
query37	0.09	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.04
query40	0.17	0.16	0.14
query41	0.08	0.03	0.02
query42	0.04	0.03	0.03
query43	0.05	0.04	0.03
Total cold run time: 96.19 s
Total hot run time: 23.98 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 95.45% (42/44) 🎉
Increment coverage report
Complete coverage report

The partition-state API handed out the map the MV owns: a caller could add or change an entry after
the lock was released, while the task result copies that same map into the journal, and a replay that
replaced the field left the caller's reference pointing at state the MV no longer owned. The journal
channel had no test that went through the representation a restart actually reads either, so a member
that failed to serialize would have kept every replay test green.

Key changes:
- Return an unmodifiable detached snapshot from MTMV.getPartitionStates, under the read lock rather than the write lock, since it no longer needs to initialize the field
- Ignore a null payload in alterPartitionStates, so a journal without the member leaves the states alone instead of clearing them; the dedicated alter op applied null as an empty map before, while the task result replay had always checked
- Stop the getter from turning "no state yet" into an empty map: the task result carries the field, and a member that is present but empty means "clear" on replay, which could wipe a mark that landed between the payload and the replay

Unit Test:
- MTMVTest: the getter's snapshot rejects writes and its values are copies, the ADD_TASK payload survives its JSON round trip, and states are seeded through the replay setter rather than the getter
- AlterMTMVTest: replay driven by the journal bytes (AlterMTMV.write / read) for a payload with state, a payload that empties it, and an older payload without the member, plus the serialized member name
@yujun777

Copy link
Copy Markdown
Contributor Author

run buildall

@yujun777

Copy link
Copy Markdown
Contributor Author

/review

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17842	3913	3818	3818
q2	2194	350	295	295
q3	10151	1372	794	794
q4	4677	478	355	355
q5	7522	827	550	550
q6	174	173	136	136
q7	738	781	588	588
q8	9306	1460	1639	1460
q9	5443	4195	4180	4180
q10	6835	1329	1022	1022
q11	417	268	243	243
q12	643	415	292	292
q13	18070	2599	2003	2003
q14	262	258	230	230
q15	q16	730	713	673	673
q17	1833	1149	979	979
q18	6538	5580	5523	5523
q19	1185	1204	937	937
q20	480	385	267	267
q21	5404	2958	2660	2660
q22	428	355	285	285
Total cold run time: 100872 ms
Total hot run time: 27290 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4229	4130	4077	4077
q2	710	564	523	523
q3	4438	4842	4346	4346
q4	2229	2289	1435	1435
q5	4196	4073	4092	4073
q6	218	172	129	129
q7	1728	1580	1429	1429
q8	2142	2267	2073	2073
q9	7400	7319	7303	7303
q10	3671	3637	3162	3162
q11	561	404	369	369
q12	737	731	524	524
q13	2466	2766	2137	2137
q14	283	283	261	261
q15	q16	734	736	629	629
q17	7972	7181	7118	7118
q18	11860	11048	11793	11048
q19	1172	1076	1097	1076
q20	2251	2218	1945	1945
q21	5286	4490	4427	4427
q22	498	457	398	398
Total cold run time: 64781 ms
Total hot run time: 58482 ms

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

Static review completed for exact head 14e5372 against base 934233d. Recommendation: approve; no new blocking issue was substantiated at this head.

The PR goal is met within its stated scope: it adds the per-partition state DTO and a persistence/replay channel without changing refresh or visibility decisions. The MV getter returns a detached deep snapshot under mvRwLock, replay replacement and live ADD_TASK payload capture copy state under the write lock, and edit-log submission preserves the lock-acquisition order. No live ALTER_PARTITION_STATES producer or state consumer exists in this head, so deferred invalidation/cleanup behavior is not introduced here.

Persistence and compatibility checkpoints are covered: old MTMV images normalize an absent field to an empty map; old AlterMTMV journals omit the new member and replay preserves existing state; present-empty and present-nonempty payloads round-trip distinctly; the enum is Gson name-serialized. The dedicated replay test drives AlterMTMV.write/read for nonempty, empty, and absent payloads, and MTMV tests cover image round trips, detached ownership, ADD_TASK payload serialization, and non-IVM gating.

Critical checkpoint conclusions: no new configuration, static-initialization, RPC/protocol, transaction, or data-visibility path is introduced; lock ownership and error/absent-payload handling are explicit; the change is focused and does not add an observable hot-path concern. The only test-shape concern found by a subagent is the same ADD_TASK wire-round-trip point already present in discussion_r4045710021, so it was not duplicated as a new inline comment. The other existing ownership thread is likewise treated as addressed by this head.

There is no additional user-provided review focus. This was a static review only; no builds or tests were run per the review instructions.

@hello-stephen

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

query5	4307	605	472	472
query6	432	210	189	189
query7	4819	530	295	295
query8	331	181	162	162
query9	8812	4011	3996	3996
query10	453	294	257	257
query11	5941	3538	3225	3225
query12	153	90	86	86
query13	1269	618	425	425
query14	6563	4564	4230	4230
query14_1	3991	3954	3981	3954
query15	203	201	184	184
query16	985	480	425	425
query17	959	698	549	549
query18	2431	454	335	335
query19	207	184	140	140
query20	81	81	79	79
query21	221	137	118	118
query22	13059	12987	12843	12843
query23	14285	12959	12431	12431
query23_1	12558	12480	12572	12480
query24	7302	1114	683	683
query24_1	681	670	665	665
query25	556	431	378	378
query26	1264	326	170	170
query27	2639	555	340	340
query28	4540	1960	1957	1957
query29	1607	744	536	536
query30	303	222	180	180
query31	888	754	629	629
query32	154	101	95	95
query33	537	318	250	250
query34	1192	1165	662	662
query35	731	759	650	650
query36	820	800	710	710
query37	146	118	92	92
query38	1816	1751	1705	1705
query39	683	685	650	650
query39_1	647	674	639	639
query40	217	124	99	99
query41	70	69	67	67
query42	96	97	96	96
query43	335	358	306	306
query44	1388	709	717	709
query45	181	188	168	168
query46	1029	1197	725	725
query47	1501	1532	1385	1385
query48	427	396	304	304
query49	623	402	290	290
query50	1003	347	245	245
query51	10663	10317	10274	10274
query52	87	87	77	77
query53	235	259	174	174
query54	247	209	188	188
query55	79	74	68	68
query56	257	205	225	205
query57	1479	1369	1365	1365
query58	286	261	243	243
query59	2005	2034	1851	1851
query60	277	248	215	215
query61	145	139	147	139
query62	396	325	266	266
query63	214	175	178	175
query64	2797	1046	797	797
query65	3466	3398	3373	3373
query66	1850	420	299	299
query67	19988	20036	19890	19890
query68	3338	1474	926	926
query69	404	314	258	258
query70	911	859	813	813
query71	301	230	208	208
query72	2581	2471	2250	2250
query73	797	748	463	463
query74	4600	4508	4291	4291
query75	2335	2306	1967	1967
query76	2323	1140	772	772
query77	369	412	306	306
query78	9043	9066	8424	8424
query79	1385	1200	722	722
query80	578	462	379	379
query81	538	321	279	279
query82	634	161	131	131
query83	315	230	198	198
query84	327	147	114	114
query85	885	462	396	396
query86	332	234	238	234
query87	1994	1946	1813	1813
query88	3610	2752	2712	2712
query89	374	287	245	245
query90	1926	182	181	181
query91	169	155	130	130
query92	101	90	92	90
query93	1469	1502	905	905
query94	521	349	307	307
query95	643	360	426	360
query96	1003	798	339	339
query97	2429	2436	2353	2353
query98	159	150	142	142
query99	717	746	623	623
Total cold run time: 236609 ms
Total hot run time: 152448 ms

@hello-stephen

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

query1	0.00	0.00	0.01
query2	0.10	0.05	0.05
query3	0.27	0.14	0.13
query4	1.61	0.14	0.13
query5	0.24	0.23	0.23
query6	1.16	0.96	0.95
query7	0.04	0.01	0.01
query8	0.07	0.04	0.04
query9	0.39	0.33	0.34
query10	0.56	0.57	0.56
query11	0.20	0.14	0.14
query12	0.18	0.15	0.14
query13	0.47	0.46	0.46
query14	0.95	0.96	0.95
query15	0.61	0.59	0.58
query16	0.30	0.33	0.31
query17	1.12	1.09	1.09
query18	0.21	0.20	0.20
query19	1.95	1.88	1.93
query20	0.02	0.01	0.01
query21	15.43	0.19	0.13
query22	4.96	0.06	0.05
query23	16.15	0.32	0.11
query24	3.05	0.42	0.38
query25	0.13	0.05	0.05
query26	0.73	0.22	0.15
query27	0.04	0.03	0.03
query28	3.56	0.81	0.35
query29	12.48	4.07	3.19
query30	0.29	0.16	0.15
query31	2.77	0.55	0.30
query32	3.22	0.59	0.49
query33	3.14	3.14	3.21
query34	15.68	3.97	3.27
query35	3.19	3.21	3.26
query36	0.56	0.45	0.41
query37	0.09	0.07	0.07
query38	0.05	0.04	0.03
query39	0.04	0.03	0.03
query40	0.17	0.16	0.14
query41	0.08	0.04	0.03
query42	0.04	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 96.34 s
Total hot run time: 23.96 s

@yujun777

Copy link
Copy Markdown
Contributor Author

run cloud_p0

@gavinchou
gavinchou merged commit addf0c8 into apache:master Sep 21, 2026
40 of 41 checks passed
morningman added a commit that referenced this pull request Sep 23, 2026
…on PRs from master in merge order (#67347 #68193 #68336 #68170 #68180) (#68405)

Cherry-picked from #67347, #68193, #68336, #68170, #68180

Batch pick of every merged PR carrying the `incremental-computation`
label that `branch-incremental-computation` does not have yet (no
`incremental-computation-picked` label), in the order they landed on
master (`git log --first-parent`). One commit per PR, each ending with
`(cherry picked from commit <master sha>)`. Follows the same convention
as #67830, #68017, #68073, #68151, #68236 and #68303.

| # | Master commit | PR | Title |
|---|---|---|---|
| 1 | a7c0a78 | #67347 | [fix](cloud) bind the packed slice location
lifetime to its writer |
| 2 | addf0c8 | #68193 | [feature](ivm) Add the per-partition
refresh state and its journal channel |
| 3 | e885b46 | #68336 | [refactor](ivm) Rename
IvmInfo.refreshVersion to sequencePrefix |
| 4 | 01efbca | #68170 | [fix](ivm) Fall back to complete refresh
when the IVM stream is unusable |
| 5 | d6c1a2b | #68180 | [fix](ivm) Choose IVM baseline rebuild
partitions from the MV partition mapping |

Not included on purpose:

- The 29 labelled PRs that already carry
`incremental-computation-picked` (every other closed PR with the label).
This batch closes the selection query: 34 closed labelled PRs = 29
already picked + these 5.

### Prerequisite check

- **The IVM series (#68193, #68336, #68170, #68180)** — one series by
the same author, merged 2026-09-21/22, all tracing to issue #65418.
#68193 says in its own description that it "adds the state that the
following PRs need" — `MTMVPartitionState` plus its journal channel —
and #68336 is the rename of the field sitting next to it. The PRs that
consume that state are in this batch too, so the series is carried whole
and in master merge order. Its earlier PRs (#67802, #67837, #67814,
#68138, #67646, #67669, #67575) were picked in the previous rounds.
- **#67347** is standalone (cloud packed-file slice lifetime). Every
file that uses the APIs it changes is in the pick;
`be/src/io/fs/packed_file_system.cpp`, which also reads the global slice
index but is not modified, compiles unchanged against the picked
headers.
- **No unpicked master commit is required by any of the five.** Verified
by compiling, not by inspection alone: the whole FE main + test tree
compiles and the touched unit tests pass (below), and every BE/cloud
file the picks touch passes a `-fsyntax-only` compile with the real
build's flags.
- The unlabelled master commits touching the same files (#67186 Hive
partition batching, #66530 external scan task reuse, #66761
TIMESTAMP_NS, #67545 DLF, #67067 eager-agg) are *not* prerequisites —
see the drift check: none of the picks' own added lines reference what
they introduce.

### Drift check against master

Per pick, `git show` of the branch commit against the master squash,
with `index`/`@@` lines stripped: #67347, #68193 and #68336 are
identical. Two differ, both mechanically:

- **#68170 / `MTMVTask.java`** — master's context around
`executePartitionBasedRefresh` carries #67186's `try` block and snapshot
preload; this branch does not have #67186, so the auto-merge kept the
branch's block. The pick's own added and removed lines are identical to
master's.
- **#68180 / `MTMV.java`** — master's squash also adds `import
org.apache.doris.datasource.mvcc.MvccSnapshot;`, for #67186's
`pinnedSnapshots` overloads of `calculatePartitionMappings` /
`getEffectiveQueryUsedBaseTablePartitionMap`. Those overloads do not
exist here and the pick's new code only calls the single-argument form,
which exists on both sides, so the import is not needed and not carried.

For every file this batch touches, `git diff upstream-apache/master --
<file>` was taken and each master-side line attributed to the unpicked
commit that added it. All 42 files resolve: 37 have no master-side
difference at all, and the 5 that do are fully owned by

| file | master-side lines | owner |
|---|---|---|
| `MTMV.java` | 20 | #67186 |
| `MTMVTask.java` | 46 | #67186, #66530 |
| `MTMVTaskTest.java` | 44 | #67186 |
| `MTMVPartitionUtil.java` | 65 | #67186, #67545 |
| `MTMVRelatedPartitionDescSyncLimitGenerator.java` | 3 | #66761 |

i.e. nothing belonging to the picks is missing, and no unlabelled commit
has to come along.

### Verification

- FE: `run-fe-ut.sh --run` on this branch (regenerates thrift/protobuf,
compiles fe-core main 4480 files + test 1485 files) over the 11 touched
test classes — `AlterMTMVTest` 25, `MTMVTest` 23, `MTMVTaskTest` 48,
`MetaLockUtilsTest` 6, `IvmBaselineRebuildTest` 37,
`IvmAggDeltaHandlerTest` 33, `IvmDeltaRewriteStateTest` 10,
`IvmFailureReasonTest` 1, `IvmInfoTest` 6, `IvmSequenceCalculatorTest`
4, `DatabaseTransactionMgrTest` 20 — **213 tests, 0 failures, 0 errors,
0 skipped, BUILD SUCCESS**.
- FE checkstyle on fe-core: 0 violations.
- BE/cloud: `-fsyntax-only` with the Release flags of the real build and
its own compiler (`/opt/homebrew/opt/llvm@20/bin/clang++`) on
`be/src/io/fs/packed_file_manager.cpp`,
`be/src/io/fs/packed_file_writer.cpp`,
`be/src/cloud/cloud_rowset_writer.cpp` and
`be/test/io/fs/packed_file_manager_test.cpp` (the last with `-DBE_TEST
-fno-access-control`): no errors.
- The three new regression suites parse
(`test_ivm_baseline_marker_scope`, `test_ivm_chained_stream_scope`,
`test_ivm_partitions_fallback_stream_unusable`); their `.out` files are
the upstream ones, unmodified.

---------

Co-authored-by: Xin Liao <liaoxin@selectdb.com>
Co-authored-by: yujun <yujun@selectdb.com>
yujun777 added a commit to yujun777/doris that referenced this pull request Sep 23, 2026
…of through a barrier

Issue Number: N/A

Related PR: apache#68170, apache#68180, apache#68193

Trace issue: apache#65418

Problem Summary: An IVM MV keeps rows that a metadata-only base-table change (DROP / TRUNCATE /
REPLACE / RECOVER PARTITION) has made unusable, because such a change emits no row binlog. The
invalidation used to be recorded at MV granularity -- IvmInfo.completeBaselineRebuildRequired /
pendingBaselineRebuildPartitions plus a schemaChangeVersion guard -- which is coarse: one dirty
partition drags the whole MV to a COMPLETE refresh, a task result produced before the invalidation is
discarded, and a strict INCREMENTAL is rejected until a COMPLETE has run.

This replaces the barrier with a per-MV-partition requirement:

* MTMV.partitionStates maps each MV partition to {refreshEpoch, latestEpoch} (persisted as `pst`,
  journaled through ALTER_PARTITION_STATES). A partition is dirty iff latestEpoch > refreshEpoch.
  A refresh reads the requirement per batch before touching base tables and publishes only
  refreshEpoch once that batch's data is committed, so an invalidation arriving mid-refresh is not
  swallowed and a partition whose data transaction committed without its epochs being published is
  still rebuilt rather than read as clean.
* An invalidation that can be placed on the MV partitions reading the changed base partitions raises
  only their requirement; every other partition keeps catching up incrementally. Alignment runs
  after partition sync and before any base table is read, so a mark always has an entry to land on.
* The refresh routes on the criterion: dirty partitions are rebuilt by the partition executor (under
  a strict INCREMENTAL request as well), the rest are caught up incrementally. When every partition
  needs a rebuild, or the MV is in SCHEMA_CHANGE, the refresh runs as COMPLETE. A refresh that
  rebuilt partitions the request did not ask for reports how many in IvmRebuiltPartitions.
* A whole-MV invalidation -- a change that cannot be placed on any partition, and a property change
  that widens what the MV maintains -- goes through the MV state instead of the barrier flag, and
  the barrier fields, the refresh-time guard and the pending-rebuild rejection are gone. A rename of
  an IVM MV's base table no longer moves it into that state, and the dependency mapping moves with
  the rename so a later metadata-only change to the new name still finds the MV.
* A stream that has to be reconciled before a rebuild is made a real requirement on the partitions
  ahead of the reconciliation, so a crash between creating the replacement stream and publishing the
  rebuild cannot let the next refresh add its historical rows to the old baseline again.
* A base-table change that only narrows excluded_trigger_tables no longer invalidates the snapshot or
  the version: the rows the MV holds stay valid, and an excluded table's changes are not applied,
  including the ones that arrived before it was excluded.

A strict REFRESH ... INCREMENTAL that meets an invalidated baseline no longer fails: it rebuilds
(the whole MV for a schema-level invalidation, the invalidated partitions otherwise) and reports the
count in IvmRebuiltPartitions. An excluded base table's changes are not applied, including those
that arrived before it was excluded -- run a COMPLETE refresh if you need them.

- Test: Unit Test / Regression test
    - FE unit tests: IvmBaselineRebuildTest, MTMVTaskTest, MTMVTest, MTMVPlanUtilTest,
      CreateMTMVCommandTest, MTMVRelationManagerTest, AlterMTMVTest, IvmInfoTest,
      MTMVRefreshSnapshotTest, MTMVPartitionUtilTest, MetaLockUtilsTest -- all pass.
    - Regression: mtmv_p0/ivm -- all 97 suites pass with the stored expectations compared, not
      regenerated.
- Behavior changed: Yes (see the release note)
- Does this need documentation: Yes -- recorded in the doc-changes note that accompanies this work.
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.

6 participants