Skip to content

[improvement](be) Add ORC v2 stripe merged reads#65478

Open
xylaaaaa wants to merge 1 commit into
apache:masterfrom
xylaaaaa:pr/orc-v2-stripe-prefetch-clean
Open

[improvement](be) Add ORC v2 stripe merged reads#65478
xylaaaaa wants to merge 1 commit into
apache:masterfrom
xylaaaaa:pr/orc-v2-stripe-prefetch-clean

Conversation

@xylaaaaa

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: ORC file scanner v2 used a thin ORC input stream that issued reads directly through the underlying file reader. It did not implement the v1 ORC stripe-level stream collection and small-range merge path, so remote object storage scans could regress to many small stream reads for wide ORC files, multi-stripe files, and lazy or predicate-driven scans. This change adds a v2-native ORC input stream that implements beforeReadStripe(), builds selected stream ranges, merges adjacent small streams with Doris PrefetchRange policy, and serves arbitrary repeated or backward stream reads from an immutable merged-range cache. Large streams and unmerged single streams continue to read directly. The reader is wired into ORC v2 without changing v1 or falling back to v1.

Release note

Improve ORC file scanner v2 remote read performance by merging selected small stripe stream reads.

Check List (For Author)

  • Test: Unit Test / Manual test / Static analysis
    • Unit Test: ./run-be-ut.sh --run --filter='OrcFileInputStreamTest.*:NewOrcReaderTest.StripePrefetchPublishesMergedReadProfile' -j 8 (passed)
    • Manual test: git diff --check (passed)
    • Manual test: build-support/check-format.sh (passed)
    • Manual test: ninja -C be/ut_build_ASAN src/format/CMakeFiles/Format.dir/__/format_v2/orc/orc_file_input_stream.cpp.o test/CMakeFiles/doris_be_test.dir/format_v2/orc/orc_file_input_stream_test.cpp.o (passed)
    • Static analysis: build-support/run-clang-tidy.sh --build-dir be/ut_build_ASAN --files ... (attempted; own signed/unsigned diagnostic fixed; remaining failures are pre-existing/toolchain diagnostics in be/src/core/types.h and be/src/io/fs/buffered_reader.h)
  • Behavior changed: Yes. ORC v2 now merges selected small stripe streams and reads each merged cluster through a cached span instead of issuing one remote read per small stream request.
  • Does this need documentation: No

Copilot AI review requested due to automatic review settings July 11, 2026 04:01
@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?

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@xylaaaaa

Copy link
Copy Markdown
Contributor Author

run buildall

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

I found one blocking compatibility regression in the ORC v2 stripe merged read path and left it inline.

Critical checkpoint conclusions:

  • Goal/fit: the PR adds ORC v2 stripe-level merged reads and the implementation is otherwise focused on that path.
  • Configuration/compatibility: orc_once_max_read_bytes = 0 is accepted by FE and tolerated by the existing v1 ORC path, but the new v2 input stream asserts during initialization. This is the submitted issue.
  • Parallel paths: compared the new v2 behavior with the existing v1 ORC merged-read path; the zero-value behavior is inconsistent.
  • Lifecycle/concurrency/profile: reviewed stream ownership, beforeReadStripe() flush behavior, and tracing/profile wrapping; no separate substantiated issue found.
  • Tests: the PR adds input-stream unit coverage and a reader integration/profile test, but it does not cover the accepted zero-value session config. I did not run BE tests in this checkout because .worktree_initialized and thirdparty/installed are missing.
  • User focus: no additional user-provided focus points were present.

Subagent conclusions: OPT-1 and TSC-1 both identified the same orc_once_max_read_bytes = 0 compatibility regression and were merged into inline comment MAIN-1. No other candidates remained after duplicate merging. Convergence round 1 ended with both optimizer-rewrite and tests-session-config replying NO_NEW_VALUABLE_FINDINGS for the final ledger/comment set.

Comment thread be/src/format_v2/orc/orc_file_input_stream.cpp Outdated
@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 86.67% (208/240) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 56.91% (23555/41393)
Line Coverage 40.59% (230384/567648)
Region Coverage 36.49% (182049/498937)
Branch Coverage 37.56% (81257/216357)

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17610	3993	3988	3988
q2	2000	326	214	214
q3	10317	1419	797	797
q4	4685	474	336	336
q5	7521	864	573	573
q6	177	170	135	135
q7	766	880	631	631
q8	9331	1599	1596	1596
q9	5674	4449	4408	4408
q10	6748	1803	1525	1525
q11	491	347	318	318
q12	708	551	447	447
q13	18141	3435	2723	2723
q14	264	261	236	236
q15	q16	803	780	726	726
q17	1026	977	946	946
q18	6857	5701	5478	5478
q19	1319	1157	1068	1068
q20	766	653	547	547
q21	6000	2688	2543	2543
q22	419	361	301	301
Total cold run time: 101623 ms
Total hot run time: 29536 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4345	4303	4247	4247
q2	284	327	214	214
q3	4650	4967	4418	4418
q4	2101	2170	1352	1352
q5	4434	4305	4305	4305
q6	234	178	128	128
q7	1720	1651	1905	1651
q8	2677	2174	2204	2174
q9	8082	8227	7812	7812
q10	4707	4701	4191	4191
q11	556	417	391	391
q12	795	773	546	546
q13	3268	3618	2903	2903
q14	294	314	275	275
q15	q16	714	736	653	653
q17	1319	1327	1314	1314
q18	7931	7442	7453	7442
q19	1108	1096	1054	1054
q20	2200	2195	1942	1942
q21	5211	4525	4360	4360
q22	524	469	393	393
Total cold run time: 57154 ms
Total hot run time: 51765 ms

@hello-stephen

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

query5	4354	673	498	498
query6	484	254	231	231
query7	4933	564	344	344
query8	372	208	189	189
query9	8820	4112	4096	4096
query10	494	369	336	336
query11	5845	2369	2155	2155
query12	170	108	108	108
query13	1301	668	464	464
query14	6314	5354	5032	5032
query14_1	4352	4345	4311	4311
query15	214	211	194	194
query16	1031	497	486	486
query17	1015	787	629	629
query18	2481	529	388	388
query19	230	214	170	170
query20	119	115	122	115
query21	240	170	138	138
query22	13730	13565	13443	13443
query23	17309	16571	16087	16087
query23_1	16313	16305	16286	16286
query24	7559	1781	1316	1316
query24_1	1359	1323	1334	1323
query25	610	508	450	450
query26	1376	366	229	229
query27	2574	588	396	396
query28	4484	2071	2030	2030
query29	1141	691	566	566
query30	354	274	244	244
query31	1139	1106	1003	1003
query32	123	78	68	68
query33	563	356	294	294
query34	1171	1135	649	649
query35	786	787	684	684
query36	1404	1414	1262	1262
query37	211	110	98	98
query38	1902	1727	1673	1673
query39	942	924	890	890
query39_1	889	874	880	874
query40	254	167	148	148
query41	79	78	76	76
query42	100	97	95	95
query43	319	331	281	281
query44	1404	789	769	769
query45	206	192	185	185
query46	1063	1207	730	730
query47	2411	2341	2308	2308
query48	399	440	310	310
query49	604	464	336	336
query50	1155	438	362	362
query51	11011	11049	10802	10802
query52	94	89	78	78
query53	267	277	226	226
query54	300	266	230	230
query55	76	72	69	69
query56	311	318	305	305
query57	1448	1416	1335	1335
query58	298	280	273	273
query59	1583	1662	1441	1441
query60	341	289	266	266
query61	195	232	188	188
query62	705	655	595	595
query63	245	214	211	211
query64	3067	1282	1090	1090
query65	4886	4800	4697	4697
query66	1871	546	429	429
query67	29562	29533	29245	29245
query68	3031	1551	1082	1082
query69	438	298	277	277
query70	1083	966	965	965
query71	355	327	308	308
query72	3441	2862	2707	2707
query73	847	777	440	440
query74	5104	4959	4743	4743
query75	2653	2627	2238	2238
query76	2383	1178	775	775
query77	376	392	303	303
query78	12330	12402	11603	11603
query79	1380	1185	795	795
query80	1221	576	507	507
query81	523	331	280	280
query82	581	164	130	130
query83	404	333	300	300
query84	336	174	141	141
query85	1131	700	622	622
query86	401	314	270	270
query87	1838	1818	1789	1789
query88	3741	2830	2811	2811
query89	473	412	360	360
query90	1801	204	204	204
query91	221	212	186	186
query92	72	71	63	63
query93	1511	1488	999	999
query94	648	379	353	353
query95	809	624	489	489
query96	1037	869	364	364
query97	2705	2697	2548	2548
query98	212	220	204	204
query99	1151	1163	1036	1036
Total cold run time: 267722 ms
Total hot run time: 182992 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 2d2fdbaf4f7cb35e491a3d0c0ba59a8998137212, data reload: false

query1	0.01	0.01	0.01
query2	0.09	0.04	0.05
query3	0.25	0.13	0.14
query4	1.64	0.14	0.13
query5	0.23	0.21	0.22
query6	1.22	1.05	1.05
query7	0.04	0.01	0.00
query8	0.05	0.04	0.04
query9	0.38	0.31	0.32
query10	0.60	0.55	0.54
query11	0.20	0.14	0.14
query12	0.20	0.14	0.15
query13	0.47	0.46	0.47
query14	1.02	0.99	1.01
query15	0.62	0.59	0.62
query16	0.31	0.32	0.31
query17	1.07	1.10	1.08
query18	0.21	0.21	0.20
query19	2.02	1.95	1.93
query20	0.01	0.01	0.01
query21	15.44	0.24	0.14
query22	4.75	0.06	0.05
query23	16.16	0.29	0.14
query24	2.96	0.44	0.31
query25	0.09	0.05	0.05
query26	0.75	0.21	0.16
query27	0.04	0.03	0.04
query28	3.52	0.91	0.56
query29	12.51	4.13	3.30
query30	0.28	0.15	0.15
query31	2.76	0.57	0.31
query32	3.21	0.59	0.48
query33	3.19	3.17	3.18
query34	15.61	4.22	3.55
query35	3.53	3.52	3.58
query36	0.57	0.43	0.43
query37	0.10	0.07	0.06
query38	0.05	0.03	0.04
query39	0.03	0.03	0.03
query40	0.19	0.16	0.16
query41	0.07	0.03	0.02
query42	0.04	0.02	0.02
query43	0.04	0.04	0.04
Total cold run time: 96.53 s
Total hot run time: 25.02 s

@xylaaaaa xylaaaaa force-pushed the pr/orc-v2-stripe-prefetch-clean branch from 2d2fdba to fa4dad3 Compare July 11, 2026 10:47
@xylaaaaa

Copy link
Copy Markdown
Contributor Author

/review

1 similar comment
@Gabriel39

Copy link
Copy Markdown
Contributor

/review

@Gabriel39

Copy link
Copy Markdown
Contributor

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.

Reviewed the ORC v2 stripe merged-read change. I found one blocking issue: the new merged-range cache uses untracked std::vector<char> storage for query-sized read spans, bypassing Doris memory tracking. I submitted one inline comment.

Critical checkpoints:

  • Goal/test coverage: the PR implements ORC v2 stripe stream collection and merged small-stream reads; tests cover merge/direct/zero-value/profile paths, but allocator-aware memory accounting is still missing.
  • Scope: the implementation is focused on the ORC v2 input stream and reader wiring.
  • Concurrency/lifecycle: I did not find new shared cross-thread state; active cluster readers are flushed on stripe transition and destruction. The substantiated issue is memory accounting, not a race.
  • Configuration/session compatibility: orc_once_max_read_bytes and orc_max_merge_distance_bytes are forwarded to BE. The earlier orc_once_max_read_bytes = 0 crash is already covered by an existing thread and current head now allows zero.
  • Parallel paths/compatibility: the existing v1 ORC merge helper uses Doris allocator-aware storage for the same kind of cache; the v2 path should preserve that memory-accounting behavior.
  • Error handling: changed read paths check Status and convert read failures to ORC parse errors at the expected boundary.
  • Performance/observability: merged-read profile counters were added, but the merged cache allocation itself is not tracked by Doris memory accounting.
  • Tests: I did not run BE unit tests in this checkout because thirdparty/installed and protoc are missing; git diff --check passed.
  • User focus: no additional user-provided review focus was supplied.

Subagent conclusions:

  • optimizer-rewrite reported OPT-001 as a duplicate of MAIN-001; no optimizer/rewrite issue was found.
  • tests-session-config reported TSC-1 as a duplicate of MAIN-001; no separate tests/session/config issue was found.
  • Convergence round 1 ended with both live subagents returning NO_NEW_VALUABLE_FINDINGS for the same final comment set.

}

const size_t range_size = _range.end_offset - _range.start_offset;
_cache.resize(range_size);

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 cache should use Doris allocator-aware storage instead of a plain std::vector<char>. _load() resizes _cache to the full merged span, which is capped by orc_once_max_read_bytes; that session variable is only lower-bounded at 0 in FE and is forwarded directly to BE, so one scan can allocate multi-megabyte buffers per active merged cluster here. The existing v1 ORC merge reader keeps the same kind of cache in DorisUniqueBufferPtr<char>, which charges the allocation through Doris' memory accounting. Please switch this cache to the Doris allocator path, for example the same DorisUniqueBufferPtr<char> / make_unique_buffer pattern, so ORC v2 merged reads cannot bypass query memory tracking.

@xylaaaaa xylaaaaa force-pushed the pr/orc-v2-stripe-prefetch-clean branch from fa4dad3 to 5eab058 Compare July 11, 2026 13:36
@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 one additional blocking issue: ORC v2 now derives natural_read_size from the mutable BE config orc_natural_read_size_mb without validating it, so an accepted zero value can abort BE during ORC v2 reader initialization.

Existing inline threads already cover zero orc_once_max_read_bytes behavior and allocator-aware storage for the merged-range cache, so I did not duplicate those comments.

Critical checkpoint conclusions: the PR implements the intended ORC v2 small-stream merge path and keeps the change focused; CMake globs include the new production and test files; no new optimizer/rewrite, transaction, persistence, FE/BE protocol, or concurrency issue was found; lifecycle/profile flushing was reviewed around stripe switch and reader teardown; configuration review found the new natural-read-size validation gap; tests cover merge/direct/zero-once/profile behavior but do not cover invalid orc_natural_read_size_mb; validation here was static review plus git diff --check because this checkout lacks thirdparty/installed and thirdparty/installed/bin/protoc.

Comment thread be/src/format_v2/orc/orc_reader.cpp Outdated
auto input_stream = std::make_unique<DorisOrcInputStream>(_file_description->path,
_tracing_file_reader, _io_ctx.get());
OrcFileInputStreamOptions input_stream_options;
input_stream_options.natural_read_size = config::orc_natural_read_size_mb << 20;

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 makes ORC v2 depend on a mutable BE config value that is not validated before it reaches the new constructor check. orc_natural_read_size_mb is declared with DEFINE_mInt32, so /api/update_config can accept orc_natural_read_size_mb=0, and this line then derives natural_read_size = 0; immediately after that, OrcFileInputStream aborts on DORIS_CHECK_GT(_options.natural_read_size, 0) during reader initialization. That turns an accepted runtime config into a BE process crash for any ORC v2 scan. Please add a validator for a safe positive range, and compute the byte value after validation with a safe cast, or reject/report the invalid value before constructing the input stream.

@xylaaaaa xylaaaaa force-pushed the pr/orc-v2-stripe-prefetch-clean branch from 5eab058 to 530ae71 Compare July 12, 2026 04:45
@xylaaaaa

Copy link
Copy Markdown
Contributor Author

run buildall

### What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: ORC file scanner v2 used a thin ORC input stream that issued reads directly through the underlying file reader. It did not implement the v1 ORC stripe-level stream collection and small-range merge path, so remote object storage scans could regress to many small stream reads for wide ORC files, multi-stripe files, and lazy or predicate-driven scans. This change adds a v2-native ORC input stream that implements beforeReadStripe(), builds selected stream ranges, merges adjacent small streams with Doris PrefetchRange policy, and serves arbitrary repeated or backward stream reads from an immutable merged-range cache. Large streams and unmerged single streams continue to read directly. The reader is wired into ORC v2 without changing v1 or falling back to v1.

### Release note

Improve ORC file scanner v2 remote read performance by merging selected small stripe stream reads.

### Check List (For Author)

- Test: Unit Test / Manual test / Static analysis
    - Unit Test: ./run-be-ut.sh --run --filter='OrcFileInputStreamTest.*:NewOrcReaderTest.StripePrefetchPublishesMergedReadProfile' -j 8 (passed, reported by user)
    - Manual test: git diff --check (passed)
    - Manual test: build-support/check-format.sh (passed)
    - Manual test: ninja -C be/ut_build_ASAN src/format/CMakeFiles/Format.dir/__/format_v2/orc/orc_file_input_stream.cpp.o test/CMakeFiles/doris_be_test.dir/format_v2/orc/orc_file_input_stream_test.cpp.o (passed)
    - Static analysis: build-support/run-clang-tidy.sh --build-dir be/ut_build_ASAN --files ... (attempted; own signed/unsigned diagnostic fixed; remaining failures are pre-existing/toolchain diagnostics in be/src/core/types.h and be/src/io/fs/buffered_reader.h)
- Behavior changed: Yes. ORC v2 now merges selected small stripe streams and reads each merged cluster through a cached span instead of issuing one remote read per small stream request.
- Does this need documentation: No
@xylaaaaa xylaaaaa force-pushed the pr/orc-v2-stripe-prefetch-clean branch from 530ae71 to cd574c6 Compare July 12, 2026 05:28
@xylaaaaa

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 87.79% (230/262) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 56.90% (23554/41393)
Line Coverage 40.59% (230397/567670)
Region Coverage 36.48% (182018/498943)
Branch Coverage 37.55% (81254/216361)

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 88.93% (233/262) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 74.80% (30212/40388)
Line Coverage 58.82% (331825/564108)
Region Coverage 55.58% (278344/500839)
Branch Coverage 56.90% (123146/216439)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants