Skip to content

[feature](iceberg) Support Iceberg position deletes system table#65135

Open
hubgeter wants to merge 16 commits into
apache:masterfrom
hubgeter:support_iceberg_sys_pos_del
Open

[feature](iceberg) Support Iceberg position deletes system table#65135
hubgeter wants to merge 16 commits into
apache:masterfrom
hubgeter:support_iceberg_sys_pos_del

Conversation

@hubgeter

@hubgeter hubgeter commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: close #xxx

Related PR: #xxx

Problem Summary:

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?

@hubgeter

hubgeter commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@hubgeter

hubgeter commented Jul 2, 2026

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.

Requesting changes for one correctness issue in the new Iceberg position_deletes system table path.

Subagent results: optimizer-rewrite and tests-session-config both completed their initial passes without candidates. After MAIN-1 was added to the proposed final comment set, convergence round 1 asked both live agents to review the same ledger/comment set; both replied exactly NO_NEW_VALUABLE_FINDINGS.

User focus: no additional user-provided review focus.

Checkpoint conclusions: static review covered the FE table function/system-table resolution path, Iceberg split construction, Thrift handoff, BE position-delete reader, and the new regression coverage. No existing inline comments were present, so this is not a duplicate. git diff --check passed against the fetched base. I did not run FE/BE builds or tests because this checkout is missing thirdparty/installed and thirdparty/installed/bin/protoc.

Map<String, String> partitionJson = new LinkedHashMap<>();
List<PartitionField> fields = partitionSpec.fields();
for (int i = 0; i < fields.size(); i++) {
partitionJson.put(fields.get(i).name(), partitionValues.get(i));

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.

The partition payload here loses the actual JSON types. getPartitionValues() returns strings for every Iceberg partition value, and Gson serializes this Map<String, String> as e.g. {"id":"1"} for an integer partition. On BE, _append_partition_column() deserializes that object straight into the partition struct column; the struct serde forwards "1" to the numeric field serde, which does not strip JSON quotes, and nullable struct fields then turn the parse failure into NULL. So a table partitioned by an integer/date field will expose wrong partition values in $position_deletes even though the new tests only cover string dt partitions. Please preserve typed JSON values here, and add a regression with at least one non-string partition column.

@hello-stephen

Copy link
Copy Markdown
Contributor

Cloud UT Coverage Report

Increment line coverage 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.39% (1896/2450)
Line Coverage 64.50% (34095/52862)
Region Coverage 64.87% (17536/27032)
Branch Coverage 54.05% (9400/17390)

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 2.84% (5/176) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 0.79% (3/381) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 56.14% (22840/40683)
Line Coverage 39.78% (221486/556718)
Region Coverage 35.78% (175039/489209)
Branch Coverage 36.87% (77900/211261)

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17662	4058	4107	4058
q2	2031	346	202	202
q3	10366	1511	863	863
q4	4762	485	351	351
q5	8156	869	589	589
q6	319	177	137	137
q7	890	863	639	639
q8	10645	1807	1712	1712
q9	5876	4488	4426	4426
q10	6874	1825	1538	1538
q11	515	350	326	326
q12	733	564	438	438
q13	18116	3537	2817	2817
q14	279	259	242	242
q15	q16	804	800	717	717
q17	1032	983	1098	983
q18	7317	5702	5512	5512
q19	1162	1396	1143	1143
q20	963	769	574	574
q21	6008	2900	2714	2714
q22	478	367	307	307
Total cold run time: 104988 ms
Total hot run time: 30288 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4992	4749	4769	4749
q2	294	338	213	213
q3	4999	5159	4673	4673
q4	2092	2450	1396	1396
q5	4760	4676	4908	4676
q6	237	174	129	129
q7	1872	1767	1577	1577
q8	2446	2100	2098	2098
q9	7349	7262	7209	7209
q10	4691	4654	4223	4223
q11	531	385	351	351
q12	753	752	533	533
q13	3058	3386	2760	2760
q14	284	287	275	275
q15	q16	684	709	621	621
q17	1286	1265	1271	1265
q18	7311	6905	6888	6888
q19	1174	1139	1139	1139
q20	2234	2221	1938	1938
q21	5290	4553	4419	4419
q22	530	469	400	400
Total cold run time: 56867 ms
Total hot run time: 51532 ms

@hello-stephen

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

query5	4364	632	483	483
query6	454	220	199	199
query7	4844	589	345	345
query8	341	187	170	170
query9	8755	4021	4038	4021
query10	473	346	300	300
query11	5979	2387	2151	2151
query12	161	104	105	104
query13	1292	605	436	436
query14	6287	5336	5004	5004
query14_1	4298	4288	4290	4288
query15	212	206	183	183
query16	1080	493	435	435
query17	1142	734	608	608
query18	2523	479	354	354
query19	222	200	156	156
query20	111	114	113	113
query21	245	159	137	137
query22	13590	13758	13514	13514
query23	17345	16513	16246	16246
query23_1	16346	16385	16324	16324
query24	7539	1800	1296	1296
query24_1	1342	1328	1297	1297
query25	578	467	390	390
query26	1380	353	206	206
query27	2605	610	383	383
query28	4431	2039	1999	1999
query29	1044	622	472	472
query30	341	255	226	226
query31	1121	1104	1002	1002
query32	112	61	60	60
query33	532	328	256	256
query34	1167	1141	651	651
query35	768	775	685	685
query36	1419	1434	1242	1242
query37	158	104	110	104
query38	1882	1711	1659	1659
query39	917	945	891	891
query39_1	870	876	889	876
query40	259	163	143	143
query41	68	66	68	66
query42	97	94	93	93
query43	323	334	282	282
query44	1429	791	758	758
query45	211	187	184	184
query46	1104	1342	729	729
query47	2416	2335	2289	2289
query48	398	415	298	298
query49	579	428	312	312
query50	1088	431	339	339
query51	4426	4492	4387	4387
query52	86	85	77	77
query53	270	281	207	207
query54	275	225	208	208
query55	75	71	66	66
query56	312	279	283	279
query57	1472	1414	1326	1326
query58	280	266	248	248
query59	1611	1726	1422	1422
query60	318	269	260	260
query61	150	143	149	143
query62	687	653	583	583
query63	252	206	210	206
query64	2556	776	605	605
query65	4915	4822	4798	4798
query66	1829	515	396	396
query67	29810	29786	29516	29516
query68	3174	1498	996	996
query69	425	310	267	267
query70	1009	980	941	941
query71	352	310	316	310
query72	3092	2740	2518	2518
query73	848	780	453	453
query74	5129	4969	4787	4787
query75	2623	2587	2221	2221
query76	2336	1201	798	798
query77	359	390	285	285
query78	12518	12476	11944	11944
query79	1410	1196	788	788
query80	767	540	454	454
query81	491	322	285	285
query82	592	164	121	121
query83	374	314	294	294
query84	291	164	127	127
query85	960	604	521	521
query86	428	294	288	288
query87	1834	1827	1775	1775
query88	3691	2766	2755	2755
query89	476	408	356	356
query90	1904	199	194	194
query91	201	189	165	165
query92	61	64	58	58
query93	1639	1481	933	933
query94	631	377	326	326
query95	807	502	549	502
query96	1098	851	344	344
query97	2702	2675	2551	2551
query98	227	207	201	201
query99	1168	1170	1034	1034
Total cold run time: 259504 ms
Total hot run time: 174067 ms

@hello-stephen

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

query1	0.00	0.01	0.00
query2	0.10	0.04	0.05
query3	0.26	0.14	0.14
query4	1.62	0.15	0.14
query5	0.24	0.22	0.22
query6	1.23	1.10	1.10
query7	0.04	0.01	0.01
query8	0.06	0.04	0.04
query9	0.37	0.31	0.31
query10	0.57	0.56	0.56
query11	0.19	0.14	0.14
query12	0.19	0.15	0.14
query13	0.47	0.48	0.48
query14	1.00	1.02	1.01
query15	0.62	0.61	0.61
query16	0.32	0.33	0.32
query17	1.11	1.14	1.14
query18	0.23	0.22	0.21
query19	2.02	1.98	1.92
query20	0.02	0.01	0.01
query21	15.44	0.22	0.13
query22	4.88	0.05	0.05
query23	16.13	0.32	0.12
query24	3.04	0.44	0.34
query25	0.11	0.05	0.05
query26	0.74	0.21	0.15
query27	0.06	0.04	0.04
query28	3.51	0.94	0.56
query29	12.56	4.35	3.45
query30	0.28	0.15	0.16
query31	2.77	0.59	0.32
query32	3.22	0.61	0.49
query33	3.19	3.24	3.24
query34	15.58	4.27	3.53
query35	3.56	3.55	3.55
query36	0.56	0.44	0.45
query37	0.09	0.07	0.06
query38	0.06	0.04	0.04
query39	0.04	0.04	0.03
query40	0.18	0.17	0.16
query41	0.08	0.03	0.04
query42	0.04	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 96.82 s
Total hot run time: 25.53 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 71.39% (272/381) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 74.67% (29651/39712)
Line Coverage 58.62% (324461/553484)
Region Coverage 55.65% (273392/491268)
Branch Coverage 56.70% (119916/211502)

@hubgeter

hubgeter commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@hubgeter

hubgeter commented Jul 2, 2026

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.

I found two correctness issues in the new Iceberg system-table changes: the native $position_deletes partition payload is still incompatible with partition spec evolution, and the JNI metadata scanner regresses Kerberos auth property propagation for existing Iceberg metadata tables.

Critical checkpoints: goal/behavior is partially achieved; scope is focused on Iceberg system-table plumbing; compatibility has the JNI auth regression; tests miss partition-spec evolution and Kerberos JNI metadata-table coverage; no separate concurrency/lifecycle issue was found. Validation was static review against the GitHub PR patch and live PR metadata; I did not run build/tests.

split.setPartitionSpecId(deleteFile.specId());
PartitionSpec partitionSpec = icebergTable.specs().get(deleteFile.specId());
if (partitionSpec != null && partitionSpec.isPartitioned() && deleteFile.partition() != null) {
split.setPartitionDataJson(getPartitionDataObjectJson(

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.

This builds partition_data_json from only the delete file's own PartitionSpec, but the $position_deletes output schema is the metadata table schema, whose partition column uses Iceberg's unified partition type (the union of partition fields across specs). After ALTER TABLE ... ADD PARTITION FIELD, older delete files still have the old spec and this JSON omits the new field. BE then deserializes it into the output STRUCT, and DataTypeStructSerDe requires every field in order, so select partition from tbl$position_deletes fails with Actual struct field number ... is less than schema field number .... Please generate the JSON against the metadata table partition struct, filling fields absent from this delete file's spec with null, and add a regression that writes deletes before and after partition-spec evolution.

.collect(Collectors
.toMap(kv1 -> kv1.getKey().substring(HADOOP_OPTION_PREFIX.length()), kv1 -> kv1.getValue()));
this.preExecutionAuthenticator = PreExecutionAuthenticatorCache.getAuthenticator(hadoopOptionParams);
this.preExecutionAuthenticator = PreExecutionAuthenticatorCache.getAuthenticator(params);

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.

This drops the transport-prefix stripping that the BE side still relies on. IcebergSysTableJniReader prefixes every scan property with hadoop.; for HDFS Kerberos the FE/backend properties already contain keys like hadoop.security.authentication, hadoop.kerberos.principal, and hadoop.kerberos.keytab. Passing the raw params map here turns those into doubled keys such as hadoop.hadoop.security.authentication, while AuthenticationConfig only checks the normal Hadoop keys before creating the Kerberos authenticator. Existing $snapshots/$files scans against a Kerberized Iceberg/HDFS catalog will therefore fall back to simple auth. Please keep building the stripped Hadoop option map for PreExecutionAuthenticatorCache (as Paimon/Hudi do), and keep scanner-only keys out of the cache input.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17628	4042	4050	4042
q2	2082	322	199	199
q3	10248	1430	802	802
q4	4688	478	342	342
q5	7552	882	571	571
q6	191	176	142	142
q7	792	846	637	637
q8	9417	1735	1642	1642
q9	5752	4505	4505	4505
q10	6750	1795	1558	1558
q11	523	355	321	321
q12	717	554	439	439
q13	18077	3391	2818	2818
q14	282	261	242	242
q15	q16	787	775	718	718
q17	1064	965	1098	965
q18	6945	5935	5527	5527
q19	1161	1189	1123	1123
q20	760	690	516	516
q21	5926	2926	2638	2638
q22	459	373	322	322
Total cold run time: 101801 ms
Total hot run time: 30069 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5124	4817	4819	4817
q2	296	347	218	218
q3	5004	5356	4748	4748
q4	2062	2164	1390	1390
q5	4826	4822	4693	4693
q6	243	178	130	130
q7	1852	1755	1551	1551
q8	2457	2225	2191	2191
q9	7754	7414	7233	7233
q10	4689	4595	4145	4145
q11	529	399	369	369
q12	745	744	539	539
q13	3011	3352	2797	2797
q14	269	290	264	264
q15	q16	680	703	612	612
q17	1292	1283	1293	1283
q18	7396	7022	6752	6752
q19	1135	1109	1104	1104
q20	2246	2209	1942	1942
q21	5301	4616	4540	4540
q22	517	458	389	389
Total cold run time: 57428 ms
Total hot run time: 51707 ms

@hello-stephen

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

query5	4313	645	526	526
query6	470	226	223	223
query7	4871	560	350	350
query8	349	192	179	179
query9	8817	4143	4133	4133
query10	477	367	311	311
query11	5923	2410	2139	2139
query12	167	100	99	99
query13	1301	607	420	420
query14	6285	5360	5028	5028
query14_1	4356	4331	4351	4331
query15	219	200	181	181
query16	1033	484	492	484
query17	1180	766	597	597
query18	2474	490	353	353
query19	252	199	155	155
query20	118	109	109	109
query21	241	163	136	136
query22	13650	13577	13353	13353
query23	17556	16594	16157	16157
query23_1	16363	16222	16273	16222
query24	7538	1780	1328	1328
query24_1	1323	1303	1318	1303
query25	589	473	400	400
query26	1345	378	221	221
query27	2577	635	392	392
query28	4472	2038	2040	2038
query29	1121	647	495	495
query30	344	270	226	226
query31	1125	1120	1007	1007
query32	110	64	62	62
query33	538	336	258	258
query34	1210	1167	636	636
query35	793	782	679	679
query36	1438	1425	1243	1243
query37	203	109	95	95
query38	1907	1702	1649	1649
query39	926	921	886	886
query39_1	880	901	882	882
query40	252	168	143	143
query41	69	63	61	61
query42	93	94	92	92
query43	329	330	279	279
query44	1463	783	783	783
query45	207	187	175	175
query46	1093	1187	758	758
query47	2355	2320	2193	2193
query48	388	403	308	308
query49	583	436	324	324
query50	1054	427	359	359
query51	4407	4469	4337	4337
query52	85	89	76	76
query53	264	281	202	202
query54	285	222	222	222
query55	77	73	74	73
query56	292	298	279	279
query57	1427	1393	1307	1307
query58	307	254	253	253
query59	1589	1672	1404	1404
query60	321	273	255	255
query61	166	156	152	152
query62	709	649	594	594
query63	245	208	208	208
query64	2517	761	596	596
query65	4844	4797	4705	4705
query66	1855	514	419	419
query67	29482	28959	29425	28959
query68	3066	1592	920	920
query69	423	313	261	261
query70	1122	985	905	905
query71	354	318	316	316
query72	2973	2651	2365	2365
query73	839	797	471	471
query74	5147	4967	4749	4749
query75	2636	2594	2229	2229
query76	2358	1185	841	841
query77	371	384	278	278
query78	12590	12663	11975	11975
query79	1474	1151	754	754
query80	646	565	452	452
query81	469	322	283	283
query82	599	156	125	125
query83	416	320	299	299
query84	281	161	132	132
query85	970	612	511	511
query86	379	296	301	296
query87	1834	1828	1748	1748
query88	3771	2808	2770	2770
query89	465	412	349	349
query90	1975	204	206	204
query91	210	194	164	164
query92	66	61	58	58
query93	1558	1551	1055	1055
query94	576	373	323	323
query95	813	591	477	477
query96	1130	844	359	359
query97	2676	2736	2546	2546
query98	212	204	208	204
query99	1185	1152	1018	1018
Total cold run time: 259488 ms
Total hot run time: 173742 ms

@hello-stephen

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

query1	0.00	0.00	0.00
query2	0.09	0.05	0.05
query3	0.27	0.14	0.14
query4	1.61	0.15	0.15
query5	0.27	0.22	0.23
query6	1.26	1.09	1.08
query7	0.04	0.01	0.00
query8	0.06	0.04	0.04
query9	0.39	0.32	0.32
query10	0.59	0.54	0.55
query11	0.20	0.14	0.14
query12	0.18	0.14	0.14
query13	0.47	0.47	0.47
query14	1.00	1.02	1.00
query15	0.61	0.59	0.63
query16	0.33	0.32	0.31
query17	1.07	1.12	1.07
query18	0.21	0.20	0.21
query19	2.04	1.89	1.93
query20	0.02	0.01	0.01
query21	15.44	0.18	0.14
query22	5.03	0.05	0.05
query23	16.08	0.31	0.12
query24	2.99	0.42	0.35
query25	0.14	0.06	0.05
query26	0.80	0.22	0.14
query27	0.04	0.03	0.04
query28	3.53	1.01	0.56
query29	12.50	4.37	3.49
query30	0.28	0.16	0.15
query31	2.78	0.61	0.32
query32	3.23	0.60	0.50
query33	3.30	3.18	3.22
query34	15.55	4.22	3.49
query35	3.54	3.54	3.50
query36	0.61	0.43	0.43
query37	0.09	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.17	0.16	0.15
query41	0.10	0.03	0.02
query42	0.05	0.03	0.03
query43	0.05	0.04	0.03
Total cold run time: 97.1 s
Total hot run time: 25.22 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 71.39% (272/381) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 74.66% (29659/39725)
Line Coverage 58.60% (324487/553741)
Region Coverage 55.27% (271734/491664)
Branch Coverage 56.59% (119755/211607)

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 0.51% (2/389) 🎉
Increment coverage report
Complete coverage report

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

fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/source/IcebergScanNode.java:993
partition_data_json 仍按 delete file 自己的 PartitionSpec 生成,但 $position_deletes 的 partition 输出列来自 Iceberg metadata table schema,可能是跨多个 partition spec 的 unified struct。表发生 partition spec evolution 后,旧 delete file 的 JSON 会缺少新字段,BE 反序列化 struct 时可能报字段数不匹配,导致 select partition from tbl$position_deletes 失败。建议按 metadata table 的 partition struct 生成 JSON,缺失字段填 null,并补一个“delete 前后发生 partition spec evolution”的回归测试。

"file");
}
_delete_file_desc = &_iceberg_file_desc->delete_files[0];
_delete_file_kind = is_iceberg_deletion_vector(*_delete_file_desc)

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.

if (is_iceberg_deletion_vector(...)) {
_delete_file_kind = DELETION_VECTOR;
} else if (content == POSITION_DELETE) {
_delete_file_kind = POSITION_DELETE;
} else {
return Status::InternalError(...);
}

@Gabriel39

Copy link
Copy Markdown
Contributor

[P1] fe/be-java-extensions/iceberg-metadata-scanner/src/main/java/org/apache/doris/iceberg/IcebergSysTableJniScanner.java:66
当前把完整 params 传给 PreExecutionAuthenticatorCache.getAuthenticator(),但 BE 的 IcebergSysTableJniReader 会把 scan properties 统一加 hadoop. 前缀传入 JNI scanner。旧实现会 strip 掉这个 transport prefix;现在 Kerberos 配置会变成 hadoop.hadoop.security.authentication / hadoop.hadoop.kerberos.principal,AuthenticationConfig 读不到正常 key,从而回退 simple auth。这个会回归已有 $snapshots、$files 等 Iceberg metadata table 在 Kerberized HDFS catalog 上的读取。建议恢复和 Paimon/Hudi 一致的 prefix stripping,并避免 scanner-only 参数进入 authenticator 输入。

Comment thread fe/fe-core/src/main/java/org/apache/doris/datasource/TableFormatType.java Outdated
@924060929

924060929 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Thanks for the work — the native $position_deletes path is a nice improvement over the JNI-only approach. I built the branch and ran it against a live Iceberg REST catalog (Spark 4.0 / iceberg-rest 1.10 / MinIO); the happy path (single-spec partitioned/unpartitioned, v2 & v3) works correctly. A few issues worth addressing, ordered by severity.

1. (High) Kerberos / hadoop.username auth is silently dropped for all Iceberg JNI sys-table reads

The refactor in IcebergSysTableJniScanner now passes the raw JNI params map to PreExecutionAuthenticatorCache.getAuthenticator(...), dropping the old HADOOP_OPTION_PREFIX filter+strip. But BE iceberg_sys_table_jni_reader.cpp (unchanged) prefixes every catalog property with hadoop.:

params[HADOOP_OPTION_PREFIX + kv.first] = kv.second;  // hadoop.security.authentication -> hadoop.hadoop.security.authentication

So AuthenticationConfig looks up the unprefixed keys (hadoop.security.authentication, hadoop.kerberos.principal/keytab, hadoop.username) and finds only the double-prefixed hadoop.hadoop.*, silently falling back to SimpleAuthenticationConfig(user="hadoop"). PaimonJniScanner still strips the prefix, i.e. this is the prior convention.

Impact: on a kerberized catalog, select * from tbl$snapshots (or any JNI sys table) would read manifests without Kerberos; simple-auth catalogs with a custom hadoop.username read as hadoop; the authenticator cache key also collapses to a constant.

Verified by running the real classes:

  • AuthenticationConfig.getKerberosConfig({hadoop.hadoop.security.authentication=kerberos, ...})SimpleAuthenticationConfig
  • AuthenticationConfig.getKerberosConfig({hadoop.security.authentication=kerberos, ...}) (prefix stripped) → KerberosAuthenticationConfig

(Confirmed at the auth-config selection level; I didn't stand up a full kerberized cluster.) Suggest restoring the hadoop.-prefix filter/strip before getAuthenticator.

2. (Medium) $position_deletes can't be queried at all for tables with AVRO delete files

Avro is a first-class Iceberg delete-file format (write.delete.format.default=avro) and is commonly produced (Flink pipelines in particular). For any such table, $position_deletes / iceberg_meta(...) fails entirely: getNativePositionDeleteFileFormat throws UnsupportedOperationException for FileFormat.AVRO, and since doGetPositionDeletesSystemTableSplits only catches IOException, it escapes planning:

select * from tbl$position_deletes;
ERROR 1105 (HY000): errCode = 2, detailMessage = UnsupportedOperationException: Unsupported Iceberg position delete file format: AVRO

(reproduced on the built branch; same via iceberg_meta(...)).

The main question is whether avro delete files should be supported here — if yes, the BE reader's parquet/orc routing needs an avro branch.

3. (Medium) partition column is silently NULL after partition evolution or for NULL partition values

getPartitionDataObjectJson builds the JSON from the delete file's own spec fields, and GsonUtils.GSON (no serializeNulls) drops null values — so the JSON can carry fewer fields than the sys table's partition column, which is the union partition type across all specs (Partitioning.partitionType). The BE struct serde then yields a whole-NULL partition (no error).

Reproduced on the built branch, all struct<a,b>:

delete file partition FE JSON Doris partition
(a=p1, b=q1) {"a":"p1","b":"q1"} {"a":"p1", "b":"q1"}
(a=p1, b=NULL) {"a":"p1"} (b dropped) NULL
spec0 file after ALTER TABLE ADD PARTITION FIELD id {"dt":...} NULL

The query succeeds but the partition column silently loses data — any table that has undergone partition evolution shows NULL partitions for delete files written under older specs. This isn't covered by the "Preserve typed partition values" commit (that fixed value typing, not the struct shape). Suggest emitting the partition in the table's unified partition type (coerce PartitionData, as Iceberg's own metadata scan does) and enabling null serialization so the field count always matches the schema.

4. (Latent crash, low reachability) optional row column + schema evolution

When a position-delete file actually contains the optional row struct and the table schema later evolves, the standalone ParquetReader init (no column_descson_before_init_reader skipped → ConstNode table_info_node whose children_column_exists() is always true) can default-insert and dereference a null child reader in StructColumnReader::read_column_data → SIGSEGV. Mainstream Spark MoR deletes don't populate row (this PR's own test asserts it's always NULL), so it's hard to hit in practice, but it's a latent crash for files written by engines that do populate row. (Code trace only — not reproduced e2e.)

Minor / nits

  • file_scanner.cpp: the ~10-line position-deletes reader-creation block is byte-identical in the FORMAT_PARQUET and FORMAT_ORC arms and is format-independent (the reader dispatches on the delete file's own format); consider hoisting it once before the switch. Mapping PUFFIN → FORMAT_PARQUET in getNativePositionDeleteFileFormat exists only to land DV ranges on an arm containing that block.
  • iceberg_meta(query_type=...) resolves via tbl + "$" + queryType split on the last $, so query_type='foo$snapshots' silently resolves to the snapshots table and returns data instead of erroring (reproduced: count=2). Consider looking the type up directly in the supported sys-tables map.
  • _init_deletion_vector_reader materializes the whole roaring bitmap into a std::vector<uint64_t> up front; iterating the compressed bitmap per batch would bound memory for large deletion vectors.
  • doGetPositionDeletesSystemTableSplits iterates planFiles() (one split per delete file, no size-based split via planTasks/TableScanUtil.splitFiles), so a large delete file gets no intra-file parallelism unlike the data path.

hubgeter added 3 commits July 3, 2026 18:16
### What problem does this PR solve?

Issue Number: close #xxx

Related PR: apache#64886

Problem Summary: Address review feedback for the Iceberg position deletes system table. The position deletes split now reuses the normal Iceberg table format and BE chooses the native reader from Iceberg delete content, partition JSON is generated against the metadata table unified partition struct so partition spec evolution fills missing fields with null, and the JNI metadata scanner restores Hadoop option prefix stripping for Kerberos authentication. The extra iceberg_meta TVF path is removed from this PR scope. The regression framework Spark JDBC helper from PR apache#64886 is picked into this branch and the position_deletes suite now cross-checks Spark and Doris metadata table results.

### Release note

None

### Check List (For Author)

- Test: Regression test / Unit Test / Manual test
    - ENABLE_PCH=OFF ./build.sh --be --fe -j 16
    - ./run-regression-test.sh --run -d external_table_p0/iceberg -s test_iceberg_position_deletes_sys_table ...
    - ./run-regression-test.sh --run -d external_table_p0/iceberg -s test_iceberg_sys_table ...
    - EXTRA_FE_MODULES=iceberg=be-java-extensions/iceberg-metadata-scanner ./run-fe-ut.sh --run org.apache.doris.iceberg.IcebergSysTableJniScannerTest
- Behavior changed: No
- Does this need documentation: No
@924060929

924060929 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Design notes (for discussion, not blockers)

Separating these from the bugs above since they're about the integration seams, not clear defects. The core direction is right: position_deletes is fundamentally a file scan (unlike the other sys tables, which are JVM-side DataTasks), so reading it natively in BE and reusing the Parquet/ORC readers + the deletion-vector helper is the correct call.

  • Partition column is built at the wrong layer. Rendering the delete file's own-spec partition to plan-time JSON and then matching it positionally against the sys table's union partition struct (Partitioning.partitionType) is exactly what produces the silent-NULL in # 3. Coercing PartitionData to the table's unified partition type (as Iceberg's own metadata scan does) would be more robust than reconstructing per-file-spec JSON on the FE.

  • Sys-table split planning isn't polymorphic. position_deletes is special-cased by string compare in doGetSystemTableSplits plus a parallel setIcebergPositionDeleteSysTableParams. The next natively-planned sys table would need the same copy-paste (string check + doGetXxxSplits + createXxxSysSplit + setXxxParams + a new TableFormatType + a BE bypass). A hook on SysTable/IcebergSysTable would localize this.

  • IcebergSplit has become a 3-way union. Seven positionDelete* fields + a boolean discriminator now sit on the shared IcebergSplit alongside the data-split and JNI-serialized-split shapes. positionDeleteContent is a primitive int defaulting to 0, which is the DATA content id — a split that sets the DV flag but forgets to set the content would be misread as a plain position delete with no error. A subclass (or a self-describing descriptor) would make the three shapes explicit.

  • Thrift TIcebergDeleteFileDesc.file_format is stamped for this path but deliberately left unset by the MOR delete path (and PUFFIN is relabeled PARQUET so the range lands on the duplicated file_scanner branch). Worth aligning so the same field means one thing regardless of which producer filled it.

These are design opinions, not blockers — happy to defer to your and the committers' judgment.

### What problem does this PR solve?

Issue Number: None

Related PR: apache#64886

Problem Summary: After rebasing onto master, Iceberg scans can use FileScannerV2. Iceberg position delete system table ranges still need the dedicated position delete reader path instead of the normal Iceberg data reader or JNI metadata reader path. This change adds a FileScannerV2 table reader adapter that reuses the existing position delete system table reader, keeps the FileScannerV1 path unchanged, and extends the regression suite to cover both scanner paths plus Doris/Spark alternating Iceberg operations.

### Release note

Support Iceberg position_deletes system table queries when FileScannerV2 is enabled.

### Check List (For Author)

- Test: Regression test / Build / Manual test
    - `./build.sh --be --fe`
    - `./run-regression-test.sh --conf /tmp/doris-position-deletes-regression-conf.groovy --run -d external_table_p0/iceberg -s test_iceberg_position_deletes_sys_table`
    - Deployed `/mnt/disk1/changyuwei/doris-deploy`; `SHOW FRONTENDS` and `SHOW BACKENDS` both reported Alive=true.
- Behavior changed: Yes. Iceberg position_deletes system table queries now work through FileScannerV2.
- Does this need documentation: No
@hubgeter hubgeter force-pushed the support_iceberg_sys_pos_del branch from 9d441a1 to 80e4825 Compare July 3, 2026 12:32
@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

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

### What problem does this PR solve?

Issue Number: None

Related PR: apache#65135

Problem Summary: PR review raised concern that ORC Iceberg position delete system table splits could be routed through FileScannerV2, whose position delete reader only supports Parquet delete files. FileScannerV2 already rejects ORC ranges and the V1 position delete system table reader owns ORC support, but the boundary was not covered by a focused unit test. Add a FileScannerV2 test that locks Parquet position delete and deletion-vector routing to V2 while proving ORC position delete ranges make the mixed split source fall back to V1. Also document why the V2 deletion-vector reader reports EOF only on the next empty call: FileScannerV2 treats eof=true as advancing to the next split without returning the current block.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ./run-be-ut.sh --run --filter=FileScannerV2Test.IcebergPositionDeletesOrcFallsBackToV1 -j 8
- Behavior changed: No
- Does this need documentation: No
@hubgeter hubgeter requested a review from yiguolei as a code owner July 9, 2026 02:41
@hubgeter

hubgeter commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

Cloud UT Coverage Report

Increment line coverage 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.39% (1896/2450)
Line Coverage 64.47% (34078/52862)
Region Coverage 64.89% (17542/27032)
Branch Coverage 54.05% (9400/17390)

@hubgeter

hubgeter commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

Cloud UT Coverage Report

Increment line coverage 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.39% (1896/2450)
Line Coverage 64.44% (34064/52862)
Region Coverage 64.83% (17526/27032)
Branch Coverage 54.03% (9395/17390)

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17708	4170	4090	4090
q2	2060	328	203	203
q3	10239	1398	882	882
q4	4683	470	344	344
q5	7524	874	584	584
q6	182	169	134	134
q7	759	845	646	646
q8	9369	1491	1617	1491
q9	5653	4373	4366	4366
q10	6796	1783	1550	1550
q11	515	347	322	322
q12	708	546	429	429
q13	18192	3370	2750	2750
q14	270	274	235	235
q15	q16	778	789	706	706
q17	948	956	1050	956
q18	6901	5692	5563	5563
q19	1161	1240	1119	1119
q20	775	699	541	541
q21	5779	2891	2786	2786
q22	465	379	329	329
Total cold run time: 101465 ms
Total hot run time: 30026 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5140	4910	4877	4877
q2	294	334	222	222
q3	5012	5353	4595	4595
q4	2219	2227	1460	1460
q5	4826	4966	4700	4700
q6	231	186	130	130
q7	1849	1798	1574	1574
q8	2398	2142	2158	2142
q9	7754	7463	7170	7170
q10	4695	4625	4170	4170
q11	524	378	353	353
q12	721	745	540	540
q13	3033	3357	2808	2808
q14	275	278	261	261
q15	q16	680	706	631	631
q17	1297	1269	1262	1262
q18	7576	6960	6940	6940
q19	1105	1071	1080	1071
q20	2237	2227	1934	1934
q21	5394	4705	4581	4581
q22	519	462	436	436
Total cold run time: 57779 ms
Total hot run time: 51857 ms

@hello-stephen

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

query5	4339	635	482	482
query6	496	224	197	197
query7	4985	592	361	361
query8	349	194	197	194
query9	8769	4035	4019	4019
query10	476	346	307	307
query11	5959	2324	2115	2115
query12	165	107	96	96
query13	1233	617	439	439
query14	6233	5269	4954	4954
query14_1	4312	4305	4290	4290
query15	217	214	183	183
query16	1020	498	450	450
query17	959	738	602	602
query18	2444	517	359	359
query19	221	194	158	158
query20	112	112	110	110
query21	236	157	133	133
query22	13584	13565	13363	13363
query23	17332	16511	16102	16102
query23_1	16355	16314	16288	16288
query24	7446	1780	1330	1330
query24_1	1326	1312	1314	1312
query25	581	480	409	409
query26	1343	361	211	211
query27	2626	606	389	389
query28	4503	2015	2007	2007
query29	1090	652	505	505
query30	341	270	224	224
query31	1135	1106	991	991
query32	113	63	64	63
query33	549	339	277	277
query34	1209	1215	656	656
query35	783	809	676	676
query36	1410	1425	1233	1233
query37	162	118	105	105
query38	1887	1706	1675	1675
query39	947	922	908	908
query39_1	882	884	888	884
query40	247	165	143	143
query41	73	69	70	69
query42	98	96	97	96
query43	329	326	282	282
query44	1444	782	786	782
query45	208	191	176	176
query46	1088	1237	758	758
query47	2411	2383	2246	2246
query48	417	443	314	314
query49	610	439	320	320
query50	1008	435	346	346
query51	10595	10831	10579	10579
query52	95	89	78	78
query53	268	303	228	228
query54	307	270	254	254
query55	78	76	76	76
query56	313	314	321	314
query57	1436	1436	1326	1326
query58	284	267	258	258
query59	1599	1670	1467	1467
query60	330	269	259	259
query61	152	143	142	142
query62	700	646	594	594
query63	250	211	213	211
query64	2829	1058	855	855
query65	4855	4800	4783	4783
query66	1826	516	376	376
query67	29660	29570	29422	29422
query68	3029	1689	915	915
query69	435	292	272	272
query70	1101	981	999	981
query71	369	326	327	326
query72	3071	2742	2490	2490
query73	793	735	430	430
query74	5102	5008	4787	4787
query75	2614	2582	2223	2223
query76	2311	1210	776	776
query77	356	379	288	288
query78	12237	12415	11802	11802
query79	1396	1165	759	759
query80	1308	548	466	466
query81	526	326	280	280
query82	636	159	127	127
query83	371	323	302	302
query84	326	164	130	130
query85	965	602	505	505
query86	437	316	279	279
query87	1832	1827	1748	1748
query88	3731	2826	2794	2794
query89	463	408	367	367
query90	1896	204	200	200
query91	202	195	163	163
query92	65	63	95	63
query93	1751	1572	966	966
query94	752	360	316	316
query95	772	607	475	475
query96	1048	824	362	362
query97	2690	2693	2558	2558
query98	212	206	203	203
query99	1155	1168	1034	1034
Total cold run time: 265937 ms
Total hot run time: 180413 ms

@hello-stephen

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

query1	0.01	0.01	0.01
query2	0.10	0.05	0.05
query3	0.26	0.14	0.14
query4	1.62	0.14	0.14
query5	0.26	0.24	0.23
query6	1.27	1.11	1.12
query7	0.04	0.01	0.01
query8	0.05	0.03	0.04
query9	0.39	0.32	0.32
query10	0.56	0.60	0.56
query11	0.22	0.14	0.14
query12	0.18	0.14	0.15
query13	0.48	0.49	0.47
query14	1.00	1.00	1.03
query15	0.62	0.60	0.62
query16	0.33	0.31	0.32
query17	1.13	1.07	1.10
query18	0.23	0.21	0.21
query19	2.07	1.99	1.91
query20	0.02	0.01	0.01
query21	15.45	0.20	0.13
query22	4.99	0.05	0.06
query23	16.13	0.32	0.12
query24	2.95	0.40	0.32
query25	0.12	0.05	0.04
query26	0.72	0.21	0.14
query27	0.04	0.04	0.04
query28	3.47	0.97	0.54
query29	12.47	4.03	3.23
query30	0.27	0.15	0.16
query31	2.77	0.62	0.31
query32	3.22	0.59	0.49
query33	3.16	3.17	3.13
query34	15.57	4.21	3.54
query35	3.53	3.54	3.54
query36	0.57	0.45	0.43
query37	0.09	0.07	0.07
query38	0.05	0.03	0.03
query39	0.04	0.03	0.03
query40	0.18	0.16	0.16
query41	0.08	0.04	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.03
Total cold run time: 96.79 s
Total hot run time: 25.04 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 69.68% (648/930) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 74.82% (30025/40131)
Line Coverage 58.87% (329298/559405)
Region Coverage 55.62% (276046/496323)
Branch Coverage 56.85% (121590/213862)

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

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

@Gabriel39

Copy link
Copy Markdown
Contributor

/review

@Gabriel39 Gabriel39 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Requesting changes for two correctness gaps in the native Iceberg $position_deletes path: partition-field renames silently lose values from older delete files, and valid Avro position-delete files fail during FE planning.

@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: You've hit your usage limit. Visit https://chatgpt.com/codex/settings/usage to purchase more credits or try again at 10:57 AM.
Workflow run: https://github.com/apache/doris/actions/runs/29081461863

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

### What problem does this PR solve?

Issue Number: None

Related PR: apache#65135

Problem Summary: Iceberg preserves a partition field ID when a partition field is renamed, while the position_deletes metadata table exposes the latest field name. Doris matched historical partition values by name, so delete rows written under an older spec returned NULL for the renamed field. Match partition values by partition field ID, add focused FE coverage, and add a Spark/Doris regression that writes deletes before and after the rename. Keep unsupported AVRO position delete files fail-fast and cover that boundary explicitly.

### Release note

Fix partition values in Iceberg position_deletes metadata queries after partition-field renames.

### Check List (For Author)

- Test: Unit Test / Regression Test
    - ./run-fe-ut.sh --run org.apache.doris.datasource.iceberg.source.IcebergScanNodeTest
    - ./run-regression-test.sh --run -d external_table_p0/iceberg -s test_iceberg_position_deletes_sys_table
    - ./build.sh --fe
- Behavior changed: Yes. Historical position delete rows retain values after a partition field rename.
- Does this need documentation: No
@hubgeter

Copy link
Copy Markdown
Contributor Author

run buildall

### What problem does this PR solve?

Issue Number: None

Related PR: apache#65135

Problem Summary: Merge the latest master without restoring the removed per-split FileScanner V1 fallback. Route Iceberg position-delete system table reads for both Parquet and ORC through FileScannerV2, while keeping AVRO explicitly unsupported.

### Release note

Support Iceberg ORC position-delete files in the position_deletes system table FileScannerV2 path.

### Check List (For Author)

- Test: Manual test
    - clang-format 16 dry-run check for the changed C++ files
    - Targeted Ninja compilation of the reader and FileScannerV2 unit-test objects
- Behavior changed: Yes. ORC position-delete files now use the V2 reader; AVRO remains rejected.
- Does this need documentation: No
@hubgeter

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 0.85% (8/936) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 56.82% (23543/41433)
Line Coverage 40.50% (230183/568380)
Region Coverage 36.41% (181894/499522)
Branch Coverage 37.45% (81197/216805)

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

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

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 74.15% (694/936) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 74.76% (30225/40428)
Line Coverage 58.72% (331660/564818)
Region Coverage 55.49% (278226/501418)
Branch Coverage 56.76% (123099/216883)

@Gabriel39

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.

Automated review completed. I found two issues that should be addressed before this lands: one compatibility issue in the native $position_deletes scan range protocol during smooth/rolling upgrade, and one regression-test assertion gap for ORC row projection.

Checkpoint summary: FE planning/schema, BE native reader behavior, FE/BE thrift routing, permissions, partition evolution/rename/type handling, deletion vectors, scanner v1/v2 paths, and test coverage were reviewed statically. Existing review threads for Avro support and prior partition/auth concerns were treated as already-known and not duplicated. No additional user-provided focus was present.

private void setIcebergPositionDeleteSysTableParams(TFileRangeDesc rangeDesc, IcebergSplit icebergSplit,
TTableFormatFileDesc tableFormatFileDesc, TIcebergFileDesc fileDesc) {
rangeDesc.setFormatType(icebergSplit.getPositionDeleteFileFormat());
tableFormatFileDesc.setTableLevelRowCount(-1);

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.

This native $position_deletes path needs a BE support/smooth-upgrade guard before it emits Parquet/ORC/Puffin ranges. The range format is switched to the delete file format here and the only signal that it is a system-table range is the top-level iceberg_params.content set below; old BEs do not have the new is_iceberg_position_deletes_sys_table routing, so they will take the ordinary Iceberg Parquet/ORC reader path against the metadata-table slots if FederationBackendPolicy assigns the split to them during rolling/smooth upgrade. Other new plan shapes already skip Backend.isSmoothUpgradeSrc() BEs before dispatch; this should similarly fall back, gate on all selected BEs supporting the new route, or fail during planning instead of sending a range old BEs can misread.

assertEquals(orcUnpartitionedCount, (long) sql(
"""select `row` from pd_orc_unpartitioned\$position_deletes""").size())
assertTrue(unpartitionedRows.every { it[0] == null })
try {

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.

This assertion is still checking unpartitionedRows, which is the Parquet result populated above. The ORC query on the preceding lines only has its row count checked, so a regression in pd_orc_unpartitioned$position_deletes.row values would still pass this test. Please store the ORC row result in its own variable and assert that variable here.

### What problem does this PR solve?

Issue Number: None

Related PR: apache#65135

Problem Summary: The native Iceberg position_deletes system table range requires the new BE reader routing. During smooth upgrade, the external scan backend pool could still include an old source BE and dispatch a Parquet, ORC, or deletion-vector range that the old process would misread. Reject native position_deletes planning when a selected backend is a smooth-upgrade source. Also fix the ORC regression assertion so it validates the ORC row result instead of reusing the Parquet result.

### Release note

Prevent Iceberg position_deletes scans from being dispatched to smooth-upgrade source backends.

### Check List (For Author)

- Test: Unit Test / Regression test attempted
    - ./run-fe-ut.sh --run org.apache.doris.datasource.iceberg.source.IcebergScanNodeTest passed 6 tests.
    - ./run-regression-test.sh --conf /tmp/doris-position-deletes-regression-conf-9030.groovy --run -d external_table_p0/iceberg -s test_iceberg_position_deletes_sys_table was attempted; the available cluster failed before assertions with an FE NullPointerException on DESC because it does not contain the PR implementation.
- Behavior changed: Yes. Native position_deletes planning now fails while a selected backend is a smooth-upgrade source.
- Does this need documentation: No
@hubgeter

Copy link
Copy Markdown
Contributor Author

/review

@hubgeter

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

Cloud UT Coverage Report

Increment line coverage 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.39% (1896/2450)
Line Coverage 64.46% (34073/52862)
Region Coverage 64.89% (17541/27032)
Branch Coverage 54.08% (9404/17390)

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

Found one issue in the V1 native $position_deletes reader. I could not run builds/tests in this review-only checkout; validation was static against the provided patch and current source.

if (_delete_file_desc->file_format == TFileFormatType::FORMAT_PARQUET) {
auto parquet_reader = ParquetReader::create_unique(
_profile, *_range_params, _range, _batch_size, &_state->timezone_obj(),
&_io_context.io_ctx, _state, _meta_cache);

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.

This V1 system-table reader is passing the nested Parquet reader a private _io_context instead of the scanner IO context. The same member is used for the ORC and Puffin DV paths, but FileScanner::try_stop() only flips the scanner _io_ctx->should_stop, and the scanner counters/profile are populated from the scanner-owned reader/cache stats. Existing V1 Iceberg delete-vector reads pass this->get_io_ctx() into the helper, so this new path can keep reading large delete files after a LIMIT/cancellation stop and underreport the actual delete-file IO. Please thread the scanner IOContext into this reader, or mirror should_stop and merge the private stats back before counter collection.

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.

5 participants