github-actions[bot] commented on code in PR #69716:
URL: https://github.com/apache/doris/pull/69716#discussion_r4396835123


##########
be/src/format_v2/delimited_text/delimited_text_reader.cpp:
##########
@@ -561,8 +562,14 @@ Status DelimitedTextReader::_open_file() {
     } else {
         auto reader_options = 
FileFactory::get_reader_options(_runtime_state->query_options(),
                                                               
*_file_description);
-        auto file_reader = DORIS_TRY(FileFactory::create_file_reader(
-                *_system_properties, *_file_description, reader_options, 
_profile));
+        // Include the prefix used to align non-first splits. Unknown-size 
first splits read to
+        // EOF; PrefetchBufferedReader bounds this range by the opened file's 
physical size.
+        const auto prefetch_end = _size < 0 ? 
std::numeric_limits<size_t>::max()
+                                            : cast_set<size_t>(_start_offset + 
_size);
+        auto file_reader = DORIS_TRY(io::DelegateReader::create_file_reader(
+                _profile, *_system_properties, *_file_description, 
reader_options,

Review Comment:
   [P2] Publish the prefetch counters before dropping this reader
   
   This call now registers `PrefetchBufferedReader` profile counters, but 
`DelimitedTextReader::close()` only closes/resets the line reader and drops the 
file reader. Neither those close/destructor paths nor `ProfileCollector` 
invokes `collect_profile_before_close()`. The callback that publishes 
`ReadTime`, `PreRequestIO` and `PreRequestBytes` is therefore never called, so 
completed S3 CSV/Text scans display zero prefetch I/O. Drain the background 
reads and collect the reader profile before releasing it, and assert these 
counters in the new S3 test; its current assertions check only the outer 
tracing statistics.



##########
be/src/format_v2/delimited_text/delimited_text_reader.cpp:
##########
@@ -561,8 +562,14 @@ Status DelimitedTextReader::_open_file() {
     } else {
         auto reader_options = 
FileFactory::get_reader_options(_runtime_state->query_options(),
                                                               
*_file_description);
-        auto file_reader = DORIS_TRY(FileFactory::create_file_reader(
-                *_system_properties, *_file_description, reader_options, 
_profile));
+        // Include the prefix used to align non-first splits. Unknown-size 
first splits read to
+        // EOF; PrefetchBufferedReader bounds this range by the opened file's 
physical size.
+        const auto prefetch_end = _size < 0 ? 
std::numeric_limits<size_t>::max()
+                                            : cast_set<size_t>(_start_offset + 
_size);
+        auto file_reader = DORIS_TRY(io::DelegateReader::create_file_reader(
+                _profile, *_system_properties, *_file_description, 
reader_options,
+                io::DelegateReader::AccessMode::SEQUENTIAL, _io_ctx,
+                io::PrefetchRange(_start_offset, prefetch_end)));

Review Comment:
   [P1] Keep scanner state alive until timed-out reads finish
   
   Sharing the `IOContext` does not own its raw `file_cache_stats` pointer. 
`PrefetchBuffer::close()` returns without joining when its wait times out, but 
`PrefetchBufferedReader::_close_internal()` still returns the underlying 
reader's successful close; `DelimitedTextReader::close()` can then discard the 
wrappers and the scanner can destroy its statistics. A pending 
`CachedRemoteFileReader` read subsequently runs its deferred `_update_stats()` 
through that freed pointer. For example, a cached 2 MiB object with 
`buffered_reader_read_timeout_ms=10` and a GET delayed 100 ms can outlive both 
the foreground-read timeout and the close timeout; only one buffer is in range. 
Ensure every pending task is drained before releasing scanner-owned pointees, 
or retain ownership and propagate a retryable close failure. This is separate 
from concurrent counter updates and occurs with one pending task.



##########
be/src/format_v2/delimited_text/delimited_text_reader.cpp:
##########
@@ -561,8 +562,14 @@ Status DelimitedTextReader::_open_file() {
     } else {
         auto reader_options = 
FileFactory::get_reader_options(_runtime_state->query_options(),
                                                               
*_file_description);
-        auto file_reader = DORIS_TRY(FileFactory::create_file_reader(
-                *_system_properties, *_file_description, reader_options, 
_profile));
+        // Include the prefix used to align non-first splits. Unknown-size 
first splits read to
+        // EOF; PrefetchBufferedReader bounds this range by the opened file's 
physical size.
+        const auto prefetch_end = _size < 0 ? 
std::numeric_limits<size_t>::max()
+                                            : cast_set<size_t>(_start_offset + 
_size);
+        auto file_reader = DORIS_TRY(io::DelegateReader::create_file_reader(
+                _profile, *_system_properties, *_file_description, 
reader_options,
+                io::DelegateReader::AccessMode::SEQUENTIAL, _io_ctx,

Review Comment:
   [P1] Isolate the cache statistics used by prefetch workers
   
   For cached S3 CSV/Text, this call now queues four 4 MiB reads by default, 
all sharing `_io_ctx->file_cache_stats`. 
`CachedRemoteFileReader::_update_stats()` performs unsynchronized plain `+=` 
writes to `bytes_read_from_remote/local`, while 
`FileScannerV2::_collect_realtime_counter_deltas()` reads those fields and 
`DORIS_CHECK`s that they never decrease. A worker can load an old total, 
another worker can publish a larger total that the scanner samples, and the 
first worker can then store its stale smaller sum; the next scanner sample 
aborts BE. Previously this v2 path read synchronously. Use worker-local 
statistics merged on the scanner thread, or synchronize both updates and 
snapshots. The added test disables file cache and uses one worker, so it misses 
this path.



##########
be/src/format_v2/delimited_text/delimited_text_reader.cpp:
##########
@@ -561,8 +562,14 @@ Status DelimitedTextReader::_open_file() {
     } else {
         auto reader_options = 
FileFactory::get_reader_options(_runtime_state->query_options(),
                                                               
*_file_description);
-        auto file_reader = DORIS_TRY(FileFactory::create_file_reader(
-                *_system_properties, *_file_description, reader_options, 
_profile));
+        // Include the prefix used to align non-first splits. Unknown-size 
first splits read to
+        // EOF; PrefetchBufferedReader bounds this range by the opened file's 
physical size.
+        const auto prefetch_end = _size < 0 ? 
std::numeric_limits<size_t>::max()
+                                            : cast_set<size_t>(_start_offset + 
_size);
+        auto file_reader = DORIS_TRY(io::DelegateReader::create_file_reader(

Review Comment:
   [P1] Handle accepted buffer sizes before selecting prefetch
   
   This also moves v2 CSV/Text onto a buffer-ring assumption that the previous 
raw-reader path did not require. `remote_storage_read_buffer_mb` accepts an 
integer such as `6` without validation. `PrefetchBufferedReader` then creates 
`floor(6/4) = 1` buffers but uses 6 MiB as its ring modulus. On an 8 MiB S3 
CSV/Text scan, offset 4 MiB computes `get_buffer_pos() = (4 % 6) / 4 = 1` and 
indexes the nonexistent `_pre_buffers[1]`; a non-first split can hit it during 
initialization. Normalize the ring geometry or validate the setting 
consistently before enabling this path, and cover a non-multiple-of-four 
setting with a scan crossing 4 MiB.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to