db_options_test.cc 29 KB

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