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