/Users/deen/code/yugabyte-db/src/yb/rocksdb/db/file_indexer_test.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 <string> |
25 | | |
26 | | #include <gtest/gtest.h> |
27 | | |
28 | | #include "yb/rocksdb/db/dbformat.h" |
29 | | #include "yb/rocksdb/db/file_indexer.h" |
30 | | #include "yb/rocksdb/db/version_edit.h" |
31 | | #include "yb/rocksdb/port/stack_trace.h" |
32 | | |
33 | | #include "yb/rocksdb/util/testutil.h" |
34 | | |
35 | | namespace rocksdb { |
36 | | |
37 | | class IntComparator : public Comparator { |
38 | | public: |
39 | 93 | int Compare(const Slice& a, const Slice& b) const override { |
40 | 93 | assert(a.size() == 8); |
41 | 93 | assert(b.size() == 8); |
42 | 93 | int64_t diff = *reinterpret_cast<const int64_t*>(a.data()) - |
43 | 93 | *reinterpret_cast<const int64_t*>(b.data()); |
44 | 93 | if (diff < 0) { |
45 | 39 | return -1; |
46 | 54 | } else if (diff == 0) { |
47 | 7 | return 0; |
48 | 47 | } else { |
49 | 47 | return 1; |
50 | 47 | } |
51 | 93 | } |
52 | | |
53 | 0 | const char* Name() const override { return "IntComparator"; } |
54 | | |
55 | | void FindShortestSeparator(std::string* start, |
56 | 0 | const Slice& limit) const override {} |
57 | | |
58 | 0 | void FindShortSuccessor(std::string* key) const override {} |
59 | | }; |
60 | | |
61 | | class FileIndexerTest : public RocksDBTest { |
62 | | public: |
63 | | FileIndexerTest() |
64 | 5 | : kNumLevels(4), files(new std::vector<FileMetaData*>[kNumLevels]) {} |
65 | | |
66 | 5 | ~FileIndexerTest() { |
67 | 5 | ClearFiles(); |
68 | 5 | delete[] files; |
69 | 5 | } |
70 | | |
71 | 35 | void AddFile(int level, int64_t smallest, int64_t largest) { |
72 | 35 | auto* f = new FileMetaData(); |
73 | 35 | f->smallest = BoundaryValues(smallest); |
74 | 35 | f->largest = BoundaryValues(largest); |
75 | 35 | files[level].push_back(f); |
76 | 35 | } |
77 | | |
78 | 70 | FileBoundaryValues<InternalKey> BoundaryValues(int64_t v) { |
79 | 70 | return MakeFileBoundaryValues(std::string(reinterpret_cast<char*>(&v), 8), 0, kTypeValue); |
80 | 70 | } |
81 | | |
82 | 8 | void ClearFiles() { |
83 | 40 | for (uint32_t i = 0; i < kNumLevels; ++i) { |
84 | 35 | for (auto* f : files[i]) { |
85 | 35 | delete f; |
86 | 35 | } |
87 | 32 | files[i].clear(); |
88 | 32 | } |
89 | 8 | } |
90 | | |
91 | | void GetNextLevelIndex(const uint32_t level, const uint32_t file_index, |
92 | | const int cmp_smallest, const int cmp_largest, int32_t* left_index, |
93 | 124 | int32_t* right_index) { |
94 | 124 | *left_index = 100; |
95 | 124 | *right_index = 100; |
96 | 124 | indexer->GetNextLevelIndex(level, file_index, cmp_smallest, cmp_largest, |
97 | 124 | left_index, right_index); |
98 | 124 | } |
99 | | |
100 | | int32_t left = 100; |
101 | | int32_t right = 100; |
102 | | const uint32_t kNumLevels; |
103 | | IntComparator ucmp; |
104 | | FileIndexer* indexer; |
105 | | |
106 | | std::vector<FileMetaData*>* files; |
107 | | }; |
108 | | |
109 | | // Case 0: Empty |
110 | 1 | TEST_F(FileIndexerTest, Empty) { |
111 | 1 | Arena arena; |
112 | 1 | indexer = new FileIndexer(&ucmp); |
113 | 1 | indexer->UpdateIndex(&arena, 0, files); |
114 | 1 | delete indexer; |
115 | 1 | } |
116 | | |
117 | | // Case 1: no overlap, files are on the left of next level files |
118 | 1 | TEST_F(FileIndexerTest, no_overlap_left) { |
119 | 1 | Arena arena; |
120 | 1 | indexer = new FileIndexer(&ucmp); |
121 | | // level 1 |
122 | 1 | AddFile(1, 100, 200); |
123 | 1 | AddFile(1, 300, 400); |
124 | 1 | AddFile(1, 500, 600); |
125 | | // level 2 |
126 | 1 | AddFile(2, 1500, 1600); |
127 | 1 | AddFile(2, 1601, 1699); |
128 | 1 | AddFile(2, 1700, 1800); |
129 | | // level 3 |
130 | 1 | AddFile(3, 2500, 2600); |
131 | 1 | AddFile(3, 2601, 2699); |
132 | 1 | AddFile(3, 2700, 2800); |
133 | 1 | indexer->UpdateIndex(&arena, kNumLevels, files); |
134 | 3 | for (uint32_t level = 1; level < 3; ++level) { |
135 | 8 | for (uint32_t f = 0; f < 3; ++f) { |
136 | 6 | GetNextLevelIndex(level, f, -1, -1, &left, &right); |
137 | 6 | ASSERT_EQ(0, left); |
138 | 6 | ASSERT_EQ(-1, right); |
139 | 6 | GetNextLevelIndex(level, f, 0, -1, &left, &right); |
140 | 6 | ASSERT_EQ(0, left); |
141 | 6 | ASSERT_EQ(-1, right); |
142 | 6 | GetNextLevelIndex(level, f, 1, -1, &left, &right); |
143 | 6 | ASSERT_EQ(0, left); |
144 | 6 | ASSERT_EQ(-1, right); |
145 | 6 | GetNextLevelIndex(level, f, 1, 0, &left, &right); |
146 | 6 | ASSERT_EQ(0, left); |
147 | 6 | ASSERT_EQ(-1, right); |
148 | 6 | GetNextLevelIndex(level, f, 1, 1, &left, &right); |
149 | 6 | ASSERT_EQ(0, left); |
150 | 6 | ASSERT_EQ(2, right); |
151 | 6 | } |
152 | 2 | } |
153 | 1 | delete indexer; |
154 | 1 | ClearFiles(); |
155 | 1 | } |
156 | | |
157 | | // Case 2: no overlap, files are on the right of next level files |
158 | 1 | TEST_F(FileIndexerTest, no_overlap_right) { |
159 | 1 | Arena arena; |
160 | 1 | indexer = new FileIndexer(&ucmp); |
161 | | // level 1 |
162 | 1 | AddFile(1, 2100, 2200); |
163 | 1 | AddFile(1, 2300, 2400); |
164 | 1 | AddFile(1, 2500, 2600); |
165 | | // level 2 |
166 | 1 | AddFile(2, 1500, 1600); |
167 | 1 | AddFile(2, 1501, 1699); |
168 | 1 | AddFile(2, 1700, 1800); |
169 | | // level 3 |
170 | 1 | AddFile(3, 500, 600); |
171 | 1 | AddFile(3, 501, 699); |
172 | 1 | AddFile(3, 700, 800); |
173 | 1 | indexer->UpdateIndex(&arena, kNumLevels, files); |
174 | 3 | for (uint32_t level = 1; level < 3; ++level) { |
175 | 8 | for (uint32_t f = 0; f < 3; ++f) { |
176 | 6 | GetNextLevelIndex(level, f, -1, -1, &left, &right); |
177 | 6 | ASSERT_EQ(f == 0 ? 0 : 3, left); |
178 | 6 | ASSERT_EQ(2, right); |
179 | 6 | GetNextLevelIndex(level, f, 0, -1, &left, &right); |
180 | 6 | ASSERT_EQ(3, left); |
181 | 6 | ASSERT_EQ(2, right); |
182 | 6 | GetNextLevelIndex(level, f, 1, -1, &left, &right); |
183 | 6 | ASSERT_EQ(3, left); |
184 | 6 | ASSERT_EQ(2, right); |
185 | 6 | GetNextLevelIndex(level, f, 1, -1, &left, &right); |
186 | 6 | ASSERT_EQ(3, left); |
187 | 6 | ASSERT_EQ(2, right); |
188 | 6 | GetNextLevelIndex(level, f, 1, 0, &left, &right); |
189 | 6 | ASSERT_EQ(3, left); |
190 | 6 | ASSERT_EQ(2, right); |
191 | 6 | GetNextLevelIndex(level, f, 1, 1, &left, &right); |
192 | 6 | ASSERT_EQ(3, left); |
193 | 6 | ASSERT_EQ(2, right); |
194 | 6 | } |
195 | 2 | } |
196 | 1 | delete indexer; |
197 | 1 | } |
198 | | |
199 | | // Case 3: empty L2 |
200 | 1 | TEST_F(FileIndexerTest, empty_L2) { |
201 | 1 | Arena arena; |
202 | 1 | indexer = new FileIndexer(&ucmp); |
203 | 4 | for (uint32_t i = 1; i < kNumLevels; ++i) { |
204 | 3 | ASSERT_EQ(0U, indexer->LevelIndexSize(i)); |
205 | 3 | } |
206 | | // level 1 |
207 | 1 | AddFile(1, 2100, 2200); |
208 | 1 | AddFile(1, 2300, 2400); |
209 | 1 | AddFile(1, 2500, 2600); |
210 | | // level 3 |
211 | 1 | AddFile(3, 500, 600); |
212 | 1 | AddFile(3, 501, 699); |
213 | 1 | AddFile(3, 700, 800); |
214 | 1 | indexer->UpdateIndex(&arena, kNumLevels, files); |
215 | 4 | for (uint32_t f = 0; f < 3; ++f) { |
216 | 3 | GetNextLevelIndex(1, f, -1, -1, &left, &right); |
217 | 3 | ASSERT_EQ(0, left); |
218 | 3 | ASSERT_EQ(-1, right); |
219 | 3 | GetNextLevelIndex(1, f, 0, -1, &left, &right); |
220 | 3 | ASSERT_EQ(0, left); |
221 | 3 | ASSERT_EQ(-1, right); |
222 | 3 | GetNextLevelIndex(1, f, 1, -1, &left, &right); |
223 | 3 | ASSERT_EQ(0, left); |
224 | 3 | ASSERT_EQ(-1, right); |
225 | 3 | GetNextLevelIndex(1, f, 1, -1, &left, &right); |
226 | 3 | ASSERT_EQ(0, left); |
227 | 3 | ASSERT_EQ(-1, right); |
228 | 3 | GetNextLevelIndex(1, f, 1, 0, &left, &right); |
229 | 3 | ASSERT_EQ(0, left); |
230 | 3 | ASSERT_EQ(-1, right); |
231 | 3 | GetNextLevelIndex(1, f, 1, 1, &left, &right); |
232 | 3 | ASSERT_EQ(0, left); |
233 | 3 | ASSERT_EQ(-1, right); |
234 | 3 | } |
235 | 1 | delete indexer; |
236 | 1 | ClearFiles(); |
237 | 1 | } |
238 | | |
239 | | // Case 4: mixed |
240 | 1 | TEST_F(FileIndexerTest, mixed) { |
241 | 1 | Arena arena; |
242 | 1 | indexer = new FileIndexer(&ucmp); |
243 | | // level 1 |
244 | 1 | AddFile(1, 100, 200); |
245 | 1 | AddFile(1, 250, 400); |
246 | 1 | AddFile(1, 450, 500); |
247 | | // level 2 |
248 | 1 | AddFile(2, 100, 150); // 0 |
249 | 1 | AddFile(2, 200, 250); // 1 |
250 | 1 | AddFile(2, 251, 300); // 2 |
251 | 1 | AddFile(2, 301, 350); // 3 |
252 | 1 | AddFile(2, 500, 600); // 4 |
253 | | // level 3 |
254 | 1 | AddFile(3, 0, 50); |
255 | 1 | AddFile(3, 100, 200); |
256 | 1 | AddFile(3, 201, 250); |
257 | 1 | indexer->UpdateIndex(&arena, kNumLevels, files); |
258 | | // level 1, 0 |
259 | 1 | GetNextLevelIndex(1, 0, -1, -1, &left, &right); |
260 | 1 | ASSERT_EQ(0, left); |
261 | 1 | ASSERT_EQ(0, right); |
262 | 1 | GetNextLevelIndex(1, 0, 0, -1, &left, &right); |
263 | 1 | ASSERT_EQ(0, left); |
264 | 1 | ASSERT_EQ(0, right); |
265 | 1 | GetNextLevelIndex(1, 0, 1, -1, &left, &right); |
266 | 1 | ASSERT_EQ(0, left); |
267 | 1 | ASSERT_EQ(1, right); |
268 | 1 | GetNextLevelIndex(1, 0, 1, 0, &left, &right); |
269 | 1 | ASSERT_EQ(1, left); |
270 | 1 | ASSERT_EQ(1, right); |
271 | 1 | GetNextLevelIndex(1, 0, 1, 1, &left, &right); |
272 | 1 | ASSERT_EQ(1, left); |
273 | 1 | ASSERT_EQ(4, right); |
274 | | // level 1, 1 |
275 | 1 | GetNextLevelIndex(1, 1, -1, -1, &left, &right); |
276 | 1 | ASSERT_EQ(1, left); |
277 | 1 | ASSERT_EQ(1, right); |
278 | 1 | GetNextLevelIndex(1, 1, 0, -1, &left, &right); |
279 | 1 | ASSERT_EQ(1, left); |
280 | 1 | ASSERT_EQ(1, right); |
281 | 1 | GetNextLevelIndex(1, 1, 1, -1, &left, &right); |
282 | 1 | ASSERT_EQ(1, left); |
283 | 1 | ASSERT_EQ(3, right); |
284 | 1 | GetNextLevelIndex(1, 1, 1, 0, &left, &right); |
285 | 1 | ASSERT_EQ(4, left); |
286 | 1 | ASSERT_EQ(3, right); |
287 | 1 | GetNextLevelIndex(1, 1, 1, 1, &left, &right); |
288 | 1 | ASSERT_EQ(4, left); |
289 | 1 | ASSERT_EQ(4, right); |
290 | | // level 1, 2 |
291 | 1 | GetNextLevelIndex(1, 2, -1, -1, &left, &right); |
292 | 1 | ASSERT_EQ(4, left); |
293 | 1 | ASSERT_EQ(3, right); |
294 | 1 | GetNextLevelIndex(1, 2, 0, -1, &left, &right); |
295 | 1 | ASSERT_EQ(4, left); |
296 | 1 | ASSERT_EQ(3, right); |
297 | 1 | GetNextLevelIndex(1, 2, 1, -1, &left, &right); |
298 | 1 | ASSERT_EQ(4, left); |
299 | 1 | ASSERT_EQ(4, right); |
300 | 1 | GetNextLevelIndex(1, 2, 1, 0, &left, &right); |
301 | 1 | ASSERT_EQ(4, left); |
302 | 1 | ASSERT_EQ(4, right); |
303 | 1 | GetNextLevelIndex(1, 2, 1, 1, &left, &right); |
304 | 1 | ASSERT_EQ(4, left); |
305 | 1 | ASSERT_EQ(4, right); |
306 | | // level 2, 0 |
307 | 1 | GetNextLevelIndex(2, 0, -1, -1, &left, &right); |
308 | 1 | ASSERT_EQ(0, left); |
309 | 1 | ASSERT_EQ(1, right); |
310 | 1 | GetNextLevelIndex(2, 0, 0, -1, &left, &right); |
311 | 1 | ASSERT_EQ(1, left); |
312 | 1 | ASSERT_EQ(1, right); |
313 | 1 | GetNextLevelIndex(2, 0, 1, -1, &left, &right); |
314 | 1 | ASSERT_EQ(1, left); |
315 | 1 | ASSERT_EQ(1, right); |
316 | 1 | GetNextLevelIndex(2, 0, 1, 0, &left, &right); |
317 | 1 | ASSERT_EQ(1, left); |
318 | 1 | ASSERT_EQ(1, right); |
319 | 1 | GetNextLevelIndex(2, 0, 1, 1, &left, &right); |
320 | 1 | ASSERT_EQ(1, left); |
321 | 1 | ASSERT_EQ(2, right); |
322 | | // level 2, 1 |
323 | 1 | GetNextLevelIndex(2, 1, -1, -1, &left, &right); |
324 | 1 | ASSERT_EQ(1, left); |
325 | 1 | ASSERT_EQ(1, right); |
326 | 1 | GetNextLevelIndex(2, 1, 0, -1, &left, &right); |
327 | 1 | ASSERT_EQ(1, left); |
328 | 1 | ASSERT_EQ(1, right); |
329 | 1 | GetNextLevelIndex(2, 1, 1, -1, &left, &right); |
330 | 1 | ASSERT_EQ(1, left); |
331 | 1 | ASSERT_EQ(2, right); |
332 | 1 | GetNextLevelIndex(2, 1, 1, 0, &left, &right); |
333 | 1 | ASSERT_EQ(2, left); |
334 | 1 | ASSERT_EQ(2, right); |
335 | 1 | GetNextLevelIndex(2, 1, 1, 1, &left, &right); |
336 | 1 | ASSERT_EQ(2, left); |
337 | 1 | ASSERT_EQ(2, right); |
338 | | // level 2, [2 - 4], no overlap |
339 | 4 | for (uint32_t f = 2; f <= 4; ++f) { |
340 | 3 | GetNextLevelIndex(2, f, -1, -1, &left, &right); |
341 | 3 | ASSERT_EQ(f == 2 ? 2 : 3, left); |
342 | 3 | ASSERT_EQ(2, right); |
343 | 3 | GetNextLevelIndex(2, f, 0, -1, &left, &right); |
344 | 3 | ASSERT_EQ(3, left); |
345 | 3 | ASSERT_EQ(2, right); |
346 | 3 | GetNextLevelIndex(2, f, 1, -1, &left, &right); |
347 | 3 | ASSERT_EQ(3, left); |
348 | 3 | ASSERT_EQ(2, right); |
349 | 3 | GetNextLevelIndex(2, f, 1, 0, &left, &right); |
350 | 3 | ASSERT_EQ(3, left); |
351 | 3 | ASSERT_EQ(2, right); |
352 | 3 | GetNextLevelIndex(2, f, 1, 1, &left, &right); |
353 | 3 | ASSERT_EQ(3, left); |
354 | 3 | ASSERT_EQ(2, right); |
355 | 3 | } |
356 | 1 | delete indexer; |
357 | 1 | ClearFiles(); |
358 | 1 | } |
359 | | |
360 | | } // namespace rocksdb |
361 | | |
362 | 13.2k | int main(int argc, char** argv) { |
363 | 13.2k | rocksdb::port::InstallStackTraceHandler(); |
364 | 13.2k | ::testing::InitGoogleTest(&argc, argv); |
365 | 13.2k | return RUN_ALL_TESTS(); |
366 | 13.2k | } |