]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/db/db_dynamic_level_test.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / rocksdb / db / db_dynamic_level_test.cc
CommitLineData
7c673cae 1// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
11fdf7f2
TL
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).
7c673cae
FG
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
10// Introduction of SyncPoint effectively disabled building and running this test
11// in Release build.
12// which is a pity, it is a good test
13#if !defined(ROCKSDB_LITE)
14
15#include "db/db_test_util.h"
16#include "port/port.h"
17#include "port/stack_trace.h"
18
f67539c2 19namespace ROCKSDB_NAMESPACE {
7c673cae
FG
20class DBTestDynamicLevel : public DBTestBase {
21 public:
22 DBTestDynamicLevel() : DBTestBase("/db_dynamic_level_test") {}
23};
24
25TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase) {
26 if (!Snappy_Supported() || !LZ4_Supported()) {
27 return;
28 }
29 // Use InMemoryEnv, or it would be too slow.
494da23a 30 std::unique_ptr<Env> env(new MockEnv(env_));
7c673cae
FG
31
32 const int kNKeys = 1000;
33 int keys[kNKeys];
34
35 auto verify_func = [&]() {
36 for (int i = 0; i < kNKeys; i++) {
37 ASSERT_NE("NOT_FOUND", Get(Key(i)));
38 ASSERT_NE("NOT_FOUND", Get(Key(kNKeys * 2 + i)));
39 if (i < kNKeys / 10) {
40 ASSERT_EQ("NOT_FOUND", Get(Key(kNKeys + keys[i])));
41 } else {
42 ASSERT_NE("NOT_FOUND", Get(Key(kNKeys + keys[i])));
43 }
44 }
45 };
46
47 Random rnd(301);
48 for (int ordered_insert = 0; ordered_insert <= 1; ordered_insert++) {
49 for (int i = 0; i < kNKeys; i++) {
50 keys[i] = i;
51 }
52 if (ordered_insert == 0) {
53 std::random_shuffle(std::begin(keys), std::end(keys));
54 }
55 for (int max_background_compactions = 1; max_background_compactions < 4;
56 max_background_compactions += 2) {
57 Options options;
58 options.env = env.get();
59 options.create_if_missing = true;
7c673cae
FG
60 options.write_buffer_size = 2048;
61 options.max_write_buffer_number = 2;
62 options.level0_file_num_compaction_trigger = 2;
63 options.level0_slowdown_writes_trigger = 2;
64 options.level0_stop_writes_trigger = 2;
65 options.target_file_size_base = 2048;
66 options.level_compaction_dynamic_level_bytes = true;
67 options.max_bytes_for_level_base = 10240;
68 options.max_bytes_for_level_multiplier = 4;
69 options.soft_rate_limit = 1.1;
70 options.max_background_compactions = max_background_compactions;
71 options.num_levels = 5;
72
73 options.compression_per_level.resize(3);
74 options.compression_per_level[0] = kNoCompression;
75 options.compression_per_level[1] = kLZ4Compression;
76 options.compression_per_level[2] = kSnappyCompression;
77 options.env = env_;
78
79 DestroyAndReopen(options);
80
81 for (int i = 0; i < kNKeys; i++) {
82 int key = keys[i];
83 ASSERT_OK(Put(Key(kNKeys + key), RandomString(&rnd, 102)));
84 ASSERT_OK(Put(Key(key), RandomString(&rnd, 102)));
85 ASSERT_OK(Put(Key(kNKeys * 2 + key), RandomString(&rnd, 102)));
86 ASSERT_OK(Delete(Key(kNKeys + keys[i / 10])));
87 env_->SleepForMicroseconds(5000);
88 }
89
90 uint64_t int_prop;
91 ASSERT_TRUE(db_->GetIntProperty("rocksdb.background-errors", &int_prop));
92 ASSERT_EQ(0U, int_prop);
93
94 // Verify DB
95 for (int j = 0; j < 2; j++) {
96 verify_func();
97 if (j == 0) {
98 Reopen(options);
99 }
100 }
101
102 // Test compact range works
103 dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
104 // All data should be in the last level.
105 ColumnFamilyMetaData cf_meta;
106 db_->GetColumnFamilyMetaData(&cf_meta);
107 ASSERT_EQ(5U, cf_meta.levels.size());
108 for (int i = 0; i < 4; i++) {
109 ASSERT_EQ(0U, cf_meta.levels[i].files.size());
110 }
111 ASSERT_GT(cf_meta.levels[4U].files.size(), 0U);
112 verify_func();
113
114 Close();
115 }
116 }
117
118 env_->SetBackgroundThreads(1, Env::LOW);
119 env_->SetBackgroundThreads(1, Env::HIGH);
120}
121
122// Test specific cases in dynamic max bytes
123TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase2) {
124 Random rnd(301);
125 int kMaxKey = 1000000;
126
127 Options options = CurrentOptions();
494da23a 128 options.compression = kNoCompression;
7c673cae 129 options.create_if_missing = true;
7c673cae
FG
130 options.write_buffer_size = 20480;
131 options.max_write_buffer_number = 2;
132 options.level0_file_num_compaction_trigger = 2;
133 options.level0_slowdown_writes_trigger = 9999;
134 options.level0_stop_writes_trigger = 9999;
135 options.target_file_size_base = 9102;
136 options.level_compaction_dynamic_level_bytes = true;
137 options.max_bytes_for_level_base = 40960;
138 options.max_bytes_for_level_multiplier = 4;
139 options.max_background_compactions = 2;
140 options.num_levels = 5;
141 options.max_compaction_bytes = 0; // Force not expanding in compactions
142 BlockBasedTableOptions table_options;
143 table_options.block_size = 1024;
144 options.table_factory.reset(NewBlockBasedTableFactory(table_options));
145
146 DestroyAndReopen(options);
147 ASSERT_OK(dbfull()->SetOptions({
148 {"disable_auto_compactions", "true"},
149 }));
150
151 uint64_t int_prop;
152 std::string str_prop;
153
154 // Initial base level is the last level
155 ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
156 ASSERT_EQ(4U, int_prop);
157
158 // Put about 28K to L0
159 for (int i = 0; i < 70; i++) {
160 ASSERT_OK(Put(Key(static_cast<int>(rnd.Uniform(kMaxKey))),
161 RandomString(&rnd, 380)));
162 }
163 ASSERT_OK(dbfull()->SetOptions({
164 {"disable_auto_compactions", "false"},
165 }));
166 Flush();
167 dbfull()->TEST_WaitForCompact();
168 ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
169 ASSERT_EQ(4U, int_prop);
170
494da23a
TL
171 // Insert extra about 28K to L0. After they are compacted to L4, the base
172 // level should be changed to L3.
7c673cae
FG
173 ASSERT_OK(dbfull()->SetOptions({
174 {"disable_auto_compactions", "true"},
175 }));
176 for (int i = 0; i < 70; i++) {
177 ASSERT_OK(Put(Key(static_cast<int>(rnd.Uniform(kMaxKey))),
178 RandomString(&rnd, 380)));
179 }
180
181 ASSERT_OK(dbfull()->SetOptions({
182 {"disable_auto_compactions", "false"},
183 }));
184 Flush();
185 dbfull()->TEST_WaitForCompact();
186 ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
187 ASSERT_EQ(3U, int_prop);
188 ASSERT_TRUE(db_->GetProperty("rocksdb.num-files-at-level1", &str_prop));
189 ASSERT_EQ("0", str_prop);
190 ASSERT_TRUE(db_->GetProperty("rocksdb.num-files-at-level2", &str_prop));
191 ASSERT_EQ("0", str_prop);
192
494da23a 193 // Write even more data while leaving the base level at L3.
7c673cae
FG
194 ASSERT_OK(dbfull()->SetOptions({
195 {"disable_auto_compactions", "true"},
196 }));
197 // Write about 40K more
198 for (int i = 0; i < 100; i++) {
199 ASSERT_OK(Put(Key(static_cast<int>(rnd.Uniform(kMaxKey))),
200 RandomString(&rnd, 380)));
201 }
202 ASSERT_OK(dbfull()->SetOptions({
203 {"disable_auto_compactions", "false"},
204 }));
205 Flush();
7c673cae
FG
206 dbfull()->TEST_WaitForCompact();
207 ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
208 ASSERT_EQ(3U, int_prop);
7c673cae 209
494da23a
TL
210 // Fill up L0, and then run an (auto) L0->Lmax compaction to raise the base
211 // level to 2.
7c673cae
FG
212 ASSERT_OK(dbfull()->SetOptions({
213 {"disable_auto_compactions", "true"},
214 }));
215 // Write about 650K more.
216 // Each file is about 11KB, with 9KB of data.
217 for (int i = 0; i < 1300; i++) {
218 ASSERT_OK(Put(Key(static_cast<int>(rnd.Uniform(kMaxKey))),
219 RandomString(&rnd, 380)));
220 }
494da23a
TL
221
222 // Make sure that the compaction starts before the last bit of data is
223 // flushed, so that the base level isn't raised to L1.
f67539c2 224 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({
494da23a
TL
225 {"CompactionJob::Run():Start", "DynamicLevelMaxBytesBase2:0"},
226 });
f67539c2 227 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
494da23a 228
7c673cae
FG
229 ASSERT_OK(dbfull()->SetOptions({
230 {"disable_auto_compactions", "false"},
231 }));
494da23a
TL
232
233 TEST_SYNC_POINT("DynamicLevelMaxBytesBase2:0");
7c673cae
FG
234 Flush();
235 dbfull()->TEST_WaitForCompact();
236 ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
237 ASSERT_EQ(2U, int_prop);
f67539c2
TL
238 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
239 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
7c673cae 240
494da23a
TL
241 // Write more data until the base level changes to L1. There will be
242 // a manual compaction going on at the same time.
f67539c2 243 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({
494da23a
TL
244 {"CompactionJob::Run():Start", "DynamicLevelMaxBytesBase2:1"},
245 {"DynamicLevelMaxBytesBase2:2", "CompactionJob::Run():End"},
7c673cae
FG
246 {"DynamicLevelMaxBytesBase2:compact_range_finish",
247 "FlushJob::WriteLevel0Table"},
248 });
f67539c2 249 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
7c673cae 250
f67539c2 251 ROCKSDB_NAMESPACE::port::Thread thread([this] {
7c673cae
FG
252 TEST_SYNC_POINT("DynamicLevelMaxBytesBase2:compact_range_start");
253 ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
254 TEST_SYNC_POINT("DynamicLevelMaxBytesBase2:compact_range_finish");
255 });
256
494da23a 257 TEST_SYNC_POINT("DynamicLevelMaxBytesBase2:1");
7c673cae
FG
258 for (int i = 0; i < 2; i++) {
259 ASSERT_OK(Put(Key(static_cast<int>(rnd.Uniform(kMaxKey))),
260 RandomString(&rnd, 380)));
261 }
494da23a 262 TEST_SYNC_POINT("DynamicLevelMaxBytesBase2:2");
7c673cae
FG
263
264 Flush();
265
266 thread.join();
267
f67539c2
TL
268 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
269 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
7c673cae
FG
270
271 ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
272 ASSERT_EQ(1U, int_prop);
273}
274
275// Test specific cases in dynamic max bytes
276TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesCompactRange) {
277 Random rnd(301);
278 int kMaxKey = 1000000;
279
280 Options options = CurrentOptions();
281 options.create_if_missing = true;
7c673cae
FG
282 options.write_buffer_size = 2048;
283 options.max_write_buffer_number = 2;
284 options.level0_file_num_compaction_trigger = 2;
285 options.level0_slowdown_writes_trigger = 9999;
286 options.level0_stop_writes_trigger = 9999;
287 options.target_file_size_base = 2;
288 options.level_compaction_dynamic_level_bytes = true;
289 options.max_bytes_for_level_base = 10240;
290 options.max_bytes_for_level_multiplier = 4;
291 options.max_background_compactions = 1;
292 const int kNumLevels = 5;
293 options.num_levels = kNumLevels;
294 options.max_compaction_bytes = 1; // Force not expanding in compactions
295 BlockBasedTableOptions table_options;
296 table_options.block_size = 1024;
297 options.table_factory.reset(NewBlockBasedTableFactory(table_options));
298
299 DestroyAndReopen(options);
300
301 // Compact against empty DB
302 dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
303
304 uint64_t int_prop;
305 std::string str_prop;
306
307 // Initial base level is the last level
308 ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
309 ASSERT_EQ(4U, int_prop);
310
311 // Put about 7K to L0
312 for (int i = 0; i < 140; i++) {
313 ASSERT_OK(Put(Key(static_cast<int>(rnd.Uniform(kMaxKey))),
314 RandomString(&rnd, 80)));
315 }
316 Flush();
317 dbfull()->TEST_WaitForCompact();
318 if (NumTableFilesAtLevel(0) == 0) {
319 // Make sure level 0 is not empty
320 ASSERT_OK(Put(Key(static_cast<int>(rnd.Uniform(kMaxKey))),
321 RandomString(&rnd, 80)));
322 Flush();
323 }
324
325 ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
326 ASSERT_EQ(3U, int_prop);
327 ASSERT_TRUE(db_->GetProperty("rocksdb.num-files-at-level1", &str_prop));
328 ASSERT_EQ("0", str_prop);
329 ASSERT_TRUE(db_->GetProperty("rocksdb.num-files-at-level2", &str_prop));
330 ASSERT_EQ("0", str_prop);
331
f67539c2
TL
332 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
333 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
7c673cae
FG
334
335 std::set<int> output_levels;
f67539c2 336 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
7c673cae
FG
337 "CompactionPicker::CompactRange:Return", [&](void* arg) {
338 Compaction* compaction = reinterpret_cast<Compaction*>(arg);
339 output_levels.insert(compaction->output_level());
340 });
f67539c2 341 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
7c673cae
FG
342
343 dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
344 ASSERT_EQ(output_levels.size(), 2);
345 ASSERT_TRUE(output_levels.find(3) != output_levels.end());
346 ASSERT_TRUE(output_levels.find(4) != output_levels.end());
347 ASSERT_TRUE(db_->GetProperty("rocksdb.num-files-at-level0", &str_prop));
348 ASSERT_EQ("0", str_prop);
349 ASSERT_TRUE(db_->GetProperty("rocksdb.num-files-at-level3", &str_prop));
350 ASSERT_EQ("0", str_prop);
351 // Base level is still level 3.
352 ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
353 ASSERT_EQ(3U, int_prop);
354}
355
356TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBaseInc) {
357 Options options = CurrentOptions();
358 options.create_if_missing = true;
7c673cae
FG
359 options.write_buffer_size = 2048;
360 options.max_write_buffer_number = 2;
361 options.level0_file_num_compaction_trigger = 2;
362 options.level0_slowdown_writes_trigger = 2;
363 options.level0_stop_writes_trigger = 2;
364 options.target_file_size_base = 2048;
365 options.level_compaction_dynamic_level_bytes = true;
366 options.max_bytes_for_level_base = 10240;
367 options.max_bytes_for_level_multiplier = 4;
368 options.soft_rate_limit = 1.1;
369 options.max_background_compactions = 2;
370 options.num_levels = 5;
11fdf7f2 371 options.max_compaction_bytes = 100000000;
7c673cae
FG
372
373 DestroyAndReopen(options);
374
375 int non_trivial = 0;
f67539c2 376 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
7c673cae 377 "DBImpl::BackgroundCompaction:NonTrivial",
11fdf7f2 378 [&](void* /*arg*/) { non_trivial++; });
f67539c2 379 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
7c673cae
FG
380
381 Random rnd(301);
382 const int total_keys = 3000;
383 const int random_part_size = 100;
384 for (int i = 0; i < total_keys; i++) {
385 std::string value = RandomString(&rnd, random_part_size);
386 PutFixed32(&value, static_cast<uint32_t>(i));
387 ASSERT_OK(Put(Key(i), value));
388 }
389 Flush();
390 dbfull()->TEST_WaitForCompact();
f67539c2 391 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
7c673cae
FG
392
393 ASSERT_EQ(non_trivial, 0);
394
395 for (int i = 0; i < total_keys; i++) {
396 std::string value = Get(Key(i));
397 ASSERT_EQ(DecodeFixed32(value.c_str() + random_part_size),
398 static_cast<uint32_t>(i));
399 }
400
401 env_->SetBackgroundThreads(1, Env::LOW);
402 env_->SetBackgroundThreads(1, Env::HIGH);
403}
404
405TEST_F(DBTestDynamicLevel, DISABLED_MigrateToDynamicLevelMaxBytesBase) {
406 Random rnd(301);
407 const int kMaxKey = 2000;
408
409 Options options;
410 options.create_if_missing = true;
7c673cae
FG
411 options.write_buffer_size = 2048;
412 options.max_write_buffer_number = 8;
413 options.level0_file_num_compaction_trigger = 4;
414 options.level0_slowdown_writes_trigger = 4;
415 options.level0_stop_writes_trigger = 8;
416 options.target_file_size_base = 2048;
417 options.level_compaction_dynamic_level_bytes = false;
418 options.max_bytes_for_level_base = 10240;
419 options.max_bytes_for_level_multiplier = 4;
420 options.soft_rate_limit = 1.1;
421 options.num_levels = 8;
422
423 DestroyAndReopen(options);
424
425 auto verify_func = [&](int num_keys, bool if_sleep) {
426 for (int i = 0; i < num_keys; i++) {
427 ASSERT_NE("NOT_FOUND", Get(Key(kMaxKey + i)));
428 if (i < num_keys / 10) {
429 ASSERT_EQ("NOT_FOUND", Get(Key(i)));
430 } else {
431 ASSERT_NE("NOT_FOUND", Get(Key(i)));
432 }
433 if (if_sleep && i % 1000 == 0) {
434 // Without it, valgrind may choose not to give another
435 // thread a chance to run before finishing the function,
436 // causing the test to be extremely slow.
437 env_->SleepForMicroseconds(1);
438 }
439 }
440 };
441
442 int total_keys = 1000;
443 for (int i = 0; i < total_keys; i++) {
444 ASSERT_OK(Put(Key(i), RandomString(&rnd, 102)));
445 ASSERT_OK(Put(Key(kMaxKey + i), RandomString(&rnd, 102)));
446 ASSERT_OK(Delete(Key(i / 10)));
447 }
448 verify_func(total_keys, false);
449 dbfull()->TEST_WaitForCompact();
450
451 options.level_compaction_dynamic_level_bytes = true;
452 options.disable_auto_compactions = true;
453 Reopen(options);
454 verify_func(total_keys, false);
455
456 std::atomic_bool compaction_finished;
457 compaction_finished = false;
458 // Issue manual compaction in one thread and still verify DB state
459 // in main thread.
f67539c2 460 ROCKSDB_NAMESPACE::port::Thread t([&]() {
7c673cae
FG
461 CompactRangeOptions compact_options;
462 compact_options.change_level = true;
463 compact_options.target_level = options.num_levels - 1;
464 dbfull()->CompactRange(compact_options, nullptr, nullptr);
465 compaction_finished.store(true);
466 });
467 do {
468 verify_func(total_keys, true);
469 } while (!compaction_finished.load());
470 t.join();
471
472 ASSERT_OK(dbfull()->SetOptions({
473 {"disable_auto_compactions", "false"},
474 }));
475
476 int total_keys2 = 2000;
477 for (int i = total_keys; i < total_keys2; i++) {
478 ASSERT_OK(Put(Key(i), RandomString(&rnd, 102)));
479 ASSERT_OK(Put(Key(kMaxKey + i), RandomString(&rnd, 102)));
480 ASSERT_OK(Delete(Key(i / 10)));
481 }
482
483 verify_func(total_keys2, false);
484 dbfull()->TEST_WaitForCompact();
485 verify_func(total_keys2, false);
486
487 // Base level is not level 1
488 ASSERT_EQ(NumTableFilesAtLevel(1), 0);
489 ASSERT_EQ(NumTableFilesAtLevel(2), 0);
490}
f67539c2 491} // namespace ROCKSDB_NAMESPACE
7c673cae
FG
492
493#endif // !defined(ROCKSDB_LITE)
494
495int main(int argc, char** argv) {
496#if !defined(ROCKSDB_LITE)
f67539c2 497 ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
7c673cae
FG
498 ::testing::InitGoogleTest(&argc, argv);
499 return RUN_ALL_TESTS();
500#else
11fdf7f2
TL
501 (void) argc;
502 (void) argv;
7c673cae
FG
503 return 0;
504#endif
505}