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