Skip to content

[feature](routineload) Add routine load target-table alter support#64878

Open
0AyanamiRei wants to merge 20 commits into
apache:masterfrom
0AyanamiRei:feature/routine-load-target-table-switch
Open

[feature](routineload) Add routine load target-table alter support#64878
0AyanamiRei wants to merge 20 commits into
apache:masterfrom
0AyanamiRei:feature/routine-load-target-table-switch

Conversation

@0AyanamiRei

@0AyanamiRei 0AyanamiRei commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: N/A

Related PR: N/A

Problem Summary:

Routine Load target-table alteration was initially limited to the target-only syntax ALTER ROUTINE LOAD FOR [db.]job ON table. It could not alter supported job or data-source properties in the same statement.

This PR replaces that syntax with the explicit, composable form:

ALTER ROUTINE LOAD FOR [<db>.]<job_name>
SET TARGET TABLE = "<table_name>"
[<job_properties>]
FROM [<data_source>]
[<data_source_properties>]

The implementation has the following behavior and constraints:

  • SET TARGET TABLE can be combined with supported job properties and Kafka/Kinesis data-source properties.
  • Target switching remains mutually exclusive with load clauses such as COLUMNS, WHERE, and PARTITION.
  • The job must be paused and single-table. The target must be a non-temporary OLAP table in the job database, pass LOAD privilege checks, and be compatible with the existing load description, distribution mode, and partial-update settings.
  • An explicit FROM type must match the existing job type; Kafka and Kinesis jobs cannot be converted into each other.
  • Existing Doris mutable-property allowlists are preserved. Unknown/create-only properties are rejected, including Kafka multi-table routing properties during ALTER. Doris retains its existing support for altering kafka_topic, unlike StarRocks.
  • Target-table, job-property, and data-source changes are applied and persisted together. Kafka source changes are staged or prevalidated to avoid partial in-memory mutation, and replay does not perform offset lookups or Cloud MetaService RPCs.
  • Kafka/Kinesis default offsets or positions are changed only when explicitly supplied. Altering a broker, stream, or custom property no longer synthesizes and overwrites an unspecified default position.
  • Routine Load progress is preserved for target-only/custom-property changes; topic or stream changes retain the existing Doris progress-reset behavior.

Release note

ALTER ROUTINE LOAD now uses SET TARGET TABLE = "table" to switch the target table and supports combining the switch with supported PROPERTIES and FROM data-source properties in one statement.

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason
  • Behavior changed:

    • No.
    • Yes. The target-table syntax changes from ON table to SET TARGET TABLE = "table", and supported job/source properties can now be altered in the same statement.
  • Does this need documentation?

Check List (For Reviewer who merge this PR)

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

### What problem does this PR solve?

Issue Number: None
Related PR: None
Problem Summary: Allow paused single-table Routine Load jobs to switch their target table with ALTER ROUTINE LOAD FOR [db.]job ON <table>, while preserving existing progress and replaying the new table binding from edit log.

### Release note

Support ALTER ROUTINE LOAD ... ON <table> to switch the target table for paused single-table routine load jobs.

### Check List (For Author)

- Test: FE unit test
  - "/data/data3/huangruixin/include/src-master/apache-maven-3.9.9/bin/mvn -pl fe-core -am -DskipITs -Dcheckstyle.skip=true -DfailIfNoTests=false -Dtest=org.apache.doris.nereids.trees.plans.commands.AlterRoutineLoadCommandTest,org.apache.doris.persist.AlterRoutineLoadOperationLogTest,org.apache.doris.load.routineload.KafkaRoutineLoadJobTest test"
  - Kinesis unit tests skipped per user request
- Behavior changed: Yes (new ALTER ROUTINE LOAD target-table switch behavior)
- Does this need documentation: Yes (documented in /data/data3/huangruixin/docs/routine-load-alter-table-design.html)
@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?

@0AyanamiRei
0AyanamiRei marked this pull request as draft June 26, 2026 06:04
### What problem does this PR solve?

Issue Number: None

Related PR: apache#64878

Problem Summary: Follow-up review found two issues in the new routine load target-table alter support. First, `AlterRoutineLoadCommand` had an import order regression that could fail FE checkstyle. Second, alter validation only rechecked `PARTIAL_COLUMNS=true` from the current command, which left the effective partial-update state under-validated when the existing job or a `unique_key_update_mode` change required merge-on-write semantics. This change restores import ordering, validates the effective unique key update mode against the destination table, and adds focused FE unit coverage for those cases.

### Release note

Routine Load alter now rejects target-table or unique-key-update changes that are incompatible with partial update requirements.

### Check List (For Author)

- Test: Unit Test
- Behavior changed: Yes
- Does this need documentation: No
@0AyanamiRei
0AyanamiRei marked this pull request as ready for review June 29, 2026 01:11
@0AyanamiRei

Copy link
Copy Markdown
Contributor Author

run buildall

### What problem does this PR solve?

Issue Number: None

Related PR: apache#64878

Problem Summary: The routine load target-table alter change hit FE checkstyle in CI because one validation error message exceeded the line-length limit and a unit-test import order did not match the FE custom import ordering rule. This commit makes the minimal formatting-only fixes so the branch aligns with FE style checks.

### Release note

None

### Check List (For Author)

- Test: No need to test (formatting-only fix requested by reviewer; no local build or test run)
- Behavior changed: No
- Does this need documentation: No
@0AyanamiRei 0AyanamiRei changed the title [feature](fe) Add routine load target-table alter support [feature](routineload) Add routine load target-table alter support Jun 29, 2026
@sollhui

sollhui commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

/review

### What problem does this PR solve?

Issue Number: None

Related PR: apache#64878

Problem Summary: The routine load target-table alter implementation had a single-use helper for constructing the validation load descriptor snapshot, and the parser branch for table-only alter did not mark the intended phase-one scope. This commit inlines the one-off snapshot construction at the validation call site and documents that the current parser branch only supports target table alteration before future support for combining target-table and property changes.

### Release note

None

### Check List (For Author)

- Test: No need to test (review follow-up only; no local build or test run)
- Behavior changed: No
- Does this need documentation: No
@0AyanamiRei

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.

Review completed for PR 64878 at head 760890d.

I found one correctness issue: validation can accept an alter that later leaves the routine-load job in partial-update mode on a non-MoW table.

Critical checkpoints:

  • Goal: the PR adds single-table routine-load target-table alteration while preserving stream progress; the implementation largely wires parser, command validation, job mutation, replay, display, and tests, but the partial-update validation path is inconsistent with mutation for one property combination.
  • Scope/focus: the target-table change is small and localized to routine-load command/job/persistence paths.
  • Concurrency/lifecycle: mutation is still gated by the existing paused-job write lock; no new background thread or lock order was introduced.
  • Configuration/session propagation: no new config item; existing routine-load session/job properties are reused.
  • Compatibility/persistence: new log field is backward-readable by current code; target-table id is replayed in Kafka and Kinesis paths.
  • Parallel paths: Kafka and Kinesis both update/replay targetTableId; scheduling/task planning uses the current job tableId.
  • Tests: parser/command/persistence/unit coverage and a Kafka regression were added. I verified git diff --check and mvn -pl fe-core -DskipTests checkstyle:check. I did not run FE compile/unit/regression tests because this checkout lacks thirdparty/installed/bin/protoc and thirdparty/installed.
  • User focus: no additional user-provided focus was present.

Subagent conclusions: optimizer-rewrite proposed OPT-001, which became inline comment MAIN-001. tests-session-config reported no distinct candidate. Convergence round 1 ended with both live subagents replying NO_NEW_VALUABLE_FINDINGS for the same current ledger/comment set.

@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/28345324644

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

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 50.63% (40/79) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17723	4017	4145	4017
q2	2022	319	187	187
q3	10328	1532	851	851
q4	4699	468	341	341
q5	7700	845	582	582
q6	204	173	141	141
q7	776	848	628	628
q8	10199	1487	1606	1487
q9	5907	4480	4460	4460
q10	6772	1809	1503	1503
q11	440	286	248	248
q12	629	430	310	310
q13	18087	3385	2817	2817
q14	265	256	244	244
q15	q16	782	773	706	706
q17	1029	955	1029	955
q18	6797	5786	5453	5453
q19	1173	1277	1096	1096
q20	509	411	263	263
q21	5699	2559	2539	2539
q22	446	356	301	301
Total cold run time: 102186 ms
Total hot run time: 29129 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4418	4256	4290	4256
q2	320	366	227	227
q3	4539	4941	4364	4364
q4	2083	2151	1366	1366
q5	4451	4327	4297	4297
q6	233	181	134	134
q7	1740	1936	1826	1826
q8	2423	2181	2100	2100
q9	8114	8044	8082	8044
q10	4852	4758	4301	4301
q11	565	425	389	389
q12	735	762	646	646
q13	3317	3589	2994	2994
q14	300	305	278	278
q15	q16	758	761	679	679
q17	1350	1344	1328	1328
q18	7947	7410	6831	6831
q19	1137	1104	1129	1104
q20	2274	2215	1948	1948
q21	5268	4573	4537	4537
q22	511	465	402	402
Total cold run time: 57335 ms
Total hot run time: 52051 ms

@hello-stephen

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

query5	4322	626	484	484
query6	430	183	171	171
query7	4810	553	302	302
query8	334	180	163	163
query9	8757	4085	4079	4079
query10	424	316	261	261
query11	5806	2352	2123	2123
query12	156	102	99	99
query13	1278	579	413	413
query14	6270	5269	4957	4957
query14_1	4327	4295	4289	4289
query15	219	202	179	179
query16	1038	447	432	432
query17	1107	711	604	604
query18	2432	465	337	337
query19	197	181	145	145
query20	113	108	103	103
query21	214	144	116	116
query22	13798	13672	13407	13407
query23	17262	16399	16148	16148
query23_1	16279	16175	16292	16175
query24	7465	1786	1326	1326
query24_1	1337	1283	1325	1283
query25	579	455	388	388
query26	1318	326	174	174
query27	2678	583	345	345
query28	4474	2032	2037	2032
query29	1099	651	520	520
query30	309	235	208	208
query31	1126	1091	946	946
query32	106	64	60	60
query33	547	320	262	262
query34	1167	1109	654	654
query35	775	796	686	686
query36	1414	1390	1241	1241
query37	154	115	92	92
query38	1902	1723	1671	1671
query39	926	936	915	915
query39_1	873	882	896	882
query40	231	126	106	106
query41	69	68	68	68
query42	91	90	88	88
query43	324	322	277	277
query44	1473	817	782	782
query45	216	194	181	181
query46	1075	1199	760	760
query47	2345	2351	2264	2264
query48	404	411	323	323
query49	595	438	326	326
query50	1069	370	267	267
query51	4406	4417	4350	4350
query52	82	83	73	73
query53	244	274	199	199
query54	277	234	211	211
query55	77	73	68	68
query56	261	233	236	233
query57	1428	1435	1302	1302
query58	245	217	223	217
query59	1558	1650	1439	1439
query60	284	256	239	239
query61	182	177	213	177
query62	704	644	573	573
query63	237	193	190	190
query64	2525	773	625	625
query65	4820	4804	4771	4771
query66	1818	460	330	330
query67	28846	28759	28682	28682
query68	3220	1539	931	931
query69	418	308	261	261
query70	1082	1022	991	991
query71	311	238	213	213
query72	2915	2867	2340	2340
query73	890	800	439	439
query74	5133	4990	4751	4751
query75	2601	2541	2180	2180
query76	2308	1201	783	783
query77	392	379	293	293
query78	12392	12431	11997	11997
query79	1407	1137	762	762
query80	1236	454	387	387
query81	514	280	250	250
query82	612	156	117	117
query83	317	276	247	247
query84	264	139	115	115
query85	885	510	438	438
query86	439	325	276	276
query87	1841	1827	1776	1776
query88	3756	2810	2779	2779
query89	426	378	334	334
query90	1870	186	187	186
query91	174	160	137	137
query92	65	62	53	53
query93	1600	1474	874	874
query94	715	352	333	333
query95	669	469	347	347
query96	1139	806	348	348
query97	2683	2660	2554	2554
query98	217	206	201	201
query99	1161	1163	1067	1067
Total cold run time: 257841 ms
Total hot run time: 171607 ms

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.10	0.04	0.05
query3	0.25	0.16	0.13
query4	1.60	0.14	0.14
query5	0.24	0.22	0.22
query6	1.26	1.05	1.02
query7	0.03	0.01	0.01
query8	0.06	0.04	0.04
query9	0.39	0.32	0.34
query10	0.58	0.54	0.58
query11	0.18	0.15	0.15
query12	0.18	0.15	0.14
query13	0.48	0.47	0.47
query14	1.02	1.01	0.98
query15	0.61	0.59	0.58
query16	0.33	0.31	0.30
query17	1.08	1.12	1.04
query18	0.22	0.21	0.22
query19	2.05	1.90	1.90
query20	0.01	0.01	0.01
query21	15.44	0.19	0.14
query22	4.95	0.06	0.05
query23	16.13	0.31	0.12
query24	2.98	0.41	0.31
query25	0.11	0.06	0.04
query26	0.74	0.23	0.15
query27	0.05	0.03	0.03
query28	3.53	0.90	0.52
query29	12.50	4.33	3.45
query30	0.28	0.15	0.16
query31	2.77	0.60	0.31
query32	3.22	0.60	0.50
query33	3.17	3.16	3.31
query34	15.51	4.21	3.50
query35	3.48	3.51	3.54
query36	0.54	0.42	0.43
query37	0.10	0.07	0.06
query38	0.05	0.04	0.03
query39	0.04	0.03	0.03
query40	0.17	0.16	0.15
query41	0.08	0.03	0.03
query42	0.03	0.02	0.02
query43	0.04	0.04	0.03
Total cold run time: 96.59 s
Total hot run time: 24.95 s

### What problem does this PR solve?

Issue Number: None

Related PR: apache#64878

Problem Summary: ALTER ROUTINE LOAD validation handled unique_key_update_mode and legacy partial_columns with different precedence from the mutation path. An ALTER containing unique_key_update_mode=UPSERT and partial_columns=true could pass validation on a non-MoW table, then be applied as UPDATE_FIXED_COLUMNS. Flexible partial-update ALTERs on non-MoW tables were also rejected by the generic PARTIAL_COLUMNS validation before reaching the flexible partial-update validation path. This change makes generic partial-column validation apply only to fixed partial update mode and makes the mutation path ignore legacy partial_columns when an explicit unique_key_update_mode is present. The routine load alter regression test also declares its polling counters as local variables to satisfy regression framework script checks.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.nereids.trees.plans.commands.AlterRoutineLoadCommandTest,org.apache.doris.load.routineload.KafkaRoutineLoadJobTest,org.apache.doris.load.routineload.KinesisRoutineLoadJobTest
- Behavior changed: No
- Does this need documentation: No
@0AyanamiRei

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 74.57% (217/291) 🎉
Increment coverage report
Complete coverage report

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review completed for PR 64878 at head 8b19f60c7a9c973cb565b6963e76cfdf836a24d2.

I found five new P1 correctness issues and am requesting changes. I did not repeat the existing threads covering target authorization/identity races, ALTER execution context, Kafka datetime-origin replacement, or the resolved metadata-lock I/O concern.

Critical checkpoints:

  • Goal: the PR adds composable paused-job target switching with job/source-property changes and durable replay. The parser and happy path are present, but the five inline issues show data-position loss, rejected-ALTER side effects, stale-target concurrency, and failover divergence, so the goal is not yet safely met.
  • Scope/focus: the 16 changed paths form a focused end-to-end FE/parser/persistence/test change. No unrelated production change was found.
  • Concurrency: tableId, load descriptors, and source state are shared across concurrent ALTER/control/SHOW/update work. Job/database/table lock order showed no concrete deadlock, but MAIN-007 proves descriptor validation and application are not bound to one target version. Kafka/MetaService preparation is outside metadata locks, but MAIN-006 shows that the externally committed side effect is no longer atomic with final validation.
  • Lifecycle: target switching is limited to PAUSED jobs and existing task clearing prevents simultaneous old/new-target tasks. Resume, dynamic partition/shard discovery, progress refresh, and follower promotion were reviewed; MAIN-002, MAIN-007, and MAIN-008 fail at those lifecycle boundaries. No static/global initialization or release issue applies.
  • Configuration: no configuration item or dynamic-config behavior is added.
  • Compatibility: legacy records safely default missing targetTableId to zero, and the documented follower-first/master-last FE upgrade order excludes the dismissed old-reader election scenario. Same-version replay is still unsafe under stale Cloud progress (MAIN-008).
  • Parallel paths: Kafka and Kinesis ALTER analysis/live/replay/image behavior were compared. Kafka-only target switching is intentionally enforced; Kinesis still misses the promised unspecified-default preservation (MAIN-002).
  • Special conditions: paused state, single-table/Kafka type, target type/ID/schema/distribution, partial-update mode, pinned/unpinned partitions, numeric/symbolic/time offsets, and Cloud/non-Cloud branches were checked. MAIN-005 is the new all-numeric/mixed numeric partition-membership hole.
  • Test coverage: changed parser, command, persistence, job unit tests, and the ordered Kafka regression cover syntax and success paths. They omit the Kinesis default case, invalid numeric partition, post-reset target failure, two-ALTER descriptor race, and stale-follower replay represented by the five comments.
  • Test results: no local build or test was run because this review contract forbids builds. Current CI has compile, FE/BE/Cloud unit tests, cloud/vault regressions, coverage, formatting, and license checks passing; P0, external, and nonConcurrent regressions remain pending, while the performance job is failing.
  • Observability: existing routine-load and replay logs expose errors, but logging and swallowing the replay exception does not preserve state consistency (MAIN-008). No separate metric/logging blocker was substantiated.
  • Persistence/failover: EditLog/image/legacy-record paths were traced. MAIN-008 is a same-version replay divergence; existing context and mutable-identity threads remain applicable and were not duplicated.
  • Data modification/atomicity: no BE row-write implementation changes, but these offsets control which rows are ingested. MAIN-002 and MAIN-005 can skip records, and MAIN-006 lets an uncommitted/rejected FE ALTER durably mutate MetaService progress.
  • FE/BE propagation: no new FE-to-BE variable or protocol field is added; task planning and transaction setup consume the job's current tableId.
  • Performance: no new CPU, memory, or hot-path complexity issue was found. The earlier external-I/O-under-metadata-lock concern is already covered by discussion_r3600083763 and was not repeated.
  • Other/user focus: no additional user-provided focus was present. Two complete review rounds converged; both complementary full-review agents and the separate risk reviewer returned NO_NEW_VALUABLE_FINDINGS for this exact five-comment set and anchors.

} finally {
writeUnlock();
}
return () -> modifyPropertiesInternal(jobProperties, dataSourceProperties);

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 stored Kinesis default when this ALTER delta omits one. KinesisDataSourceProperties still calls analyzeKinesisDefaultPositionProperty() for every ALTER without explicit positions, which inserts kinesis_default_pos=LATEST into the delta. This closure feeds that synthetic value to customProperties.putAll(), so a stream/region/endpoint/custom-only ALTER overwrites an existing TRIM_HORIZON; on a stream switch, initial shard discovery then starts at LATEST and skips every record already present. Mirror Kafka's ALTER early return when neither shards nor a default was supplied, and cover live/replay/image preservation.

if (MapUtils.isNotEmpty(dataSourceProperties.getOriginalDataSourceProperties())) {
kafkaPartitionOffsets = dataSourceProperties.getKafkaPartitionOffsets();
}
if (!kafkaPartitionOffsets.isEmpty()

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] Validate numeric-offset partitions against the staged topic. For an unpinned topic switch this condition skips the old-progress check, and resolveOffsets() cannot replace it: KafkaUtil.getRealOffsets() returns an all-numeric list without contacting Kafka. ALTER ... kafka_topic=new, kafka_partitions=999, kafka_offsets=0 therefore succeeds and journals bogus progress even when new has only partition 0; dynamic discovery later ignores 999 and starts real partitions from the default. Fetch the staged topic's partition metadata for every requested ID, including all-numeric and mixed lists, before the Cloud reset or local apply.


if (!isReplay) {
kafkaPartitionOffsets = resolveOffsets(dataSourceProperties, dataSourceSnapshot);
resetCloudProgressIfNeeded(dataSourceSnapshot, kafkaPartitionOffsets);

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] Do not commit Cloud progress during preparation. This RPC runs before the new target is re-resolved/replanned and before local apply or the EditLog write. In a combined target/source ALTER, another session can drop the analyzed target or make its schema incompatible; the reset commits, final validation then throws, and the FE job/journal stay unchanged while MetaService contains the new offsets. A later progress refresh or failover can import them into the old job and skip or replay records. Use a durable two-phase/conditional protocol or compensation so a rejected ALTER cannot change MetaService.

### What problem does this PR solve?

Issue Number: None

Related PR: apache#64878

Problem Summary: Kafka routine load ALTER could keep a stale datetime origin when a symbolic default offset was supplied, reset Cloud MetaService progress before final metadata validation and edit-log persistence, and replay resolved ALTER state against follower-local progress. Routine load descriptors were also applied outside the Kafka job lock and were absent from the ALTER journal. Restore the pre-existing Kinesis ALTER implementation, keep the new preparation flow Kafka-only, persist pending Cloud progress changes until the job resumes, make replay deterministic, and journal descriptor changes with the target-table mutation.

### Release note

Fix Kafka routine load ALTER consistency for default offsets, Cloud progress, target-table changes, and replay.

### Check List (For Author)

- Test: FE unit tests and FE build
    - `./run-fe-ut.sh --run org.apache.doris.load.routineload.KafkaRoutineLoadJobTest,org.apache.doris.load.routineload.KinesisRoutineLoadJobTest,org.apache.doris.load.routineload.RoutineLoadJobTest,org.apache.doris.load.routineload.RoutineLoadManagerTest,org.apache.doris.nereids.trees.plans.commands.AlterRoutineLoadCommandTest,org.apache.doris.persist.AlterRoutineLoadOperationLogTest`
    - `./run-fe-ut.sh --run org.apache.doris.load.routineload.KafkaRoutineLoadJobTest`
    - `./build.sh --fe -j48`
- Behavior changed: Yes. Cloud progress changes are submitted when the paused Kafka job resumes, after ALTER validation and persistence; symbolic default offsets now replace an earlier datetime default correctly.
- Does this need documentation: No
@0AyanamiRei

Copy link
Copy Markdown
Contributor Author

run buildall

@sollhui

sollhui commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Request changes: two distinct PR-introduced P1 issues remain in the inline comments: checkpoint reload can cancel a valid target/property transition, and target ALTER can wait synchronously for the journal while holding database/table metadata locks.

Critical checkpoint conclusions:

  • Goal and scope: The 16-file FE/parser/test change is focused on composable paused single-table routine-load target, job, load-clause, and Kafka source ALTERs. The primary live paths are covered, but the two blockers mean the goal is not restart- and availability-safe yet.
  • Concurrency and locks: The job-write -> database-read -> table-read order is consistent, and Kafka/MetaService preparation was moved outside metadata locks. The remaining synchronous EditLog wait under those locks is a blocking availability defect; other target/authorization/descriptor races are already covered by existing threads and were not duplicated.
  • Lifecycle: The pending Cloud progress-reset state was traced across ALTER, RESUME, replay, image load, failover, retries, and both reset RPC boundaries and is reconstructible/idempotent. No static/global lifetime issue applies. Image post-processing still introduces the checkpoint-cancellation defect.
  • Configuration and compatibility: No configuration item or FE-BE protocol variable is added. Old journal records safely default the new target/descriptor fields, and parser compatibility/intentional exclusions have tests; current job-image behavior is not compatible with the newly mutable target.
  • Parallel paths and conditions: Kafka/Kinesis, UPSERT/fixed/flexible modes, partial_columns, format/fuzzy/jsonpaths, target/source combinations, omitted/direct/prefixed defaults, paused/single-table restrictions, and manual/auto resume were checked. Remaining Kinesis or pre-existing scheduler/descriptor behaviors are already threaded or outside this PR delta.
  • Tests and results: Added parser, unit, replay, and regression coverage and expected output are consistent with the exercised paths, but there is no full RoutineLoadJob image round trip for a target/property switch and no delayed-journal metadata-lock test.
  • Observability and error handling: Existing job/error logs are sufficient for these paths; no new metric is required. The cancellation catch and journal blocking are correctness issues rather than missing diagnostics.
  • Persistence, failover, and mutation atomicity: Operation-log snapshot fields and expression/separator reconstruction are sound, and live/EditLog replay mostly agree. Checkpoint reconstruction does not, while journal durability is awaited in the wrong lock scope.
  • Performance: Property staging and snapshot copies are bounded control-plane work; no hot-path CPU or memory issue was found. The unbounded metadata-lock hold is the material performance/availability concern.
  • Other issues and user focus: The final full-diff/base-side/duplicate sweep found no additional PR-introduced issue. No additional user focus was provided.

Validation was static only: the review workflow prohibits builds/tests, and this checkout has no .worktree_initialized marker, thirdparty/installed, or protoc.

modifyPropertiesInternal(command.getAnalyzedJobProperties(), dataSourceProperties,
preparedDataSourceProperties);
if (command.hasTargetTable()) {
tableId = command.getTargetTableId();

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] Make target/property alters survive checkpoint reload. EditLog replay restores this target and the new job properties, but RoutineLoadJob.gsonPostProcess() later reparses the unchanged CREATE origStmt, substitutes only the current table name, and validates the original properties against it. For example, a job created in fixed partial-update mode on MoW table A can switch to non-MoW B together with unique_key_update_mode=UPSERT, then be marked CANCELLED when an image reload validates the old fixed mode against B. Preserve the serialized current definition (or update the canonical statement) and add a full RoutineLoadJob image round-trip test.

### What problem does this PR solve?

Issue Number: None

Related PR: apache#64878

Problem Summary: Kafka routine load target-table ALTER revalidated the target while holding database and table metadata locks across the final in-memory mutation and edit-log write. The target has already been validated during command analysis, and each routine load task resolves the persisted table ID and replans under the table read lock before execution. Remove the duplicate mutation-time validation and metadata locks so ALTER commit is serialized only by the routine load job write lock.

### Release note

None

### Check List (For Author)

- Test: FE unit tests and FE build
    - `./run-fe-ut.sh --run org.apache.doris.load.routineload.KafkaRoutineLoadJobTest`
    - `./run-fe-ut.sh --run org.apache.doris.load.routineload.KafkaRoutineLoadJobTest,org.apache.doris.load.routineload.KinesisRoutineLoadJobTest,org.apache.doris.load.routineload.RoutineLoadJobTest,org.apache.doris.load.routineload.RoutineLoadManagerTest,org.apache.doris.nereids.trees.plans.commands.AlterRoutineLoadCommandTest,org.apache.doris.persist.AlterRoutineLoadOperationLogTest`
    - `./build.sh --fe -j48`
- Behavior changed: Yes. Target-table ALTER no longer repeats metadata validation during commit; task planning remains the authoritative runtime validation.
- Does this need documentation: No
@0AyanamiRei

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17636	4048	3987	3987
q2	2070	328	202	202
q3	10297	1476	915	915
q4	4704	466	352	352
q5	7508	868	566	566
q6	187	175	143	143
q7	764	821	649	649
q8	9341	1635	1586	1586
q9	5542	4373	4377	4373
q10	6749	1721	1508	1508
q11	496	358	331	331
q12	730	584	473	473
q13	18089	3407	2741	2741
q14	267	262	242	242
q15	q16	790	795	708	708
q17	1044	966	954	954
q18	6985	5928	5566	5566
q19	1193	1271	1046	1046
q20	778	664	589	589
q21	5622	2635	2416	2416
q22	438	360	300	300
Total cold run time: 101230 ms
Total hot run time: 29647 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4360	4356	4346	4346
q2	292	331	219	219
q3	4623	5002	4391	4391
q4	2085	2176	1359	1359
q5	4419	4296	4353	4296
q6	234	175	132	132
q7	1736	1951	1844	1844
q8	2576	2228	2341	2228
q9	7936	8205	7781	7781
q10	4703	4667	4217	4217
q11	602	447	399	399
q12	750	772	551	551
q13	3313	3640	2972	2972
q14	303	301	284	284
q15	q16	724	742	669	669
q17	1357	1359	1364	1359
q18	8210	7392	7306	7306
q19	1237	1154	1128	1128
q20	2225	2189	1983	1983
q21	5238	4551	4443	4443
q22	534	451	403	403
Total cold run time: 57457 ms
Total hot run time: 52310 ms

@hello-stephen

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

query5	4331	636	507	507
query6	481	223	212	212
query7	4835	634	353	353
query8	339	195	166	166
query9	8764	4005	4062	4005
query10	453	347	310	310
query11	5902	2355	2157	2157
query12	165	106	107	106
query13	1273	625	413	413
query14	6254	5209	4854	4854
query14_1	4232	4186	4153	4153
query15	205	208	177	177
query16	1007	470	444	444
query17	907	695	550	550
query18	2424	461	333	333
query19	203	182	143	143
query20	108	108	104	104
query21	235	158	136	136
query22	13584	13578	13300	13300
query23	17323	16501	16204	16204
query23_1	16229	16266	16293	16266
query24	7513	1750	1220	1220
query24_1	1265	1284	1267	1267
query25	583	458	392	392
query26	1356	343	214	214
query27	2667	603	383	383
query28	4522	1997	2006	1997
query29	1089	613	502	502
query30	338	267	232	232
query31	1121	1098	985	985
query32	113	66	61	61
query33	546	337	263	263
query34	1179	1174	651	651
query35	779	787	672	672
query36	1194	1199	1063	1063
query37	155	120	95	95
query38	1872	1705	1666	1666
query39	879	865	840	840
query39_1	834	853	868	853
query40	248	168	146	146
query41	74	72	69	69
query42	97	95	95	95
query43	328	323	281	281
query44	1411	789	766	766
query45	202	186	176	176
query46	1087	1205	712	712
query47	2141	2145	2012	2012
query48	398	425	302	302
query49	574	421	302	302
query50	1052	427	325	325
query51	10605	10821	10685	10685
query52	86	87	75	75
query53	252	280	200	200
query54	287	226	229	226
query55	73	71	63	63
query56	303	288	287	287
query57	1312	1292	1190	1190
query58	289	261	253	253
query59	1607	1658	1470	1470
query60	303	258	251	251
query61	150	147	144	144
query62	547	493	426	426
query63	237	206	209	206
query64	2824	1012	847	847
query65	4721	4622	4650	4622
query66	1823	494	383	383
query67	29381	29243	29243	29243
query68	3044	1619	948	948
query69	411	302	262	262
query70	1051	937	943	937
query71	392	336	312	312
query72	3276	2631	2355	2355
query73	838	756	392	392
query74	5055	4920	4755	4755
query75	2563	2507	2134	2134
query76	2328	1199	762	762
query77	344	379	283	283
query78	12043	11872	11451	11451
query79	1248	1168	758	758
query80	601	544	460	460
query81	480	333	290	290
query82	247	162	119	119
query83	403	331	295	295
query84	338	165	127	127
query85	916	592	518	518
query86	319	283	292	283
query87	1812	1815	1734	1734
query88	3700	2778	2787	2778
query89	404	371	317	317
query90	2110	200	198	198
query91	199	190	163	163
query92	62	63	57	57
query93	1480	1541	975	975
query94	555	347	329	329
query95	781	495	565	495
query96	1104	778	358	358
query97	2608	2640	2493	2493
query98	210	207	203	203
query99	1092	1118	956	956
Total cold run time: 261892 ms
Total hot run time: 177305 ms

@hello-stephen

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

query1	0.00	0.00	0.00
query2	0.11	0.06	0.05
query3	0.26	0.14	0.14
query4	1.61	0.13	0.13
query5	0.23	0.23	0.22
query6	1.29	1.06	1.07
query7	0.03	0.00	0.00
query8	0.06	0.03	0.04
query9	0.39	0.31	0.31
query10	0.56	0.54	0.55
query11	0.18	0.14	0.13
query12	0.18	0.14	0.14
query13	0.48	0.47	0.47
query14	1.01	0.99	1.01
query15	0.62	0.59	0.60
query16	0.31	0.32	0.34
query17	1.12	1.07	1.09
query18	0.22	0.20	0.20
query19	2.02	1.96	1.97
query20	0.02	0.01	0.01
query21	15.44	0.23	0.13
query22	4.62	0.06	0.05
query23	16.12	0.31	0.13
query24	2.92	0.46	0.32
query25	0.11	0.06	0.06
query26	0.73	0.20	0.15
query27	0.04	0.03	0.04
query28	3.52	0.95	0.57
query29	12.56	4.17	3.29
query30	0.27	0.16	0.16
query31	2.78	0.59	0.32
query32	3.21	0.60	0.49
query33	3.29	3.16	3.21
query34	15.73	4.18	3.52
query35	3.57	3.57	3.56
query36	0.55	0.45	0.45
query37	0.09	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.04	0.03
query40	0.18	0.16	0.16
query41	0.08	0.02	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.03
Total cold run time: 96.68 s
Total hot run time: 25.12 s

@sollhui

sollhui commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Request changes: two blocking issues remain in the new target-table ALTER path.

Critical checkpoint conclusions:

  • Goal and proof: The PR adds target switching and makes Kafka source/property transitions atomic and replayable. Happy-path, serialization, staging, and reset tests are present, but the target-only concurrency case and unauthorized negative path are incorrect, so the goal is not fully met.
  • Scope and clarity: The implementation is focused on routine-load command analysis, Kafka mutation, persistence, parser support, and tests; no unrelated change or new server configuration was introduced.
  • Concurrency and locking: The per-job lock serializes mutation, but target validation is performed before that lock and is not bound to the job definition, causing the first inline issue. Kafka/MetaService I/O is outside catalog/database/table metadata locks; no additional lock-order deadlock was substantiated.
  • Lifecycle: PAUSE, explicit and automatic RESUME, STOP/CANCEL, task commit, replay, image reload, and every Cloud reset crash boundary were traced. The pending-reset protocol is retry-safe and idempotent; adjacent replay/image defects are already covered by existing threads.
  • Configuration and conditions: Direct and property. Kafka defaults, omission versus replacement, datetime origins, all offset forms, and pinned/dynamic partitions were checked. Remaining distinct source-path concerns are either base-side behavior or existing review threads.
  • Compatibility and parallel paths: Legacy Alter records default the new target/descriptor fields safely, and no new FE-BE field is introduced. Kafka and Kinesis parallel paths were checked; Kinesis issues found are pre-existing or already threaded.
  • Error handling and security: Target type/temporary-table errors are emitted before authorization, creating the second inline issue. Other changed error paths preserve actionable job/request context.
  • Tests and results: Changed unit tests and the ordered regression output are internally consistent. Missing deterministic concurrent-ALTER and unauthorized existing-versus-missing target tests correspond directly to the two findings. Tests were not executed because the review contract prohibits builds and test runs.
  • Observability: Existing logs cover Kafka and MetaService failures with sufficient context; no new metric is required for this control path.
  • Persistence, failover, and data correctness: Kafka live application and EditLog replay carry the source/job delta, target ID, and descriptor consistently; Cloud reset retry ordering is sound. Metadata mutation is still not atomic with target validation in the concurrency case reported inline.
  • Performance and protocol: No new per-record hot-path work, material FE-BE protocol change, or memory-safety concern was introduced. External calls are confined to ALTER/RESUME control paths under the per-job lock.
  • User focus: No additional user-provided review focus was specified.

### What problem does this PR solve?

Issue Number: None

Related PR: apache#64878

Problem Summary: ALTER ROUTINE LOAD target-table validation resolved target metadata before authorizing the current job and requested target. A limited-RBAC user could distinguish missing, non-OLAP, or temporary target tables through different validation errors. Authorize the current job first and check the target LOAD privilege by name before resolving database or table metadata.

### Release note

Unauthorized ALTER ROUTINE LOAD target-table requests no longer reveal target table metadata.

### Check List (For Author)

- Test: FE unit tests added but not run per user request
- Behavior changed: Yes. Unauthorized requests now fail before target metadata resolution.
- Does this need documentation: No
@0AyanamiRei

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17612	4140	4173	4140
q2	2021	317	200	200
q3	10318	1358	807	807
q4	4677	469	341	341
q5	7520	840	568	568
q6	181	170	137	137
q7	747	823	627	627
q8	9972	1612	1672	1612
q9	5761	4329	4331	4329
q10	6683	1739	1476	1476
q11	504	337	315	315
q12	747	581	450	450
q13	18082	3348	2693	2693
q14	255	261	237	237
q15	q16	776	779	706	706
q17	1046	971	1015	971
q18	6856	5775	5420	5420
q19	1422	1197	1068	1068
q20	798	723	596	596
q21	5968	2581	2487	2487
q22	435	351	290	290
Total cold run time: 102381 ms
Total hot run time: 29470 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4392	4311	4299	4299
q2	286	313	209	209
q3	4549	4947	4414	4414
q4	2360	2149	1373	1373
q5	4352	4218	4236	4218
q6	229	176	127	127
q7	1707	1984	1749	1749
q8	2419	2168	2098	2098
q9	7716	7923	7654	7654
q10	4689	4679	4192	4192
q11	579	419	390	390
q12	748	758	582	582
q13	3408	3571	3005	3005
q14	350	299	266	266
q15	q16	718	754	641	641
q17	1364	1306	1312	1306
q18	7891	7485	6822	6822
q19	1120	1038	1128	1038
q20	2230	2197	1953	1953
q21	5235	4608	4441	4441
q22	518	461	400	400
Total cold run time: 56860 ms
Total hot run time: 51177 ms

@hello-stephen

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

query5	4344	636	472	472
query6	488	227	204	204
query7	4847	612	345	345
query8	337	183	173	173
query9	8762	4091	4057	4057
query10	480	366	317	317
query11	5892	2320	2112	2112
query12	151	105	110	105
query13	1268	586	443	443
query14	6252	5215	4872	4872
query14_1	4272	4228	4254	4228
query15	213	201	187	187
query16	1045	475	478	475
query17	1127	722	577	577
query18	2739	498	350	350
query19	208	192	158	158
query20	115	112	107	107
query21	228	161	140	140
query22	13520	13504	13391	13391
query23	17271	16563	16231	16231
query23_1	16283	16276	16129	16129
query24	7446	1750	1298	1298
query24_1	1306	1312	1272	1272
query25	577	468	394	394
query26	1363	361	213	213
query27	2553	624	394	394
query28	4436	2007	2029	2007
query29	1081	640	489	489
query30	339	261	230	230
query31	1118	1099	993	993
query32	105	61	63	61
query33	525	334	260	260
query34	1162	1109	637	637
query35	759	786	661	661
query36	1181	1210	1043	1043
query37	157	105	93	93
query38	1863	1712	1613	1613
query39	879	869	856	856
query39_1	829	864	831	831
query40	247	164	139	139
query41	65	62	62	62
query42	99	92	96	92
query43	316	318	280	280
query44	1420	754	747	747
query45	194	184	175	175
query46	1058	1189	715	715
query47	2121	2172	2033	2033
query48	393	429	283	283
query49	592	418	306	306
query50	1019	445	344	344
query51	10594	10355	10669	10355
query52	86	87	73	73
query53	261	268	211	211
query54	282	236	221	221
query55	75	69	66	66
query56	294	287	292	287
query57	1308	1286	1222	1222
query58	296	264	249	249
query59	1612	1607	1415	1415
query60	310	288	252	252
query61	170	147	148	147
query62	553	484	429	429
query63	245	197	207	197
query64	2774	1039	842	842
query65	4776	4634	4594	4594
query66	1813	502	381	381
query67	29322	29252	29155	29155
query68	3356	1573	1016	1016
query69	416	306	271	271
query70	1070	944	990	944
query71	368	353	357	353
query72	3057	2661	2387	2387
query73	848	776	459	459
query74	5031	4924	4744	4744
query75	2636	2496	2127	2127
query76	2335	1175	779	779
query77	346	378	285	285
query78	11838	11848	11323	11323
query79	1347	1108	749	749
query80	1303	544	478	478
query81	537	336	287	287
query82	604	161	122	122
query83	366	333	301	301
query84	279	155	130	130
query85	967	598	518	518
query86	419	301	290	290
query87	1830	1827	1767	1767
query88	3673	2769	2748	2748
query89	444	371	341	341
query90	1956	198	200	198
query91	206	188	160	160
query92	61	65	55	55
query93	1684	1482	973	973
query94	706	341	310	310
query95	807	590	463	463
query96	997	799	340	340
query97	2607	2618	2482	2482
query98	220	204	201	201
query99	1078	1114	977	977
Total cold run time: 263625 ms
Total hot run time: 177492 ms

@hello-stephen

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

query1	0.01	0.01	0.01
query2	0.10	0.05	0.05
query3	0.25	0.14	0.13
query4	1.61	0.14	0.14
query5	0.24	0.23	0.22
query6	1.26	1.10	1.06
query7	0.04	0.01	0.01
query8	0.06	0.04	0.04
query9	0.38	0.34	0.32
query10	0.56	0.55	0.55
query11	0.19	0.14	0.14
query12	0.18	0.14	0.14
query13	0.47	0.46	0.47
query14	1.03	1.00	1.00
query15	0.64	0.59	0.59
query16	0.33	0.32	0.31
query17	1.11	1.13	1.05
query18	0.22	0.21	0.20
query19	2.07	1.92	1.95
query20	0.02	0.02	0.01
query21	15.42	0.22	0.15
query22	4.92	0.05	0.05
query23	16.14	0.32	0.12
query24	3.03	0.40	0.31
query25	0.11	0.04	0.03
query26	0.73	0.21	0.14
query27	0.04	0.03	0.04
query28	3.44	0.88	0.52
query29	12.47	4.05	3.28
query30	0.28	0.16	0.16
query31	2.77	0.60	0.31
query32	3.22	0.59	0.50
query33	3.19	3.18	3.21
query34	15.67	4.19	3.54
query35	3.54	3.54	3.54
query36	0.56	0.43	0.42
query37	0.09	0.07	0.07
query38	0.05	0.05	0.04
query39	0.04	0.03	0.04
query40	0.17	0.16	0.15
query41	0.09	0.04	0.04
query42	0.04	0.03	0.03
query43	0.05	0.03	0.03
Total cold run time: 96.83 s
Total hot run time: 25.02 s

@sollhui

sollhui commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review outcome: request changes. The review is complete after two full rounds; the normal core, normal surface, and risk-focused reviewers all converged on the same final ledger and returned NO_NEW_VALUABLE_FINDINGS.

Three new P1 findings are attached inline:

  1. The implementation is Kafka-only although the PR contract advertises Kafka/Kinesis target switching.
  2. A topic-only switch on a pinned Kafka job clears progress but does not re-seed the retained partitions, so resume builds tasks with null offsets.
  3. Flexible-update validation ignores a COLUMNS descriptor staged by the same ALTER and persists a definition CREATE explicitly rejects.

Critical checkpoint conclusions:

  • Goal, scope, and tests: the 16 changed files are focused on FE routine-load ALTER syntax/state plus FE and regression coverage. The Kafka happy path is covered, but the advertised Kinesis path is absent, and coverage is missing for pinned topic-only resume and combined flexible-mode/COLUMNS ALTERs.
  • Correctness, concurrency, and parallel paths: job-lock publication and stale-task transaction fencing were traced. Existing target/mode, target/descriptor, mutable-table-ID, rename-authorization, and caller-context races were not duplicated. The new staged-definition and pinned-partition failures remain distinct.
  • Lifecycle, persistence, and compatibility: live apply, EditLog replay, checkpoint reconstruction, Cloud reset retry, RPC partial failure, crash/failover, resume, and auto-resume were reviewed. Optional new log fields are backward-compatible and the deferred Cloud reset converges; existing checkpoint and follower-local replay defects remain covered by prior threads. The parser change appears intentional, but the Kinesis release contract does not match implementation.
  • Security: authentication/authorization ordering was checked against the repository threat model. The current head addresses metadata lookup before target authorization; existing rename and mutable-table-ID privilege threads remain the applicable security findings. No additional distinct security issue was found.
  • Configuration, protocol/data writes, performance, and observability: no new configuration items, FE/BE protocol variables, storage schema changes, or data-write paths were added. Kafka/MetaService work is staged outside metadata locks in the current head; no additional substantiated performance or observability issue was found.
  • Validation status: no local build or test was run because the review contract forbids it. Live CI shows FE UT, compile, P0, external, nonconcurrent, cloud P0, and vault P0 passing; check_coverage_fe is failing.
  • Existing discussion and focus: live inline threads were re-read immediately before submission and these comments do not duplicate them. No additional user focus was supplied.

Comment thread fe/fe-core/src/main/java/org/apache/doris/load/routineload/RoutineLoadJob.java Outdated
### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#64878

Problem Summary: Keep ALTER ROUTINE LOAD target-table switching composable with existing job and Kafka/Kinesis data-source properties while removing unrelated Kafka ALTER atomicity, Cloud progress staging, partial-update compatibility, and RoutineLoadDesc persistence changes from this PR.

### Release note

ALTER ROUTINE LOAD supports SET TARGET TABLE together with supported job and Kafka/Kinesis data-source properties.

### Check List (For Author)

- Test:
    - Unit Test: Focused Routine Load FE UT, 34 tests passed
    - Build: ./build.sh --fe -j48
    - Regression test: Added Kafka end-to-end coverage; not run locally because an isolated FE/BE/Kafka cluster was not started
- Behavior changed: Yes. Paused single-table Kafka and Kinesis Routine Load jobs can switch target tables while preserving progress.
- Does this need documentation: Yes. apache/doris-website#3988
@0AyanamiRei

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17696	4113	4050	4050
q2	2013	325	195	195
q3	10284	1378	842	842
q4	4672	477	340	340
q5	7552	831	551	551
q6	194	172	140	140
q7	746	806	617	617
q8	9683	1373	1399	1373
q9	5907	4337	4304	4304
q10	6810	1735	1448	1448
q11	509	352	334	334
q12	765	608	472	472
q13	18157	3315	2686	2686
q14	267	260	246	246
q15	q16	781	778	710	710
q17	993	1046	990	990
q18	6974	5891	5524	5524
q19	1371	1264	1090	1090
q20	751	660	590	590
q21	5708	2578	2381	2381
q22	425	356	304	304
Total cold run time: 102258 ms
Total hot run time: 29187 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4492	4402	4497	4402
q2	287	313	209	209
q3	4583	4957	4468	4468
q4	2045	2222	1368	1368
q5	4404	4248	4290	4248
q6	239	178	132	132
q7	1708	1955	1704	1704
q8	2493	2242	2109	2109
q9	7863	7728	7730	7728
q10	4676	4654	4175	4175
q11	586	415	386	386
q12	749	754	541	541
q13	3403	3713	3015	3015
q14	308	315	274	274
q15	q16	715	734	642	642
q17	1365	1331	1339	1331
q18	8034	7464	6802	6802
q19	1152	1084	1108	1084
q20	2226	2224	1919	1919
q21	5261	4606	4466	4466
q22	540	492	399	399
Total cold run time: 57129 ms
Total hot run time: 51402 ms

@0AyanamiRei

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17577	4085	4086	4085
q2	2038	356	203	203
q3	10245	1416	823	823
q4	4732	474	337	337
q5	7942	877	572	572
q6	273	172	136	136
q7	800	815	617	617
q8	10712	1667	1594	1594
q9	5925	4377	4393	4377
q10	6848	1756	1464	1464
q11	525	347	319	319
q12	728	586	455	455
q13	18092	3398	2763	2763
q14	259	259	241	241
q15	q16	787	784	723	723
q17	1044	1041	985	985
q18	7149	5816	5670	5670
q19	1168	1308	1063	1063
q20	808	692	606	606
q21	5814	2674	2340	2340
q22	427	364	295	295
Total cold run time: 103893 ms
Total hot run time: 29668 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4399	4304	4315	4304
q2	302	320	213	213
q3	4621	5025	4459	4459
q4	2075	2180	1357	1357
q5	4403	4286	4289	4286
q6	258	173	125	125
q7	1741	1635	1443	1443
q8	2279	1988	1932	1932
q9	7191	7448	7155	7155
q10	4711	4594	4163	4163
q11	538	400	359	359
q12	760	751	540	540
q13	2998	3376	2813	2813
q14	302	295	270	270
q15	q16	680	706	617	617
q17	1296	1260	1266	1260
q18	7283	7023	6963	6963
q19	1125	1098	1115	1098
q20	2239	2210	1953	1953
q21	5268	4566	4368	4368
q22	540	464	410	410
Total cold run time: 55009 ms
Total hot run time: 50088 ms

@hello-stephen

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

query5	4380	632	516	516
query6	473	247	242	242
query7	3593	582	354	354
query8	220	194	177	177
query9	4538	4087	4049	4049
query10	394	349	301	301
query11	2591	2357	2127	2127
query12	151	107	104	104
query13	607	555	422	422
query14	5605	5193	4920	4920
query14_1	4276	4213	4281	4213
query15	206	208	179	179
query16	654	476	451	451
query17	698	718	572	572
query18	463	472	352	352
query19	205	191	153	153
query20	110	108	107	107
query21	172	162	142	142
query22	13529	13542	13402	13402
query23	17412	16566	16079	16079
query23_1	16231	16259	16224	16224
query24	9339	1754	1294	1294
query24_1	1271	1299	1285	1285
query25	578	462	380	380
query26	1362	345	207	207
query27	2636	597	375	375
query28	4373	2000	1980	1980
query29	1048	648	488	488
query30	442	275	235	235
query31	1136	1090	973	973
query32	111	62	64	62
query33	789	324	265	265
query34	1458	1144	632	632
query35	854	779	663	663
query36	1202	1185	1076	1076
query37	156	109	96	96
query38	1883	1710	1622	1622
query39	901	888	874	874
query39_1	831	865	873	865
query40	244	165	140	140
query41	63	64	62	62
query42	91	91	93	91
query43	315	333	290	290
query44	1441	782	758	758
query45	195	181	175	175
query46	1095	1211	699	699
query47	2129	2110	1985	1985
query48	399	412	306	306
query49	583	457	303	303
query50	1081	425	332	332
query51	10894	10393	10315	10315
query52	85	84	72	72
query53	254	279	198	198
query54	411	242	223	223
query55	166	74	66	66
query56	298	299	283	283
query57	1313	1294	1170	1170
query58	320	269	255	255
query59	1665	1673	1473	1473
query60	318	278	261	261
query61	149	148	153	148
query62	541	493	431	431
query63	241	202	199	199
query64	3332	1043	885	885
query65	4716	4624	4627	4624
query66	2286	563	381	381
query67	29320	29393	29256	29256
query68	3159	1623	1004	1004
query69	411	295	273	273
query70	1043	962	1000	962
query71	368	346	326	326
query72	3475	2672	2450	2450
query73	803	810	409	409
query74	5077	4983	4747	4747
query75	2532	2508	2137	2137
query76	3011	1187	781	781
query77	353	383	288	288
query78	11967	11946	11399	11399
query79	1334	1108	767	767
query80	686	560	462	462
query81	462	349	290	290
query82	550	158	122	122
query83	407	319	302	302
query84	326	161	129	129
query85	953	622	524	524
query86	354	286	278	278
query87	1825	1818	1745	1745
query88	3686	2774	2757	2757
query89	429	376	322	322
query90	1778	185	194	185
query91	202	189	160	160
query92	73	61	59	59
query93	1675	1517	1016	1016
query94	567	342	310	310
query95	794	580	488	488
query96	1047	810	362	362
query97	2616	2633	2469	2469
query98	218	205	197	197
query99	1104	1126	1005	1005
Total cold run time: 246687 ms
Total hot run time: 177835 ms

@hello-stephen

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

query1	0.01	0.00	0.00
query2	0.10	0.05	0.06
query3	0.29	0.14	0.14
query4	1.61	0.14	0.15
query5	0.25	0.22	0.21
query6	1.24	1.10	1.05
query7	0.05	0.01	0.01
query8	0.07	0.04	0.04
query9	0.37	0.31	0.31
query10	0.60	0.54	0.54
query11	0.19	0.14	0.14
query12	0.18	0.14	0.14
query13	0.46	0.48	0.47
query14	1.01	1.00	1.01
query15	0.62	0.59	0.59
query16	0.31	0.31	0.32
query17	1.09	1.12	1.11
query18	0.22	0.20	0.20
query19	1.98	1.91	1.95
query20	0.02	0.02	0.01
query21	15.43	0.22	0.13
query22	4.83	0.06	0.05
query23	16.14	0.30	0.12
query24	2.88	0.43	0.32
query25	0.10	0.06	0.04
query26	0.73	0.20	0.15
query27	0.03	0.03	0.05
query28	3.50	0.91	0.55
query29	12.47	4.08	3.29
query30	0.28	0.15	0.15
query31	2.79	0.59	0.31
query32	3.22	0.59	0.48
query33	3.14	3.28	3.19
query34	15.51	4.24	3.53
query35	3.55	3.53	3.53
query36	0.56	0.45	0.43
query37	0.09	0.06	0.07
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.18	0.16	0.16
query41	0.09	0.03	0.03
query42	0.05	0.03	0.03
query43	0.04	0.04	0.04
Total cold run time: 96.37 s
Total hot run time: 25.06 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 67.65% (46/68) 🎉
Increment coverage report
Complete coverage report

@sollhui

sollhui commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Requesting changes for four distinct correctness issues on the current head: the explicit FROM source type is discarded, target compatibility is checked against the old rather than effective job properties, and rejected combined ALTERs can leave unjournaled live mutations in both Kafka and Kinesis jobs.

Checkpoint conclusions:

  • Goal and scope: the target-table switch is otherwise focused and the target-only Kafka/Kinesis plumbing, progress preservation, legacy-log zero default, and replay assignment are present. The four issues below prevent the advertised combined transition from being safe.
  • Concurrency, lifecycle, and atomicity: paused-job locking and task clearing were traced through resume and transaction callbacks. Existing threads already cover mutable-target races; the two new source-specific findings below are distinct non-concurrent validation-to-commit failures.
  • Validation and compatibility: TARGET remains non-reserved, ordinary string decoding is preserved, and target OLAP/non-temporary/single-table checks are present. However, the parsed source type is not preserved and same-statement effective update properties are omitted from target planning.
  • Parallel paths and persistence: Kafka and Kinesis both assign and replay the new target ID, but both also mutate live source state before a throwable membership check and before the target/EditLog commit point, so a failed command diverges from durable state. Existing replay, image, Cloud, and journal-lock concerns were deduplicated against live threads.
  • Tests and results: the changed tests cover matching parser forms, happy-path target switches, progress preservation, and legacy-log reading, but not these four negative cases. No local build or tests were run, as required by the review task. Live FE UT, compile, formatter, license, P0/nonconcurrent/external regression, performance, and vault P0 checks pass; cloud_p0 and check_coverage_fe are red, and their TeamCity details require authentication.
  • Performance and observability: target validation adds planning only on explicit ALTER, not a scheduling hot path, and existing ALTER errors, job logs, SHOW state, and journal metrics remain available. No additional issue was found here.
  • User focus: no extra focus points were supplied.

All three independent reviewers reread this exact four-comment set and returned NO_NEW_VALUABLE_FINDINGS on round 2. The live head and inline-thread set were refreshed immediately before submission, and no unresolved or duplicate candidate remains.

}

return new AlterRoutineLoadCommand(labelNameInfo, loadPropertyMap, properties, dataSourceMapProperties);
return new AlterRoutineLoadCommand(labelNameInfo, targetTableName,

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 and validate the explicit FROM type. The grammar records ctx.type, but this builder drops it; checkDataSourceProperties() then creates the source-property object from the job's existing type, so RoutineLoadManager's later comparison is always the job type against itself. For example, a Kafka job accepts SET TARGET TABLE = "B" FROM KINESIS("property.client.id"="x") as KafkaDataSourceProperties because property.* is legal there, despite the explicit KINESIS token. Carry the parsed type into the command and reject unknown or non-matching types before constructing the property object, with cross-type negative tests.

checkDataSourceProperties();
checkPartialUpdate();
if (hasTargetTable()) {
validateTargetTable(ctx, job);

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] Plan the target with the statement's effective job properties. This call validates B using the job's current update mode because analyzedJobProperties is never overlaid. A paused UPSERT job on MoW table A can therefore switch to non-MoW B while setting unique_key_update_mode=UPDATE_FIXED_COLUMNS: B is planned as UPSERT and accepted, both job implementations install the fixed-update mode and then B's ID, and the first resumed task fails with Only unique key merge on write support partial update. Build one staged task definition containing the target and analyzed property delta, validate that definition, and add this non-concurrent combined case.

@@ -782,9 +782,12 @@ public void modifyProperties(AlterRoutineLoadCommand command) throws UserExcepti
}

modifyPropertiesInternal(jobProperties, dataSourceProperties);

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 a failed combined ALTER side-effect-free. modifyPropertiesInternal() runs before the target assignment and journal, and it publishes custom Kafka properties before checkPartitions(). On a job consuming partition 0, SET TARGET TABLE = "B" FROM KAFKA("property.client.id"="new", "kafka_partitions"="999", "kafka_offsets"="0") installs client.id, then throws because partition 999 is absent; the command reports failure with the old target and no EditLog record, but the live job has changed until failover/restart. Validate immutable staged copies first, then publish the complete target/job/source delta atomically, and assert every field is unchanged on failure.

@@ -687,9 +687,12 @@ public void modifyProperties(AlterRoutineLoadCommand command) throws UserExcepti
}

modifyPropertiesInternal(jobProperties, dataSourceProperties);

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] Apply the same failure atomicity to Kinesis. modifyPropertiesInternal() merges custom properties and replaces customKinesisShards before checkShards(), while the target assignment and EditLog call happen only afterward. A combined target ALTER that supplies property.client.timeout plus a nonexistent explicit shard therefore fails the membership check but leaves the live job's custom properties and pinned shard list changed, with the old target and no journal; resume and failover then observe different definitions. Stage source properties, shard lists/progress, common fields, and the target off-object, validate everything, and only then publish and journal the complete delta.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants