/Users/deen/code/yugabyte-db/src/yb/rocksdb/db/compaction_picker.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under the BSD-style license found in the |
3 | | // LICENSE file in the root directory of this source tree. An additional grant |
4 | | // of patent rights can be found in the PATENTS file in the same directory. |
5 | | // |
6 | | // The following only applies to changes made to this file as part of YugaByte development. |
7 | | // |
8 | | // Portions Copyright (c) YugaByte, Inc. |
9 | | // |
10 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
11 | | // in compliance with the License. You may obtain a copy of the License at |
12 | | // |
13 | | // http://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
16 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
17 | | // or implied. See the License for the specific language governing permissions and limitations |
18 | | // under the License. |
19 | | // |
20 | | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
21 | | // Use of this source code is governed by a BSD-style license that can be |
22 | | // found in the LICENSE file. See the AUTHORS file for names of contributors. |
23 | | |
24 | | #ifndef YB_ROCKSDB_DB_COMPACTION_PICKER_H |
25 | | #define YB_ROCKSDB_DB_COMPACTION_PICKER_H |
26 | | |
27 | | #pragma once |
28 | | |
29 | | #include <memory> |
30 | | #include <set> |
31 | | #include <string> |
32 | | #include <unordered_set> |
33 | | #include <vector> |
34 | | |
35 | | #include "yb/rocksdb/db/compaction.h" |
36 | | #include "yb/rocksdb/env.h" |
37 | | #include "yb/rocksdb/options.h" |
38 | | #include "yb/rocksdb/status.h" |
39 | | #include "yb/rocksdb/util/mutable_cf_options.h" |
40 | | |
41 | | |
42 | | namespace rocksdb { |
43 | | |
44 | | class LogBuffer; |
45 | | class Compaction; |
46 | | class VersionStorageInfo; |
47 | | struct CompactionInputFiles; |
48 | | |
49 | | class CompactionPicker { |
50 | | public: |
51 | | CompactionPicker(const ImmutableCFOptions& ioptions, |
52 | | const InternalKeyComparator* icmp); |
53 | | virtual ~CompactionPicker(); |
54 | | |
55 | | // Pick level and inputs for a new compaction. |
56 | | // Returns nullptr if there is no compaction to be done. |
57 | | // Otherwise returns a pointer to a heap-allocated object that |
58 | | // describes the compaction. Caller should delete the result. |
59 | | virtual std::unique_ptr<Compaction> PickCompaction( |
60 | | const std::string& cf_name, |
61 | | const MutableCFOptions& mutable_cf_options, |
62 | | VersionStorageInfo* vstorage, |
63 | | LogBuffer* log_buffer) = 0; |
64 | | |
65 | | // Return a compaction object for compacting the range [begin,end] in |
66 | | // the specified level. Returns nullptr if there is nothing in that |
67 | | // level that overlaps the specified range. Caller should delete |
68 | | // the result. |
69 | | // |
70 | | // The returned Compaction might not include the whole requested range. |
71 | | // In that case, compaction_end will be set to the next key that needs |
72 | | // compacting. In case the compaction will compact the whole range, |
73 | | // compaction_end will be set to nullptr. |
74 | | // Client is responsible for compaction_end storage -- when called, |
75 | | // *compaction_end should point to valid InternalKey! |
76 | | virtual std::unique_ptr<Compaction> CompactRange( |
77 | | const std::string& cf_name, const MutableCFOptions& mutable_cf_options, |
78 | | VersionStorageInfo* vstorage, int input_level, int output_level, |
79 | | uint32_t output_path_id, const InternalKey* begin, const InternalKey* end, |
80 | | InternalKey** compaction_end, bool* manual_conflict); |
81 | | |
82 | | // The maximum allowed output level. Default value is NumberLevels() - 1. |
83 | 27 | virtual int MaxOutputLevel() const { |
84 | 27 | return NumberLevels() - 1; |
85 | 27 | } |
86 | | |
87 | | virtual bool NeedsCompaction(const VersionStorageInfo* vstorage) const = 0; |
88 | | |
89 | | // Sanitize the input set of compaction input files. |
90 | | // When the input parameters do not describe a valid compaction, the |
91 | | // function will try to fix the input_files by adding necessary |
92 | | // files. If it's not possible to conver an invalid input_files |
93 | | // into a valid one by adding more files, the function will return a |
94 | | // non-ok status with specific reason. |
95 | | #ifndef ROCKSDB_LITE |
96 | | Status SanitizeCompactionInputFiles( |
97 | | std::unordered_set<uint64_t>* input_files, |
98 | | const ColumnFamilyMetaData& cf_meta, |
99 | | const int output_level) const; |
100 | | #endif // ROCKSDB_LITE |
101 | | |
102 | | // Free up the files that participated in a compaction |
103 | | // |
104 | | // Requirement: DB mutex held |
105 | | void ReleaseCompactionFiles(Compaction* c, Status status); |
106 | | |
107 | | // Returns true if any one of the specified files are being compacted |
108 | | bool FilesInCompaction(const std::vector<FileMetaData*>& files); |
109 | | |
110 | | // Takes a list of CompactionInputFiles and returns a (manual) Compaction |
111 | | // object. |
112 | | std::unique_ptr<Compaction> FormCompaction( |
113 | | const CompactionOptions& compact_options, |
114 | | const std::vector<CompactionInputFiles>& input_files, int output_level, |
115 | | VersionStorageInfo* vstorage, const MutableCFOptions& mutable_cf_options, |
116 | | uint32_t output_path_id) const; |
117 | | |
118 | | // Converts a set of compaction input file numbers into |
119 | | // a list of CompactionInputFiles. |
120 | | Status GetCompactionInputsFromFileNumbers( |
121 | | std::vector<CompactionInputFiles>* input_files, |
122 | | std::unordered_set<uint64_t>* input_set, |
123 | | const VersionStorageInfo* vstorage, |
124 | | const CompactionOptions& compact_options) const; |
125 | | |
126 | | // Used in universal compaction when the enabled_trivial_move |
127 | | // option is set. Checks whether there are any overlapping files |
128 | | // in the input. Returns true if the input files are non |
129 | | // overlapping. |
130 | | bool IsInputNonOverlapping(Compaction* c); |
131 | | |
132 | | // Is there currently a compaction involving level 0 taking place |
133 | 1.42k | bool IsLevel0CompactionInProgress() const { |
134 | 1.42k | return !level0_compactions_in_progress_.empty(); |
135 | 1.42k | } |
136 | | |
137 | | protected: |
138 | 92.8k | int NumberLevels() const { return ioptions_.num_levels; } |
139 | | |
140 | | // Stores the minimal range that covers all entries in inputs in |
141 | | // *smallest, *largest. |
142 | | // REQUIRES: inputs is not empty |
143 | | void GetRange(const CompactionInputFiles& inputs, |
144 | | InternalKey* smallest, |
145 | | InternalKey* largest); |
146 | | |
147 | | // Stores the minimal range that covers all entries in inputs1 and inputs2 |
148 | | // in *smallest, *largest. |
149 | | // REQUIRES: inputs is not empty |
150 | | void GetRange(const CompactionInputFiles& inputs1, |
151 | | const CompactionInputFiles& inputs2, |
152 | | InternalKey* smallest, |
153 | | InternalKey* largest); |
154 | | |
155 | | // Add more files to the inputs on "level" to make sure that |
156 | | // no newer version of a key is compacted to "level+1" while leaving an older |
157 | | // version in a "level". Otherwise, any Get() will search "level" first, |
158 | | // and will likely return an old/stale value for the key, since it always |
159 | | // searches in increasing order of level to find the value. This could |
160 | | // also scramble the order of merge operands. This function should be |
161 | | // called any time a new Compaction is created, and its inputs_[0] are |
162 | | // populated. |
163 | | // |
164 | | // Will return false if it is impossible to apply this compaction. |
165 | | bool ExpandWhileOverlapping(const std::string& cf_name, |
166 | | VersionStorageInfo* vstorage, |
167 | | CompactionInputFiles* inputs); |
168 | | |
169 | | // Returns true if any one of the parent files are being compacted |
170 | | bool RangeInCompaction(VersionStorageInfo* vstorage, |
171 | | const InternalKey* smallest, |
172 | | const InternalKey* largest, |
173 | | int level, |
174 | | int* index); |
175 | | |
176 | | bool SetupOtherInputs(const std::string& cf_name, |
177 | | const MutableCFOptions& mutable_cf_options, |
178 | | VersionStorageInfo* vstorage, |
179 | | CompactionInputFiles* inputs, |
180 | | CompactionInputFiles* output_level_inputs, |
181 | | int* parent_index, int base_index); |
182 | | |
183 | | void GetGrandparents(VersionStorageInfo* vstorage, |
184 | | const CompactionInputFiles& inputs, |
185 | | const CompactionInputFiles& output_level_inputs, |
186 | | std::vector<FileMetaData*>* grandparents); |
187 | | |
188 | | static void MarkL0FilesForDeletion(const VersionStorageInfo* vstorage, |
189 | | const ImmutableCFOptions* ioptions); |
190 | | |
191 | | const ImmutableCFOptions& ioptions_; |
192 | | |
193 | | // A helper function to SanitizeCompactionInputFiles() that |
194 | | // sanitizes "input_files" by adding necessary files. |
195 | | #ifndef ROCKSDB_LITE |
196 | | virtual Status SanitizeCompactionInputFilesForAllLevels( |
197 | | std::unordered_set<uint64_t>* input_files, |
198 | | const ColumnFamilyMetaData& cf_meta, |
199 | | const int output_level) const; |
200 | | #endif // ROCKSDB_LITE |
201 | | |
202 | | // Keeps track of all compactions that are running on Level0. |
203 | | // It is protected by DB mutex |
204 | | std::set<Compaction*> level0_compactions_in_progress_; |
205 | | |
206 | | const InternalKeyComparator* const icmp_; |
207 | | }; |
208 | | |
209 | | class LevelCompactionPicker : public CompactionPicker { |
210 | | public: |
211 | | LevelCompactionPicker(const ImmutableCFOptions& ioptions, |
212 | | const InternalKeyComparator* icmp) |
213 | 15.7k | : CompactionPicker(ioptions, icmp) {} |
214 | | |
215 | | std::unique_ptr<Compaction> PickCompaction( |
216 | | const std::string& cf_name, |
217 | | const MutableCFOptions& mutable_cf_options, |
218 | | VersionStorageInfo* vstorage, |
219 | | LogBuffer* log_buffer) override; |
220 | | |
221 | | virtual bool NeedsCompaction(const VersionStorageInfo* vstorage) const |
222 | | override; |
223 | | |
224 | | // Pick a path ID to place a newly generated file, with its level |
225 | | static uint32_t GetPathId(const ImmutableCFOptions& ioptions, |
226 | | const MutableCFOptions& mutable_cf_options, |
227 | | int level); |
228 | | |
229 | | private: |
230 | | // For the specfied level, pick a file that we want to compact. |
231 | | // Returns false if there is no file to compact. |
232 | | // If it returns true, inputs->files.size() will be exactly one. |
233 | | // If level is 0 and there is already a compaction on that level, this |
234 | | // function will return false. |
235 | | bool PickCompactionBySize(VersionStorageInfo* vstorage, int level, |
236 | | int output_level, CompactionInputFiles* inputs, |
237 | | int* parent_index, int* base_index); |
238 | | |
239 | | // If there is any file marked for compaction, put put it into inputs. |
240 | | // This is still experimental. It will return meaningful results only if |
241 | | // clients call experimental feature SuggestCompactRange() |
242 | | void PickFilesMarkedForCompactionExperimental(const std::string& cf_name, |
243 | | VersionStorageInfo* vstorage, |
244 | | CompactionInputFiles* inputs, |
245 | | int* level, int* output_level); |
246 | | }; |
247 | | |
248 | | #ifndef ROCKSDB_LITE |
249 | | class UniversalCompactionPicker : public CompactionPicker { |
250 | | public: |
251 | | UniversalCompactionPicker(const ImmutableCFOptions& ioptions, |
252 | | const InternalKeyComparator* icmp) |
253 | 425k | : CompactionPicker(ioptions, icmp) {} |
254 | | |
255 | | std::unique_ptr<Compaction> PickCompaction( |
256 | | const std::string& cf_name, |
257 | | const MutableCFOptions& mutable_cf_options, |
258 | | VersionStorageInfo* vstorage, |
259 | | LogBuffer* log_buffer) override; |
260 | | |
261 | 12 | virtual int MaxOutputLevel() const override { return NumberLevels() - 1; } |
262 | | |
263 | | virtual bool NeedsCompaction(const VersionStorageInfo* vstorage) const |
264 | | override; |
265 | | |
266 | | private: |
267 | | struct SortedRun; |
268 | | |
269 | | std::unique_ptr<Compaction> DoPickCompaction( |
270 | | const std::string& cf_name, |
271 | | const MutableCFOptions& mutable_cf_options, |
272 | | VersionStorageInfo* vstorage, |
273 | | LogBuffer* log_buffer, |
274 | | const std::vector<SortedRun>& sorted_runs); |
275 | | |
276 | | // Pick Universal compaction to limit read amplification |
277 | | std::unique_ptr<Compaction> PickCompactionUniversalReadAmp( |
278 | | const std::string& cf_name, const MutableCFOptions& mutable_cf_options, |
279 | | VersionStorageInfo* vstorage, double score, unsigned int ratio, |
280 | | unsigned int num_files, size_t always_include_threshold, |
281 | | const std::vector<SortedRun>& sorted_runs, LogBuffer* log_buffer); |
282 | | |
283 | | // Pick Universal compaction to limit space amplification. |
284 | | std::unique_ptr<Compaction> PickCompactionUniversalSizeAmp( |
285 | | const std::string& cf_name, const MutableCFOptions& mutable_cf_options, |
286 | | VersionStorageInfo* vstorage, double score, |
287 | | const std::vector<SortedRun>& sorted_runs, LogBuffer* log_buffer); |
288 | | |
289 | | // Pick Universal compaction to directly delete files that are no longer needed. |
290 | | std::unique_ptr<Compaction> PickCompactionUniversalDeletion( |
291 | | const std::string& cf_name, const MutableCFOptions& mutable_cf_options, |
292 | | VersionStorageInfo* vstorage, double score, |
293 | | const std::vector<SortedRun>& sorted_runs, LogBuffer* log_buffer); |
294 | | |
295 | | // At level 0 we could compact only continuous sequence of files. |
296 | | // Since there could be too-large-to-compact files, we could get several such sequences. |
297 | | // Files from one sequence are compacted together, and files from different sequences are not |
298 | | // compacted. |
299 | | // One sequence is std::vector<SortedRun>. |
300 | | // Several sequences are std::vector<std::vector<SortedRun>>. |
301 | | static std::vector<std::vector<SortedRun>> CalculateSortedRuns( |
302 | | const VersionStorageInfo& vstorage, |
303 | | const ImmutableCFOptions& ioptions, |
304 | | uint64_t max_file_size); |
305 | | |
306 | | // Pick a path ID to place a newly generated file, with its estimated file |
307 | | // size. |
308 | | static uint32_t GetPathId(const ImmutableCFOptions& ioptions, |
309 | | uint64_t file_size); |
310 | | }; |
311 | | |
312 | | class FIFOCompactionPicker : public CompactionPicker { |
313 | | public: |
314 | | FIFOCompactionPicker(const ImmutableCFOptions& ioptions, |
315 | | const InternalKeyComparator* icmp) |
316 | 290 | : CompactionPicker(ioptions, icmp) {} |
317 | | |
318 | | std::unique_ptr<Compaction> PickCompaction( |
319 | | const std::string& cf_name, |
320 | | const MutableCFOptions& mutable_cf_options, |
321 | | VersionStorageInfo* version, |
322 | | LogBuffer* log_buffer) override; |
323 | | |
324 | | std::unique_ptr<Compaction> CompactRange( |
325 | | const std::string& cf_name, const MutableCFOptions& mutable_cf_options, |
326 | | VersionStorageInfo* vstorage, int input_level, int output_level, |
327 | | uint32_t output_path_id, const InternalKey* begin, const InternalKey* end, |
328 | | InternalKey** compaction_end, bool* manual_conflict) override; |
329 | | |
330 | | // The maximum allowed output level. Always returns 0. |
331 | 0 | virtual int MaxOutputLevel() const override { |
332 | 0 | return 0; |
333 | 0 | } |
334 | | |
335 | | virtual bool NeedsCompaction(const VersionStorageInfo* vstorage) const |
336 | | override; |
337 | | }; |
338 | | |
339 | | class NullCompactionPicker : public CompactionPicker { |
340 | | public: |
341 | | NullCompactionPicker(const ImmutableCFOptions& ioptions, |
342 | | const InternalKeyComparator* icmp) : |
343 | 354 | CompactionPicker(ioptions, icmp) {} |
344 | 350 | virtual ~NullCompactionPicker() {} |
345 | | |
346 | | // Always return "nullptr" |
347 | | std::unique_ptr<Compaction> PickCompaction( |
348 | | const std::string& cf_name, |
349 | | const MutableCFOptions& mutable_cf_options, |
350 | | VersionStorageInfo* vstorage, |
351 | 0 | LogBuffer* log_buffer) override { |
352 | 0 | return nullptr; |
353 | 0 | } |
354 | | |
355 | | // Always return "nullptr" |
356 | | std::unique_ptr<Compaction> CompactRange( |
357 | | const std::string& cf_name, |
358 | | const MutableCFOptions& mutable_cf_options, |
359 | | VersionStorageInfo* vstorage, int input_level, |
360 | | int output_level, uint32_t output_path_id, |
361 | | const InternalKey* begin, const InternalKey* end, |
362 | | InternalKey** compaction_end, |
363 | 0 | bool* manual_conflict) override { |
364 | 0 | return nullptr; |
365 | 0 | } |
366 | | |
367 | | // Always returns false. |
368 | | virtual bool NeedsCompaction(const VersionStorageInfo* vstorage) const |
369 | 1.40k | override { |
370 | 1.40k | return false; |
371 | 1.40k | } |
372 | | }; |
373 | | #endif // !ROCKSDB_LITE |
374 | | |
375 | | // Test whether two files have overlapping key-ranges. |
376 | | bool HaveOverlappingKeyRanges(const Comparator* c, |
377 | | const SstFileMetaData& a, |
378 | | const SstFileMetaData& b); |
379 | | |
380 | | CompressionType GetCompressionType(const ImmutableCFOptions& ioptions, |
381 | | int level, int base_level, |
382 | | const bool enable_compression = true); |
383 | | |
384 | | } // namespace rocksdb |
385 | | |
386 | | #endif // YB_ROCKSDB_DB_COMPACTION_PICKER_H |