Skip to content

[improvement](compaction) Support preferred peer reads - #67375

Open
mymeiyi wants to merge 1 commit into
apache:masterfrom
mymeiyi:3-peer-read
Open

[improvement](compaction) Support preferred peer reads#67375
mymeiyi wants to merge 1 commit into
apache:masterfrom
mymeiyi:3-peer-read

Conversation

@mymeiyi

@mymeiyi mymeiyi commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Later, we will support distributed parallel compaction. compaction workers may not have the input rowsets in their local file cache.
This PR allows workers to read cached input data from the coordinator when available. It propagates an optional preferred peer through RowsetReader and IOContext. When configured, the worker tries only that peer and falls back directly to remote storage if the peer read fails.

related pr:
#67360

Copilot AI lite review requested due to automatic review settings September 1, 2026 08:55
@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.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Adds support for “preferred peer” reads in compaction/rowset reading by propagating a per-request peer address through RowsetReader into IOContext, allowing a worker to attempt a specific coordinator peer before falling back to remote storage.

Changes:

  • Extend RowsetReader API to set a preferred file-cache peer (host/port) and propagate via IOContext.
  • Update CachedRemoteFileReader to attempt the preferred peer even when global peer reads are disabled, with fallback to remote on failure.
  • Add/adjust unit tests to verify propagation and preferred-peer behavior.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
be/src/storage/rowset/rowset_reader.h Adds new RowsetReader API for preferred peer.
be/src/storage/rowset/beta_rowset_reader.h Implements preferred peer propagation into read options’ IOContext.
be/src/io/io_common.h Adds preferred peer fields to IOContext.
be/src/io/cache/cached_remote_file_reader.cpp Implements preferred-peer read attempt and remote fallback.
be/test/storage/rowset/beta_rowset_test.cpp Adds test asserting preferred peer propagates into segment IO context.
be/test/io/cache/cached_remote_file_reader_peer_test.cpp Updates/adds tests for preferred peer behavior and fallback.
be/test/storage/iterator/block_reader_binlog_vcollect_merge_test.cpp Updates fake reader to satisfy new RowsetReader API.
be/test/storage/index/inverted/similarity/collection_statistics_test.cpp Updates mock reader to satisfy new RowsetReader API.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread be/src/storage/rowset/rowset_reader.h
Comment thread be/src/storage/rowset/rowset_reader.h
Comment thread be/src/io/cache/cached_remote_file_reader.cpp
Comment thread be/test/io/cache/cached_remote_file_reader_peer_test.cpp
Comment thread be/test/io/cache/cached_remote_file_reader_peer_test.cpp
Comment thread be/test/io/cache/cached_remote_file_reader_peer_test.cpp
@mymeiyi

mymeiyi commented Sep 1, 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.

Review summary

Status: capped/incomplete. The focused per-read preferred-peer branch and direct remote fallback work, but six distinct issues still prevent the preferred endpoint from being a complete, bounded, and observable compaction contract. Two accepted issues were found in the third and final permitted round, so the substantiated set below is submitted, but further convergence was not allowed.

Critical checkpoint conclusions

  • Goal and proof: Partially achieved. The tests prove preferred-peer success, single-read fallback, and propagation into the ordinary lazy segment context. They do not prove end-to-end compaction routing: footer pre-reads, standalone index compaction, grouped range readers, and variant metadata phases bypass or lose the endpoint.
  • Scope and clarity: The diff is small and the local routing branch is clear, but storing task routing only in one BetaRowsetReader's private read options is too narrow for the existing compaction topology.
  • Concurrency and thread safety: No new shared mutable endpoint, lock ordering, or background ownership was introduced. The setter is used as setup state and no new race/deadlock was found.
  • Lifecycle: The main defects are lifecycle boundaries: IO before reader construction, IO after reconstructing independent index readers, replacement of configured readers per grouped range, and variant scans that unwrap or precede readers. The clone-only concern was dismissed because no current production clone-after-set path exists.
  • Configuration: No new configuration was added. Existing cloud/tablet/warmup/bypass and remote-only-on-miss guards behave as intended, and the per-request endpoint correctly overrides the global peer switch. The already-raised invalid-port thread remains the duplicate fence for static endpoint validation.
  • Compatibility: No storage-format, persistence, wire-protocol, or FE/BE compatibility change was introduced. All in-tree RowsetReader implementations/test doubles implement the new pure virtual method, and header-hygiene checks pass.
  • Parallel paths: Not complete. Full vertical pre-reads, V1/V2/SNII index compaction, grouped cloud compaction, and flat/nested variant metadata paths each need explicit task-level propagation.
  • Conditions and error handling: Per-read success and S3 fallback cleanup are correct. Timeout-class failures remain unbounded across later uncached reads; NOT_FOUND/overload semantics should remain distinguished.
  • Test coverage: Current unit tests cover the narrow happy path and one fallback only. Missing coverage includes cold full vertical compaction, row-count fallback, cold index compaction, grouped segment ranges, flat/nested variant metadata, repeated runtime outage, and compaction statistics.
  • Test results: build-support/check-build-hygiene.sh and git diff --check pass; live CI reports formatter/checkstyle and repository checks passing. Builds and BE/unit/regression tests were not run in this review-only job, and the build/test CI jobs are skipped.
  • Observability: Generic file-cache peer counters/hosts are correct on success, but peer bytes/time disappear from merger, task-tracker, tablet-time, and compaction-metric aggregation. Failed-attempt accounting is already covered by the existing inline thread.
  • Transactions, persistence, and data writes: No transaction, EditLog, visibility, delete-bitmap, output atomicity, or persistent metadata behavior is changed by this PR.
  • FE/BE variables: No new FE-to-BE or serialized variable is introduced.
  • Performance: Runtime-unreachable preferred peers can add the 5-second RPC timeout to every later uncached operation, while the propagation gaps send cold compaction reads back to object storage and defeat the intended optimization.
  • Other checks: No new memory-safety, nullable, data-version, or security-sensitive behavior was identified. No additional user-provided review focus was supplied.

All six live pre-existing inline threads were treated as hard duplicate fences; the comments in this review are distinct.

std::vector<RowwiseIteratorUPtr>* out_iters,
bool use_cache = false) override;
void reset_read_options() override;
void set_preferred_file_cache_peer(const std::string& host, int32_t port) override {

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] Route compaction's pre-reader footer reads through this endpoint

With the default compaction_batch_size == -1, Merger::vertical_merge_rowsets() calls BetaRowset::load_segments() for first-time footer sampling before any get_segment_iterators() call. That overload opens segments with a null IOContext, so on the cold distributed worker this feature targets, with global peer reads disabled, those footer reads still go to object storage even after this setter was called. The row-ID-conversion fallback similarly calls get_segment_num_rows(..., _stats) without _read_options.io_ctx. Please plumb the preference into these pre-reads and cover cold-cache vertical compaction; the new unit test exercises only the later lazy-iterator path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

later pr will set peer info

bool use_cache = false) override;
void reset_read_options() override;
void set_preferred_file_cache_peer(const std::string& host, int32_t port) override {
_read_options.io_ctx.preferred_peer_host = host;

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] Propagate the preferred peer into index compaction

do_inverted_index_compaction() reconstructs IndexFileReaders directly from the source rowsets, then calls init(), open(), and open_snii_index() without an IOContext. With global peer reads disabled, cold V1/V2/SNII source-index reads therefore still use object storage even after the rowset reader was configured. This phase runs after the row merge and does not reuse input_rs_readers, so fixing the footer pre-reads does not cover it. Please carry a compaction-level preferred-peer context into every source index-container read and add a cold-cache index-compaction test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

later pr will set peer info

void reset_read_options() override;
void set_preferred_file_cache_peer(const std::string& host, int32_t port) override {
_read_options.io_ctx.preferred_peer_host = host;
_read_options.io_ctx.preferred_peer_port = port;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Preserve the preference when grouped compaction rebuilds readers

The production grouped path in CloudCumulativeCompaction::do_merge_input_rowsets() ignores the configured input_rs_readers vector and calls input_rowset->create_reader() for every segment range. Each fresh reader has an empty preferred endpoint, so with global peer reads disabled the range's normal segment footer/index/data IO goes to object storage. This is not the clone or pre-reader-footer case: segment_range skips that sampler and the configured reader is replaced outright. Please keep this routing state at compaction-task scope and apply it to every range reader, with a cold-cache grouped-compaction test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

later pr will set peer info

@@ -58,6 +59,7 @@ class RowsetReader {
std::vector<RowwiseIteratorUPtr>* out_iters,
bool use_cache = false) = 0;
virtual void reset_read_options() = 0;

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] Route variant-compaction metadata reads through the task peer

With enable_vertical_compact_variant_subcolumns enabled by default, both compaction build_basic_info() paths call get_extended_compaction_schema() before the input readers are created. Its variant aggregation opens segments, column metadata, and external metadata with null/default contexts. Nested-group streaming-plan construction unwraps configured readers back to rowsets and repeats those context-free reads, and validation can do so again. On a cold worker these source reads bypass the preferred coordinator. Please keep the endpoint in task-level IO state and pass it through variant schema discovery, streaming planning, and validation, with cold-cache flat/nested variant tests.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

later pr will set peer info

return _execute_s3_fallback(empty_start, span_size, buffer, peer_result, stats, io_ctx);
}

if (!io_ctx->preferred_peer_host.empty()) {

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] Bound retries after the preferred peer becomes unreachable

This branch retains the endpoint after every RPC error, so each later uncached read can wait the 5-second BRPC timeout before falling back to S3. The ordinary candidate path evicts an endpoint after peer_rpc_failure_eviction_threshold consecutive failures (default 3), but the preferred branch bypasses that protection. A coordinator outage can therefore add roughly five seconds per cold operation throughout a compaction. Please add a task-scoped circuit breaker/cooldown for timeout-class RPC failures while preserving cache-miss/overload semantics, and add a multi-read outage test. This is distinct from the existing zero-port thread because the endpoint is initially valid and fails at runtime.

Comment thread be/src/io/io_common.h
// option and the global async file-cache write switch.
std::optional<CacheWriteMode> cache_write_mode_override = std::nullopt;
// Optional per-request peer; try only this peer before falling back to remote storage.
std::string preferred_peer_host {};

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.

[P2] Preserve preferred-peer IO in compaction statistics

A successful preferred read is recorded in FileCacheStatistics::bytes_read_from_peer and peer_io_timer, but both merger paths export only local/remote bytes and time, and Compaction updates only the local/remote compaction metrics. With global peer reading disabled, this feature therefore moves input bytes out of the remote category without adding them anywhere in the compaction task/tracker statistics, so reported compaction IO drops despite the same data being read. Please propagate peer bytes/time through horizontal, vertical, and grouped compaction (or deliberately classify them into an existing category) and add a statistics assertion.

@mymeiyi

mymeiyi commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17556	3052	3024	3024
q2	2134	250	217	217
q3	10198	897	512	512
q4	4671	254	206	206
q5	7667	567	388	388
q6	136	114	98	98
q7	541	506	400	400
q8	9252	924	930	924
q9	3459	2379	2396	2379
q10	6523	855	698	698
q11	396	196	186	186
q12	618	263	202	202
q13	18135	1522	1167	1167
q14	161	159	137	137
q15	q16	440	394	372	372
q17	1351	869	817	817
q18	3091	2286	2230	2230
q19	1306	959	761	761
q20	368	296	204	204
q21	5716	1663	1830	1663
q22	329	267	226	226
Total cold run time: 94048 ms
Total hot run time: 16811 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3378	3312	3298	3298
q2	511	386	382	382
q3	2221	2267	2153	2153
q4	1198	1159	916	916
q5	2168	2118	2125	2118
q6	164	118	91	91
q7	1029	926	855	855
q8	1588	1407	1410	1407
q9	3120	3104	3086	3086
q10	1819	1782	1604	1604
q11	353	271	251	251
q12	452	430	347	347
q13	1465	1540	1133	1133
q14	168	165	156	156
q15	q16	398	391	355	355
q17	3540	3234	3222	3222
q18	4783	4430	4704	4430
q19	874	778	958	778
q20	1027	948	835	835
q21	3892	3107	3322	3107
q22	407	348	329	329
Total cold run time: 34555 ms
Total hot run time: 30853 ms

@hello-stephen

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

query5	4266	403	320	320
query6	397	134	122	122
query7	4978	411	246	246
query8	294	126	118	118
query9	8673	2870	2881	2870
query10	394	217	189	189
query11	5376	1027	905	905
query12	115	71	70	70
query13	1190	453	334	334
query14	6126	2185	2135	2135
query14_1	1978	1970	2030	1970
query15	179	120	113	113
query16	915	368	346	346
query17	800	450	382	382
query18	2348	329	245	245
query19	166	145	109	109
query20	72	71	72	71
query21	200	101	87	87
query22	5479	5425	5472	5425
query23	6855	6162	5960	5960
query23_1	6011	6193	6135	6135
query24	7259	1097	750	750
query24_1	768	792	780	780
query25	406	277	245	245
query26	1231	213	125	125
query27	2819	430	256	256
query28	4674	1498	1514	1498
query29	914	431	337	337
query30	252	153	123	123
query31	829	422	331	331
query32	119	79	71	71
query33	450	206	164	164
query34	987	834	482	482
query35	403	397	334	334
query36	575	554	514	514
query37	119	78	70	70
query38	996	850	800	800
query39	497	489	509	489
query39_1	461	451	460	451
query40	201	91	73	73
query41	53	55	53	53
query42	76	71	70	70
query43	240	241	208	208
query44	1019	542	554	542
query45	107	105	104	104
query46	795	885	511	511
query47	771	764	720	720
query48	299	310	218	218
query49	543	240	193	193
query50	731	265	204	204
query51	8010	8257	8206	8206
query52	66	68	58	58
query53	190	197	142	142
query54	225	183	172	172
query55	107	70	60	60
query56	219	175	169	169
query57	693	671	613	613
query58	211	172	144	144
query59	1205	1234	1111	1111
query60	259	188	194	188
query61	148	111	117	111
query62	334	211	179	179
query63	173	145	139	139
query64	2748	662	591	591
query65	1616	1692	1649	1649
query66	1907	265	194	194
query67	9672	9706	9811	9706
query68	2747	1143	765	765
query69	336	210	186	186
query70	658	633	619	619
query71	246	167	153	153
query72	2344	1739	1464	1464
query73	640	614	342	342
query74	1580	1234	1156	1156
query75	1161	1086	962	962
query76	2292	753	586	586
query77	255	253	206	206
query78	3948	3718	3235	3235
query79	1198	806	611	611
query80	820	321	266	266
query81	463	154	133	133
query82	605	142	96	96
query83	293	212	188	188
query84	292	112	88	88
query85	929	362	292	292
query86	347	190	177	177
query87	1013	968	875	875
query88	2771	2110	2110	2110
query89	288	190	175	175
query90	1741	128	125	125
query91	134	120	100	100
query92	77	69	71	69
query93	1274	1083	766	766
query94	556	260	199	199
query95	527	321	232	232
query96	790	614	283	283
query97	1034	1055	1071	1055
query98	142	134	140	134
query99	427	355	309	309
Total cold run time: 174579 ms
Total hot run time: 82433 ms

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.08	0.04	0.03
query3	0.25	0.11	0.11
query4	1.60	0.10	0.09
query5	0.17	0.17	0.15
query6	1.20	0.71	0.71
query7	0.04	0.01	0.01
query8	0.05	0.03	0.03
query9	0.28	0.21	0.22
query10	0.34	0.35	0.38
query11	0.16	0.12	0.11
query12	0.14	0.12	0.12
query13	0.31	0.33	0.30
query14	0.45	0.45	0.45
query15	0.36	0.35	0.35
query16	0.22	0.21	0.23
query17	0.74	0.74	0.71
query18	0.18	0.16	0.16
query19	1.16	1.11	1.19
query20	0.01	0.01	0.01
query21	15.43	0.14	0.11
query22	5.11	0.04	0.04
query23	16.13	0.25	0.10
query24	3.00	0.33	0.27
query25	0.10	0.05	0.03
query26	0.75	0.16	0.11
query27	0.04	0.03	0.03
query28	3.69	0.51	0.27
query29	12.49	3.18	2.55
query30	0.25	0.12	0.12
query31	2.76	0.36	0.18
query32	3.52	0.32	0.24
query33	1.46	1.38	1.58
query34	15.32	2.20	1.79
query35	1.77	1.72	1.73
query36	0.47	0.29	0.30
query37	0.06	0.03	0.04
query38	0.05	0.03	0.03
query39	0.03	0.03	0.02
query40	0.12	0.08	0.08
query41	0.08	0.03	0.02
query42	0.03	0.02	0.03
query43	0.04	0.03	0.03
Total cold run time: 90.45 s
Total hot run time: 14.68 s

### What problem does this PR solve?

Issue Number: None

Related PR: apache#67466

Problem Summary: Distributed compaction readers need to read cached data from the coordinator even when general peer reads are disabled. Carry an optional preferred peer through RowsetReader and IOContext, try only that peer first, and fall back to remote storage on failure. Because worker compaction reads are one-shot, skip worker file-cache writeback and ineffective prefetch when a preferred peer is configured. Record successful preferred peers in PeerCacheNodes and cover routing, fallback, propagation, and no-write behavior.

### Release note

Support per-request preferred peer reads for backend rowset readers. Distributed compaction workers do not cache input blocks fetched through the preferred-peer path.

### Check List (For Author)

- Test: Unit Test not completed
    - ./run-be-ut.sh --run --filter=CachedRemoteFileReaderPeerTest.read_at_uses_preferred_peer_when_global_peer_read_disabled -j4 was attempted previously; configuration failed because thirdparty/installed/arrow-24.0.0 is incomplete
    - Per request, the merged changes were not compiled or run
- Behavior changed: Yes (a configured preferred peer is tried before remote storage, reported in PeerCacheNodes, and does not write worker file cache)
- Does this need documentation: No
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.

3 participants