Repository navigation
Conversation
|
Thank you for your contribution to Apache Doris. Please clearly describe your PR:
|
7048235 to
a5d11e4
Compare
a5d11e4 to
aeb3178
Compare
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Read-ahead and background hole filling both need to combine sparse logical ranges into bounded physical reads. Add a pure one-pass coalescer whose contract requires validated options and sorted, disjoint, non-empty inputs. Each merge checks the maximum gap, resulting span, and cumulative read amplification. The range-size limit controls merging; an indivisible input larger than the limit remains one read. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=FileRangeCoalescerTest.*' - Behavior changed: No; this commit adds an internal planning primitive. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Read-ahead needs to coalesce sorted page ranges and opportunistically complete highly covered File Cache blocks without repeatedly rebuilding the whole plan. Add a planner that considers only the two boundary blocks of each base range, orders candidates by additional bytes, updates affected interval components, and produces compact input-to-buffer mappings. Its complexity is O(n log n), and an oversized atomic input remains standalone without preventing unrelated blocks from being completed. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=FileRangePlannerTest.*' - Behavior changed: No; this commit adds an internal range planner. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Scanner batches expose too little future IO for efficient remote reads. Add a per-physical-column byte window that always includes current-batch pages, advances through the final scan rowids in either direction, replenishes at configurable watermarks, and retires consumed, skipped, or fallback pages without coupling the component to cache lookup or IO execution. Validate watermarks through the option type and use checked rowid conversion when querying Roaring ranks. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=ColumnReadAheadTest.*' - Behavior changed: No; this commit adds an internal read-ahead window. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Column byte windows need physical ordinal-index ranges and a safe page-decoding lifecycle. Build compressed page candidates from each FileColumnIterator ordinal index, expose prepared physical-column plans, consume planned pages only after complete decoding succeeds, and retry tracked read-ahead or page-cache decode failures through the original reader while preserving existing corruption recovery. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=ColumnReaderTest.FileColumnIteratorPreparesCompressedPageByteWindow:ColumnReaderTest.FileColumnIteratorConsumesSubmittedReadAheadPage:ColumnReaderTest.FileColumnIteratorFallsBackAfterReadAheadChecksumFailure:SegmentReadAheadTest.*:ColumnReadAheadTest.*' - Behavior changed: No; this commit connects internal components before production query integration. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Partial query ranges can cover unordered and overlapping fragments inside one File Cache block. Add a block-local planner that unions existing coverage, takes its complement to produce sorted holes, and applies the dedicated three-parameter coalescing policy without crossing the block boundary. The coalescing size limit controls combining holes; one mandatory hole may be larger and remains one remote read. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=HoleFillPlannerTest.*' - Behavior changed: No; this commit adds an internal hole-fill planner. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Query read-ahead can produce partially covered File Cache blocks that need bounded asynchronous completion before entering the existing cache write path. Add a BE-level manager that merges queued fragments, deduplicates active blocks, evicts the oldest queued block under pressure, waits for Phase 1 spare capacity, fills block-local holes through a dedicated remote-read pool, and hands completed buffers to Phase 1 without another copy. The hole-fill range limit governs coalescing and may be smaller than one cache block because a mandatory single hole is still readable. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=PartialBlockWritebackManagerTest.*:PartialBlockWritebackOptionsTest.*:AsyncCacheWriteManagerTest.ReportsOnlyUnusedPendingCapacity' - Behavior changed: No; this commit adds an unwired internal component. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Background partial-block writeback needs production defaults and a BE-owned lifetime that outlives query read-ahead work while remaining inside the File Cache lifetime. Add validated hole-fill configuration, create the manager after File Cache initialization, and stop it before File Cache teardown. Keep option invariants with PartialBlockWritebackOptions::validate(), including independent block size and hole-coalescing range limits. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=PartialBlockWritebackOptionsTest.*' - Behavior changed: No; this commit initializes an internal component that is connected to query writeback later. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Segment read-ahead must establish the range planner contract while preserving shared physical pages and cache invalidation state. Sort cache-miss pages at the segment boundary, collapse exact duplicate ranges while retaining all column owners, submit compact FileRange plans, and capture a per-submission consumer immediately before asynchronous IO. Only accepted and consumed ranges retain and invoke that consumer. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=SegmentReadAheadTest.*:ColumnReaderTest.FileColumnIteratorConsumesSubmittedReadAheadPage:ColumnReaderTest.FileColumnIteratorFallsBackAfterReadAheadChecksumFailure' - Behavior changed: No; production writeback is connected by a later commit. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Scanner batches expose too little future IO for efficient remote reads. Add a per-physical-column byte window that always includes current-batch pages, advances through the final scan rowids in either direction, replenishes at configurable watermarks, and retires consumed, skipped, or fallback pages without coupling the component to cache lookup or IO execution. Validate watermarks through the option type and use checked rowid conversion when querying Roaring ranks. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=ColumnReadAheadTest.*' - Behavior changed: No; this commit adds an internal read-ahead window. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Column byte windows need physical ordinal-index ranges and a safe page-decoding lifecycle. Build compressed page candidates from each FileColumnIterator ordinal index, expose prepared physical-column plans, consume planned pages only after complete decoding succeeds, and retry tracked read-ahead or page-cache decode failures through the original reader while preserving existing corruption recovery. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=ColumnReaderTest.FileColumnIteratorPreparesCompressedPageByteWindow:ColumnReaderTest.FileColumnIteratorConsumesSubmittedReadAheadPage:ColumnReaderTest.FileColumnIteratorFallsBackAfterReadAheadChecksumFailure:SegmentReadAheadTest.*:ColumnReadAheadTest.*' - Behavior changed: No; this commit connects internal components before production query integration. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Partial query ranges can cover unordered and overlapping fragments inside one File Cache block. Add a block-local planner that unions existing coverage, takes its complement to produce sorted holes, and applies the dedicated three-parameter coalescing policy without crossing the block boundary. The coalescing size limit controls combining holes; one mandatory hole may be larger and remains one remote read. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=HoleFillPlannerTest.*' - Behavior changed: No; this commit adds an internal hole-fill planner. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Query read-ahead can produce partially covered File Cache blocks that need bounded asynchronous completion before entering the existing cache write path. Add a BE-level manager that merges queued fragments, deduplicates active blocks, evicts the oldest queued block under pressure, waits for Phase 1 spare capacity, fills block-local holes through a dedicated remote-read pool, and hands completed buffers to Phase 1 without another copy. The hole-fill range limit governs coalescing and may be smaller than one cache block because a mandatory single hole is still readable. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=PartialBlockWritebackManagerTest.*:PartialBlockWritebackOptionsTest.*:AsyncCacheWriteManagerTest.ReportsOnlyUnusedPendingCapacity' - Behavior changed: No; this commit adds an unwired internal component. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Background partial-block writeback needs production defaults and a BE-owned lifetime that outlives query read-ahead work while remaining inside the File Cache lifetime. Add validated hole-fill configuration, create the manager after File Cache initialization, and stop it before File Cache teardown. Keep option invariants with PartialBlockWritebackOptions::validate(), including independent block size and hole-coalescing range limits. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=PartialBlockWritebackOptionsTest.*' - Behavior changed: No; this commit initializes an internal component that is connected to query writeback later. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Segment read-ahead must establish the range planner contract while preserving shared physical pages and cache invalidation state. Sort cache-miss pages at the segment boundary, collapse exact duplicate ranges while retaining all column owners, submit compact FileRange plans, and capture a per-submission consumer immediately before asynchronous IO. Only accepted and consumed ranges retain and invoke that consumer. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=SegmentReadAheadTest.*:ColumnReaderTest.FileColumnIteratorConsumesSubmittedReadAheadPage:ColumnReaderTest.FileColumnIteratorFallsBackAfterReadAheadChecksumFailure' - Behavior changed: No; production writeback is connected by a later commit. - Does this need documentation: No
55ff2ba to
64fe07a
Compare
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Asynchronous read-ahead ranges must preserve their coalesced byte boundaries and avoid populating File Cache before consumption is known. Route per-read NO_WRITE requests through CachedRemoteFileReader's existing remote-only-on-cache-miss path: a fully cached range is served locally, while incomplete coverage issues one exact remote read for the entire planned range without creating cache cells, waiting for downloading blocks, reading from peers, or submitting cache writes. Keep cache-write mode resolution in the main reader dispatch because it selects among all read paths rather than belonging to the asynchronous cache-write implementation. ### Release note None ### Check List (For Author) - Test: Unit Test and BE build - ./run-be-ut.sh -j100 --run '--filter=AsyncCachedRemoteFileReaderTest.exact_no_write_*:BlockFileCacheTest.cached_remote_file_reader_remote_only_on_miss:BlockFileCacheTest.get_downloaded_blocks_if_fully_covered_is_read_only:BlockFileCacheTest.cache_write_mode_is_resolved_for_each_read_context:AsyncFileRangeReaderTest.*:PartialBlockWritebackManagerTest.*' (29 passed) - ./build.sh --be -j100 - Behavior changed: Yes; no-write asynchronous ranges reuse full cache hits and otherwise issue one exact remote read for the planned range. - Does this need documentation: Yes; covered by the Phase 2 design document.
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Scanner batches expose too little future IO for efficient remote reads. Add a per-physical-column byte window that always includes current-batch pages, advances through the final scan rowids in either direction, replenishes at configurable watermarks, and retires consumed, skipped, or fallback pages without coupling the component to cache lookup or IO execution. Validate watermarks through the option type and use checked rowid conversion when querying Roaring ranks. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=ColumnReadAheadTest.*' - Behavior changed: No; this commit adds an internal read-ahead window. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Column byte windows need physical ordinal-index ranges and a safe page-decoding lifecycle. Build compressed page candidates from each FileColumnIterator ordinal index, expose prepared physical-column plans, consume planned pages only after complete decoding succeeds, and retry tracked read-ahead or page-cache decode failures through the original reader while preserving existing corruption recovery. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=ColumnReaderTest.FileColumnIteratorPreparesCompressedPageByteWindow:ColumnReaderTest.FileColumnIteratorConsumesSubmittedReadAheadPage:ColumnReaderTest.FileColumnIteratorFallsBackAfterReadAheadChecksumFailure:SegmentReadAheadTest.*:ColumnReadAheadTest.*' - Behavior changed: No; this commit connects internal components before production query integration. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Partial query ranges can cover unordered and overlapping fragments inside one File Cache block. Add a block-local planner that unions existing coverage, takes its complement to produce sorted holes, and applies the dedicated three-parameter coalescing policy without crossing the block boundary. The coalescing size limit controls combining holes; one mandatory hole may be larger and remains one remote read. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=HoleFillPlannerTest.*' - Behavior changed: No; this commit adds an internal hole-fill planner. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Query read-ahead can produce partially covered File Cache blocks that need bounded asynchronous completion before entering the existing cache write path. Add a BE-level manager that merges queued fragments, deduplicates active blocks, evicts the oldest queued block under pressure, waits for Phase 1 spare capacity, fills block-local holes through a dedicated remote-read pool, and hands completed buffers to Phase 1 without another copy. The hole-fill range limit governs coalescing and may be smaller than one cache block because a mandatory single hole is still readable. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=PartialBlockWritebackManagerTest.*:PartialBlockWritebackOptionsTest.*:AsyncCacheWriteManagerTest.ReportsOnlyUnusedPendingCapacity' - Behavior changed: No; this commit adds an unwired internal component. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Background partial-block writeback needs production defaults and a BE-owned lifetime that outlives query read-ahead work while remaining inside the File Cache lifetime. Add validated hole-fill configuration, create the manager after File Cache initialization, and stop it before File Cache teardown. Keep option invariants with PartialBlockWritebackOptions::validate(), including independent block size and hole-coalescing range limits. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=PartialBlockWritebackOptionsTest.*' - Behavior changed: No; this commit initializes an internal component that is connected to query writeback later. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Segment read-ahead must establish the range planner contract while preserving shared physical pages and cache invalidation state. Sort cache-miss pages at the segment boundary, collapse exact duplicate ranges while retaining all column owners, submit compact FileRange plans, and capture a per-submission consumer immediately before asynchronous IO. Only accepted and consumed ranges retain and invoke that consumer. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=SegmentReadAheadTest.*:ColumnReaderTest.FileColumnIteratorConsumesSubmittedReadAheadPage:ColumnReaderTest.FileColumnIteratorFallsBackAfterReadAheadChecksumFailure' - Behavior changed: No; production writeback is connected by a later commit. - Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: The initial query read-ahead implementation spread execution, page lifecycle, and submission state across several adapters and state machines. Rename the BE-global component to FileRangeReadScheduler, flatten its ownership and synchronization while executing work on SegmentPrefetchThreadPool, reduce column windows to pending-byte accounting, and make SegmentReadAhead the single cache-probe, coalescing, and submission boundary. SegmentReadAheadFileReader now retires pages at successful buffer reads, and background hole fill reuses its already-owned IO context. ### Release note None ### Check List (For Author) - Test: Unit Test - 61 focused read-ahead and writeback tests with ./run-be-ut.sh -j100 - 15 CachedRemoteFileReader and file-cache tests with ./run-be-ut.sh -j100 - ./build.sh --be -j100 (Release) - build-support/check-format.sh - build-support/check-build-hygiene.sh - Behavior changed: Yes; successful prefetched bytes are consumed at the exact PageIO read, while later page decode failures retry the original reader. - Does this need documentation: No
29d8551 to
6954c33
Compare
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Read-ahead and background hole filling both need to combine sparse logical ranges into bounded physical reads. Add a pure one-pass coalescer whose contract requires validated options and sorted, disjoint, non-empty inputs. Each merge checks the maximum gap, resulting span, and cumulative read amplification. The range-size limit controls merging; an indivisible input larger than the limit remains one read. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=FileRangeCoalescerTest.*' - Behavior changed: No; this commit adds an internal planning primitive. - Does this need documentation: No
There was a problem hiding this comment.
Static review of all 73 changed paths at commit 990f3eb: changes requested. One new P1 identifies a BE abort when consumed-range writeback encounters supported irregular S3 upload cache blocks. Existing blocking comment 4278847468 still applies to the row-store point-query helper at base_tablet.cpp:175: a concurrent mutable-switch disable makes create_for_query return OK/null before its unconditional assertion. Its regular-scan instance is fixed. The pruned-map-child P1 (4278847462) and delayed-reader-owner P1 (4278847472) are fixed at this head and are excluded from existing_blocking_comment_ids.
Existing nonblocking reports remain applicable and are not reposted: queued-fragment metadata growth (4278847476), lost workload-group IO context (4278847479), dictionary-page corruption recovery (4324631642), bypassed query cache-write admission (4324631645), and packed-file trace lifecycle linkage (4324631648). The old read-ahead-only cache-population issue (4278847474) is fixed by requiring async cache writing in enabled().
The reviewed flow is scalar scan/point row IDs -> column byte windows -> segment page-cache probe and range planner -> query/BE byte admission -> shared prefetch workers -> exact PageIO slices/checksum/decoder -> consumed-range dispatch -> complete writer or bounded partial-block workers -> epoch-fenced cache persistence.
- Goal and proof: the opt-in scalar cloud read-ahead and consumed-range writeback flow is implemented, with the blocking and existing recovery/admission exceptions above. Added unit tests exercise range/window planning, scheduling and decoding, but do not prove the reported irregular-cache and row-store toggle cases.
- Scope, clarity and reuse: responsibilities are separated among column windows, segment coordination, range planning, scheduling and writeback; complete blocks reuse the existing cache writer. The change is large but stays within this feature, its profiles and diagnostics.
- Concurrency and locks: foreground windows are scanner-local; shared budgets, read states, page registrations and queues use their respective locks. Waits and consumer callbacks release the page-registry mutex; activation plus the fragment mutex stabilizes hole coverage; remote tokens join accepted reads. No additional lock inversion was substantiated. Workload attachment remains the existing P2.
- Lifecycle and static initialization: shared handles retain range buffers, budgets and source readers; aliasing ownership now retains the cached wrapper through delayed fills. Foreground-only callbacks keep borrowed column/statistics access within foreground ownership. Shutdown drains managers before dependent pools/cache destruction. No new cross-translation-unit initialization dependency was identified.
- Configuration: the feature requires cloud mode and both enable switches. Window/range policies are captured per coordinator; worker counts and merge delay have runtime callbacks. Scan initialization handles OK/null after a mutable disable; the point row-store helper still does not. Supported S3 upload-buffer sizing exposes the new P1.
- Compatibility: no wire or persisted segment format is changed. Existing cache intervals must remain consumable across configuration changes and restarts; M1 violates that compatibility. No compiled ELF/glibc compatibility audit was performed in this static review.
- Thrift/protobuf: no definitions or numeric IDs change.
- Parallel paths: nested, extracted and variant columns retain original readers/prefetchers; compaction/local and delayed-materialization second-stage paths retain their established routing. Prepared scalar point iterators preserve rowset version, commit TSO and absent-column defaults.
- Conditional checks: role vectors are disjoint by earliest materialization assignment. Enabled gates and fallback checks were traced to their callers; the remaining row-store assertion and strict cache-shape probe have concrete failure scenarios.
- Tests and negative coverage: inspected all changed test bodies for EOF, sparse/reverse scans, budget rejection, short/failed reads, cancellation, epoch changes, merge/activation, resizing and shutdown. Irregular upload cache layouts, row-store switch races and dictionary cache corruption are missing negative cases. No builds or tests were run under the review-only contract.
- Test results: no regression output files change; no runtime passing result is claimed.
- Observability: shared counters cover planning, source IO, fallback, consumption and writeback; trace diagnostics include GET/range/task IDs and asynchronous tails. Packed-file lifecycle joins remain the known P3. Trace buffering is explicitly documented as uncapped diagnostic behavior.
- Transactions and persistence: transaction visibility, rowset versions, delete bitmaps, EditLog and failover protocols are unchanged; read paths retain selected rowset context.
- Data writes and atomicity: writes populate disposable File Cache through existing writer/finalize semantics and invalidation epochs. The new pre-write probe can abort before best-effort persistence; cache-write budget and metadata bounds retain their existing reported gaps.
- FE/BE variable passing: no new transmitted variables or FE send paths.
- Performance and memory: scan candidate metadata is prepared once and advanced by physical page; range buffers follow explicit query/BE byte budgets, partial buffers follow block-count limits. Repeated fragment metadata remains the known independent bound violation; no additional concrete performance defect was substantiated.
- User focus and remaining limits: no additional user focus was supplied. All changed paths and initial risks have evidence-based dispositions. Findings are based on static control-flow inspection; runtime validation remains outside this invocation.
Review converged after 2 round(s).
Existing P0/P1 findings confirmed for this head: #67292 (comment)
| } | ||
| ReadStatistics stats; | ||
| const auto context = admission_ctx.to_cache_context(&stats); | ||
| auto result = _cache->probe(cache_hash, offset, size, context); |
There was a problem hiding this comment.
[P1] Handle irregular cached upload blocks before probing
Supported S3 upload settings can leave cache blocks that are not aligned to the global block grid: s3_write_buffer_size=5.5 MiB with 1 MiB cache blocks makes S3FileWriter populate intervals such as [5,5.5) and [5.5,6.5) MiB. After the former is evicted, consuming a read-ahead range such as [5.25,5.75) fetches remote bytes and submits a partial fragment for [5,6). This call then reaches BlockFileCache::probe(), whose DORIS_CHECK requires the resident block to start at 5 MiB; finding the retained 5.5 MiB block aborts the BE. Native queries with peer reads enabled previously used the synchronous, interval-aware get_or_set() path even with async writes enabled, so enabling read-ahead newly exposes this crash. Use an interval-aware coverage check here and cover partially evicted, non-multiple S3 upload layouts.
|
run buildall |
|
/review |
There was a problem hiding this comment.
Static review of all 74 changed files at bdc93f2. Request changes: three new P2 findings are inline (two memory issues and an executor-failure abort), and existing P1 4344901080 remains blocking. The latter was independently traced from non-block-aligned S3 upload cache cells through partial writeback to the grid-only probe assertion; it is not reposted.
Existing threads were revalidated. The delayed-reader ownership, mutable-switch initialization, pruned-map-child abort, and read-ahead-only/async-writer-disabled issues are repaired. The previously reported queued-fragment metadata growth (4278847476), workload-group IO bypass (4278847479), dictionary corruption recovery (4324631642), query cache-write budget bypass (4324631645), and packed-file diagnostic lifecycle mismatch (4324631648) still apply and are not duplicated.
There was no additional user-provided focus. Applicable critical checkpoints:
- Goal and evidence: scalar scans and point reads connect column windows to range planning, asynchronous reads, exact PageIO slices, and consumed-range writeback. Unit sources exercise the main mechanisms; the new memory findings and existing blocker prevent a clean verdict.
- Scope, clarity, reuse: column planning, segment coordination, scheduling, and block writeback have separate responsibilities; original decoders and the existing cache writer are reused. Full-index copies per iterator add the memory cost identified inline.
- Concurrency: scanner submissions, shared read workers, hole dispatcher/block/remote workers, and cache writers were traced. Budget locks, read-state mutexes, fragment activation, and lifecycle flags provide the reviewed coordination; no additional concrete lock inversion was found. Shared-executor callback retention after submission failure is a new inline finding; workload-group context remains the existing finding.
- Lock weight and order: partial-block source IO and full cache probes run outside its queue mutex; fragment copies use a separate mutex. Lifecycle-to-queue ordering and race-safe final writer admission were checked.
- Lifecycle and static initialization: aliasing ownership now retains the cached wrapper through delayed hole reads; cancellation uses weak read registrations, and shared statistics survive scanner teardown. Shutdown joins work before destroying its cache/executor owners. No additional static-initialization defect was established.
- Configuration: the feature is disabled by default and requires both enable switches in cloud mode. Validators and mutable worker/read-pool/delay callbacks were inspected; all factory OK/null callers now fall back when switches close.
- Compatibility: no wire, storage-format, or persisted-schema change was introduced. Binary ABI/ELF compatibility was not executed or asserted.
- Thrift/Protobuf field IDs: not applicable; no gensrc definitions changed.
- Parallel paths: scalar regular/point/row-store reads, forward/reverse batches, sparse selection, constants, schema defaults, version/TSO values, and Page Cache were traced. Complex/variant/extracted paths retain the original readers; TopN/global delayed-materialization second-stage read-ahead remains outside this feature.
- Conditional checks and errors: optional planning/admission/read/data-page decode failures use the original path. The irregular-block assertion and dictionary recovery exception remain existing threads; the new failed-submission state transition can also abort the BE as explained inline.
- Test coverage: added C++ tests cover planners, admission, cancellation, epochs, merges, worker races, source retention, fallback, roles, and profiles; Python tests cover interval accounting and capture warnings. No new end-to-end regression suite is included. Large planning-metadata accounting, a sustained slow trace writer, and worker-creation failure after callback enqueue lack coverage.
- Test results: tests were inspected only. No builds, tests, runtime stress, benchmarks, or format-mutating checks were run; no source files were modified. No regression .out files changed.
- Observability: shared counters and process metrics expose asynchronous tails, admission, fallback, and writeback. Trace checkpoints diagnose loss, but buffering is the new inline issue and packed lifecycle matching remains the existing thread.
- Transactions and persistence: no transaction protocol, EditLog, rowset-version selection, or delete-bitmap semantics changed; point reads retain rowset version/TSO context. Master failover logic is unaffected by this read/cache optimization.
- Data writes and crashes: cache writes are best effort, use immutable file keys, and check captured invalidation epochs. No additional stale authoritative-data write was established; the existing probe abort remains a BE availability problem.
- FE/BE variable propagation: not applicable; the feature is controlled by BE configuration and adds no transmitted variable.
- Performance and memory: payload allocations are tracked and have query/BE budgets, but retained page metadata and diagnostic strings escape that accounting as described inline. Repeated queued-fragment history remains separately covered by its existing thread. No additional verified performance issue emerged in the final recheck.
Coverage limits are static-only validation, absent end-to-end runtime/race/performance/ELF evidence, and the specific missing negative tests above. No unresolved static candidate remains in the accepted review scope.
Review converged after 3 round(s).
Existing P0/P1 findings confirmed for this head: #67292 (comment)
| RETURN_IF_ERROR(_reader->get_ordinal_index_reader(ordinal_index, _opts.stats)); | ||
| DORIS_CHECK(ordinal_index != nullptr); | ||
| std::vector<ColumnReadAheadPage> pages; | ||
| pages.reserve(ordinal_index->num_data_pages()); |
There was a problem hiding this comment.
[P2] Track the retained read-ahead page metadata
Enabling read-ahead copies every physical page in each scalar column into this plain std::vector, retained as ColumnReadAhead::_pages; dense scans also retain _candidate_pages and window-map nodes. These allocations have neither a tracked allocator nor manual MemTracker accounting, and happen before scheduler admission, so they survive even when every range is rejected. On 64-bit targets the two page arrays alone require at least 44 bytes per selected page: wide segments and concurrent scanners can retain substantial memory that query limits never see. Use tracked containers or balanced accounting/reservation for the planning metadata, preferably sharing immutable ordinal metadata, and cover the budget-rejection case.
| return; | ||
| } | ||
| } | ||
| _pending.append(line); |
There was a problem hiding this comment.
[P2] Bound the trace writer's buffered memory
With tracing enabled, a slow or stalled output disk lets all read-ahead and hole-fill producers keep appending here while the writer blocks in appendv() outside the mutex. _flush_bytes only wakes that writer; it does not cap either _pending or the in-flight batch, and both are untracked std::string allocations outside the read-ahead budgets. After a burst drains, batch.clear() still retains its capacity, including after tracing is disabled. Thus diagnostic capture can exhaust BE memory despite bounded query buffers. Account for and cap retained trace bytes, report dropped events through the existing checkpoints, and release excessive burst capacity.
| } | ||
| continue; | ||
| } | ||
| DORIS_CHECK(_inflight_reads.erase(read) == 1); |
There was a problem hiding this comment.
[P2] Preserve callback ownership after worker creation fails
With the supported segment_prefetch_thread_pool_thread_num_min=0, a transient failure creating the first worker can make ThreadPool::do_submit() return an error after it has already queued this callback; it does not roll that enqueue back. This branch removes the read from _inflight_reads and marks it FAILED. If the next range or batch successfully starts a worker, the retained callback runs and _mark_running() aborts because the state is no longer QUEUED. Dropping the scheduler can also leave that callback holding raw this. Ensure failed submission relinquishes the queued callback, or coordinate its execution/lifetime before finalizing the read. Cover one worker-creation failure followed by success, beyond the current capacity/shutdown rejection tests.
|
run buildall |
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Read-ahead and background hole filling both need to combine sparse logical ranges into bounded physical reads. Add a pure one-pass coalescer whose contract requires validated options and sorted, disjoint, non-empty inputs. Each merge checks the maximum gap, resulting span, and cumulative read amplification. The range-size limit controls merging; an indivisible input larger than the limit remains one read. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=FileRangeCoalescerTest.*' - Behavior changed: No; this commit adds an internal planning primitive. - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#67611 (tracking) Related PR: apache#67292, apache#67579, apache#67612 Problem Summary: Add cache-aware range planning and the shared read-ahead statistics contract. Coalesce sorted requested ranges, optionally complete high-coverage boundary blocks, and map exact inputs back to final buffers. Keep planning timers for column initialization, exact-row batches, physical-page advancement, window discard and extension in the shared contract; collection remains with the later consumers. ### Release note Internal range planning and shared read-ahead Profile/bvar definitions. ### Check List (For Author) - Test: Unit Test — component coverage is included with this change. The integrated source snapshot d5c427f passed 198 ASAN tests from 11 suites via run-be-ut.sh -j100. This individual intermediate commit was not built separately; target-branch validation is recorded on the PR. Repository clang-format v16, build hygiene and diff checks passed on the integrated tree. No cluster or clang-tidy run. - Behavior changed: Yes — introduces the opt-in component; this synchronization preserves existing defaults and IO/writeback semantics. - Does this need documentation: Yes — component scope and current behavior are tracked in apache#67611 and the related PR descriptions.
### What problem does this PR solve? Issue Number: apache#67611 (tracking) Related PR: apache#67292, apache#67579, apache#67612 Problem Summary: Provide query/BE resident-byte admission, one exact range read per existing thread-pool task, cancellation, and owned buffer handles. Keep terminal-state checks on FileRangeRead and rejected-result construction on FileRangeReadSubmitResult. Preserve accepted-task accounting and atomic shared S3 reader statistics for concurrent requests. Admit each planned range that fits the remaining query and BE budgets in input order. Preserve the original result slots for skipped ranges and allocate only admitted buffers, so wide scans retain partial prefetch instead of rejecting an entire batch. Budget checks remain one linear pass under both locks; allocation failure and cancellation release all reservations. ### Release note Internal asynchronous file-range reads with query/BE byte budgets and IO accounting. ### Check List (For Author) - Test: Unit Test — integrated ASAN/PCH validation covers 141 tests from 8 suites through ./run-be-ut.sh --run -j100. Includes partial budget admission, original page offsets, cancellation, allocation rollback, executor rejection, consumed-range callbacks and row-store switch fallback. Individual intermediate commits are not built separately; target-branch validation is recorded on the PR. Clang-format 16, header hygiene and diff checks pass. No cluster or clang-tidy run. - Behavior changed: Yes — introduces the opt-in component; this synchronization preserves existing defaults and IO/writeback semantics. - Does this need documentation: Yes — component scope and current behavior are tracked in apache#67611 and the related PR descriptions.
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Asynchronous read-ahead ranges must preserve their coalesced byte boundaries and avoid populating File Cache before consumption is known. Route per-read NO_WRITE requests through CachedRemoteFileReader's remote-only-on-cache-miss path. Before probing downloaded cache blocks, reuse indexed in-flight async-write buffers when they completely cover the request, including requests spanning multiple cache blocks. If any in-flight block is absent, retain the existing all-cache-or-remote behavior: a fully downloaded range is served locally, while incomplete coverage issues one exact remote read for the entire planned range without creating cache cells, waiting for downloading blocks, reading from peers, or submitting cache writes. Keep cache-write mode resolution in the main reader dispatch because it selects among all read paths rather than belonging to the asynchronous cache-write implementation. ### Release note None ### Check List (For Author) - Test: Unit Test and BE build - ./run-be-ut.sh --run --filter='AsyncCachedRemoteFileReaderTest.exact_no_write*:BlockFileCacheTest.cached_remote_file_reader_remote_only_on_miss' -j100 (4 passed) - ./build.sh --be -j100 - Behavior changed: Yes; no-write asynchronous ranges reuse complete in-flight or downloaded-cache coverage and otherwise issue one exact remote read for the planned range. - Does this need documentation: Yes; covered by the Phase 2 design document.
### What problem does this PR solve?
Issue Number: None
Related PR: None
Problem Summary: Concurrent range reads must be shared at BE scope while every scanner of one query shares cancellation and resident-buffer admission. Add a startup-owned FileRangeReadScheduler in Cloud mode, a lazily shared query context, cancellation propagation, and a mutable enable_query_read_ahead switch. Query and BE resident-buffer limits are configurable through read_ahead_max_bytes_per_query and read_ahead_max_bytes_per_be. The scheduler remains available while the switch is disabled so a runtime update can enable read-ahead for newly initialized reads without restarting the BE.
### Release note
Support runtime updates to enable_query_read_ahead and configurable query/BE read-ahead memory limits.
### Check List (For Author)
- Test: Unit Test
- ./run-be-ut.sh --run --filter='FileRangeReadSchedulerTest.*:QueryContextReadAheadTest.*:SegmentReadAheadTest.*:ColumnReaderTest.*ReadAhead*' -j200
- ./build.sh --be -j200
- Behavior changed: Yes. Cloud BEs can enable or disable query read-ahead at runtime; new reads observe the updated switch.
- Does this need documentation: Yes. The read-ahead design document lists these settings.
### What problem does this PR solve? Issue Number: None Related PR: apache#67611, apache#67612, apache#67292, apache#67579 Problem Summary: Aggregate range-read counters cannot identify repeated object intervals or separate diagnostic overhead from read latency. Synchronize the final shared diagnostics from the validation branch as one infrastructure component: stable IO identities and S3 outcomes, read-only cache/inflight coverage snapshots, task provenance, typed timing fields, a batched standalone JSONL writer and shutdown draining, and the offline overlap/timing analyzer. Keep scanner consumption and hole-fill lifecycle producers in their owning later components. Trace is disabled by default and does not change read planning, concurrency or writeback. ### Release note Add enable_read_io_trace=false and dedicated diagnostic files controlled by read_io_trace_dir, read_io_trace_flush_bytes=1 MiB and read_io_trace_flush_interval_ms=1000. Enabled diagnostics can affect timing and should be used for isolated captures. ### Check List (For Author) - Test: Unit Test - Independent incremental ASAN/PCH run-be-ut.sh -j100 on master d4f052b: 75 tests from 8 suites passed. - Python offline analyzer: 15 tests passed. - Repository clang-format 16, check-format, BE header hygiene and git diff --check passed. - The first build was interrupted after /tmp filled; resumed incrementally with a data-disk TMPDIR. No clean rebuild or ccache cleanup. - No cluster, external-object-store benchmark or clang-tidy run. - Behavior changed: Yes, opt-in diagnostic recording; read and persistence decisions are unchanged. - Does this need documentation: Yes, tools/read_io_trace/README.md and the related PR/tracking descriptions.
### What problem does this PR solve? Issue Number: None Related PR: apache#67292, apache#67612, apache#67579 Problem Summary: With PCH disabled, the IO unity translation unit includes err_utils.cpp before file_meta_cache.cpp. The namespace-scope ErrorCode using-directive leaks into the generated protobuf headers and makes LIMIT_REACH ambiguous. Scope the import to the two localfs_error overloads that use it, preserving the existing error-code mappings. This synchronizes the fix already present in apache#67579 into the infrastructure and full feature branches. ### Release note None ### Check List (For Author) - Test: Manual compiler check. Reproduced the original LIMIT_REACH error in IO unity_2 with PCH imports removed; the same ASAN/UBSAN, coverage and -Werror syntax-only check passes after the fix. Repository clang-format 16, format check, build-hygiene check and git diff --check pass. No full BE build or runtime tests were rerun for this scope-only change. - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Issue Number: apache#67611 (tracking) Related PR: apache#67292, apache#67579, apache#67612 Problem Summary: Build each scan column's eligible physical page indexes once and advance compressed-byte windows from the page index resolved by the column reader. A window's second selected page triggers the following window. Retain predictions for ascending batches inside reverse scans; group exact-row requests by distinct pages. ColumnReadAheadPlan owns reset and per-call timing aggregation, retaining vector capacity. Window accounting stays with ColumnReadAhead. ### Release note Internal page-driven column windows for query read-ahead. ### Check List (For Author) - Test: Unit Test — component coverage is included with this change. The integrated source snapshot d5c427f passed 198 ASAN tests from 11 suites via run-be-ut.sh -j100. This individual intermediate commit was not built separately; target-branch validation is recorded on the PR. Repository clang-format v16, build hygiene and diff checks passed on the integrated tree. No cluster or clang-tidy run. - Behavior changed: Yes — introduces the opt-in component; this synchronization preserves existing defaults and IO/writeback semantics. - Does this need documentation: Yes — component scope and current behavior are tracked in apache#67611 and the related PR descriptions.
### What problem does this PR solve? Issue Number: apache#67611 (tracking) Related PR: apache#67292, apache#67579, apache#67612 Problem Summary: Coordinate all resolvable column plans, probe Page Cache, plan and submit ranges, and register exact page slices. Reuse a physical page's existing buffer when independent column windows overlap it. Keep synchronous fallback and per-page ownership accounting; expose planner and consumption statistics. Register only ranges admitted by the scheduler, preserving the planner's original range indices and buffer offsets. Complete unadmitted pages immediately so PageIO uses the original reader, and publish consumed-range callbacks only for admitted buffers. The window, coalescing, block-fill and hole-fill policies are unchanged. ### Release note Internal segment-level coordination for concurrent data-page reads. ### Check List (For Author) - Test: Unit Test — integrated ASAN/PCH validation covers 141 tests from 8 suites through ./run-be-ut.sh --run -j100. Includes partial budget admission, original page offsets, cancellation, allocation rollback, executor rejection, consumed-range callbacks and row-store switch fallback. Individual intermediate commits are not built separately; target-branch validation is recorded on the PR. Clang-format 16, header hygiene and diff checks pass. No cluster or clang-tidy run. - Behavior changed: Yes — introduces the opt-in component; this synchronization preserves existing defaults and IO/writeback semantics. - Does this need documentation: Yes — component scope and current behavior are tracked in apache#67611 and the related PR descriptions.
### What problem does this PR solve? Issue Number: Part of apache#67611 Related PR: apache#67579, apache#67292 Problem Summary: Prepare eligible top-level scalar pages once after pruning and advance scan windows at the data-page read entry before Page Cache lookup. Scalar point reads retain exact-row preparation. Report initialization and page-advancement time, then let ColumnReadAheadPlan accumulate its maintenance sub-timers. Preserve existing page decoding, cache hits and synchronous fallback. ARRAY/MAP/STRUCT, including offsets, null maps and nested children, keep the upstream reader implementation. Their children may have independent predicate/lazy ordinals, so this component adds no dependent-item preparation or cursor-equality assertion. Cover the nested STRUCT/MAP lazy-read crash and complex-column preparation boundary. ### Release note Connect top-level scalar data-page reads to byte-window read-ahead. ### Check List (For Author) - Test: Unit Test — 134 tests from 4 suites passed on the integrated apache#67579 tree with ./run-be-ut.sh -j100 --run (ASAN/PCH, no clean). Repository clang-format 16, header hygiene and git diff --check passed. No cluster or clang-tidy run. This intermediate component commit was not built separately. - Behavior changed: Yes — introduces opt-in scalar read-ahead while preserving complex-column behavior. - Does this need documentation: Yes — scope and synchronization are recorded in apache#67611 and the related PR descriptions.
### What problem does this PR solve? Issue Number: Part of apache#67611 Related PR: apache#67579, apache#67292 Problem Summary: Initialize eager and lazy top-level scalar windows together after segment pruning instead of rebuilding rowid plans every scanner batch. Later physical page reads advance each window. Select the reader per column: eligible scalars use the read-ahead wrapper; complex and extracted variant columns retain the original reader and segment prefetchers. Keep reverse-scan behavior and configure compressed-byte windows, coalescing limits and optional foreground block completion. Test mixed scalar/complex planning and legacy prefetch initialization with the new context enabled or absent. ### Release note Opt-in regular segment scans use page-driven read-ahead across scanner batches for top-level scalar columns. ### Check List (For Author) - Test: Unit Test — 134 tests from 4 suites passed on the integrated apache#67579 tree with ./run-be-ut.sh -j100 --run (ASAN/PCH, no clean). Repository clang-format 16, header hygiene and git diff --check passed. No cluster or clang-tidy run. This intermediate component commit was not built separately. - Behavior changed: Yes — introduces opt-in scalar scan initialization with a 4 MiB eager window and a 1 MiB lazy window; complex columns retain their existing read and prefetch path. - Does this need documentation: Yes — scope and synchronization are recorded in apache#67611 and the related PR descriptions.
### What problem does this PR solve? Issue Number: apache#67611 (tracking) Related PR: apache#67292, apache#67579, apache#67612 Problem Summary: Expose complete-block submission, tracked owned-buffer handoff, and low-priority spare-capacity admission together as one cache-writer component. Reuse existing epoch checks and asynchronous disk writes. Background hole filling can pass a completed block without another data copy while normal foreground cache writes keep priority. ### Release note Internal complete-block and zero-copy handoff for best-effort cache population. ### Check List (For Author) - Test: Unit Test — component coverage is included with this change. The integrated source snapshot d5c427f passed 198 ASAN tests from 11 suites via run-be-ut.sh -j100. This individual intermediate commit was not built separately; target-branch validation is recorded on the PR. Repository clang-format v16, build hygiene and diff checks passed on the integrated tree. No cluster or clang-tidy run. - Behavior changed: Yes — introduces the opt-in component; this synchronization preserves existing defaults and IO/writeback semantics. - Does this need documentation: Yes — component scope and current behavior are tracked in apache#67611 and the related PR descriptions.
### What problem does this PR solve?
Issue Number: None
Related PR: None
Problem Summary: Query read-ahead produces variable file ranges, while the existing asynchronous File Cache writer accepts complete fixed-size blocks. Add a synchronous ownership-transfer boundary that splits an already consumed range at cache-block boundaries, routes complete blocks and partial fragments to separate consumers, and handles the short physical EOF block as complete. The dispatcher reports generated and accepted fragments without retaining the query range buffer.
### Release note
None
### Check List (For Author)
- Test: Unit Test
- ./run-be-ut.sh -j100 --run '--filter=RangeWritebackDispatcherTest.*'
- Behavior changed: No
- Does this need documentation: No
### What problem does this PR solve? Issue Number: None Related PR: apache#67292 Problem Summary: Partial query ranges can cover unordered and overlapping fragments inside one File Cache block. Add a block-local planner that unions existing coverage, takes its complement to produce sorted holes, and applies the dedicated three-parameter coalescing policy without crossing the block boundary. The coalescing size limit controls combining holes; one mandatory hole may be larger and remains one remote read. ### Release note None ### Check List (For Author) - Test: Unit Test - ./run-be-ut.sh -j100 --run '--filter=HoleFillPlannerTest.*' - Behavior changed: No; this commit adds an internal hole-fill planner. - Does this need documentation: No
### What problem does this PR solve? Issue Number: Part of apache#67611 Related PR: apache#67292, apache#67579 Problem Summary: Partial cache blocks need bounded background completion without stalling query reads. Keep queued fragments mergeable under a configurable aggregation delay and a BE byte budget. One HoleFillDispatch thread owns admission-time-ordered deadline and writer-capacity checks, stops at the first future deadline, bypasses busy writers for other due tasks, and hands off at most the configured block-worker slots. Workers execute ready tasks with reusable remote-read tokens: one hole range is read inline and multiple ranges use the shared remote pool. Retain cache/inflight reuse, epoch checks, eviction, dynamic worker/pool/delay updates, and complete-block handoff. Trace fragment lifecycles and submission/queue timings with serialization outside the queue mutex. Cancel queued and undelivered work at shutdown and drain executing reads before destroying the remote pool. ### Release note Add opt-in background cache-block hole filling with queued-fragment aggregation, dedicated dispatch, bounded worker handoff and parallel hole reads. ### Check List (For Author) - Test: Unit Test - Component tests are included with the implementation; rebase and synchronization validation is recorded in the related PRs and tracking issue. - Repository clang-format 16, header hygiene and git diff --check passed before folding. - No cluster, external-object-store benchmark or clang-tidy run during synchronization. - Behavior changed: Yes, includes final component behavior and applicable diagnostic instrumentation; default enable switches remain off. - Does this need documentation: Yes, tools/read_io_trace/README.md and related PR/tracking descriptions.
### What problem does this PR solve? Issue Number: apache#67611 (tracking) Related PR: apache#67292 Problem Summary: Background partial-block writeback needs production defaults and a BE-owned lifetime bounded by the File Cache lifecycle. Add validated hole-fill configuration, create the manager after File Cache initialization, and stop it before File Cache teardown. Configure a 4 GiB BE-wide queued/active buffer budget and a 1.0 hole-read amplification limit. Use hole_fill_workers_per_be for block workers (default 32, range 1 through 128) and hole_fill_remote_read_threads_per_be for the shared multi-range remote-read pool (default 64, positive values). Both settings resize their pools at runtime without rebuilding the manager. Single-range reads execute on block workers outside the remote-read pool limit. Add mutable hole_fill_merge_delay_ms with a 2000 ms default and nonnegative validation. Positive values delay activation from the first admission timestamp; dynamic updates apply to already queued tasks without resetting that timestamp. ### Release note Support runtime resizing of BE-wide block workers and the shared multi-range remote-read pool. Configure minimum queued-fragment aggregation time through hole_fill_merge_delay_ms; its 2000 ms default keeps queued fragments mergeable before dispatch, and setting it to 0 disables deliberate waiting. Limit queued/active partial-block buffers to 4 GiB per BE and use a 1.0 background read-amplification limit. ### Check List (For Author) - Test: Unit Test - Existing PartialBlockWritebackOptionsTest coverage via run-be-ut.sh -j100 with ASAN/PCH; no new tests for the default-value update. - Behavior changed: Yes; configure background hole filling, resize its pools at runtime, and adjust queued partial-block aggregation delay. - Does this need documentation: Yes; configuration and execution contracts are tracked in apache#67611 and apache#67292.
### What problem does this PR solve? Issue Number: Part of apache#67611 Related PR: apache#67292, apache#67579 Problem Summary: Consumed read-ahead buffers can span complete and partial cache blocks. Split each range, submit complete blocks to the existing asynchronous cache writer, and enqueue partial fragments for background completion under the captured invalidation epoch. Preserve unified cache/inflight reuse and mixed outcomes. Carry the originating read identity into partial tasks and interval traces, and separate complete/partial foreground dispatch time in Profile counters. Read and persistence outcomes remain best effort. ### Release note None ### Check List (For Author) - Test: Unit Test - Component tests are included with the implementation; rebase and synchronization validation is recorded in the related PRs and tracking issue. - Repository clang-format 16, header hygiene and git diff --check passed before folding. - No cluster, external-object-store benchmark or clang-tidy run during synchronization. - Behavior changed: Yes, includes final component behavior and applicable diagnostic instrumentation; default enable switches remain off. - Does this need documentation: Yes, tools/read_io_trace/README.md and related PR/tracking descriptions.
### What problem does this PR solve? Issue Number: Part of apache#67611 Related PR: apache#67292, apache#67579 Problem Summary: Centralize query read-ahead construction so regular scans and exact-row callers share range planning, byte windows, cache probes, scheduler ownership and writeback setup. Merge per-read IO statistics into caller accounting and publish each consumed range once. Submit writeback only for consumed ranges that read remote bytes, preserving no-write policy and avoiding redundant hole filling for File Cache or inflight hits. Carry the read identity through the consumed-range callback so offline traces can attribute background work to its foreground source. Require both query read-ahead and asynchronous cache writes so disabling the writer preserves synchronous cache filling. Handle a switch changing during scan initialization through the original reader. Keep delayed hole-fill sources open with an aliasing shared_ptr that retains the cached wrapper; regression tests release both the foreground reader and writeback context before completing the queued fill. ### Release note None ### Check List (For Author) - Test: Unit Test - Component tests are included with the implementation; rebase and synchronization validation is recorded in the related PRs and tracking issue. - Repository clang-format 16, header hygiene and git diff --check passed before folding. - No cluster, external-object-store benchmark or clang-tidy run during synchronization. - Behavior changed: Yes, includes final component behavior and applicable diagnostic instrumentation; default enable switches remain off. - Does this need documentation: Yes, tools/read_io_trace/README.md and related PR/tracking descriptions.
### What problem does this PR solve? Issue Number: Part of apache#67611 Related PR: apache#67579, apache#67292 Problem Summary: Short-circuit point queries read row-store data or missing column-store values through exact row IDs. Create one request-scoped range-read context, initialize the scalar row-store or missing top-level scalar iterators against the shared read-ahead reader, and submit the required pages before decoding. Complex columns and extracted variant paths retain Segment's original iterator/reader resolution. Preserve row-cache behavior, result padding, request-scoped constants and synchronous fallback. Append read-ahead Profile statistics to point-query diagnostics; BE cumulative counters retain unsampled totals. Include exact-row helpers and tests in this component. TopN second-stage integration remains identical to the master base and is outside this PR series. Handle a dynamic switch closing after a point request creates its context: if create_for_query returns no read-ahead object, read row-store data synchronously through the already loaded segment. The deterministic row-store test closes either enable switch after segment resolution, verifies that no segment-loader call is made, and compares the result with the original reader. Rebase compatibility: reuse the segment returned by primary-key lookup in both the read-ahead and synchronous row-store paths, preserving master's segment and acquired-rowset lifetime. The pinned master reaches the RLE header from 905 translation units; five added read-stack translation units and the cached-reader test bring the measured total to 911. Rebaseline that reverse-reach table entry to 911 without changing layering rules or disabling any gate. ### Release note Use query range read-ahead for scalar point-query data pages when enable_query_read_ahead and enable_async_file_cache_write are enabled. ### Check List (For Author) - Test: Unit Test — pre-rebase integrated ASAN/PCH validation covered 141 tests from 8 suites through ./run-be-ut.sh --run -j100. Includes partial budget admission, original page offsets, cancellation, allocation rollback, executor rejection, consumed-range callbacks and row-store switch fallback. Individual intermediate commits are not built separately; target-branch validation is recorded on the PR. Clang-format 16, header hygiene and diff checks pass. No cluster or clang-tidy run. - Behavior changed: Yes — adds scalar point-query prefetch without changing complex-column decoding, scheduling limits or query results. - Does this need documentation: Yes — scope and synchronization are recorded in apache#67611 and the related PR descriptions.
|
run buildall |
TPC-H: Total hot run time: 28438 ms |
TPC-DS: Total hot run time: 150596 ms |
ClickBench: Total hot run time: 24.25 s |
BE UT Coverage ReportIncrement line coverage Increment coverage report
|
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
What problem does this PR solve?
Issue Number: Part of #67611
Related PR: #67579 (validation and follow-ups), #67612 (infrastructure split)
Problem Summary:
Doris data pages are commonly much smaller than a 1 MiB File Cache block. On a cache miss, the existing query path expands a page read to the block boundary. This behaves like a fixed 1 MiB read-ahead for continuous scans, but the size and shape cannot follow the actual scan. Sparse point-query data-page reads can therefore download a full block for a small page, while sequential scans still expose one remote page dependency at a time through
FileColumnIterator.This PR adds an opt-in cloud query path that prepares each eligible top-level scalar scan column's compressed data pages once after pruning, advances its window on physical data-page reads, merges nearby pages into bounded file ranges, and serves the original exact page slices to the existing PageIO and decoder. Only a range that PageIO actually consumes becomes eligible for File Cache writeback. Complete cache blocks use the existing asynchronous cache writer; partial blocks enter a bounded background pipeline that fills their holes and then hands a complete block to the same writer.
The implementation covers top-level scalar columns in regular segment scans and short-circuit point queries, including scalar row-store reads. ARRAY/MAP/STRUCT and their offsets, null maps and children retain the original readers and legacy segment prefetchers; variant paths remain on the original path. TopN/global delayed-materialization second-stage read-ahead is outside the current PRs; that path stays identical to master. The feature is disabled by default and requires both
enable_query_read_ahead=trueandenable_async_file_cache_write=true. Planning, admission, asynchronous read, checksum, decode, and best-effort writeback failures preserve the original query result path.Entry paths and component boundaries
flowchart TB SCAN["Regular SegmentIterator scan"] POINT["PointQueryExecutor<br/>row store or missing columns"] SCAN --> COLUMNS["After pruning: initialize scalar column windows once"] POINT --> LOOKUP["Collect exact row IDs and required scalar columns"] COLUMNS --> SEGMENT["SegmentReadAhead"] LOOKUP --> SEGMENT SCAN --> COMPLEX["Complex columns: original reader and prefetch"] POINT --> COMPLEX SEGMENT --> PLAN["FileRangePlanner"] PLAN --> SCHED["FileRangeReadScheduler"] SCHED --> POOL["Existing SegmentPrefetchThreadPool"] POOL --> READER["SegmentReadAheadFileReader"] READER --> PAGEIO["Existing PageIO and decoder"] READER --> WRITEBACK["Consumed-range writeback"]ColumnReadAhead/ColumnReadAheadPlanSegmentReadAheadFileRangePlannerFileRangeReadSchedulerSegmentReadAheadFileReaderRangeWritebackDispatcher/RangeCacheWritebackPartialBlockWritebackManagerRead-ahead window
Columns are classified by dependency: eager columns have no earlier filtering dependency; lazy columns depend on an earlier filter or expression result. After segment pruning, initialize all currently resolvable eager and lazy windows together. Build each column's candidate-page indexes once from the pruned selection. Later data-page reads advance the window using the already resolved physical page index, before Page Cache lookup. Small scanner batches no longer rebuild rowid plans for every column.
Each window selects eligible pages until their compressed bytes reach the configured size; its final page can cross that size. The second selected page triggers the next window, or the only page for a one-page window. First access and a jump beyond planned coverage start at the current page. Reverse scans retain predictions while reading an ascending batch and retire them when the next lower batch begins.
Scalar point reads keep exact-row preparation, grouping sorted row IDs by distinct pages. Complex columns keep the original dependent-child reading path. Page completion updates ownership/accounting; the page-read position drives scan-window extension. Initial planning remains on the scanner thread; no separate planning pool is introduced.
read_ahead_eager_window_bytesread_ahead_lazy_window_bytesflowchart TD Init["After pruning: select candidate pages once<br/>initialize eager and lazy windows together"] --> Read Read["Column reader resolves a physical data page"] --> Advance["Retire passed predictions<br/>include the current page"] Advance --> Outside{"At or beyond planned coverage?"} Outside -- Yes --> Start["Start a byte window at this page<br/>mark its second selected page as the trigger"] Outside -- No --> Trigger Start --> Trigger{"Current page reaches the trigger?"} Trigger -- Yes --> Append["Append the next byte window<br/>move the trigger into it"] Trigger -- No --> Apply Append --> Apply["Submit newly planned pages<br/>reuse existing buffered pages"] Apply --> PageIO["Existing Page Cache / PageIO / decoder"] PageIO --> ReadThe window is a planning unit, not a resident-memory limit; query and BE budgets bound retained range buffers.
ReadAheadColumnInitTimecovers initialization,ReadAheadPageAdvanceTimecovers page-driven maintenance, andReadAheadCurrentBatchPlanTimecovers the retained exact-row path. Window discard and extension remain sub-timers underReadAheadColumnPlanTime.Range planning and concurrent I/O
The range merge uses a left-to-right algorithm inspired by Velox. Here, “merge” means combining nearby requested page intervals into one physical object-store GET.
SegmentReadAheadsupplies sorted, disjoint, non-empty page intervals; one linear pass adds the next interval only when every configured limit remains satisfied.read_ahead_max_gap_bytesread_ahead_max_range_bytesread_ahead_max_read_amplification_ratioAfter the base ranges are formed,
FileRangePlannerexamines their boundary File Cache blocks.read_ahead_block_fill_min_coverage=1.0requires full requested-page coverage, so the default adds no foreground bytes to complete a partial block. Lowering this threshold retains the existing optional completion algorithm within the 2 MiB range limit.flowchart LR PAGES["Sorted unique data-page intervals"] --> MERGE["Linear three-limit merge"] MERGE --> BASE["Base ranges"] BASE --> COVER{"Boundary block coverage<br/>at least 50 percent?"} COVER -->|"Yes and final range at most 2 MiB"| COMPLETE["Extend to block boundary"] COVER -->|No| KEEP["Keep base range"] COMPLETE --> BATCH["One atomic submission batch"] KEEP --> BATCH BATCH -->|Accepted| WORKERS["Concurrent range reads"] BATCH -->|Rejected| FALLBACK["Original synchronous path"]FileRangeReadSchedulerwalks the planned ranges once under both query and BE budget locks, admitting each range that fits and continuing past skipped ranges so later smaller ranges can still proceed. Returned handles preserve the original range indices, with empty slots for budget skips; only admitted ranges receive buffers and tasks. It adds no range-count or concurrency quota. Accepted tasks run on the existing segment-prefetch thread pool, whose configured thread count controls physical read concurrency; the scheduler does not own or stop that shared pool. A byte reservation follows the query-owned buffer lifetime and is released with the last reference.Scheduled reads suppress direct cache writes. A ready range is indexed back to every exact page it contains, so PageIO still receives the original offset and size and keeps the existing checksum and decoder behavior.
sequenceDiagram participant Scan as Scanner participant Column as ColumnReadAhead participant Segment as SegmentReadAhead participant Scheduler as FileRangeReadScheduler participant PageIO Scan->>Column: initialize candidates and first windows after pruning Column->>Segment: eager and lazy initial plans Segment->>Scheduler: page-cache probe, merge, complete blocks, submit ranges loop Physical data-page reads Scan->>Column: resolved page index Column->>Segment: new and released pages when the window changes Segment->>Scheduler: submit newly planned ranges Scan->>PageIO: exact page offset and size PageIO->>Segment: read buffered page Segment-->>PageIO: ready slice or original-reader fallback endPoint queries create one request-scoped range-read context and plan either the row-store column or all missing column-store values before decoding; existing row-cache and result-padding behavior remains unchanged. The point-query component owns the shared exact-row page helpers and their tests.
Consumed-range writeback
A ready range that read remote bytes becomes eligible for writeback when PageIO successfully reads its first registered page, and it is published at most once. Pure File Cache/inflight hits skip writeback. A prefetched range whose pages are all passed without use is released without a cache write.
flowchart TD CONSUMED["Consumed ready range"] --> ORIGIN{"Range read remote bytes?"} ORIGIN -- No --> SKIP["Skip duplicate writeback"] ORIGIN -- Yes --> SPLIT["Split at 1 MiB File Cache boundaries"] SPLIT --> FULL{"Fragment covers the complete valid block?"} FULL -->|Yes| ASYNC["Existing AsyncCacheWriteManager"] FULL -->|No| PARTIAL["PartialBlockWritebackManager queue"] PARTIAL --> DISPATCH["HoleFillDispatch: ordered deadline and capacity checks"] DISPATCH --> ELIGIBLE{"Aggregation deadline elapsed<br/>and cache writer has capacity?"} ELIGIBLE -- No --> WAIT["Dispatcher waits on condition variable<br/>task remains queued and mergeable"] WAIT --> ELIGIBLE ELIGIBLE -- Yes --> READY["Bounded worker handoff"] READY --> WORKER["Block worker: recheck cache and plan block-local holes"] WORKER --> COUNT{"Number of merged hole ranges?"} COUNT -- Zero --> OWNED["Complete owned block buffer"] COUNT -- One --> INLINE["Read directly on the block worker"] COUNT -- Multiple --> REMOTE["HoleFillRemoteReadPool: one task per range"] REMOTE --> JOIN["Block worker joins all accepted reads"] INLINE --> RESULT{"All reads succeeded?"} JOIN --> RESULT RESULT -- Yes --> OWNED RESULT -- No --> DROP["Drop best-effort writeback"] OWNED --> ASYNC ASYNC --> CACHE["Existing File Cache write path"]Complete 1 MiB fragments, including a shorter physical EOF block, enter the existing asynchronous cache writer directly. Partial fragments are copied into a BE-level queue. Fragments for the same queued block merge under that task's fragment lock; an already active fill is deduplicated. A combined inflight-buffer and File Cache probe skips cached/downloading blocks before admission and once when a worker starts the task, outside the queue mutex. The task then executes its planned GETs and retains the final cache-writer checks. Its source pointer reads directly from the inner remote reader while retaining the cached wrapper as the shared owner, keeping the source open through delayed hole filling.
Queued partial blocks retain a mutable minimum aggregation interval,
hole_fill_merge_delay_ms=2000(milliseconds), to keep queued fragments mergeable for at least two seconds before dispatch. Timing starts at first admission; merging later fragments preserves the timestamp. The queue remains admission-time ordered, with stale replacements moving to the tail. OneHoleFillDispatchthread checks due entries and stops at the first future deadline. It can bypass a due task whose writer lacks capacity, then waits until the earliest deadline or capacity retry. Runtime delay updates wake this dispatcher; tail arrivals that cannot advance its wait leave the timer alone. Waiting releases the mutex and preserves fragment merging. Complete blocks still enter the asynchronous cache writer directly.The queue accounts one full cache-block buffer per queued or active entry and is bounded by
hole_fill_max_pending_bytes_per_be=4 GiB. When full, the oldest queued task is evicted. If every retained task is already active, new cache-only work is rejected. The query read result is unaffected in either case.Block workers, dynamically resized by
hole_fill_workers_per_be=32, consume ready tasks. The total of dispatched and executing tasks is bounded by that worker count, so excess entries stay in the mergeable queue. Dispatch moves existing list nodes into the handoff queue. Shrinking lets already-dispatched work drain before admitting more. Writer-capacity accounting includes the handoff, and final write submission still uses spare-capacity-only admission. Active-task metrics include both dispatched and executing work.Hole-fill algorithm
For one partial cache block,
HoleFillPlannerunions the covered fragments, takes their complement inside that block, and applies the same three-limit merge algorithm to the missing intervals. Hole ranges never cross a 1 MiB block boundary. A single merged range is read directly on the block worker, avoiding task submission and wakeup overhead. Multiple ranges are submitted concurrently to the BE-wideHoleFillRemoteReadPool, controlled by mutablehole_fill_remote_read_threads_per_be=64. This pool limit applies only to multi-range reads; single-range reads also run on the block workers.Each block worker creates and reuses one concurrent token for its lifetime. Before writeback or failure cleanup it joins all accepted GETs, including when a submission or read fails. Shutdown stops admission, joins the dispatcher and discards queued/undelivered work without its GETs, then joins executing block workers and releases their tokens before shutting down the remote-read pool. Block-worker and asynchronous cache-writer pools start with their configured worker counts; the remote-read pool retains at least one thread.
The hole-fill limits are tighter because crossing already covered bytes consumes background bandwidth without reducing the foreground query latency.
hole_fill_max_gap_byteshole_fill_max_range_byteshole_fill_max_read_amplification_ratioExample: all offsets below are KiB within one 1 MiB block.
[0, 256),[384, 416),[544, 1024)[256, 384), hole2[416, 544)[256, 384)and[416, 544): 256 KiB total, with no covered bytes reread.flowchart LR C1["covered 0 to 256 KiB"] --> H1["hole1 256 to 384 KiB"] H1 --> GAP["covered gap 384 to 416 KiB"] GAP --> H2["hole2 416 to 544 KiB"] H2 --> C2["covered 544 to 1024 KiB"] H1 --> GET1["GET1: 256 to 384 KiB"] H2 --> GET2["GET2: 416 to 544 KiB"] GET1 --> JOIN["Join both GETs"] GET2 --> JOIN JOIN --> BLOCK["complete block buffer"] BLOCK --> WRITER["existing async cache writer"]Failure and compatibility boundaries
enable_query_read_ahead=trueandenable_async_file_cache_write=true; runtime updates affect newly initialized reads. Disabling asynchronous cache writes retains the original query reader and cache-filling path.Configuration defaults
enable_query_read_aheadfalseenable_async_file_cache_write=true.read_ahead_max_bytes_per_query256 MiBread_ahead_max_bytes_per_be1 GiBread_ahead_eager_window_bytes4 MiBread_ahead_lazy_window_bytes1 MiBread_ahead_max_gap_bytes64 KiBread_ahead_max_range_bytes2 MiBread_ahead_max_read_amplification_ratio1.0read_ahead_block_fill_min_coverage1.0hole_fill_max_gap_bytes32 KiBhole_fill_max_range_bytes1 MiBhole_fill_max_read_amplification_ratio1.0hole_fill_max_pending_bytes_per_be4 GiBhole_fill_merge_delay_ms2000 ms0disables it. Merges keep the original timestamp.hole_fill_workers_per_be32hole_fill_remote_read_threads_per_be64Read IO diagnostics
enable_read_io_trace=falsedynamically enables actual S3 GET intervals/outcomes, range/task provenance, read-only cache/inflight coverage snapshots and typed timing events. Records are batched in memory and flushed by a dedicated writer to standalone JSONL files; they do not go tobe.INFOand have no cumulative event cap. Normal and fast shutdown drain submitted records.enable_read_io_traceread_io_trace_dirread_io_trace/subdirectory, unless explicitly setread_io_trace_flush_bytesread_io_trace_flush_interval_msThe offline analyzer reports interval union/extra transfers, within-source and cross-source overlap, submission stage totals/percentiles, queue-scan costs and GET latency.
doris_read_io_trace_record_time_nsexposes diagnostic overhead. Capture and interpretation guide. The full implementation also records consumed-range writeback, queued/active fragments and dispatcher scan timing. Profile separates complete/partial foreground submission even with tracing disabled.Commit structure
The branch is based on upstream master
33c460d7365and contains 19 commits: 18 components and one unity-build fix. Its first seven carry the shared infrastructure tracked in #67612. Shared diagnostics enter once as component 6; commit 7 scopes filesystem error-code imports for no-PCH builds. Hole-fill and consumed-range follow-ups are folded into components 15, 17 and 18, so reviewers see their final form.Performance benchmarks
Time is FE Profile Total; S3 bytes include background I/O through drain.
Hardware
ecs.g9i.xlargeecs.g9i.8xlargeTest settings
Baselineis a cold read with asynchronous cache writes and page read-ahead disabled.Enabledis a cold read with asynchronous cache writes and page read-ahead/hole filling enabled.Local File Cachereads from warmed disk File Cache with both optimizations disabled and the OS page cache cleared.enable_async_file_cache_writefalsetruefalseenable_query_read_aheadfalsetruefalseread_ahead_eager_window_bytes/read_ahead_lazy_window_bytesread_ahead_max_gap_bytes/read_ahead_max_range_bytesread_ahead_max_read_amplification_ratio/read_ahead_block_fill_min_coverageread_ahead_max_bytes_per_query/read_ahead_max_bytes_per_behole_fill_merge_delay_mshole_fill_max_pending_bytes_per_behole_fill_max_gap_bytes/hole_fill_max_range_byteshole_fill_max_read_amplification_ratiohole_fill_workers_per_be/hole_fill_remote_read_threads_per_beasync_file_cache_write_workers_per_disk/async_file_cache_write_max_pending_bytessegment_prefetch_thread_pool_thread_num_min/segment_prefetch_thread_pool_thread_num_maxfile_cache_each_block_sizedisable_storage_page_cache/storage_page_cache_limitfalse/ 20%enable_query_segment_file_cache_prefetch/enable_compaction_segment_file_cache_prefetchfalse/falseenable_read_io_tracefalseenable_sql_cache/enable_query_cachefalse/falseparallel_pipeline_task_numSummary
SSB Flat SF1000: per-query results
TPCH SF1000: per-query results
SSB SF1000: per-query results
Release note
Add an opt-in range read-ahead and partial File Cache block hole-fill pipeline for cloud query data pages. The feature is disabled by default.
Check List (For Author)
run-be-ut.sh -j100 --run(ASAN/PCH); the direct Release/PCH BE build passed withbuild.sh --be -j100.Check List (For Reviewer who merge this PR)