/Users/deen/code/yugabyte-db/src/yb/rocksdb/db/file_indexer.h
Line | Count | Source |
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_FILE_INDEXER_H |
25 | | #define YB_ROCKSDB_DB_FILE_INDEXER_H |
26 | | |
27 | | #pragma once |
28 | | |
29 | | #include <functional> |
30 | | #include <limits> |
31 | | #include <vector> |
32 | | |
33 | | #include "yb/rocksdb/port/port.h" |
34 | | #include "yb/rocksdb/util/arena.h" |
35 | | #include "yb/rocksdb/util/autovector.h" |
36 | | |
37 | | namespace rocksdb { |
38 | | |
39 | | class Comparator; |
40 | | struct FileMetaData; |
41 | | struct FileLevel; |
42 | | |
43 | | // The file tree structure in Version is prebuilt and the range of each file |
44 | | // is known. On Version::Get(), it uses binary search to find a potential file |
45 | | // and then check if a target key can be found in the file by comparing the key |
46 | | // to each file's smallest and largest key. The results of these comparisons |
47 | | // can be reused beyond checking if a key falls into a file's range. |
48 | | // With some pre-calculated knowledge, each key comparison that has been done |
49 | | // can serve as a hint to narrow down further searches: if a key compared to |
50 | | // be smaller than a file's smallest or largest, that comparison can be used |
51 | | // to find out the right bound of next binary search. Similarly, if a key |
52 | | // compared to be larger than a file's smallest or largest, it can be utilized |
53 | | // to find out the left bound of next binary search. |
54 | | // With these hints: it can greatly reduce the range of binary search, |
55 | | // especially for bottom levels, given that one file most likely overlaps with |
56 | | // only N files from level below (where N is max_bytes_for_level_multiplier). |
57 | | // So on level L, we will only look at ~N files instead of N^L files on the |
58 | | // naive approach. |
59 | | class FileIndexer { |
60 | | public: |
61 | | explicit FileIndexer(const Comparator* ucmp); |
62 | | |
63 | | size_t NumLevelIndex() const; |
64 | | |
65 | | size_t LevelIndexSize(size_t level) const; |
66 | | |
67 | | // Return a file index range in the next level to search for a key based on |
68 | | // smallest and largest key comparison for the current file specified by |
69 | | // level and file_index. When *left_index < *right_index, both index should |
70 | | // be valid and fit in the vector size. |
71 | | void GetNextLevelIndex(const size_t level, const size_t file_index, |
72 | | const int cmp_smallest, const int cmp_largest, |
73 | | int32_t* left_bound, int32_t* right_bound) const; |
74 | | |
75 | | void UpdateIndex(Arena* arena, const size_t num_levels, |
76 | | std::vector<FileMetaData*>* const files); |
77 | | |
78 | | enum { |
79 | | // MSVC version 1800 still does not have constexpr for ::max() |
80 | | kLevelMaxIndex = rocksdb::port::kMaxInt32 |
81 | | }; |
82 | | |
83 | | private: |
84 | | size_t num_levels_; |
85 | | const Comparator* ucmp_; |
86 | | |
87 | | struct IndexUnit { |
88 | | IndexUnit() |
89 | 250k | : smallest_lb(0), largest_lb(0), smallest_rb(-1), largest_rb(-1) {} |
90 | | // During file search, a key is compared against smallest and largest |
91 | | // from a FileMetaData. It can have 3 possible outcomes: |
92 | | // (1) key is smaller than smallest, implying it is also smaller than |
93 | | // larger. Precalculated index based on "smallest < smallest" can |
94 | | // be used to provide right bound. |
95 | | // (2) key is in between smallest and largest. |
96 | | // Precalculated index based on "smallest > greatest" can be used to |
97 | | // provide left bound. |
98 | | // Precalculated index based on "largest < smallest" can be used to |
99 | | // provide right bound. |
100 | | // (3) key is larger than largest, implying it is also larger than smallest. |
101 | | // Precalculated index based on "largest > largest" can be used to |
102 | | // provide left bound. |
103 | | // |
104 | | // As a result, we will need to do: |
105 | | // Compare smallest (<=) and largest keys from upper level file with |
106 | | // smallest key from lower level to get a right bound. |
107 | | // Compare smallest (>=) and largest keys from upper level file with |
108 | | // largest key from lower level to get a left bound. |
109 | | // |
110 | | // Example: |
111 | | // level 1: [50 - 60] |
112 | | // level 2: [1 - 40], [45 - 55], [58 - 80] |
113 | | // A key 35, compared to be less than 50, 3rd file on level 2 can be |
114 | | // skipped according to rule (1). LB = 0, RB = 1. |
115 | | // A key 53, sits in the middle 50 and 60. 1st file on level 2 can be |
116 | | // skipped according to rule (2)-a, but the 3rd file cannot be skipped |
117 | | // because 60 is greater than 58. LB = 1, RB = 2. |
118 | | // A key 70, compared to be larger than 60. 1st and 2nd file can be skipped |
119 | | // according to rule (3). LB = 2, RB = 2. |
120 | | // |
121 | | // Point to a left most file in a lower level that may contain a key, |
122 | | // which compares greater than smallest of a FileMetaData (upper level) |
123 | | int32_t smallest_lb; |
124 | | // Point to a left most file in a lower level that may contain a key, |
125 | | // which compares greater than largest of a FileMetaData (upper level) |
126 | | int32_t largest_lb; |
127 | | // Point to a right most file in a lower level that may contain a key, |
128 | | // which compares smaller than smallest of a FileMetaData (upper level) |
129 | | int32_t smallest_rb; |
130 | | // Point to a right most file in a lower level that may contain a key, |
131 | | // which compares smaller than largest of a FileMetaData (upper level) |
132 | | int32_t largest_rb; |
133 | | }; |
134 | | |
135 | | // Data structure to store IndexUnits in a whole level |
136 | | struct IndexLevel { |
137 | | size_t num_index; |
138 | | IndexUnit* index_units; |
139 | | |
140 | 13.2M | IndexLevel() : num_index(0), index_units(nullptr) {} |
141 | | }; |
142 | | |
143 | | void CalculateLB( |
144 | | const std::vector<FileMetaData*>& upper_files, |
145 | | const std::vector<FileMetaData*>& lower_files, IndexLevel* index_level, |
146 | | std::function<int(const FileMetaData*, const FileMetaData*)> cmp_op, |
147 | | std::function<void(IndexUnit*, int32_t)> set_index); |
148 | | |
149 | | void CalculateRB( |
150 | | const std::vector<FileMetaData*>& upper_files, |
151 | | const std::vector<FileMetaData*>& lower_files, IndexLevel* index_level, |
152 | | std::function<int(const FileMetaData*, const FileMetaData*)> cmp_op, |
153 | | std::function<void(IndexUnit*, int32_t)> set_index); |
154 | | |
155 | | autovector<IndexLevel> next_level_index_; |
156 | | int32_t* level_rb_; |
157 | | }; |
158 | | |
159 | | } // namespace rocksdb |
160 | | |
161 | | #endif // YB_ROCKSDB_DB_FILE_INDEXER_H |