/Users/deen/code/yugabyte-db/src/yb/rocksdb/db/file_indexer.cc
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 | | #include "yb/rocksdb/db/file_indexer.h" |
25 | | #include <algorithm> |
26 | | #include "yb/rocksdb/comparator.h" |
27 | | #include "yb/rocksdb/db/version_edit.h" |
28 | | |
29 | | namespace rocksdb { |
30 | | |
31 | | FileIndexer::FileIndexer(const Comparator* ucmp) |
32 | 1.34M | : num_levels_(0), ucmp_(ucmp), level_rb_(nullptr) {} |
33 | | |
34 | 0 | size_t FileIndexer::NumLevelIndex() const { return next_level_index_.size(); } |
35 | | |
36 | 3 | size_t FileIndexer::LevelIndexSize(size_t level) const { |
37 | 3 | if (level >= next_level_index_.size()) { |
38 | 3 | return 0; |
39 | 3 | } |
40 | 0 | return next_level_index_[level].num_index; |
41 | 0 | } |
42 | | |
43 | | void FileIndexer::GetNextLevelIndex(const size_t level, const size_t file_index, |
44 | | const int cmp_smallest, |
45 | | const int cmp_largest, int32_t* left_bound, |
46 | 2.63M | int32_t* right_bound) const { |
47 | 2.63M | assert(level > 0); |
48 | | |
49 | | // Last level, no hint |
50 | 2.63M | if (level == num_levels_ - 1) { |
51 | 1.90M | *left_bound = 0; |
52 | 1.90M | *right_bound = -1; |
53 | 1.90M | return; |
54 | 1.90M | } |
55 | | |
56 | 723k | assert(level < num_levels_ - 1); |
57 | 723k | assert(static_cast<int32_t>(file_index) <= level_rb_[level]); |
58 | | |
59 | 723k | const IndexUnit* index_units = next_level_index_[level].index_units; |
60 | 723k | const auto& index = index_units[file_index]; |
61 | | |
62 | 723k | if (cmp_smallest < 0) { |
63 | 255k | *left_bound = (level > 0 && file_index > 0) |
64 | 132k | ? index_units[file_index - 1].largest_lb |
65 | 122k | : 0; |
66 | 255k | *right_bound = index.smallest_rb; |
67 | 468k | } else if (cmp_smallest == 0) { |
68 | 540 | *left_bound = index.smallest_lb; |
69 | 540 | *right_bound = index.smallest_rb; |
70 | 468k | } else if (cmp_smallest > 0 && cmp_largest < 0) { |
71 | 462k | *left_bound = index.smallest_lb; |
72 | 462k | *right_bound = index.largest_rb; |
73 | 6.00k | } else if (cmp_largest == 0) { |
74 | 526 | *left_bound = index.largest_lb; |
75 | 526 | *right_bound = index.largest_rb; |
76 | 5.47k | } else if (cmp_largest > 0) { |
77 | 5.47k | *left_bound = index.largest_lb; |
78 | 5.47k | *right_bound = level_rb_[level + 1]; |
79 | 0 | } else { |
80 | 0 | assert(false); |
81 | 0 | } |
82 | | |
83 | 723k | assert(*left_bound >= 0); |
84 | 723k | assert(*left_bound <= *right_bound + 1); |
85 | 723k | assert(*right_bound <= level_rb_[level + 1]); |
86 | 723k | } |
87 | | |
88 | | void FileIndexer::UpdateIndex(Arena* arena, const size_t num_levels, |
89 | 653k | std::vector<FileMetaData*>* const files) { |
90 | 653k | if (files == nullptr) { |
91 | 0 | return; |
92 | 0 | } |
93 | 653k | if (num_levels == 0) { // uint_32 0-1 would cause bad behavior |
94 | 586k | num_levels_ = num_levels; |
95 | 586k | return; |
96 | 586k | } |
97 | 67.0k | assert(level_rb_ == nullptr); // level_rb_ should be init here |
98 | | |
99 | 67.0k | num_levels_ = num_levels; |
100 | 67.0k | next_level_index_.resize(num_levels); |
101 | | |
102 | 67.0k | char* mem = arena->AllocateAligned(num_levels_ * sizeof(int32_t)); |
103 | 67.0k | level_rb_ = new (mem) int32_t[num_levels_]; |
104 | 314k | for (size_t i = 0; i < num_levels_; i++) { |
105 | 247k | level_rb_[i] = -1; |
106 | 247k | } |
107 | | |
108 | | // L1 - Ln-1 |
109 | 199k | for (size_t level = 1; level < num_levels_ - 1; ++level) { |
110 | 132k | const auto& upper_files = files[level]; |
111 | 132k | const int32_t upper_size = static_cast<int32_t>(upper_files.size()); |
112 | 132k | const auto& lower_files = files[level + 1]; |
113 | 132k | level_rb_[level] = static_cast<int32_t>(upper_files.size()) - 1; |
114 | 132k | if (upper_size == 0) { |
115 | 76.1k | continue; |
116 | 76.1k | } |
117 | 56.7k | IndexLevel& index_level = next_level_index_[level]; |
118 | 56.7k | index_level.num_index = upper_size; |
119 | 56.7k | mem = arena->AllocateAligned(upper_size * sizeof(IndexUnit)); |
120 | 56.7k | index_level.index_units = new (mem) IndexUnit[upper_size]; |
121 | | |
122 | 56.7k | CalculateLB( |
123 | 56.7k | upper_files, lower_files, &index_level, |
124 | 682k | [this](const FileMetaData * a, const FileMetaData * b)->int { |
125 | 682k | return ucmp_->Compare(a->smallest.key.user_key(), b->largest.key.user_key()); |
126 | 682k | }, |
127 | 249k | [](IndexUnit* index, int32_t f_idx) { index->smallest_lb = f_idx; }); |
128 | 56.7k | CalculateLB( |
129 | 56.7k | upper_files, lower_files, &index_level, |
130 | 678k | [this](const FileMetaData * a, const FileMetaData * b)->int { |
131 | 678k | return ucmp_->Compare(a->largest.key.user_key(), b->largest.key.user_key()); |
132 | 678k | }, |
133 | 249k | [](IndexUnit* index, int32_t f_idx) { index->largest_lb = f_idx; }); |
134 | 56.7k | CalculateRB( |
135 | 56.7k | upper_files, lower_files, &index_level, |
136 | 631k | [this](const FileMetaData * a, const FileMetaData * b)->int { |
137 | 631k | return ucmp_->Compare(a->smallest.key.user_key(), b->smallest.key.user_key()); |
138 | 631k | }, |
139 | 249k | [](IndexUnit* index, int32_t f_idx) { index->smallest_rb = f_idx; }); |
140 | 56.7k | CalculateRB( |
141 | 56.7k | upper_files, lower_files, &index_level, |
142 | 627k | [this](const FileMetaData * a, const FileMetaData * b)->int { |
143 | 627k | return ucmp_->Compare(a->largest.key.user_key(), b->smallest.key.user_key()); |
144 | 627k | }, |
145 | 249k | [](IndexUnit* index, int32_t f_idx) { index->largest_rb = f_idx; }); |
146 | 56.7k | } |
147 | | |
148 | 67.0k | level_rb_[num_levels_ - 1] = |
149 | 67.0k | static_cast<int32_t>(files[num_levels_ - 1].size()) - 1; |
150 | 67.0k | } |
151 | | |
152 | | void FileIndexer::CalculateLB( |
153 | | const std::vector<FileMetaData*>& upper_files, |
154 | | const std::vector<FileMetaData*>& lower_files, IndexLevel* index_level, |
155 | | std::function<int(const FileMetaData*, const FileMetaData*)> cmp_op, |
156 | 113k | std::function<void(IndexUnit*, int32_t)> set_index) { |
157 | 113k | const int32_t upper_size = static_cast<int32_t>(upper_files.size()); |
158 | 113k | const int32_t lower_size = static_cast<int32_t>(lower_files.size()); |
159 | 113k | int32_t upper_idx = 0; |
160 | 113k | int32_t lower_idx = 0; |
161 | | |
162 | 113k | IndexUnit* index = index_level->index_units; |
163 | 1.47M | while (upper_idx < upper_size && lower_idx < lower_size) { |
164 | 1.36M | int cmp = cmp_op(upper_files[upper_idx], lower_files[lower_idx]); |
165 | | |
166 | 1.36M | if (cmp == 0) { |
167 | 24.7k | set_index(&index[upper_idx], lower_idx); |
168 | 24.7k | ++upper_idx; |
169 | 24.7k | ++lower_idx; |
170 | 1.33M | } else if (cmp > 0) { |
171 | | // Lower level's file (largest) is smaller, a key won't hit in that |
172 | | // file. Move to next lower file |
173 | 964k | ++lower_idx; |
174 | 372k | } else { |
175 | | // Lower level's file becomes larger, update the index, and |
176 | | // move to the next upper file |
177 | 372k | set_index(&index[upper_idx], lower_idx); |
178 | 372k | ++upper_idx; |
179 | 372k | } |
180 | 1.36M | } |
181 | | |
182 | 214k | while (upper_idx < upper_size) { |
183 | | // Lower files are exhausted, that means the remaining upper files are |
184 | | // greater than any lower files. Set the index to be the lower level size. |
185 | 100k | set_index(&index[upper_idx], lower_size); |
186 | 100k | ++upper_idx; |
187 | 100k | } |
188 | 113k | } |
189 | | |
190 | | void FileIndexer::CalculateRB( |
191 | | const std::vector<FileMetaData*>& upper_files, |
192 | | const std::vector<FileMetaData*>& lower_files, IndexLevel* index_level, |
193 | | std::function<int(const FileMetaData*, const FileMetaData*)> cmp_op, |
194 | 113k | std::function<void(IndexUnit*, int32_t)> set_index) { |
195 | 113k | const int32_t upper_size = static_cast<int32_t>(upper_files.size()); |
196 | 113k | const int32_t lower_size = static_cast<int32_t>(lower_files.size()); |
197 | 113k | int32_t upper_idx = upper_size - 1; |
198 | 113k | int32_t lower_idx = lower_size - 1; |
199 | | |
200 | 113k | IndexUnit* index = index_level->index_units; |
201 | 1.37M | while (upper_idx >= 0 && lower_idx >= 0) { |
202 | 1.25M | int cmp = cmp_op(upper_files[upper_idx], lower_files[lower_idx]); |
203 | | |
204 | 1.25M | if (cmp == 0) { |
205 | 25.6k | set_index(&index[upper_idx], lower_idx); |
206 | 25.6k | --upper_idx; |
207 | 25.6k | --lower_idx; |
208 | 1.23M | } else if (cmp < 0) { |
209 | | // Lower level's file (smallest) is larger, a key won't hit in that |
210 | | // file. Move to next lower file. |
211 | 799k | --lower_idx; |
212 | 433k | } else { |
213 | | // Lower level's file becomes smaller, update the index, and move to |
214 | | // the next the upper file |
215 | 433k | set_index(&index[upper_idx], lower_idx); |
216 | 433k | --upper_idx; |
217 | 433k | } |
218 | 1.25M | } |
219 | 152k | while (upper_idx >= 0) { |
220 | | // Lower files are exhausted, that means the remaining upper files are |
221 | | // smaller than any lower files. Set it to -1. |
222 | 38.5k | set_index(&index[upper_idx], -1); |
223 | 38.5k | --upper_idx; |
224 | 38.5k | } |
225 | 113k | } |
226 | | |
227 | | } // namespace rocksdb |