/src/rocksdb/table/block_based/block_prefetcher.cc
Line | Count | Source |
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 | | #include "table/block_based/block_prefetcher.h" |
10 | | |
11 | | #include "rocksdb/file_system.h" |
12 | | #include "table/block_based/block_based_table_reader.h" |
13 | | |
14 | | namespace ROCKSDB_NAMESPACE { |
15 | | void BlockPrefetcher::PrefetchIfNeeded( |
16 | | const BlockBasedTable::Rep* rep, const BlockHandle& handle, |
17 | | const size_t readahead_size, bool is_for_compaction, |
18 | | const bool no_sequential_checking, const ReadOptions& read_options, |
19 | | const std::function<void(bool, uint64_t&, uint64_t&)>& readaheadsize_cb, |
20 | 49.0k | bool is_async_io_prefetch) { |
21 | 49.0k | if (read_options.read_tier == ReadTier::kBlockCacheTier) { |
22 | | // Disable prefetching when IO disallowed. (Note that we haven't allocated |
23 | | // any buffers yet despite the various tracked settings.) |
24 | 0 | return; |
25 | 0 | } |
26 | | |
27 | 49.0k | ReadaheadParams readahead_params; |
28 | 49.0k | readahead_params.initial_readahead_size = readahead_size; |
29 | 49.0k | readahead_params.max_readahead_size = readahead_size; |
30 | 49.0k | readahead_params.num_buffers = is_async_io_prefetch ? 2 : 1; |
31 | | |
32 | 49.0k | const size_t len = BlockBasedTable::BlockSizeWithTrailer(handle); |
33 | 49.0k | const size_t offset = handle.offset(); |
34 | 49.0k | if (is_for_compaction) { |
35 | 20.4k | if (!rep->file->use_direct_io() && compaction_readahead_size_ > 0) { |
36 | | // If FS supports prefetching (readahead_limit_ will be non zero in that |
37 | | // case) and current block exists in prefetch buffer then return. |
38 | 20.4k | if (offset + len <= readahead_limit_) { |
39 | 0 | return; |
40 | 0 | } |
41 | 20.4k | IOOptions opts; |
42 | 20.4k | IODebugContext dbg; |
43 | 20.4k | Status s = rep->file->PrepareIOOptions(read_options, opts, &dbg); |
44 | 20.4k | if (!s.ok()) { |
45 | 0 | return; |
46 | 0 | } |
47 | 20.4k | if (rep->fs_prefetch_support) { |
48 | 20.4k | s = rep->file->Prefetch(opts, offset, len + compaction_readahead_size_); |
49 | 20.4k | if (s.ok()) { |
50 | 20.4k | readahead_limit_ = offset + len + compaction_readahead_size_; |
51 | 20.4k | return; |
52 | 20.4k | } else if (!s.IsNotSupported()) { |
53 | 0 | return; |
54 | 0 | } |
55 | | // If FS prefetch returned NotSupported despite feature bit being set, |
56 | | // fall through to use internal prefetch buffer. |
57 | 20.4k | } |
58 | 20.4k | } |
59 | | // If FS prefetch is not supported, fall back to use internal prefetch |
60 | | // buffer. |
61 | | // |
62 | | // num_file_reads is used by FilePrefetchBuffer only when |
63 | | // implicit_auto_readahead is set. |
64 | 0 | readahead_params.initial_readahead_size = compaction_readahead_size_; |
65 | 0 | readahead_params.max_readahead_size = compaction_readahead_size_; |
66 | 0 | rep->CreateFilePrefetchBufferIfNotExists( |
67 | 0 | readahead_params, &prefetch_buffer_, |
68 | 0 | /*readaheadsize_cb=*/nullptr, |
69 | 0 | /*usage=*/FilePrefetchBufferUsage::kCompactionPrefetch); |
70 | 0 | return; |
71 | 20.4k | } |
72 | | |
73 | | // Explicit user requested readahead. |
74 | 28.6k | if (readahead_size > 0) { |
75 | 0 | rep->CreateFilePrefetchBufferIfNotExists( |
76 | 0 | readahead_params, &prefetch_buffer_, readaheadsize_cb, |
77 | 0 | /*usage=*/FilePrefetchBufferUsage::kUserScanPrefetch); |
78 | 0 | return; |
79 | 0 | } |
80 | | |
81 | | // Implicit readahead. |
82 | | |
83 | | // If max_auto_readahead_size is set to be 0 by user, no data will be |
84 | | // prefetched. |
85 | 28.6k | size_t max_auto_readahead_size = rep->table_options.max_auto_readahead_size; |
86 | 28.6k | if (max_auto_readahead_size == 0 || initial_auto_readahead_size_ == 0) { |
87 | 0 | return; |
88 | 0 | } |
89 | | |
90 | 28.6k | if (initial_auto_readahead_size_ > max_auto_readahead_size) { |
91 | 0 | initial_auto_readahead_size_ = max_auto_readahead_size; |
92 | 0 | } |
93 | | |
94 | 28.6k | readahead_params.initial_readahead_size = initial_auto_readahead_size_; |
95 | 28.6k | readahead_params.max_readahead_size = max_auto_readahead_size; |
96 | 28.6k | readahead_params.implicit_auto_readahead = true; |
97 | 28.6k | readahead_params.num_file_reads_for_auto_readahead = |
98 | 28.6k | rep->table_options.num_file_reads_for_auto_readahead; |
99 | | |
100 | | // In case of no_sequential_checking, it will skip the num_file_reads_ and |
101 | | // will always creates the FilePrefetchBuffer. |
102 | 28.6k | if (no_sequential_checking) { |
103 | 0 | rep->CreateFilePrefetchBufferIfNotExists( |
104 | 0 | readahead_params, &prefetch_buffer_, readaheadsize_cb, |
105 | 0 | /*usage=*/FilePrefetchBufferUsage::kUserScanPrefetch); |
106 | 0 | return; |
107 | 0 | } |
108 | | |
109 | | // If FS supports prefetching (readahead_limit_ will be non zero in that case) |
110 | | // and current block exists in prefetch buffer then return. |
111 | 28.6k | if (offset + len <= readahead_limit_) { |
112 | 1.77k | UpdateReadPattern(offset, len); |
113 | 1.77k | return; |
114 | 1.77k | } |
115 | | |
116 | 26.8k | if (!IsBlockSequential(offset)) { |
117 | 1.12k | UpdateReadPattern(offset, len); |
118 | 1.12k | ResetValues(rep->table_options.initial_auto_readahead_size); |
119 | 1.12k | return; |
120 | 1.12k | } |
121 | 25.7k | UpdateReadPattern(offset, len); |
122 | | |
123 | | // Implicit auto readahead, which will be enabled if the number of reads |
124 | | // reached `table_options.num_file_reads_for_auto_readahead` (default: 2) and |
125 | | // scans are sequential. |
126 | 25.7k | num_file_reads_++; |
127 | 25.7k | if (num_file_reads_ <= rep->table_options.num_file_reads_for_auto_readahead) { |
128 | 25.0k | return; |
129 | 25.0k | } |
130 | | |
131 | 659 | readahead_params.num_file_reads = num_file_reads_; |
132 | 659 | if (rep->file->use_direct_io()) { |
133 | 0 | rep->CreateFilePrefetchBufferIfNotExists( |
134 | 0 | readahead_params, &prefetch_buffer_, readaheadsize_cb, |
135 | 0 | /*usage=*/FilePrefetchBufferUsage::kUserScanPrefetch); |
136 | 0 | return; |
137 | 0 | } |
138 | | |
139 | 659 | if (readahead_size_ > max_auto_readahead_size) { |
140 | 0 | readahead_size_ = max_auto_readahead_size; |
141 | 0 | } |
142 | | |
143 | | // If prefetch is not supported, fall back to use internal prefetch buffer. |
144 | 659 | IOOptions opts; |
145 | 659 | Status s = rep->file->PrepareIOOptions(read_options, opts); |
146 | 659 | if (!s.ok()) { |
147 | 0 | return; |
148 | 0 | } |
149 | | |
150 | 688 | if (rep->fs_prefetch_support) { |
151 | 688 | s = rep->file->Prefetch( |
152 | 688 | opts, handle.offset(), |
153 | 688 | BlockBasedTable::BlockSizeWithTrailer(handle) + readahead_size_); |
154 | 688 | if (s.ok()) { |
155 | 688 | readahead_limit_ = offset + len + readahead_size_; |
156 | | // Keep exponentially increasing readahead size until |
157 | | // max_auto_readahead_size. |
158 | 688 | readahead_size_ = std::min(max_auto_readahead_size, readahead_size_ * 2); |
159 | 688 | return; |
160 | 688 | } |
161 | 688 | } |
162 | | // If FS prefetch is not supported or returned NotSupported, fall back to use |
163 | | // internal prefetch buffer. |
164 | 18.4E | rep->CreateFilePrefetchBufferIfNotExists( |
165 | 18.4E | readahead_params, &prefetch_buffer_, readaheadsize_cb, |
166 | 18.4E | /*usage=*/FilePrefetchBufferUsage::kUserScanPrefetch); |
167 | 18.4E | } |
168 | | } // namespace ROCKSDB_NAMESPACE |