|
10 | 10 | #include "file/random_access_file_reader.h"
|
11 | 11 |
|
12 | 12 | #include <algorithm>
|
| 13 | +#include <cstddef> |
13 | 14 | #include <mutex>
|
| 15 | +#include <utility> |
14 | 16 |
|
15 | 17 | #include "file/file_util.h"
|
16 | 18 | #include "monitoring/histogram.h"
|
@@ -599,4 +601,103 @@ void RandomAccessFileReader::ReadAsyncCallback(const FSReadRequest& req,
|
599 | 601 | RecordIOStats(stats_, file_temperature_, is_last_level_, req.result.size());
|
600 | 602 | delete read_async_info;
|
601 | 603 | }
|
| 604 | + |
| 605 | +// RocksDB-Cloud contribution begin |
| 606 | + |
| 607 | +// Callback data for non-direct IO version of MultiReadAsync. |
| 608 | +struct MultiReadAsyncCbInfo { |
| 609 | + MultiReadAsyncCbInfo( |
| 610 | + std::function<void(const FSReadRequest*, size_t, void*)> cb, void* cb_arg, |
| 611 | + uint64_t start_time) |
| 612 | + : cb_(cb), cb_arg_(cb_arg), start_time_(start_time) {} |
| 613 | + |
| 614 | + std::function<void(const FSReadRequest*, size_t, void*)> cb_; |
| 615 | + void* cb_arg_; |
| 616 | + uint64_t start_time_; |
| 617 | + FileOperationInfo::StartTimePoint fs_start_ts_; |
| 618 | +}; |
| 619 | + |
| 620 | +IOStatus RandomAccessFileReader::MultiReadAsync( |
| 621 | + FSReadRequest* reqs, size_t num_reqs, const IOOptions& opts, |
| 622 | + std::function<void(const FSReadRequest*, size_t, void*)> cb, void* cb_arg, |
| 623 | + void** io_handles, size_t* num_io_handles, IOHandleDeleter* del_fns, |
| 624 | + AlignedBuf* /* aligned_buf */) { |
| 625 | + IOStatus s; |
| 626 | + uint64_t elapsed = 0; |
| 627 | + |
| 628 | + if (use_direct_io()) { |
| 629 | + return IOStatus::InvalidArgument( |
| 630 | + "DirectIO support not implemented for MultiReadAsync"); |
| 631 | + } |
| 632 | + |
| 633 | + // Create a callback and populate info. |
| 634 | + auto read_async_callback = |
| 635 | + std::bind_front(&RandomAccessFileReader::MultiReadAsyncCallback, this); |
| 636 | + |
| 637 | + auto cb_info = |
| 638 | + new MultiReadAsyncCbInfo(std::move(cb), cb_arg, clock_->NowMicros()); |
| 639 | + if (ShouldNotifyListeners()) { |
| 640 | + cb_info->fs_start_ts_ = FileOperationInfo::StartNow(); |
| 641 | + } |
| 642 | + |
| 643 | + StopWatch sw(clock_, nullptr /*stats*/, 0 /*hist_type*/, &elapsed, |
| 644 | + true /*overwrite*/, true /*delay_enabled*/); |
| 645 | + s = file_->MultiReadAsync(reqs, num_reqs, opts, read_async_callback, cb_info, |
| 646 | + io_handles, num_io_handles, del_fns, nullptr); |
| 647 | + |
| 648 | + RecordTick(stats_, READ_ASYNC_MICROS, elapsed); |
| 649 | + |
| 650 | +// Suppress false positive clang analyzer warnings. |
| 651 | +// Memory is not released if file_->ReadAsync returns !s.ok(), because |
| 652 | +// ReadAsyncCallback is never called in that case. If ReadAsyncCallback is |
| 653 | +// called then ReadAsync should always return IOStatus::OK(). |
| 654 | +#ifndef __clang_analyzer__ |
| 655 | + if (!s.ok()) { |
| 656 | + delete cb_info; |
| 657 | + } |
| 658 | +#endif // __clang_analyzer__ |
| 659 | + |
| 660 | + return s; |
| 661 | +} |
| 662 | + |
| 663 | +void RandomAccessFileReader::MultiReadAsyncCallback(const FSReadRequest* reqs, |
| 664 | + size_t n_reqs, |
| 665 | + void* cb_arg) { |
| 666 | + auto cb_info = static_cast<MultiReadAsyncCbInfo*>(cb_arg); |
| 667 | + assert(cb_info); |
| 668 | + assert(cb_info->cb_); |
| 669 | + |
| 670 | + cb_info->cb_(reqs, n_reqs, cb_info->cb_arg_); |
| 671 | + |
| 672 | + // Update stats and notify listeners. |
| 673 | + if (stats_ != nullptr && file_read_hist_ != nullptr) { |
| 674 | + // elapsed doesn't take into account delay and overwrite as StopWatch does |
| 675 | + // in Read. |
| 676 | + uint64_t elapsed = clock_->NowMicros() - cb_info->start_time_; |
| 677 | + file_read_hist_->Add(elapsed); |
| 678 | + } |
| 679 | + |
| 680 | + for (size_t idx = 0; idx < n_reqs; idx++) { |
| 681 | + auto& req = reqs[idx]; |
| 682 | + if (req.status.ok()) { |
| 683 | + RecordInHistogram(stats_, ASYNC_READ_BYTES, req.result.size()); |
| 684 | + } else if (!req.status.IsAborted()) { |
| 685 | + RecordTick(stats_, ASYNC_READ_ERROR_COUNT, 1); |
| 686 | + } |
| 687 | + if (ShouldNotifyListeners()) { |
| 688 | + auto finish_ts = FileOperationInfo::FinishNow(); |
| 689 | + NotifyOnFileReadFinish(req.offset, req.result.size(), |
| 690 | + cb_info->fs_start_ts_, finish_ts, req.status); |
| 691 | + } |
| 692 | + if (!req.status.ok()) { |
| 693 | + NotifyOnIOError(req.status, FileOperationType::kRead, file_name(), |
| 694 | + req.result.size(), req.offset); |
| 695 | + } |
| 696 | + RecordIOStats(stats_, file_temperature_, is_last_level_, req.result.size()); |
| 697 | + } |
| 698 | + delete cb_info; |
| 699 | +} |
| 700 | + |
| 701 | +// RocksDB-Cloud contribution end |
| 702 | + |
602 | 703 | } // namespace ROCKSDB_NAMESPACE
|
0 commit comments