]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/db/db_options_test.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rocksdb / db / db_options_test.cc
1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
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).
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 #include <limits>
10 #include <string>
11 #include <unordered_map>
12
13 #include "db/column_family.h"
14 #include "db/db_impl.h"
15 #include "db/db_test_util.h"
16 #include "options/options_helper.h"
17 #include "port/stack_trace.h"
18 #include "rocksdb/cache.h"
19 #include "rocksdb/convenience.h"
20 #include "rocksdb/rate_limiter.h"
21 #include "util/random.h"
22 #include "util/sync_point.h"
23 #include "util/testutil.h"
24
25 namespace rocksdb {
26
27 class DBOptionsTest : public DBTestBase {
28 public:
29 DBOptionsTest() : DBTestBase("/db_options_test") {}
30
31 #ifndef ROCKSDB_LITE
32 std::unordered_map<std::string, std::string> GetMutableDBOptionsMap(
33 const DBOptions& options) {
34 std::string options_str;
35 GetStringFromDBOptions(&options_str, options);
36 std::unordered_map<std::string, std::string> options_map;
37 StringToMap(options_str, &options_map);
38 std::unordered_map<std::string, std::string> mutable_map;
39 for (const auto opt : db_options_type_info) {
40 if (opt.second.is_mutable &&
41 opt.second.verification != OptionVerificationType::kDeprecated) {
42 mutable_map[opt.first] = options_map[opt.first];
43 }
44 }
45 return mutable_map;
46 }
47
48 std::unordered_map<std::string, std::string> GetMutableCFOptionsMap(
49 const ColumnFamilyOptions& options) {
50 std::string options_str;
51 GetStringFromColumnFamilyOptions(&options_str, options);
52 std::unordered_map<std::string, std::string> options_map;
53 StringToMap(options_str, &options_map);
54 std::unordered_map<std::string, std::string> mutable_map;
55 for (const auto opt : cf_options_type_info) {
56 if (opt.second.is_mutable &&
57 opt.second.verification != OptionVerificationType::kDeprecated) {
58 mutable_map[opt.first] = options_map[opt.first];
59 }
60 }
61 return mutable_map;
62 }
63
64 std::unordered_map<std::string, std::string> GetRandomizedMutableCFOptionsMap(
65 Random* rnd) {
66 Options options;
67 options.env = env_;
68 ImmutableDBOptions db_options(options);
69 test::RandomInitCFOptions(&options, rnd);
70 auto sanitized_options = SanitizeOptions(db_options, options);
71 auto opt_map = GetMutableCFOptionsMap(sanitized_options);
72 delete options.compaction_filter;
73 return opt_map;
74 }
75
76 std::unordered_map<std::string, std::string> GetRandomizedMutableDBOptionsMap(
77 Random* rnd) {
78 DBOptions db_options;
79 test::RandomInitDBOptions(&db_options, rnd);
80 auto sanitized_options = SanitizeOptions(dbname_, db_options);
81 return GetMutableDBOptionsMap(sanitized_options);
82 }
83 #endif // ROCKSDB_LITE
84 };
85
86 // RocksDB lite don't support dynamic options.
87 #ifndef ROCKSDB_LITE
88
89 TEST_F(DBOptionsTest, GetLatestDBOptions) {
90 // GetOptions should be able to get latest option changed by SetOptions.
91 Options options;
92 options.create_if_missing = true;
93 options.env = env_;
94 Random rnd(228);
95 Reopen(options);
96 auto new_options = GetRandomizedMutableDBOptionsMap(&rnd);
97 ASSERT_OK(dbfull()->SetDBOptions(new_options));
98 ASSERT_EQ(new_options, GetMutableDBOptionsMap(dbfull()->GetDBOptions()));
99 }
100
101 TEST_F(DBOptionsTest, GetLatestCFOptions) {
102 // GetOptions should be able to get latest option changed by SetOptions.
103 Options options;
104 options.create_if_missing = true;
105 options.env = env_;
106 Random rnd(228);
107 Reopen(options);
108 CreateColumnFamilies({"foo"}, options);
109 ReopenWithColumnFamilies({"default", "foo"}, options);
110 auto options_default = GetRandomizedMutableCFOptionsMap(&rnd);
111 auto options_foo = GetRandomizedMutableCFOptionsMap(&rnd);
112 ASSERT_OK(dbfull()->SetOptions(handles_[0], options_default));
113 ASSERT_OK(dbfull()->SetOptions(handles_[1], options_foo));
114 ASSERT_EQ(options_default,
115 GetMutableCFOptionsMap(dbfull()->GetOptions(handles_[0])));
116 ASSERT_EQ(options_foo,
117 GetMutableCFOptionsMap(dbfull()->GetOptions(handles_[1])));
118 }
119
120 TEST_F(DBOptionsTest, SetBytesPerSync) {
121 const size_t kValueSize = 1024 * 1024; // 1MB
122 Options options;
123 options.create_if_missing = true;
124 options.bytes_per_sync = 1024 * 1024;
125 options.use_direct_reads = false;
126 options.write_buffer_size = 400 * kValueSize;
127 options.disable_auto_compactions = true;
128 options.compression = kNoCompression;
129 options.env = env_;
130 Reopen(options);
131 int counter = 0;
132 int low_bytes_per_sync = 0;
133 int i = 0;
134 const std::string kValue(kValueSize, 'v');
135 ASSERT_EQ(options.bytes_per_sync, dbfull()->GetDBOptions().bytes_per_sync);
136 rocksdb::SyncPoint::GetInstance()->SetCallBack(
137 "WritableFileWriter::RangeSync:0", [&](void* /*arg*/) {
138 counter++;
139 });
140
141 WriteOptions write_opts;
142 // should sync approximately 40MB/1MB ~= 40 times.
143 for (i = 0; i < 40; i++) {
144 Put(Key(i), kValue, write_opts);
145 }
146 rocksdb::SyncPoint::GetInstance()->EnableProcessing();
147 ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
148 rocksdb::SyncPoint::GetInstance()->DisableProcessing();
149 low_bytes_per_sync = counter;
150 ASSERT_GT(low_bytes_per_sync, 35);
151 ASSERT_LT(low_bytes_per_sync, 45);
152
153 counter = 0;
154 // 8388608 = 8 * 1024 * 1024
155 ASSERT_OK(dbfull()->SetDBOptions({{"bytes_per_sync", "8388608"}}));
156 ASSERT_EQ(8388608, dbfull()->GetDBOptions().bytes_per_sync);
157 // should sync approximately 40MB*2/8MB ~= 10 times.
158 // data will be 40*2MB because of previous Puts too.
159 for (i = 0; i < 40; i++) {
160 Put(Key(i), kValue, write_opts);
161 }
162 rocksdb::SyncPoint::GetInstance()->EnableProcessing();
163 ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
164 ASSERT_GT(counter, 5);
165 ASSERT_LT(counter, 15);
166
167 // Redundant assert. But leaving it here just to get the point across that
168 // low_bytes_per_sync > counter.
169 ASSERT_GT(low_bytes_per_sync, counter);
170 }
171
172 TEST_F(DBOptionsTest, SetWalBytesPerSync) {
173 const size_t kValueSize = 1024 * 1024 * 3;
174 Options options;
175 options.create_if_missing = true;
176 options.wal_bytes_per_sync = 512;
177 options.write_buffer_size = 100 * kValueSize;
178 options.disable_auto_compactions = true;
179 options.compression = kNoCompression;
180 options.env = env_;
181 Reopen(options);
182 ASSERT_EQ(512, dbfull()->GetDBOptions().wal_bytes_per_sync);
183 int counter = 0;
184 int low_bytes_per_sync = 0;
185 rocksdb::SyncPoint::GetInstance()->SetCallBack(
186 "WritableFileWriter::RangeSync:0", [&](void* /*arg*/) {
187 counter++;
188 });
189 rocksdb::SyncPoint::GetInstance()->EnableProcessing();
190 const std::string kValue(kValueSize, 'v');
191 int i = 0;
192 for (; i < 10; i++) {
193 Put(Key(i), kValue);
194 }
195 // Do not flush. If we flush here, SwitchWAL will reuse old WAL file since its
196 // empty and will not get the new wal_bytes_per_sync value.
197 low_bytes_per_sync = counter;
198 //5242880 = 1024 * 1024 * 5
199 ASSERT_OK(dbfull()->SetDBOptions({{"wal_bytes_per_sync", "5242880"}}));
200 ASSERT_EQ(5242880, dbfull()->GetDBOptions().wal_bytes_per_sync);
201 counter = 0;
202 i = 0;
203 for (; i < 10; i++) {
204 Put(Key(i), kValue);
205 }
206 ASSERT_GT(counter, 0);
207 ASSERT_GT(low_bytes_per_sync, 0);
208 ASSERT_GT(low_bytes_per_sync, counter);
209 }
210
211 TEST_F(DBOptionsTest, WritableFileMaxBufferSize) {
212 Options options;
213 options.create_if_missing = true;
214 options.writable_file_max_buffer_size = 1024 * 1024;
215 options.level0_file_num_compaction_trigger = 3;
216 options.max_manifest_file_size = 1;
217 options.env = env_;
218 int buffer_size = 1024 * 1024;
219 Reopen(options);
220 ASSERT_EQ(buffer_size,
221 dbfull()->GetDBOptions().writable_file_max_buffer_size);
222
223 std::atomic<int> match_cnt(0);
224 std::atomic<int> unmatch_cnt(0);
225 rocksdb::SyncPoint::GetInstance()->SetCallBack(
226 "WritableFileWriter::WritableFileWriter:0", [&](void* arg) {
227 int value = static_cast<int>(reinterpret_cast<uintptr_t>(arg));
228 if (value == buffer_size) {
229 match_cnt++;
230 } else {
231 unmatch_cnt++;
232 }
233 });
234 rocksdb::SyncPoint::GetInstance()->EnableProcessing();
235 int i = 0;
236 for (; i < 3; i++) {
237 ASSERT_OK(Put("foo", ToString(i)));
238 ASSERT_OK(Put("bar", ToString(i)));
239 Flush();
240 }
241 dbfull()->TEST_WaitForCompact();
242 ASSERT_EQ(unmatch_cnt, 0);
243 ASSERT_GE(match_cnt, 11);
244
245 ASSERT_OK(
246 dbfull()->SetDBOptions({{"writable_file_max_buffer_size", "524288"}}));
247 buffer_size = 512 * 1024;
248 match_cnt = 0;
249 unmatch_cnt = 0; // SetDBOptions() will create a WriteableFileWriter
250
251 ASSERT_EQ(buffer_size,
252 dbfull()->GetDBOptions().writable_file_max_buffer_size);
253 i = 0;
254 for (; i < 3; i++) {
255 ASSERT_OK(Put("foo", ToString(i)));
256 ASSERT_OK(Put("bar", ToString(i)));
257 Flush();
258 }
259 dbfull()->TEST_WaitForCompact();
260 ASSERT_EQ(unmatch_cnt, 0);
261 ASSERT_GE(match_cnt, 11);
262 }
263
264 TEST_F(DBOptionsTest, SetOptionsAndReopen) {
265 Random rnd(1044);
266 auto rand_opts = GetRandomizedMutableCFOptionsMap(&rnd);
267 ASSERT_OK(dbfull()->SetOptions(rand_opts));
268 // Verify if DB can be reopen after setting options.
269 Options options;
270 options.env = env_;
271 ASSERT_OK(TryReopen(options));
272 }
273
274 TEST_F(DBOptionsTest, EnableAutoCompactionAndTriggerStall) {
275 const std::string kValue(1024, 'v');
276 for (int method_type = 0; method_type < 2; method_type++) {
277 for (int option_type = 0; option_type < 4; option_type++) {
278 Options options;
279 options.create_if_missing = true;
280 options.disable_auto_compactions = true;
281 options.write_buffer_size = 1024 * 1024 * 10;
282 options.compression = CompressionType::kNoCompression;
283 options.level0_file_num_compaction_trigger = 1;
284 options.level0_stop_writes_trigger = std::numeric_limits<int>::max();
285 options.level0_slowdown_writes_trigger = std::numeric_limits<int>::max();
286 options.hard_pending_compaction_bytes_limit =
287 std::numeric_limits<uint64_t>::max();
288 options.soft_pending_compaction_bytes_limit =
289 std::numeric_limits<uint64_t>::max();
290 options.env = env_;
291
292 DestroyAndReopen(options);
293 int i = 0;
294 for (; i < 1024; i++) {
295 Put(Key(i), kValue);
296 }
297 Flush();
298 for (; i < 1024 * 2; i++) {
299 Put(Key(i), kValue);
300 }
301 Flush();
302 dbfull()->TEST_WaitForFlushMemTable();
303 ASSERT_EQ(2, NumTableFilesAtLevel(0));
304 uint64_t l0_size = SizeAtLevel(0);
305
306 switch (option_type) {
307 case 0:
308 // test with level0_stop_writes_trigger
309 options.level0_stop_writes_trigger = 2;
310 options.level0_slowdown_writes_trigger = 2;
311 break;
312 case 1:
313 options.level0_slowdown_writes_trigger = 2;
314 break;
315 case 2:
316 options.hard_pending_compaction_bytes_limit = l0_size;
317 options.soft_pending_compaction_bytes_limit = l0_size;
318 break;
319 case 3:
320 options.soft_pending_compaction_bytes_limit = l0_size;
321 break;
322 }
323 Reopen(options);
324 dbfull()->TEST_WaitForCompact();
325 ASSERT_FALSE(dbfull()->TEST_write_controler().IsStopped());
326 ASSERT_FALSE(dbfull()->TEST_write_controler().NeedsDelay());
327
328 SyncPoint::GetInstance()->LoadDependency(
329 {{"DBOptionsTest::EnableAutoCompactionAndTriggerStall:1",
330 "BackgroundCallCompaction:0"},
331 {"DBImpl::BackgroundCompaction():BeforePickCompaction",
332 "DBOptionsTest::EnableAutoCompactionAndTriggerStall:2"},
333 {"DBOptionsTest::EnableAutoCompactionAndTriggerStall:3",
334 "DBImpl::BackgroundCompaction():AfterPickCompaction"}});
335 // Block background compaction.
336 SyncPoint::GetInstance()->EnableProcessing();
337
338 switch (method_type) {
339 case 0:
340 ASSERT_OK(
341 dbfull()->SetOptions({{"disable_auto_compactions", "false"}}));
342 break;
343 case 1:
344 ASSERT_OK(dbfull()->EnableAutoCompaction(
345 {dbfull()->DefaultColumnFamily()}));
346 break;
347 }
348 TEST_SYNC_POINT("DBOptionsTest::EnableAutoCompactionAndTriggerStall:1");
349 // Wait for stall condition recalculate.
350 TEST_SYNC_POINT("DBOptionsTest::EnableAutoCompactionAndTriggerStall:2");
351
352 switch (option_type) {
353 case 0:
354 ASSERT_TRUE(dbfull()->TEST_write_controler().IsStopped());
355 break;
356 case 1:
357 ASSERT_FALSE(dbfull()->TEST_write_controler().IsStopped());
358 ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
359 break;
360 case 2:
361 ASSERT_TRUE(dbfull()->TEST_write_controler().IsStopped());
362 break;
363 case 3:
364 ASSERT_FALSE(dbfull()->TEST_write_controler().IsStopped());
365 ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
366 break;
367 }
368 TEST_SYNC_POINT("DBOptionsTest::EnableAutoCompactionAndTriggerStall:3");
369
370 // Background compaction executed.
371 dbfull()->TEST_WaitForCompact();
372 ASSERT_FALSE(dbfull()->TEST_write_controler().IsStopped());
373 ASSERT_FALSE(dbfull()->TEST_write_controler().NeedsDelay());
374 }
375 }
376 }
377
378 TEST_F(DBOptionsTest, SetOptionsMayTriggerCompaction) {
379 Options options;
380 options.create_if_missing = true;
381 options.level0_file_num_compaction_trigger = 1000;
382 options.env = env_;
383 Reopen(options);
384 for (int i = 0; i < 3; i++) {
385 // Need to insert two keys to avoid trivial move.
386 ASSERT_OK(Put("foo", ToString(i)));
387 ASSERT_OK(Put("bar", ToString(i)));
388 Flush();
389 }
390 ASSERT_EQ("3", FilesPerLevel());
391 ASSERT_OK(
392 dbfull()->SetOptions({{"level0_file_num_compaction_trigger", "3"}}));
393 dbfull()->TEST_WaitForCompact();
394 ASSERT_EQ("0,1", FilesPerLevel());
395 }
396
397 TEST_F(DBOptionsTest, SetBackgroundCompactionThreads) {
398 Options options;
399 options.create_if_missing = true;
400 options.max_background_compactions = 1; // default value
401 options.env = env_;
402 Reopen(options);
403 ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
404 ASSERT_OK(dbfull()->SetDBOptions({{"max_background_compactions", "3"}}));
405 ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
406 auto stop_token = dbfull()->TEST_write_controler().GetStopToken();
407 ASSERT_EQ(3, dbfull()->TEST_BGCompactionsAllowed());
408 }
409
410 TEST_F(DBOptionsTest, SetBackgroundJobs) {
411 Options options;
412 options.create_if_missing = true;
413 options.max_background_jobs = 8;
414 options.env = env_;
415 Reopen(options);
416
417 for (int i = 0; i < 2; ++i) {
418 if (i > 0) {
419 options.max_background_jobs = 12;
420 ASSERT_OK(dbfull()->SetDBOptions(
421 {{"max_background_jobs",
422 std::to_string(options.max_background_jobs)}}));
423 }
424
425 ASSERT_EQ(options.max_background_jobs / 4,
426 dbfull()->TEST_BGFlushesAllowed());
427 ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
428
429 auto stop_token = dbfull()->TEST_write_controler().GetStopToken();
430
431 ASSERT_EQ(options.max_background_jobs / 4,
432 dbfull()->TEST_BGFlushesAllowed());
433 ASSERT_EQ(3 * options.max_background_jobs / 4,
434 dbfull()->TEST_BGCompactionsAllowed());
435 }
436 }
437
438 TEST_F(DBOptionsTest, AvoidFlushDuringShutdown) {
439 Options options;
440 options.create_if_missing = true;
441 options.disable_auto_compactions = true;
442 options.env = env_;
443 WriteOptions write_without_wal;
444 write_without_wal.disableWAL = true;
445
446 ASSERT_FALSE(options.avoid_flush_during_shutdown);
447 DestroyAndReopen(options);
448 ASSERT_OK(Put("foo", "v1", write_without_wal));
449 Reopen(options);
450 ASSERT_EQ("v1", Get("foo"));
451 ASSERT_EQ("1", FilesPerLevel());
452
453 DestroyAndReopen(options);
454 ASSERT_OK(Put("foo", "v2", write_without_wal));
455 ASSERT_OK(dbfull()->SetDBOptions({{"avoid_flush_during_shutdown", "true"}}));
456 Reopen(options);
457 ASSERT_EQ("NOT_FOUND", Get("foo"));
458 ASSERT_EQ("", FilesPerLevel());
459 }
460
461 TEST_F(DBOptionsTest, SetDelayedWriteRateOption) {
462 Options options;
463 options.create_if_missing = true;
464 options.delayed_write_rate = 2 * 1024U * 1024U;
465 options.env = env_;
466 Reopen(options);
467 ASSERT_EQ(2 * 1024U * 1024U, dbfull()->TEST_write_controler().max_delayed_write_rate());
468
469 ASSERT_OK(dbfull()->SetDBOptions({{"delayed_write_rate", "20000"}}));
470 ASSERT_EQ(20000, dbfull()->TEST_write_controler().max_delayed_write_rate());
471 }
472
473 TEST_F(DBOptionsTest, MaxTotalWalSizeChange) {
474 Random rnd(1044);
475 const auto value_size = size_t(1024);
476 std::string value;
477 test::RandomString(&rnd, value_size, &value);
478
479 Options options;
480 options.create_if_missing = true;
481 options.env = env_;
482 CreateColumnFamilies({"1", "2", "3"}, options);
483 ReopenWithColumnFamilies({"default", "1", "2", "3"}, options);
484
485 WriteOptions write_options;
486
487 const int key_count = 100;
488 for (int i = 0; i < key_count; ++i) {
489 for (size_t cf = 0; cf < handles_.size(); ++cf) {
490 ASSERT_OK(Put(static_cast<int>(cf), Key(i), value));
491 }
492 }
493 ASSERT_OK(dbfull()->SetDBOptions({{"max_total_wal_size", "10"}}));
494
495 for (size_t cf = 0; cf < handles_.size(); ++cf) {
496 dbfull()->TEST_WaitForFlushMemTable(handles_[cf]);
497 ASSERT_EQ("1", FilesPerLevel(static_cast<int>(cf)));
498 }
499 }
500
501 TEST_F(DBOptionsTest, SetStatsDumpPeriodSec) {
502 Options options;
503 options.create_if_missing = true;
504 options.stats_dump_period_sec = 5;
505 options.env = env_;
506 Reopen(options);
507 ASSERT_EQ(5, dbfull()->GetDBOptions().stats_dump_period_sec);
508
509 for (int i = 0; i < 20; i++) {
510 int num = rand() % 5000 + 1;
511 ASSERT_OK(dbfull()->SetDBOptions(
512 {{"stats_dump_period_sec", std::to_string(num)}}));
513 ASSERT_EQ(num, dbfull()->GetDBOptions().stats_dump_period_sec);
514 }
515 }
516
517 static void assert_candidate_files_empty(DBImpl* dbfull, const bool empty) {
518 dbfull->TEST_LockMutex();
519 JobContext job_context(0);
520 dbfull->FindObsoleteFiles(&job_context, false);
521 ASSERT_EQ(empty, job_context.full_scan_candidate_files.empty());
522 dbfull->TEST_UnlockMutex();
523 if (job_context.HaveSomethingToDelete()) {
524 // fulfill the contract of FindObsoleteFiles by calling PurgeObsoleteFiles
525 // afterwards; otherwise the test may hang on shutdown
526 dbfull->PurgeObsoleteFiles(job_context);
527 }
528 job_context.Clean();
529 }
530
531 TEST_F(DBOptionsTest, DeleteObsoleteFilesPeriodChange) {
532 SpecialEnv env(env_);
533 env.time_elapse_only_sleep_ = true;
534 Options options;
535 options.env = &env;
536 options.create_if_missing = true;
537 ASSERT_OK(TryReopen(options));
538
539 // Verify that candidate files set is empty when no full scan requested.
540 assert_candidate_files_empty(dbfull(), true);
541
542 ASSERT_OK(
543 dbfull()->SetDBOptions({{"delete_obsolete_files_period_micros", "0"}}));
544
545 // After delete_obsolete_files_period_micros updated to 0, the next call
546 // to FindObsoleteFiles should make a full scan
547 assert_candidate_files_empty(dbfull(), false);
548
549 ASSERT_OK(
550 dbfull()->SetDBOptions({{"delete_obsolete_files_period_micros", "20"}}));
551
552 assert_candidate_files_empty(dbfull(), true);
553
554 env.addon_time_.store(20);
555 assert_candidate_files_empty(dbfull(), true);
556
557 env.addon_time_.store(21);
558 assert_candidate_files_empty(dbfull(), false);
559
560 Close();
561 }
562
563 TEST_F(DBOptionsTest, MaxOpenFilesChange) {
564 SpecialEnv env(env_);
565 Options options;
566 options.env = CurrentOptions().env;
567 options.max_open_files = -1;
568
569 Reopen(options);
570
571 Cache* tc = dbfull()->TEST_table_cache();
572
573 ASSERT_EQ(-1, dbfull()->GetDBOptions().max_open_files);
574 ASSERT_LT(2000, tc->GetCapacity());
575 ASSERT_OK(dbfull()->SetDBOptions({{"max_open_files", "1024"}}));
576 ASSERT_EQ(1024, dbfull()->GetDBOptions().max_open_files);
577 // examine the table cache (actual size should be 1014)
578 ASSERT_GT(1500, tc->GetCapacity());
579 Close();
580 }
581
582 TEST_F(DBOptionsTest, SanitizeDelayedWriteRate) {
583 Options options;
584 options.delayed_write_rate = 0;
585 Reopen(options);
586 ASSERT_EQ(16 * 1024 * 1024, dbfull()->GetDBOptions().delayed_write_rate);
587
588 options.rate_limiter.reset(NewGenericRateLimiter(31 * 1024 * 1024));
589 Reopen(options);
590 ASSERT_EQ(31 * 1024 * 1024, dbfull()->GetDBOptions().delayed_write_rate);
591 }
592
593 TEST_F(DBOptionsTest, SetFIFOCompactionOptions) {
594 Options options;
595 options.compaction_style = kCompactionStyleFIFO;
596 options.write_buffer_size = 10 << 10; // 10KB
597 options.arena_block_size = 4096;
598 options.compression = kNoCompression;
599 options.create_if_missing = true;
600 options.compaction_options_fifo.allow_compaction = false;
601 env_->time_elapse_only_sleep_ = false;
602 options.env = env_;
603
604 // Test dynamically changing compaction_options_fifo.ttl
605 env_->addon_time_.store(0);
606 options.compaction_options_fifo.ttl = 1 * 60 * 60; // 1 hour
607 ASSERT_OK(TryReopen(options));
608
609 Random rnd(301);
610 for (int i = 0; i < 10; i++) {
611 // Generate and flush a file about 10KB.
612 for (int j = 0; j < 10; j++) {
613 ASSERT_OK(Put(ToString(i * 20 + j), RandomString(&rnd, 980)));
614 }
615 Flush();
616 }
617 ASSERT_OK(dbfull()->TEST_WaitForCompact());
618 ASSERT_EQ(NumTableFilesAtLevel(0), 10);
619
620 // Add 61 seconds to the time.
621 env_->addon_time_.fetch_add(61);
622
623 // No files should be compacted as ttl is set to 1 hour.
624 ASSERT_EQ(dbfull()->GetOptions().compaction_options_fifo.ttl, 3600);
625 dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
626 ASSERT_EQ(NumTableFilesAtLevel(0), 10);
627
628 // Set ttl to 1 minute. So all files should get deleted.
629 ASSERT_OK(dbfull()->SetOptions({{"compaction_options_fifo", "{ttl=60;}"}}));
630 ASSERT_EQ(dbfull()->GetOptions().compaction_options_fifo.ttl, 60);
631 dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
632 ASSERT_OK(dbfull()->TEST_WaitForCompact());
633 ASSERT_EQ(NumTableFilesAtLevel(0), 0);
634
635 // Test dynamically changing compaction_options_fifo.max_table_files_size
636 env_->addon_time_.store(0);
637 options.compaction_options_fifo.max_table_files_size = 500 << 10; // 00KB
638 options.compaction_options_fifo.ttl = 0;
639 DestroyAndReopen(options);
640
641 for (int i = 0; i < 10; i++) {
642 // Generate and flush a file about 10KB.
643 for (int j = 0; j < 10; j++) {
644 ASSERT_OK(Put(ToString(i * 20 + j), RandomString(&rnd, 980)));
645 }
646 Flush();
647 }
648 ASSERT_OK(dbfull()->TEST_WaitForCompact());
649 ASSERT_EQ(NumTableFilesAtLevel(0), 10);
650
651 // No files should be compacted as max_table_files_size is set to 500 KB.
652 ASSERT_EQ(dbfull()->GetOptions().compaction_options_fifo.max_table_files_size,
653 500 << 10);
654 dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
655 ASSERT_EQ(NumTableFilesAtLevel(0), 10);
656
657 // Set max_table_files_size to 12 KB. So only 1 file should remain now.
658 ASSERT_OK(dbfull()->SetOptions(
659 {{"compaction_options_fifo", "{max_table_files_size=12288;}"}}));
660 ASSERT_EQ(dbfull()->GetOptions().compaction_options_fifo.max_table_files_size,
661 12 << 10);
662 dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
663 ASSERT_OK(dbfull()->TEST_WaitForCompact());
664 ASSERT_EQ(NumTableFilesAtLevel(0), 1);
665
666 // Test dynamically changing compaction_options_fifo.allow_compaction
667 options.compaction_options_fifo.max_table_files_size = 500 << 10; // 500KB
668 options.compaction_options_fifo.ttl = 0;
669 options.compaction_options_fifo.allow_compaction = false;
670 options.level0_file_num_compaction_trigger = 6;
671 DestroyAndReopen(options);
672
673 for (int i = 0; i < 10; i++) {
674 // Generate and flush a file about 10KB.
675 for (int j = 0; j < 10; j++) {
676 ASSERT_OK(Put(ToString(i * 20 + j), RandomString(&rnd, 980)));
677 }
678 Flush();
679 }
680 ASSERT_OK(dbfull()->TEST_WaitForCompact());
681 ASSERT_EQ(NumTableFilesAtLevel(0), 10);
682
683 // No files should be compacted as max_table_files_size is set to 500 KB and
684 // allow_compaction is false
685 ASSERT_EQ(dbfull()->GetOptions().compaction_options_fifo.allow_compaction,
686 false);
687 dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
688 ASSERT_EQ(NumTableFilesAtLevel(0), 10);
689
690 // Set allow_compaction to true. So number of files should be between 1 and 5.
691 ASSERT_OK(dbfull()->SetOptions(
692 {{"compaction_options_fifo", "{allow_compaction=true;}"}}));
693 ASSERT_EQ(dbfull()->GetOptions().compaction_options_fifo.allow_compaction,
694 true);
695 dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
696 ASSERT_OK(dbfull()->TEST_WaitForCompact());
697 ASSERT_GE(NumTableFilesAtLevel(0), 1);
698 ASSERT_LE(NumTableFilesAtLevel(0), 5);
699 }
700
701 TEST_F(DBOptionsTest, CompactionReadaheadSizeChange) {
702 SpecialEnv env(env_);
703 Options options;
704 options.env = &env;
705
706 options.compaction_readahead_size = 0;
707 options.new_table_reader_for_compaction_inputs = true;
708 options.level0_file_num_compaction_trigger = 2;
709 const std::string kValue(1024, 'v');
710 Reopen(options);
711
712 ASSERT_EQ(0, dbfull()->GetDBOptions().compaction_readahead_size);
713 ASSERT_OK(dbfull()->SetDBOptions({{"compaction_readahead_size", "256"}}));
714 ASSERT_EQ(256, dbfull()->GetDBOptions().compaction_readahead_size);
715 for (int i = 0; i < 1024; i++) {
716 Put(Key(i), kValue);
717 }
718 Flush();
719 for (int i = 0; i < 1024 * 2; i++) {
720 Put(Key(i), kValue);
721 }
722 Flush();
723 dbfull()->TEST_WaitForCompact();
724 ASSERT_EQ(256, env_->compaction_readahead_size_);
725 Close();
726 }
727 #endif // ROCKSDB_LITE
728
729 } // namespace rocksdb
730
731 int main(int argc, char** argv) {
732 rocksdb::port::InstallStackTraceHandler();
733 ::testing::InitGoogleTest(&argc, argv);
734 return RUN_ALL_TESTS();
735 }