Skip to content

[refactor](changelog) Use explicit column mappings for reads and writes - #69585

Open
TsukiokaKogane wants to merge 1 commit into
apache:masterfrom
TsukiokaKogane:refactor_change_log_column_mapping
Open

TsukiokaKogane wants to merge 1 commit into
apache:masterfrom
TsukiokaKogane:refactor_change_log_column_mapping

Conversation

@TsukiokaKogane

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: close #xxx

Related PR: #xxx

Problem Summary:

Changelog execution currently infers current/before column relationships from column names and physical positions. This couples read projection and write processing to the storage layout, while publish retries and recovery lack an explicit, transaction-bound mapping contract.

This PR introduces structured column mappings across FE and BE:

  • FE generates slot pairs for reads and immutable UID mappings for writes.
  • Write mappings are bound to actual transaction IDs, frozen at precommit or commit, and retained for replay and lagging-replica republish.
  • Remote commit, asynchronous publish, and Cloud transaction contexts carry the same write-time snapshots.
  • BE resolves UID mappings into schema-bound column positions once per write or publish operation. Scanner translates read slot pairs into ReadSchema ordinals.

The change removes execution-time relationship inference, preserves key-only historical lookup and complete-row comparison for MIN_DELTA, and validates mappings before publication. Ordinary writes do not require changelog mappings. Mixed-version compatibility adapters are outside the scope of this PR.

Release note

None

Check List (For Author)

  • Test

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

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

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

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

@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@TsukiokaKogane
TsukiokaKogane force-pushed the refactor_change_log_column_mapping branch from 9db0ae2 to 3411ce2 Compare October 25, 2026 09:38
### What problem does this PR solve?

Related PR: apache#67456, apache#66472

Problem Summary: Changelog execution inferred current/before relationships
from column names and layout positions, coupling query projection to storage
layout and leaving publish retries without a stable write-time relationship.
Plan explicit slot pairs for reads and immutable source/current/before UID
snapshots for writes. Register snapshots against actual transaction IDs,
freeze them at precommit/commit, and retain them for replay and lagging-replica
republish. Propagate the same snapshots through remote commit, pending publish
persistence and Cloud transaction contexts. Resolve a schema-bound CID layout
once per write/publish operation and keep query protocol parsing in Scanner.
Validate mappings before visibility, preserve key-only historical lookup,
and propagate pending-record save failures before queueing asynchronous work.

### Release note

Changelog reads and writes use explicit column mappings. Changelog requests
requiring mappings now reject missing or malformed mappings. Mixed-version
adapters and rolling-upgrade behavior are outside this implementation scope.

### Check List (For Author)

- Test: 85 targeted FE unit tests passed. FE and ASAN BE builds passed. FE Checkstyle, clang-format 16, header hygiene, changed-line clang-tidy and git diff --check passed. BE unit compilation was stopped at the user's request before execution; no BE unit pass result is claimed. Regression tests were not run at the user's request. Existing macOS ANN test portability adjustments used locally are excluded from this commit.
- Behavior changed: Yes (explicit changelog protocol contract and transaction-bound recovery snapshots; ordinary writes do not require mappings).
- Does this need documentation: No (local design and implementation notes are excluded from this code commit).
@TsukiokaKogane
TsukiokaKogane force-pushed the refactor_change_log_column_mapping branch from 3411ce2 to fe2e078 Compare October 25, 2026 09:39
@TsukiokaKogane

Copy link
Copy Markdown
Contributor Author

run buildall

@TsukiokaKogane

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Request changes: two P1 regressions remain at head fe2e078: transactional VALUES into changelog tables fails through non-master FEs, and existing changelog tables created with light_schema_change=false lose write availability after upgrade. Both are explained inline. There were no existing inline threads to carry forward.

Static review covered all 88 changed files and their related FE/BE control flow. Three reviewers covered FE, BE, and transaction snapshot durability; the final unchanged finding set converged in round 2. No additional user focus was supplied.

Critical checkpoint conclusions:

  1. Goal and proof: explicit read slot pairs and transaction-bound write UID snapshots implement the intended identity contract on the checked normal paths. The two inline scenarios prevent the goal being met for all supported tables and FE roles. Added unit tests cover resolver validation, reordered tuples, immutable snapshots, replay, pending-publish persistence, queue rejection, and Cloud bitmap eviction; they miss these two scenarios.
  2. Scope and clarity: changes stay focused on mapping production, transport, resolution, and corresponding reader API/test updates.
  3. Concurrency: immutable snapshot replacement and synchronized status transitions freeze registration before PRECOMMITTED/COMMITTED persistence. BE queues use _async_publish_lock; transaction locks retain txn-before-map order, and normal/async publishers retain changelog-before-base tablet locking. Retry cleanup releases tablet locks before requeueing. No additional lock inversion was substantiated.
  4. Lifecycle and static initialization: layouts pin both schemas; synchronous derive contexts borrow the owned layout; queued/running/retry tasks retain mappings. No new global initializer or ownership cycle was found.
  5. Configuration: none added.
  6. Compatibility: new pending metadata is optional, but persisted old source UIDs are not migrated (second finding). Mixed-version adapters are explicitly excluded by the PR: an older remote writer omitting the new snapshot list is rejected even for an ordinary target. This declared limit is not separately reposted as an inline finding.
  7. Thrift/protobuf: every touched definition was compared with live-current branch-3.1, branch-4.0, branch-4.1, and branch-4.2. New IDs are unused there, new fields are optional/repeated, and no enum or existing field meaning is changed.
  8. Parallel paths: local/Cloud group writers, normal/async publish, recovery, bitmap-cache misses, remote commit, broker/stream/routine loads, actual-child republish, direct/vertical readers, compaction, and schema change were traced. The non-master VALUES exception is the first finding.
  9. Conditional checks: validation branches correspond to concrete malformed mappings/projections or failed persistence/ownership transfer. Existing VARIANT rejection excludes the suspected extracted-column layout mismatch.
  10. Test coverage: useful unit cases were added, but follower transactional VALUES and replay of old light-schema-change-disabled tables need coverage. No build, unit test, regression run, or runtime fault injection was performed under this static-only contract.
  11. Expected results: no regression .out files changed; new unit expectations were inspected against the relevant layouts and error paths.
  12. Observability: missing mappings report transaction/tablet context, queue submission failure logs tablet/version/status, and existing publish statistics remain. No additional metric requirement was established.
  13. Transactions and persistence: commit/precommit Gson state carries actual-write snapshots in both edit-log modes; replay rebuilds retained child aliases. Durable pending records retain the same mapping across restart and async retry; Cloud TxnVal preserves it independently of bitmap-LRU eviction.
  14. Writes and atomicity: layout validation precedes rowset visibility, and existing bitmap/dual-rowset ordering remains. No additional new crash/atomicity defect was substantiated on the checked paths.
  15. FE-BE variables: read pairs, sink schema thrift/protobuf forwarding, publish/republish snapshots, remote commit, Cloud attachment, and pending-record recovery are covered. The first finding identifies where registration fails before transport.
  16. Performance: layout resolution occurs per writer/publish operation; derive reuses resolved vectors and COW columns. No new rowwise name lookup, pathological retry scan, or significant allocation regression was substantiated.
  17. Other invariants: version visibility and MoW placeholder replacement are unchanged; nullable widening uses the existing helper, and error paths fail before publication. No additional verified issue was found in the final recheck.

Convergence: true, 2 rounds. Remaining limits: static analysis only; no runtime or build validation, and mixed-version behavior has the declared limitation above. No unresolved candidate or uncovered assigned scope remains.

Review converged after 2 round(s).

taskInfo.isLoadToSingleTablet(), taskInfo.isStrictMode(), timeout, uniquekeyUpdateMode,
uniquekeyUpdateNewRowPolicy, partialUpdateInputColumns);
if (!Config.isCloudMode() && !(loadPlanInfo.olapTableSink instanceof GroupCommitBlockSink)) {
Env.getCurrentGlobalTransactionMgr().registerChangelogWriteMappings(dbId, taskInfo.getTxnId(),

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] Register transactional VALUES snapshots on the master

In a shared-nothing cluster, connect to a follower/observer and run BEGIN; INSERT INTO t VALUES (...); COMMIT; against a changelog-enabled table. BatchInsertIntoTableCommand implements NoForward: InsertUtils.beginBatchInsertTransaction forwards only beginTxn to the master, then InsertStreamTxnExecutor plans locally. The master's BACKEND_STREAMING PREPARE state is deliberately not journaled (DatabaseTransactionMgr.persistTransactionState / enqueueTransactionState), so this new local registration throws Cannot register changelog mappings for missing transaction ... before execution. Forward the exact write snapshot to the transaction-owning master, or perform planning there; merely skipping follower registration would leave the required publish snapshot missing. Please cover explicit transactional VALUES through a non-master FE.

Preconditions.checkState(before != null, "Missing before column: %s", source.getName());
beforeUid = before.getUniqueId();
}
entries.add(new Entry(source.getUniqueId(), current.getUniqueId(), beforeUid));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Migrate existing changelog source IDs before requiring unique UIDs

A changelog DUP table (k INT, v INT) created before this change with light_schema_change=false is valid, but both source columns retain UID -1: the old table UID initializer returned early, while only the companion index initialized its IDs. The new OlapTable.initSchemaColumnUniqueId guard fixes new creations, but its caller is the create-table path; neither OlapTable.gsonPostProcess nor MaterializedIndexMeta.gsonPostProcess migrates existing source IDs. After a full upgrade, every INSERT/load into that persisted table reaches this method and fails with Duplicate source UID: -1 in the constructor. Provide compatible identity migration/resolution for the existing FE/BE schemas before requiring unique source UIDs, and add coverage that loads an old catalog with this table property.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17632	5275	5094	5094
q2	2121	351	250	250
q3	10213	1383	843	843
q4	4684	464	335	335
q5	7431	804	544	544
q6	184	185	152	152
q7	758	788	610	610
q8	9260	1349	1045	1045
q9	5585	4214	4201	4201
q10	6839	1301	1043	1043
q11	431	250	228	228
q12	631	398	275	275
q13	18105	3556	3027	3027
q14	279	281	254	254
q15	q16	729	713	676	676
q17	1227	750	570	570
q18	7131	6243	6163	6163
q19	1115	1000	613	613
q20	422	337	229	229
q21	4969	2127	2310	2127
q22	346	297	256	256
Total cold run time: 100092 ms
Total hot run time: 28535 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5615	5633	5612	5612
q2	667	579	550	550
q3	5243	5399	4912	4912
q4	1987	2176	1544	1544
q5	5301	5173	5679	5173
q6	256	202	147	147
q7	2363	2126	1981	1981
q8	3070	2876	2725	2725
q9	8099	7952	7976	7952
q10	3748	3677	3235	3235
q11	614	456	410	410
q12	685	722	524	524
q13	3483	3812	3253	3253
q14	301	325	314	314
q15	q16	703	724	675	675
q17	8272	7492	7519	7492
q18	13012	12221	12979	12221
q19	912	780	788	780
q20	2162	2144	1919	1919
q21	5710	4631	4727	4631
q22	505	434	404	404
Total cold run time: 72708 ms
Total hot run time: 66454 ms

@hello-stephen

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

query5	4311	590	443	443
query6	425	205	200	200
query7	4813	439	222	222
query8	318	167	154	154
query9	8765	3066	3063	3063
query10	480	314	276	276
query11	6061	3872	3580	3580
query12	147	89	86	86
query13	1249	451	325	325
query14	6046	3915	3648	3648
query14_1	3434	3438	3431	3431
query15	206	201	182	182
query16	929	456	441	441
query17	866	667	571	571
query18	2423	430	321	321
query19	195	178	136	136
query20	84	86	84	84
query21	201	128	108	108
query22	12939	12974	12809	12809
query23	13605	12883	12442	12442
query23_1	12583	12682	12545	12545
query24	7388	817	464	464
query24_1	480	484	476	476
query25	534	413	366	366
query26	1266	254	141	141
query27	2781	441	264	264
query28	4617	1921	1901	1901
query29	1574	617	455	455
query30	308	222	189	189
query31	995	929	819	819
query32	151	98	90	90
query33	528	312	252	252
query34	898	846	494	494
query35	738	769	645	645
query36	820	841	713	713
query37	117	99	88	88
query38	1770	1759	1670	1670
query39	798	813	750	750
query39_1	736	729	744	729
query40	230	120	99	99
query41	74	67	69	67
query42	90	86	83	83
query43	336	365	318	318
query44	1295	670	680	670
query45	179	182	174	174
query46	810	993	562	562
query47	3027	3001	2545	2545
query48	292	302	215	215
query49	570	383	293	293
query50	667	279	214	214
query51	10591	10299	10237	10237
query52	78	80	69	69
query53	182	208	153	153
query54	242	188	172	172
query55	69	67	68	67
query56	221	204	209	204
query57	1627	1613	1584	1584
query58	278	266	249	249
query59	2139	2222	1924	1924
query60	281	237	219	219
query61	141	134	135	134
query62	388	330	280	280
query63	185	153	159	153
query64	2730	937	750	750
query65	3323	3261	3262	3261
query66	1777	438	291	291
query67	20068	20346	20288	20288
query68	2974	1002	607	607
query69	385	292	251	251
query70	848	802	743	743
query71	300	229	204	204
query72	2694	2564	2317	2317
query73	513	517	292	292
query74	4610	4523	4329	4329
query75	2341	2270	1920	1920
query76	2308	1018	589	589
query77	338	363	263	263
query78	9973	9836	9233	9233
query79	952	889	513	513
query80	1269	416	324	324
query81	577	319	276	276
query82	572	133	103	103
query83	272	195	177	177
query84	307	126	103	103
query85	1094	420	372	372
query86	387	246	229	229
query87	1969	1925	1788	1788
query88	3611	2643	2624	2624
query89	327	286	238	238
query90	1835	166	163	163
query91	162	150	122	122
query92	100	87	92	87
query93	990	994	564	564
query94	580	311	281	281
query95	574	384	312	312
query96	677	480	227	227
query97	2446	2434	2319	2319
query98	156	148	147	147
query99	782	763	659	659
Total cold run time: 235234 ms
Total hot run time: 150609 ms

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17391	5269	5056	5056
q2	2151	307	245	245
q3	10146	1402	828	828
q4	4678	457	333	333
q5	7425	794	542	542
q6	186	189	156	156
q7	731	793	603	603
q8	9265	1330	1104	1104
q9	5398	4201	4175	4175
q10	6827	1282	1040	1040
q11	428	246	234	234
q12	641	394	278	278
q13	18115	3537	3005	3005
q14	275	278	252	252
q15	q16	735	706	690	690
q17	1205	764	596	596
q18	6919	6161	6122	6122
q19	1103	946	620	620
q20	390	336	229	229
q21	4632	2198	2304	2198
q22	341	295	255	255
Total cold run time: 98982 ms
Total hot run time: 28561 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5609	5595	5585	5585
q2	681	567	536	536
q3	5209	5409	4987	4987
q4	1990	2147	1538	1538
q5	5268	5149	5431	5149
q6	255	206	156	156
q7	2313	2035	1879	1879
q8	3110	2668	2725	2668
q9	8035	8014	7924	7924
q10	3717	3685	3261	3261
q11	613	591	422	422
q12	710	714	512	512
q13	3495	3937	3251	3251
q14	337	337	304	304
q15	q16	730	706	662	662
q17	8211	7455	6856	6856
q18	13023	12235	12952	12235
q19	901	801	808	801
q20	2157	2160	1927	1927
q21	5621	4590	4707	4590
q22	497	457	412	412
Total cold run time: 72482 ms
Total hot run time: 65655 ms

@hello-stephen

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

query5	4308	576	451	451
query6	416	210	190	190
query7	4819	428	236	236
query8	311	169	151	151
query9	8782	3098	3087	3087
query10	478	311	262	262
query11	5976	3853	3559	3559
query12	144	90	86	86
query13	1242	418	308	308
query14	6175	3944	3645	3645
query14_1	3460	3431	3406	3406
query15	206	199	189	189
query16	942	447	414	414
query17	862	680	526	526
query18	2422	428	316	316
query19	199	165	138	138
query20	87	83	84	83
query21	214	127	106	106
query22	13014	13001	12889	12889
query23	13632	12720	12550	12550
query23_1	12560	12565	12647	12565
query24	7312	835	460	460
query24_1	475	494	485	485
query25	546	439	396	396
query26	1264	252	137	137
query27	2766	440	280	280
query28	4604	1916	1931	1916
query29	1556	596	472	472
query30	301	229	181	181
query31	1000	935	814	814
query32	163	96	96	96
query33	539	305	265	265
query34	942	847	506	506
query35	737	738	652	652
query36	850	845	732	732
query37	124	100	82	82
query38	1770	1725	1692	1692
query39	797	796	749	749
query39_1	733	722	764	722
query40	223	115	100	100
query41	71	69	68	68
query42	89	85	88	85
query43	344	370	313	313
query44	1287	682	701	682
query45	177	181	165	165
query46	843	973	572	572
query47	2896	2986	2862	2862
query48	302	310	245	245
query49	576	396	298	298
query50	664	266	204	204
query51	10286	10251	10558	10251
query52	83	84	68	68
query53	187	208	151	151
query54	237	218	173	173
query55	68	65	68	65
query56	239	212	210	210
query57	1649	1623	1564	1564
query58	284	259	264	259
query59	2149	2134	1954	1954
query60	290	241	240	240
query61	145	150	146	146
query62	392	328	299	299
query63	188	156	161	156
query64	2765	951	757	757
query65	3343	3262	3256	3256
query66	1773	430	306	306
query67	20374	20238	20135	20135
query68	2977	1005	600	600
query69	388	300	254	254
query70	815	742	773	742
query71	287	234	217	217
query72	2739	2547	2290	2290
query73	514	524	294	294
query74	4601	4524	4355	4355
query75	2331	2281	1930	1930
query76	2294	1016	604	604
query77	345	363	299	299
query78	9835	9746	9201	9201
query79	967	831	531	531
query80	1253	423	354	354
query81	586	327	267	267
query82	578	140	101	101
query83	305	196	182	182
query84	308	127	97	97
query85	870	445	371	371
query86	400	240	233	233
query87	2004	1952	1810	1810
query88	3751	2678	2660	2660
query89	332	273	244	244
query90	1945	164	173	164
query91	161	154	132	132
query92	99	88	83	83
query93	1045	988	568	568
query94	649	308	265	265
query95	565	395	305	305
query96	674	482	235	235
query97	2458	2448	2370	2370
query98	162	154	144	144
query99	772	760	654	654
Total cold run time: 235305 ms
Total hot run time: 151333 ms

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.14	0.09	0.08
query3	0.35	0.13	0.12
query4	1.61	0.13	0.13
query5	0.27	0.25	0.25
query6	1.16	0.66	0.65
query7	0.05	0.01	0.01
query8	0.09	0.07	0.07
query9	0.44	0.37	0.37
query10	0.61	0.56	0.57
query11	0.32	0.17	0.19
query12	0.31	0.18	0.19
query13	0.53	0.51	0.52
query14	0.94	0.93	0.95
query15	0.66	0.58	0.58
query16	0.38	0.35	0.37
query17	1.01	1.02	1.01
query18	0.28	0.28	0.26
query19	1.98	1.90	1.91
query20	0.02	0.01	0.02
query21	15.39	0.34	0.30
query22	4.91	0.14	0.12
query23	15.82	0.48	0.28
query24	2.07	0.55	0.39
query25	0.16	0.10	0.11
query26	0.79	0.26	0.20
query27	0.11	0.10	0.09
query28	3.45	0.85	0.40
query29	12.61	4.41	3.41
query30	0.34	0.17	0.14
query31	2.76	0.57	0.33
query32	3.22	0.59	0.47
query33	2.96	3.02	3.10
query34	15.89	4.08	3.46
query35	3.39	3.39	3.37
query36	0.57	0.51	0.49
query37	0.12	0.10	0.10
query38	0.08	0.07	0.07
query39	0.06	0.06	0.06
query40	0.19	0.16	0.16
query41	0.11	0.06	0.05
query42	0.06	0.06	0.06
query43	0.07	0.06	0.05
Total cold run time: 96.29 s
Total hot run time: 25.26 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 61.69% (161/261) 🎉
Increment coverage report
Complete coverage report

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants