1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. 2 // This source code is licensed under both the GPLv2 (found in the 3 // COPYING file in the root directory) and Apache 2.0 License 4 // (found in the LICENSE.Apache file in the root directory). 5 // 6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved. 7 // Use of this source code is governed by a BSD-style license that can be 8 // found in the LICENSE file. See the AUTHORS file for names of contributors. 9 10 #pragma once 11 #include <atomic> 12 #include <sstream> 13 #include <string> 14 #include "port/port.h" 15 #include "rocksdb/env.h" 16 #include "rocksdb/file_system.h" 17 #include "rocksdb/listener.h" 18 #include "rocksdb/rate_limiter.h" 19 #include "util/aligned_buffer.h" 20 21 namespace ROCKSDB_NAMESPACE { 22 class Statistics; 23 class HistogramImpl; 24 25 using AlignedBuf = std::unique_ptr<const char[]>; 26 27 // RandomAccessFileReader is a wrapper on top of Env::RnadomAccessFile. It is 28 // responsible for: 29 // - Handling Buffered and Direct reads appropriately. 30 // - Rate limiting compaction reads. 31 // - Notifying any interested listeners on the completion of a read. 32 // - Updating IO stats. 33 class RandomAccessFileReader { 34 private: 35 #ifndef ROCKSDB_LITE NotifyOnFileReadFinish(uint64_t offset,size_t length,const FileOperationInfo::TimePoint & start_ts,const FileOperationInfo::TimePoint & finish_ts,const Status & status)36 void NotifyOnFileReadFinish(uint64_t offset, size_t length, 37 const FileOperationInfo::TimePoint& start_ts, 38 const FileOperationInfo::TimePoint& finish_ts, 39 const Status& status) const { 40 FileOperationInfo info(file_name_, start_ts, finish_ts); 41 info.offset = offset; 42 info.length = length; 43 info.status = status; 44 45 for (auto& listener : listeners_) { 46 listener->OnFileReadFinish(info); 47 } 48 } 49 #endif // ROCKSDB_LITE 50 ShouldNotifyListeners()51 bool ShouldNotifyListeners() const { return !listeners_.empty(); } 52 53 std::unique_ptr<FSRandomAccessFile> file_; 54 std::string file_name_; 55 Env* env_; 56 Statistics* stats_; 57 uint32_t hist_type_; 58 HistogramImpl* file_read_hist_; 59 RateLimiter* rate_limiter_; 60 std::vector<std::shared_ptr<EventListener>> listeners_; 61 62 public: 63 explicit RandomAccessFileReader( 64 std::unique_ptr<FSRandomAccessFile>&& raf, const std::string& _file_name, 65 Env* env = nullptr, Statistics* stats = nullptr, uint32_t hist_type = 0, 66 HistogramImpl* file_read_hist = nullptr, 67 RateLimiter* rate_limiter = nullptr, 68 const std::vector<std::shared_ptr<EventListener>>& listeners = {}) file_(std::move (raf))69 : file_(std::move(raf)), 70 file_name_(std::move(_file_name)), 71 env_(env), 72 stats_(stats), 73 hist_type_(hist_type), 74 file_read_hist_(file_read_hist), 75 rate_limiter_(rate_limiter), 76 listeners_() { 77 #ifndef ROCKSDB_LITE 78 std::for_each(listeners.begin(), listeners.end(), 79 [this](const std::shared_ptr<EventListener>& e) { 80 if (e->ShouldBeNotifiedOnFileIO()) { 81 listeners_.emplace_back(e); 82 } 83 }); 84 #else // !ROCKSDB_LITE 85 (void)listeners; 86 #endif 87 } 88 RandomAccessFileReader(RandomAccessFileReader && o)89 RandomAccessFileReader(RandomAccessFileReader&& o) ROCKSDB_NOEXCEPT { 90 *this = std::move(o); 91 } 92 93 RandomAccessFileReader& operator=(RandomAccessFileReader&& o) 94 ROCKSDB_NOEXCEPT { 95 file_ = std::move(o.file_); 96 env_ = std::move(o.env_); 97 stats_ = std::move(o.stats_); 98 hist_type_ = std::move(o.hist_type_); 99 file_read_hist_ = std::move(o.file_read_hist_); 100 rate_limiter_ = std::move(o.rate_limiter_); 101 return *this; 102 } 103 104 RandomAccessFileReader(const RandomAccessFileReader&) = delete; 105 RandomAccessFileReader& operator=(const RandomAccessFileReader&) = delete; 106 107 // In non-direct IO mode, 108 // 1. if using mmap, result is stored in a buffer other than scratch; 109 // 2. if not using mmap, result is stored in the buffer starting from scratch. 110 // 111 // In direct IO mode, an aligned buffer is allocated internally. 112 // 1. If aligned_buf is null, then results are copied to the buffer 113 // starting from scratch; 114 // 2. Otherwise, scratch is not used and can be null, the aligned_buf owns 115 // the internally allocated buffer on return, and the result refers to a 116 // region in aligned_buf. 117 Status Read(uint64_t offset, size_t n, Slice* result, char* scratch, 118 AlignedBuf* aligned_buf, bool for_compaction = false) const; 119 120 // REQUIRES: 121 // num_reqs > 0, reqs do not overlap, and offsets in reqs are increasing. 122 // In non-direct IO mode, aligned_buf should be null; 123 // In direct IO mode, aligned_buf stores the aligned buffer allocated inside 124 // MultiRead, the result Slices in reqs refer to aligned_buf. 125 Status MultiRead(FSReadRequest* reqs, size_t num_reqs, 126 AlignedBuf* aligned_buf) const; 127 Prefetch(uint64_t offset,size_t n)128 Status Prefetch(uint64_t offset, size_t n) const { 129 return file_->Prefetch(offset, n, IOOptions(), nullptr); 130 } 131 file()132 FSRandomAccessFile* file() { return file_.get(); } 133 file_name()134 std::string file_name() const { return file_name_; } 135 use_direct_io()136 bool use_direct_io() const { return file_->use_direct_io(); } 137 }; 138 } // namespace ROCKSDB_NAMESPACE 139