db_options_test.cc 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663
  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 "rocksdb/utilities/options_util.h"
  22. #include "test_util/mock_time_env.h"
  23. #include "test_util/sync_point.h"
  24. #include "test_util/testutil.h"
  25. #include "util/random.h"
  26. #include "utilities/fault_injection_fs.h"
  27. namespace ROCKSDB_NAMESPACE {
  28. class DBOptionsTest : public DBTestBase {
  29. public:
  30. DBOptionsTest() : DBTestBase("db_options_test", /*env_do_fsync=*/true) {}
  31. std::unordered_map<std::string, std::string> GetMutableDBOptionsMap(
  32. const DBOptions& options) {
  33. std::string options_str;
  34. std::unordered_map<std::string, std::string> mutable_map;
  35. ConfigOptions config_options(options);
  36. config_options.delimiter = "; ";
  37. EXPECT_OK(GetStringFromMutableDBOptions(
  38. config_options, MutableDBOptions(options), &options_str));
  39. EXPECT_OK(StringToMap(options_str, &mutable_map));
  40. return mutable_map;
  41. }
  42. std::unordered_map<std::string, std::string> GetMutableCFOptionsMap(
  43. const ColumnFamilyOptions& options) {
  44. std::string options_str;
  45. ConfigOptions config_options;
  46. config_options.delimiter = "; ";
  47. std::unordered_map<std::string, std::string> mutable_map;
  48. EXPECT_OK(GetStringFromMutableCFOptions(
  49. config_options, MutableCFOptions(options), &options_str));
  50. EXPECT_OK(StringToMap(options_str, &mutable_map));
  51. for (auto& opt : TEST_GetImmutableInMutableCFOptions()) {
  52. // Not yet mutable but migrated to MutableCFOptions in preparation for
  53. // being mutable
  54. mutable_map.erase(opt);
  55. }
  56. return mutable_map;
  57. }
  58. std::unordered_map<std::string, std::string> GetRandomizedMutableCFOptionsMap(
  59. Random* rnd) {
  60. Options options = CurrentOptions();
  61. options.env = env_;
  62. ImmutableDBOptions db_options(options);
  63. test::RandomInitCFOptions(&options, options, rnd);
  64. auto sanitized_options =
  65. SanitizeCfOptions(db_options, /*read_only*/ false, 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. };
  78. TEST_F(DBOptionsTest, ImmutableTrackAndVerifyWalsInManifest) {
  79. Options options;
  80. options.env = env_;
  81. options.track_and_verify_wals_in_manifest = true;
  82. ImmutableDBOptions db_options(options);
  83. ASSERT_TRUE(db_options.track_and_verify_wals_in_manifest);
  84. Reopen(options);
  85. ASSERT_TRUE(dbfull()->GetDBOptions().track_and_verify_wals_in_manifest);
  86. Status s =
  87. dbfull()->SetDBOptions({{"track_and_verify_wals_in_manifest", "false"}});
  88. ASSERT_FALSE(s.ok());
  89. }
  90. TEST_F(DBOptionsTest, ImmutableVerifySstUniqueIdInManifest) {
  91. Options options;
  92. options.env = env_;
  93. options.verify_sst_unique_id_in_manifest = true;
  94. ImmutableDBOptions db_options(options);
  95. ASSERT_TRUE(db_options.verify_sst_unique_id_in_manifest);
  96. Reopen(options);
  97. ASSERT_TRUE(dbfull()->GetDBOptions().verify_sst_unique_id_in_manifest);
  98. Status s =
  99. dbfull()->SetDBOptions({{"verify_sst_unique_id_in_manifest", "false"}});
  100. ASSERT_FALSE(s.ok());
  101. }
  102. // RocksDB lite don't support dynamic options.
  103. TEST_F(DBOptionsTest, AvoidUpdatingOptions) {
  104. Options options;
  105. options.env = env_;
  106. options.max_background_jobs = 4;
  107. options.delayed_write_rate = 1024;
  108. Reopen(options);
  109. SyncPoint::GetInstance()->DisableProcessing();
  110. SyncPoint::GetInstance()->ClearAllCallBacks();
  111. bool is_changed_stats = false;
  112. SyncPoint::GetInstance()->SetCallBack(
  113. "DBImpl::WriteOptionsFile:PersistOptions", [&](void* /*arg*/) {
  114. ASSERT_FALSE(is_changed_stats); // should only save options file once
  115. is_changed_stats = true;
  116. });
  117. SyncPoint::GetInstance()->EnableProcessing();
  118. // helper function to check the status and reset after each check
  119. auto is_changed = [&] {
  120. bool ret = is_changed_stats;
  121. is_changed_stats = false;
  122. return ret;
  123. };
  124. // without changing the value, but it's sanitized to a different value
  125. ASSERT_OK(dbfull()->SetDBOptions({{"bytes_per_sync", "0"}}));
  126. ASSERT_TRUE(is_changed());
  127. // without changing the value
  128. ASSERT_OK(dbfull()->SetDBOptions({{"max_background_jobs", "4"}}));
  129. ASSERT_FALSE(is_changed());
  130. // changing the value
  131. ASSERT_OK(dbfull()->SetDBOptions({{"bytes_per_sync", "123"}}));
  132. ASSERT_TRUE(is_changed());
  133. // update again
  134. ASSERT_OK(dbfull()->SetDBOptions({{"bytes_per_sync", "123"}}));
  135. ASSERT_FALSE(is_changed());
  136. // without changing a default value
  137. ASSERT_OK(dbfull()->SetDBOptions({{"strict_bytes_per_sync", "false"}}));
  138. ASSERT_FALSE(is_changed());
  139. // now change
  140. ASSERT_OK(dbfull()->SetDBOptions({{"strict_bytes_per_sync", "true"}}));
  141. ASSERT_TRUE(is_changed());
  142. // multiple values without change
  143. ASSERT_OK(dbfull()->SetDBOptions(
  144. {{"max_total_wal_size", "0"}, {"stats_dump_period_sec", "600"}}));
  145. ASSERT_FALSE(is_changed());
  146. // multiple values with change
  147. ASSERT_OK(dbfull()->SetDBOptions(
  148. {{"max_open_files", "100"}, {"stats_dump_period_sec", "600"}}));
  149. ASSERT_TRUE(is_changed());
  150. }
  151. TEST_F(DBOptionsTest, GetLatestDBOptions) {
  152. // GetOptions should be able to get latest option changed by SetOptions.
  153. Options options;
  154. options.create_if_missing = true;
  155. options.env = env_;
  156. Random rnd(228);
  157. Reopen(options);
  158. auto new_options = GetRandomizedMutableDBOptionsMap(&rnd);
  159. ASSERT_OK(dbfull()->SetDBOptions(new_options));
  160. ASSERT_EQ(new_options, GetMutableDBOptionsMap(dbfull()->GetDBOptions()));
  161. }
  162. TEST_F(DBOptionsTest, GetLatestCFOptions) {
  163. // GetOptions should be able to get latest option changed by SetOptions.
  164. Options options;
  165. options.create_if_missing = true;
  166. options.env = env_;
  167. Random rnd(228);
  168. Reopen(options);
  169. CreateColumnFamilies({"foo"}, options);
  170. ReopenWithColumnFamilies({"default", "foo"}, options);
  171. auto options_default = GetRandomizedMutableCFOptionsMap(&rnd);
  172. auto options_foo = GetRandomizedMutableCFOptionsMap(&rnd);
  173. ASSERT_OK(dbfull()->SetOptions(handles_[0], options_default));
  174. ASSERT_OK(dbfull()->SetOptions(handles_[1], options_foo));
  175. ASSERT_EQ(options_default,
  176. GetMutableCFOptionsMap(dbfull()->GetOptions(handles_[0])));
  177. ASSERT_EQ(options_foo,
  178. GetMutableCFOptionsMap(dbfull()->GetOptions(handles_[1])));
  179. }
  180. TEST_F(DBOptionsTest, SetMutableTableOptions) {
  181. Options options;
  182. options.create_if_missing = true;
  183. options.env = env_;
  184. options.blob_file_size = 16384;
  185. BlockBasedTableOptions bbto;
  186. bbto.no_block_cache = true;
  187. bbto.block_size = 8192;
  188. bbto.block_restart_interval = 7;
  189. options.table_factory.reset(NewBlockBasedTableFactory(bbto));
  190. Reopen(options);
  191. ColumnFamilyHandle* cfh = dbfull()->DefaultColumnFamily();
  192. Options c_opts = dbfull()->GetOptions(cfh);
  193. const auto* c_bbto =
  194. c_opts.table_factory->GetOptions<BlockBasedTableOptions>();
  195. ASSERT_NE(c_bbto, nullptr);
  196. ASSERT_EQ(c_opts.blob_file_size, 16384);
  197. ASSERT_EQ(c_bbto->no_block_cache, true);
  198. ASSERT_EQ(c_bbto->block_size, 8192);
  199. ASSERT_EQ(c_bbto->block_restart_interval, 7);
  200. ASSERT_OK(dbfull()->SetOptions(
  201. cfh, {{"table_factory.block_size", "16384"},
  202. {"table_factory.block_restart_interval", "11"}}));
  203. // Old c_bbto
  204. ASSERT_EQ(c_bbto->block_size, 8192);
  205. ASSERT_EQ(c_bbto->block_restart_interval, 7);
  206. // New c_bbto
  207. c_opts = dbfull()->GetOptions(cfh);
  208. c_bbto = c_opts.table_factory->GetOptions<BlockBasedTableOptions>();
  209. ASSERT_EQ(c_bbto->block_size, 16384);
  210. ASSERT_EQ(c_bbto->block_restart_interval, 11);
  211. // Now set an option that is not mutable - options should not change
  212. // FIXME: find a way to make this fail again
  213. // ASSERT_NOK(
  214. // dbfull()->SetOptions(cfh, {{"table_factory.no_block_cache", "false"}}));
  215. c_opts = dbfull()->GetOptions(cfh);
  216. ASSERT_EQ(c_bbto, c_opts.table_factory->GetOptions<BlockBasedTableOptions>());
  217. ASSERT_EQ(c_bbto->no_block_cache, true);
  218. ASSERT_EQ(c_bbto->block_size, 16384);
  219. ASSERT_EQ(c_bbto->block_restart_interval, 11);
  220. // Set some that are mutable and some that are not - options should not change
  221. // FIXME: find a way to make this fail again
  222. // ASSERT_NOK(dbfull()->SetOptions(
  223. // cfh, {{"table_factory.no_block_cache", "false"},
  224. // {"table_factory.block_size", "8192"},
  225. // {"table_factory.block_restart_interval", "7"}}));
  226. c_opts = dbfull()->GetOptions(cfh);
  227. ASSERT_EQ(c_bbto, c_opts.table_factory->GetOptions<BlockBasedTableOptions>());
  228. ASSERT_EQ(c_bbto->no_block_cache, true);
  229. ASSERT_EQ(c_bbto->block_size, 16384);
  230. ASSERT_EQ(c_bbto->block_restart_interval, 11);
  231. // Set some that are mutable and some that do not exist - options should not
  232. // change
  233. ASSERT_NOK(dbfull()->SetOptions(
  234. cfh, {{"table_factory.block_size", "8192"},
  235. {"table_factory.does_not_exist", "true"},
  236. {"table_factory.block_restart_interval", "7"}}));
  237. c_opts = dbfull()->GetOptions(cfh);
  238. ASSERT_EQ(c_bbto, c_opts.table_factory->GetOptions<BlockBasedTableOptions>());
  239. ASSERT_EQ(c_bbto->no_block_cache, true);
  240. ASSERT_EQ(c_bbto->block_size, 16384);
  241. ASSERT_EQ(c_bbto->block_restart_interval, 11);
  242. // Trying to change the table factory fails
  243. ASSERT_NOK(dbfull()->SetOptions(
  244. cfh, {{"table_factory", TableFactory::kPlainTableName()}}));
  245. // Set some on the table and some on the Column Family
  246. ASSERT_OK(dbfull()->SetOptions(
  247. cfh, {{"table_factory.block_size", "16384"},
  248. {"blob_file_size", "32768"},
  249. {"table_factory.block_restart_interval", "13"}}));
  250. c_opts = dbfull()->GetOptions(cfh);
  251. ASSERT_EQ(c_opts.blob_file_size, 32768);
  252. c_bbto = c_opts.table_factory->GetOptions<BlockBasedTableOptions>();
  253. ASSERT_EQ(c_bbto->block_size, 16384);
  254. ASSERT_EQ(c_bbto->block_restart_interval, 13);
  255. // Set some on the table and a bad one on the ColumnFamily - options should
  256. // not change
  257. ASSERT_NOK(dbfull()->SetOptions(
  258. cfh, {{"table_factory.block_size", "1024"},
  259. {"no_such_option", "32768"},
  260. {"table_factory.block_restart_interval", "7"}}));
  261. ASSERT_EQ(c_bbto, c_opts.table_factory->GetOptions<BlockBasedTableOptions>());
  262. ASSERT_EQ(c_bbto->block_size, 16384);
  263. ASSERT_EQ(c_bbto->block_restart_interval, 13);
  264. }
  265. TEST_F(DBOptionsTest, SetWithCustomMemTableFactory) {
  266. class DummySkipListFactory : public SkipListFactory {
  267. public:
  268. static const char* kClassName() { return "DummySkipListFactory"; }
  269. const char* Name() const override { return kClassName(); }
  270. explicit DummySkipListFactory() : SkipListFactory(2) {}
  271. };
  272. {
  273. // Verify the DummySkipList cannot be created
  274. ConfigOptions config_options;
  275. config_options.ignore_unsupported_options = false;
  276. std::unique_ptr<MemTableRepFactory> factory;
  277. ASSERT_NOK(MemTableRepFactory::CreateFromString(
  278. config_options, DummySkipListFactory::kClassName(), &factory));
  279. }
  280. Options options;
  281. options.create_if_missing = true;
  282. options.env = env_;
  283. options.disable_auto_compactions = false;
  284. options.memtable_factory.reset(new DummySkipListFactory());
  285. Reopen(options);
  286. ColumnFamilyHandle* cfh = dbfull()->DefaultColumnFamily();
  287. ASSERT_OK(dbfull()->SetOptions(cfh, {{"disable_auto_compactions", "true"}}));
  288. ColumnFamilyDescriptor cfd;
  289. ASSERT_OK(cfh->GetDescriptor(&cfd));
  290. ASSERT_STREQ(cfd.options.memtable_factory->Name(),
  291. DummySkipListFactory::kClassName());
  292. ColumnFamilyHandle* test = nullptr;
  293. ASSERT_OK(dbfull()->CreateColumnFamily(options, "test", &test));
  294. ASSERT_OK(test->GetDescriptor(&cfd));
  295. ASSERT_STREQ(cfd.options.memtable_factory->Name(),
  296. DummySkipListFactory::kClassName());
  297. ASSERT_OK(dbfull()->DropColumnFamily(test));
  298. delete test;
  299. }
  300. TEST_F(DBOptionsTest, SetBytesPerSync) {
  301. const size_t kValueSize = 1024 * 1024; // 1MB
  302. Options options;
  303. options.create_if_missing = true;
  304. options.bytes_per_sync = 1024 * 1024;
  305. options.use_direct_reads = false;
  306. options.write_buffer_size = 400 * kValueSize;
  307. options.disable_auto_compactions = true;
  308. options.compression = kNoCompression;
  309. options.env = env_;
  310. Reopen(options);
  311. int counter = 0;
  312. int low_bytes_per_sync = 0;
  313. int i = 0;
  314. const std::string kValue(kValueSize, 'v');
  315. ASSERT_EQ(options.bytes_per_sync, dbfull()->GetDBOptions().bytes_per_sync);
  316. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
  317. "WritableFileWriter::RangeSync:0", [&](void* /*arg*/) { counter++; });
  318. WriteOptions write_opts;
  319. // should sync approximately 40MB/1MB ~= 40 times.
  320. for (i = 0; i < 40; i++) {
  321. ASSERT_OK(Put(Key(i), kValue, write_opts));
  322. }
  323. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  324. ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
  325. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
  326. low_bytes_per_sync = counter;
  327. ASSERT_GT(low_bytes_per_sync, 35);
  328. ASSERT_LT(low_bytes_per_sync, 45);
  329. counter = 0;
  330. // 8388608 = 8 * 1024 * 1024
  331. ASSERT_OK(dbfull()->SetDBOptions({{"bytes_per_sync", "8388608"}}));
  332. ASSERT_EQ(8388608, dbfull()->GetDBOptions().bytes_per_sync);
  333. // should sync approximately 40MB*2/8MB ~= 10 times.
  334. // data will be 40*2MB because of previous Puts too.
  335. for (i = 0; i < 40; i++) {
  336. ASSERT_OK(Put(Key(i), kValue, write_opts));
  337. }
  338. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  339. ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
  340. ASSERT_GT(counter, 5);
  341. ASSERT_LT(counter, 15);
  342. // Redundant assert. But leaving it here just to get the point across that
  343. // low_bytes_per_sync > counter.
  344. ASSERT_GT(low_bytes_per_sync, counter);
  345. }
  346. TEST_F(DBOptionsTest, SetWalBytesPerSync) {
  347. const size_t kValueSize = 1024 * 1024 * 3;
  348. Options options;
  349. options.create_if_missing = true;
  350. options.wal_bytes_per_sync = 512;
  351. options.write_buffer_size = 100 * kValueSize;
  352. options.disable_auto_compactions = true;
  353. options.compression = kNoCompression;
  354. options.env = env_;
  355. Reopen(options);
  356. ASSERT_EQ(512, dbfull()->GetDBOptions().wal_bytes_per_sync);
  357. std::atomic_int counter{0};
  358. int low_bytes_per_sync = 0;
  359. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
  360. "WritableFileWriter::RangeSync:0",
  361. [&](void* /*arg*/) { counter.fetch_add(1); });
  362. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  363. const std::string kValue(kValueSize, 'v');
  364. int i = 0;
  365. for (; i < 10; i++) {
  366. ASSERT_OK(Put(Key(i), kValue));
  367. }
  368. // Do not flush. If we flush here, SwitchWAL will reuse old WAL file since its
  369. // empty and will not get the new wal_bytes_per_sync value.
  370. low_bytes_per_sync = counter;
  371. // 5242880 = 1024 * 1024 * 5
  372. ASSERT_OK(dbfull()->SetDBOptions({{"wal_bytes_per_sync", "5242880"}}));
  373. ASSERT_EQ(5242880, dbfull()->GetDBOptions().wal_bytes_per_sync);
  374. counter = 0;
  375. i = 0;
  376. for (; i < 10; i++) {
  377. ASSERT_OK(Put(Key(i), kValue));
  378. }
  379. ASSERT_GT(counter, 0);
  380. ASSERT_GT(low_bytes_per_sync, 0);
  381. ASSERT_GT(low_bytes_per_sync, counter);
  382. }
  383. TEST_F(DBOptionsTest, WritableFileMaxBufferSize) {
  384. Options options;
  385. options.create_if_missing = true;
  386. options.writable_file_max_buffer_size = 1024 * 1024;
  387. options.level0_file_num_compaction_trigger = 3;
  388. options.max_manifest_file_size = 1;
  389. options.env = env_;
  390. int buffer_size = 1024 * 1024;
  391. Reopen(options);
  392. ASSERT_EQ(buffer_size,
  393. dbfull()->GetDBOptions().writable_file_max_buffer_size);
  394. std::atomic<int> match_cnt(0);
  395. std::atomic<int> unmatch_cnt(0);
  396. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
  397. "WritableFileWriter::WritableFileWriter:0", [&](void* arg) {
  398. int value = static_cast<int>(reinterpret_cast<uintptr_t>(arg));
  399. if (value == buffer_size) {
  400. match_cnt++;
  401. } else {
  402. unmatch_cnt++;
  403. }
  404. });
  405. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  406. int i = 0;
  407. for (; i < 3; i++) {
  408. ASSERT_OK(Put("foo", std::to_string(i)));
  409. ASSERT_OK(Put("bar", std::to_string(i)));
  410. ASSERT_OK(Flush());
  411. }
  412. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  413. ASSERT_EQ(unmatch_cnt, 0);
  414. ASSERT_GE(match_cnt, 11);
  415. ASSERT_OK(
  416. dbfull()->SetDBOptions({{"writable_file_max_buffer_size", "524288"}}));
  417. buffer_size = 512 * 1024;
  418. match_cnt = 0;
  419. unmatch_cnt = 0; // SetDBOptions() will create a WritableFileWriter
  420. ASSERT_EQ(buffer_size,
  421. dbfull()->GetDBOptions().writable_file_max_buffer_size);
  422. i = 0;
  423. for (; i < 3; i++) {
  424. ASSERT_OK(Put("foo", std::to_string(i)));
  425. ASSERT_OK(Put("bar", std::to_string(i)));
  426. ASSERT_OK(Flush());
  427. }
  428. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  429. ASSERT_EQ(unmatch_cnt, 0);
  430. ASSERT_GE(match_cnt, 11);
  431. }
  432. TEST_F(DBOptionsTest, SetOptionsAndReopen) {
  433. Random rnd(1044);
  434. auto rand_opts = GetRandomizedMutableCFOptionsMap(&rnd);
  435. ASSERT_OK(dbfull()->SetOptions(rand_opts));
  436. // Verify if DB can be reopen after setting options.
  437. Options options;
  438. options.env = env_;
  439. ASSERT_OK(TryReopen(options));
  440. }
  441. TEST_F(DBOptionsTest, EnableAutoCompactionAndTriggerStall) {
  442. const std::string kValue(1024, 'v');
  443. for (int method_type = 0; method_type < 2; method_type++) {
  444. for (int option_type = 0; option_type < 4; option_type++) {
  445. Options options;
  446. options.create_if_missing = true;
  447. options.disable_auto_compactions = true;
  448. options.write_buffer_size = 1024 * 1024 * 10;
  449. options.compression = CompressionType::kNoCompression;
  450. options.level0_file_num_compaction_trigger = 1;
  451. options.level0_stop_writes_trigger = std::numeric_limits<int>::max();
  452. options.level0_slowdown_writes_trigger = std::numeric_limits<int>::max();
  453. options.hard_pending_compaction_bytes_limit =
  454. std::numeric_limits<uint64_t>::max();
  455. options.soft_pending_compaction_bytes_limit =
  456. std::numeric_limits<uint64_t>::max();
  457. options.env = env_;
  458. DestroyAndReopen(options);
  459. int i = 0;
  460. for (; i < 1024; i++) {
  461. ASSERT_OK(Put(Key(i), kValue));
  462. }
  463. ASSERT_OK(Flush());
  464. for (; i < 1024 * 2; i++) {
  465. ASSERT_OK(Put(Key(i), kValue));
  466. }
  467. ASSERT_OK(Flush());
  468. ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
  469. ASSERT_EQ(2, NumTableFilesAtLevel(0));
  470. uint64_t l0_size = SizeAtLevel(0);
  471. switch (option_type) {
  472. case 0:
  473. // test with level0_stop_writes_trigger
  474. options.level0_stop_writes_trigger = 2;
  475. options.level0_slowdown_writes_trigger = 2;
  476. break;
  477. case 1:
  478. options.level0_slowdown_writes_trigger = 2;
  479. break;
  480. case 2:
  481. options.hard_pending_compaction_bytes_limit = l0_size;
  482. options.soft_pending_compaction_bytes_limit = l0_size;
  483. break;
  484. case 3:
  485. options.soft_pending_compaction_bytes_limit = l0_size;
  486. break;
  487. }
  488. Reopen(options);
  489. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  490. ASSERT_FALSE(dbfull()->TEST_write_controler().IsStopped());
  491. ASSERT_FALSE(dbfull()->TEST_write_controler().NeedsDelay());
  492. SyncPoint::GetInstance()->LoadDependency(
  493. {{"DBOptionsTest::EnableAutoCompactionAndTriggerStall:1",
  494. "BackgroundCallCompaction:0"},
  495. {"DBImpl::BackgroundCompaction():BeforePickCompaction",
  496. "DBOptionsTest::EnableAutoCompactionAndTriggerStall:2"},
  497. {"DBOptionsTest::EnableAutoCompactionAndTriggerStall:3",
  498. "DBImpl::BackgroundCompaction():AfterPickCompaction"}});
  499. // Block background compaction.
  500. SyncPoint::GetInstance()->EnableProcessing();
  501. switch (method_type) {
  502. case 0:
  503. ASSERT_OK(
  504. dbfull()->SetOptions({{"disable_auto_compactions", "false"}}));
  505. break;
  506. case 1:
  507. ASSERT_OK(dbfull()->EnableAutoCompaction(
  508. {dbfull()->DefaultColumnFamily()}));
  509. break;
  510. }
  511. TEST_SYNC_POINT("DBOptionsTest::EnableAutoCompactionAndTriggerStall:1");
  512. // Wait for stall condition recalculate.
  513. TEST_SYNC_POINT("DBOptionsTest::EnableAutoCompactionAndTriggerStall:2");
  514. switch (option_type) {
  515. case 0:
  516. ASSERT_TRUE(dbfull()->TEST_write_controler().IsStopped());
  517. break;
  518. case 1:
  519. ASSERT_FALSE(dbfull()->TEST_write_controler().IsStopped());
  520. ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
  521. break;
  522. case 2:
  523. ASSERT_TRUE(dbfull()->TEST_write_controler().IsStopped());
  524. break;
  525. case 3:
  526. ASSERT_FALSE(dbfull()->TEST_write_controler().IsStopped());
  527. ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
  528. break;
  529. }
  530. TEST_SYNC_POINT("DBOptionsTest::EnableAutoCompactionAndTriggerStall:3");
  531. // Background compaction executed.
  532. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  533. ASSERT_FALSE(dbfull()->TEST_write_controler().IsStopped());
  534. ASSERT_FALSE(dbfull()->TEST_write_controler().NeedsDelay());
  535. }
  536. }
  537. }
  538. TEST_F(DBOptionsTest, SetOptionsMayTriggerCompaction) {
  539. Options options;
  540. options.level_compaction_dynamic_level_bytes = false;
  541. options.create_if_missing = true;
  542. options.level0_file_num_compaction_trigger = 1000;
  543. options.env = env_;
  544. Reopen(options);
  545. for (int i = 0; i < 3; i++) {
  546. // Need to insert two keys to avoid trivial move.
  547. ASSERT_OK(Put("foo", std::to_string(i)));
  548. ASSERT_OK(Put("bar", std::to_string(i)));
  549. ASSERT_OK(Flush());
  550. }
  551. ASSERT_EQ("3", FilesPerLevel());
  552. ASSERT_OK(
  553. dbfull()->SetOptions({{"level0_file_num_compaction_trigger", "3"}}));
  554. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  555. ASSERT_EQ("0,1", FilesPerLevel());
  556. }
  557. TEST_F(DBOptionsTest, SetBackgroundCompactionThreads) {
  558. Options options;
  559. options.create_if_missing = true;
  560. options.max_background_compactions = 1; // default value
  561. options.env = env_;
  562. Reopen(options);
  563. ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
  564. ASSERT_OK(dbfull()->SetDBOptions({{"max_background_compactions", "3"}}));
  565. ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
  566. auto stop_token = dbfull()->TEST_write_controler().GetStopToken();
  567. ASSERT_EQ(3, dbfull()->TEST_BGCompactionsAllowed());
  568. }
  569. TEST_F(DBOptionsTest, SetBackgroundFlushThreads) {
  570. Options options;
  571. options.create_if_missing = true;
  572. options.max_background_flushes = 1;
  573. options.env = env_;
  574. Reopen(options);
  575. ASSERT_EQ(1, dbfull()->TEST_BGFlushesAllowed());
  576. ASSERT_EQ(1, env_->GetBackgroundThreads(Env::Priority::HIGH));
  577. ASSERT_OK(dbfull()->SetDBOptions({{"max_background_flushes", "3"}}));
  578. ASSERT_EQ(3, env_->GetBackgroundThreads(Env::Priority::HIGH));
  579. ASSERT_EQ(3, dbfull()->TEST_BGFlushesAllowed());
  580. }
  581. TEST_F(DBOptionsTest, SetBackgroundJobs) {
  582. Options options;
  583. options.create_if_missing = true;
  584. options.max_background_jobs = 8;
  585. options.env = env_;
  586. Reopen(options);
  587. for (int i = 0; i < 2; ++i) {
  588. if (i > 0) {
  589. options.max_background_jobs = 12;
  590. ASSERT_OK(dbfull()->SetDBOptions(
  591. {{"max_background_jobs",
  592. std::to_string(options.max_background_jobs)}}));
  593. }
  594. const int expected_max_flushes = options.max_background_jobs / 4;
  595. ASSERT_EQ(expected_max_flushes, dbfull()->TEST_BGFlushesAllowed());
  596. ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
  597. auto stop_token = dbfull()->TEST_write_controler().GetStopToken();
  598. const int expected_max_compactions = 3 * expected_max_flushes;
  599. ASSERT_EQ(expected_max_flushes, dbfull()->TEST_BGFlushesAllowed());
  600. ASSERT_EQ(expected_max_compactions, dbfull()->TEST_BGCompactionsAllowed());
  601. ASSERT_EQ(expected_max_flushes,
  602. env_->GetBackgroundThreads(Env::Priority::HIGH));
  603. ASSERT_EQ(expected_max_compactions,
  604. env_->GetBackgroundThreads(Env::Priority::LOW));
  605. }
  606. }
  607. TEST_F(DBOptionsTest, AvoidFlushDuringShutdown) {
  608. Options options;
  609. options.create_if_missing = true;
  610. options.disable_auto_compactions = true;
  611. options.env = env_;
  612. WriteOptions write_without_wal;
  613. write_without_wal.disableWAL = true;
  614. ASSERT_FALSE(options.avoid_flush_during_shutdown);
  615. DestroyAndReopen(options);
  616. ASSERT_OK(Put("foo", "v1", write_without_wal));
  617. Reopen(options);
  618. ASSERT_EQ("v1", Get("foo"));
  619. ASSERT_EQ("1", FilesPerLevel());
  620. DestroyAndReopen(options);
  621. ASSERT_OK(Put("foo", "v2", write_without_wal));
  622. ASSERT_OK(dbfull()->SetDBOptions({{"avoid_flush_during_shutdown", "true"}}));
  623. Reopen(options);
  624. ASSERT_EQ("NOT_FOUND", Get("foo"));
  625. ASSERT_EQ("", FilesPerLevel());
  626. }
  627. TEST_F(DBOptionsTest, SetDelayedWriteRateOption) {
  628. Options options;
  629. options.create_if_missing = true;
  630. options.delayed_write_rate = 2 * 1024U * 1024U;
  631. options.env = env_;
  632. Reopen(options);
  633. ASSERT_EQ(2 * 1024U * 1024U,
  634. dbfull()->TEST_write_controler().max_delayed_write_rate());
  635. ASSERT_OK(dbfull()->SetDBOptions({{"delayed_write_rate", "20000"}}));
  636. ASSERT_EQ(20000, dbfull()->TEST_write_controler().max_delayed_write_rate());
  637. }
  638. TEST_F(DBOptionsTest, MaxTotalWalSizeChange) {
  639. Random rnd(1044);
  640. const auto value_size = size_t(1024);
  641. std::string value = rnd.RandomString(value_size);
  642. Options options;
  643. options.create_if_missing = true;
  644. options.env = env_;
  645. CreateColumnFamilies({"1", "2", "3"}, options);
  646. ReopenWithColumnFamilies({"default", "1", "2", "3"}, options);
  647. WriteOptions write_options;
  648. const int key_count = 100;
  649. for (int i = 0; i < key_count; ++i) {
  650. for (size_t cf = 0; cf < handles_.size(); ++cf) {
  651. ASSERT_OK(Put(static_cast<int>(cf), Key(i), value));
  652. }
  653. }
  654. ASSERT_OK(dbfull()->SetDBOptions({{"max_total_wal_size", "10"}}));
  655. for (size_t cf = 0; cf < handles_.size(); ++cf) {
  656. ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable(handles_[cf]));
  657. ASSERT_EQ("1", FilesPerLevel(static_cast<int>(cf)));
  658. }
  659. }
  660. TEST_F(DBOptionsTest, SetStatsDumpPeriodSec) {
  661. Options options;
  662. options.create_if_missing = true;
  663. options.stats_dump_period_sec = 5;
  664. options.env = env_;
  665. Reopen(options);
  666. ASSERT_EQ(5u, dbfull()->GetDBOptions().stats_dump_period_sec);
  667. for (int i = 0; i < 20; i++) {
  668. unsigned int num = rand() % 5000 + 1;
  669. ASSERT_OK(dbfull()->SetDBOptions(
  670. {{"stats_dump_period_sec", std::to_string(num)}}));
  671. ASSERT_EQ(num, dbfull()->GetDBOptions().stats_dump_period_sec);
  672. }
  673. Close();
  674. }
  675. TEST_F(DBOptionsTest, SetStatsDumpPeriodSecRace) {
  676. // This is a mini-stress test looking for inconsistency between the reported
  677. // state of the option and the behavior in effect for the DB, after the last
  678. // modification to that option (indefinite inconsistency).
  679. std::vector<std::thread> threads;
  680. for (int i = 0; i < 12; i++) {
  681. threads.emplace_back([this, i]() {
  682. ASSERT_OK(dbfull()->SetDBOptions(
  683. {{"stats_dump_period_sec", i % 2 ? "100" : "0"}}));
  684. });
  685. }
  686. for (auto& t : threads) {
  687. t.join();
  688. }
  689. bool stats_dump_set = dbfull()->GetDBOptions().stats_dump_period_sec > 0;
  690. bool task_enabled = dbfull()->TEST_GetPeriodicTaskScheduler().TEST_HasTask(
  691. PeriodicTaskType::kDumpStats);
  692. ASSERT_EQ(stats_dump_set, task_enabled);
  693. }
  694. TEST_F(DBOptionsTest, SetOptionsAndFileRace) {
  695. // This is a mini-stress test looking for inconsistency between the reported
  696. // state of the option and what is persisted in the options file, after the
  697. // last modification to that option (indefinite inconsistency).
  698. std::vector<std::thread> threads;
  699. for (int i = 0; i < 12; i++) {
  700. threads.emplace_back([this, i]() {
  701. ASSERT_OK(dbfull()->SetOptions({{"ttl", std::to_string(i * 100)}}));
  702. });
  703. }
  704. for (auto& t : threads) {
  705. t.join();
  706. }
  707. auto setting_in_mem = dbfull()->GetOptions().ttl;
  708. std::vector<ColumnFamilyDescriptor> cf_descs;
  709. DBOptions db_options;
  710. ConfigOptions cfg;
  711. cfg.env = env_;
  712. ASSERT_OK(LoadLatestOptions(cfg, dbname_, &db_options, &cf_descs, nullptr));
  713. ASSERT_EQ(cf_descs.size(), 1);
  714. ASSERT_EQ(setting_in_mem, cf_descs[0].options.ttl);
  715. }
  716. TEST_F(DBOptionsTest, SetOptionsStatsPersistPeriodSec) {
  717. Options options;
  718. options.create_if_missing = true;
  719. options.stats_persist_period_sec = 5;
  720. options.env = env_;
  721. Reopen(options);
  722. ASSERT_EQ(5u, dbfull()->GetDBOptions().stats_persist_period_sec);
  723. ASSERT_OK(dbfull()->SetDBOptions({{"stats_persist_period_sec", "12345"}}));
  724. ASSERT_EQ(12345u, dbfull()->GetDBOptions().stats_persist_period_sec);
  725. ASSERT_NOK(dbfull()->SetDBOptions({{"stats_persist_period_sec", "abcde"}}));
  726. ASSERT_EQ(12345u, dbfull()->GetDBOptions().stats_persist_period_sec);
  727. }
  728. static void assert_candidate_files_empty(DBImpl* dbfull, const bool empty) {
  729. dbfull->TEST_LockMutex();
  730. JobContext job_context(0);
  731. dbfull->FindObsoleteFiles(&job_context, false);
  732. ASSERT_EQ(empty, job_context.full_scan_candidate_files.empty());
  733. dbfull->TEST_UnlockMutex();
  734. if (job_context.HaveSomethingToDelete()) {
  735. // fulfill the contract of FindObsoleteFiles by calling PurgeObsoleteFiles
  736. // afterwards; otherwise the test may hang on shutdown
  737. dbfull->PurgeObsoleteFiles(job_context);
  738. }
  739. job_context.Clean();
  740. }
  741. TEST_F(DBOptionsTest, DeleteObsoleteFilesPeriodChange) {
  742. Options options;
  743. options.env = env_;
  744. SetTimeElapseOnlySleepOnReopen(&options);
  745. options.create_if_missing = true;
  746. ASSERT_OK(TryReopen(options));
  747. // Verify that candidate files set is empty when no full scan requested.
  748. assert_candidate_files_empty(dbfull(), true);
  749. ASSERT_OK(
  750. dbfull()->SetDBOptions({{"delete_obsolete_files_period_micros", "0"}}));
  751. // After delete_obsolete_files_period_micros updated to 0, the next call
  752. // to FindObsoleteFiles should make a full scan
  753. assert_candidate_files_empty(dbfull(), false);
  754. ASSERT_OK(
  755. dbfull()->SetDBOptions({{"delete_obsolete_files_period_micros", "20"}}));
  756. assert_candidate_files_empty(dbfull(), true);
  757. env_->MockSleepForMicroseconds(20);
  758. assert_candidate_files_empty(dbfull(), true);
  759. env_->MockSleepForMicroseconds(1);
  760. assert_candidate_files_empty(dbfull(), false);
  761. Close();
  762. }
  763. TEST_F(DBOptionsTest, MaxOpenFilesChange) {
  764. SpecialEnv env(env_);
  765. Options options;
  766. options.env = CurrentOptions().env;
  767. options.max_open_files = -1;
  768. Reopen(options);
  769. Cache* tc = dbfull()->TEST_table_cache();
  770. ASSERT_EQ(-1, dbfull()->GetDBOptions().max_open_files);
  771. ASSERT_LT(2000, tc->GetCapacity());
  772. ASSERT_OK(dbfull()->SetDBOptions({{"max_open_files", "1024"}}));
  773. ASSERT_EQ(1024, dbfull()->GetDBOptions().max_open_files);
  774. // examine the table cache (actual size should be 1014)
  775. ASSERT_GT(1500, tc->GetCapacity());
  776. Close();
  777. }
  778. TEST_F(DBOptionsTest, SanitizeDelayedWriteRate) {
  779. Options options;
  780. options.env = CurrentOptions().env;
  781. options.delayed_write_rate = 0;
  782. Reopen(options);
  783. ASSERT_EQ(16 * 1024 * 1024, dbfull()->GetDBOptions().delayed_write_rate);
  784. options.rate_limiter.reset(NewGenericRateLimiter(31 * 1024 * 1024));
  785. Reopen(options);
  786. ASSERT_EQ(31 * 1024 * 1024, dbfull()->GetDBOptions().delayed_write_rate);
  787. }
  788. TEST_F(DBOptionsTest, SanitizeUniversalTTLCompaction) {
  789. Options options;
  790. options.env = CurrentOptions().env;
  791. options.compaction_style = kCompactionStyleUniversal;
  792. options.ttl = 0;
  793. options.periodic_compaction_seconds = 0;
  794. Reopen(options);
  795. ASSERT_EQ(0, dbfull()->GetOptions().ttl);
  796. ASSERT_EQ(0, dbfull()->GetOptions().periodic_compaction_seconds);
  797. options.ttl = 0;
  798. options.periodic_compaction_seconds = 100;
  799. Reopen(options);
  800. ASSERT_EQ(0, dbfull()->GetOptions().ttl);
  801. ASSERT_EQ(100, dbfull()->GetOptions().periodic_compaction_seconds);
  802. options.ttl = 100;
  803. options.periodic_compaction_seconds = 0;
  804. Reopen(options);
  805. ASSERT_EQ(100, dbfull()->GetOptions().ttl);
  806. ASSERT_EQ(100, dbfull()->GetOptions().periodic_compaction_seconds);
  807. options.ttl = 100;
  808. options.periodic_compaction_seconds = 500;
  809. Reopen(options);
  810. ASSERT_EQ(100, dbfull()->GetOptions().ttl);
  811. ASSERT_EQ(100, dbfull()->GetOptions().periodic_compaction_seconds);
  812. }
  813. TEST_F(DBOptionsTest, SanitizeTtlDefault) {
  814. Options options;
  815. options.env = CurrentOptions().env;
  816. Reopen(options);
  817. ASSERT_EQ(30 * 24 * 60 * 60, dbfull()->GetOptions().ttl);
  818. options.compaction_style = kCompactionStyleLevel;
  819. options.ttl = 0;
  820. Reopen(options);
  821. ASSERT_EQ(0, dbfull()->GetOptions().ttl);
  822. options.ttl = 100;
  823. Reopen(options);
  824. ASSERT_EQ(100, dbfull()->GetOptions().ttl);
  825. }
  826. TEST_F(DBOptionsTest, SanitizeFIFOPeriodicCompaction) {
  827. Options options;
  828. options.compaction_style = kCompactionStyleFIFO;
  829. options.env = CurrentOptions().env;
  830. // Default value allows RocksDB to set ttl to 30 days.
  831. ASSERT_EQ(30 * 24 * 60 * 60, dbfull()->GetOptions().ttl);
  832. // Disable
  833. options.ttl = 0;
  834. Reopen(options);
  835. ASSERT_EQ(0, dbfull()->GetOptions().ttl);
  836. options.ttl = 100;
  837. Reopen(options);
  838. ASSERT_EQ(100, dbfull()->GetOptions().ttl);
  839. options.ttl = 100 * 24 * 60 * 60;
  840. Reopen(options);
  841. ASSERT_EQ(100 * 24 * 60 * 60, dbfull()->GetOptions().ttl);
  842. // periodic_compaction_seconds should have no effect
  843. // on FIFO compaction.
  844. options.ttl = 500;
  845. options.periodic_compaction_seconds = 300;
  846. Reopen(options);
  847. ASSERT_EQ(500, dbfull()->GetOptions().ttl);
  848. }
  849. TEST_F(DBOptionsTest, SetFIFOCompactionOptions) {
  850. Options options;
  851. options.env = CurrentOptions().env;
  852. options.compaction_style = kCompactionStyleFIFO;
  853. options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
  854. options.write_buffer_size = 10 << 10; // 10KB
  855. options.arena_block_size = 4096;
  856. options.compression = kNoCompression;
  857. options.create_if_missing = true;
  858. options.compaction_options_fifo.allow_compaction = false;
  859. options.num_levels = 1;
  860. env_->SetMockSleep();
  861. options.env = env_;
  862. // NOTE: Presumed unnecessary and removed: resetting mock time in env
  863. // Test dynamically changing ttl.
  864. options.ttl = 1 * 60 * 60; // 1 hour
  865. ASSERT_OK(TryReopen(options));
  866. Random rnd(301);
  867. for (int i = 0; i < 10; i++) {
  868. // Generate and flush a file about 10KB.
  869. for (int j = 0; j < 10; j++) {
  870. ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
  871. }
  872. ASSERT_OK(Flush());
  873. }
  874. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  875. ASSERT_EQ(NumTableFilesAtLevel(0), 10);
  876. env_->MockSleepForSeconds(61);
  877. // No files should be compacted as ttl is set to 1 hour.
  878. ASSERT_EQ(dbfull()->GetOptions().ttl, 3600);
  879. ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
  880. ASSERT_EQ(NumTableFilesAtLevel(0), 10);
  881. ASSERT_EQ(options.statistics->getTickerCount(FIFO_TTL_COMPACTIONS), 0);
  882. ASSERT_EQ(options.statistics->getTickerCount(FIFO_MAX_SIZE_COMPACTIONS), 0);
  883. // Set ttl to 1 minute. So all files should get deleted.
  884. ASSERT_OK(dbfull()->SetOptions({{"ttl", "60"}}));
  885. ASSERT_EQ(dbfull()->GetOptions().ttl, 60);
  886. ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
  887. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  888. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  889. ASSERT_GT(options.statistics->getTickerCount(FIFO_TTL_COMPACTIONS), 0);
  890. ASSERT_EQ(options.statistics->getTickerCount(FIFO_MAX_SIZE_COMPACTIONS), 0);
  891. ASSERT_OK(options.statistics->Reset());
  892. // NOTE: Presumed unnecessary and removed: resetting mock time in env
  893. // Test dynamically changing compaction_options_fifo.max_table_files_size
  894. options.compaction_options_fifo.max_table_files_size = 500 << 10; // 00KB
  895. options.ttl = 0;
  896. DestroyAndReopen(options);
  897. for (int i = 0; i < 10; i++) {
  898. // Generate and flush a file about 10KB.
  899. for (int j = 0; j < 10; j++) {
  900. ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
  901. }
  902. ASSERT_OK(Flush());
  903. }
  904. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  905. ASSERT_EQ(NumTableFilesAtLevel(0), 10);
  906. // No files should be compacted as max_table_files_size is set to 500 KB.
  907. ASSERT_EQ(dbfull()->GetOptions().compaction_options_fifo.max_table_files_size,
  908. 500 << 10);
  909. ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
  910. ASSERT_EQ(NumTableFilesAtLevel(0), 10);
  911. ASSERT_EQ(options.statistics->getTickerCount(FIFO_MAX_SIZE_COMPACTIONS), 0);
  912. ASSERT_EQ(options.statistics->getTickerCount(FIFO_TTL_COMPACTIONS), 0);
  913. // Set max_table_files_size to 12 KB. So only 1 file should remain now.
  914. ASSERT_OK(dbfull()->SetOptions(
  915. {{"compaction_options_fifo", "{max_table_files_size=12288;}"}}));
  916. ASSERT_EQ(dbfull()->GetOptions().compaction_options_fifo.max_table_files_size,
  917. 12 << 10);
  918. ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
  919. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  920. ASSERT_EQ(NumTableFilesAtLevel(0), 1);
  921. ASSERT_GT(options.statistics->getTickerCount(FIFO_MAX_SIZE_COMPACTIONS), 0);
  922. ASSERT_EQ(options.statistics->getTickerCount(FIFO_TTL_COMPACTIONS), 0);
  923. ASSERT_OK(options.statistics->Reset());
  924. // Test dynamically changing compaction_options_fifo.allow_compaction
  925. options.compaction_options_fifo.max_table_files_size = 500 << 10; // 500KB
  926. options.ttl = 0;
  927. options.compaction_options_fifo.allow_compaction = false;
  928. options.level0_file_num_compaction_trigger = 6;
  929. DestroyAndReopen(options);
  930. for (int i = 0; i < 10; i++) {
  931. // Generate and flush a file about 10KB.
  932. for (int j = 0; j < 10; j++) {
  933. ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
  934. }
  935. ASSERT_OK(Flush());
  936. }
  937. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  938. ASSERT_EQ(NumTableFilesAtLevel(0), 10);
  939. // No files should be compacted as max_table_files_size is set to 500 KB and
  940. // allow_compaction is false
  941. ASSERT_EQ(dbfull()->GetOptions().compaction_options_fifo.allow_compaction,
  942. false);
  943. ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
  944. ASSERT_EQ(NumTableFilesAtLevel(0), 10);
  945. // Set allow_compaction to true. So number of files should be between 1 and 5.
  946. ASSERT_OK(dbfull()->SetOptions(
  947. {{"compaction_options_fifo", "{allow_compaction=true;}"}}));
  948. ASSERT_EQ(dbfull()->GetOptions().compaction_options_fifo.allow_compaction,
  949. true);
  950. ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
  951. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  952. ASSERT_GE(NumTableFilesAtLevel(0), 1);
  953. ASSERT_LE(NumTableFilesAtLevel(0), 5);
  954. // Test dynamically setting `file_temperature_age_thresholds`
  955. ASSERT_TRUE(
  956. dbfull()
  957. ->GetOptions()
  958. .compaction_options_fifo.file_temperature_age_thresholds.empty());
  959. ASSERT_OK(dbfull()->SetOptions({{"compaction_options_fifo",
  960. "{file_temperature_age_thresholds={{age=10;"
  961. "temperature=kWarm}:{age=30000;"
  962. "temperature=kCold}}}"}}));
  963. auto opts = dbfull()->GetOptions();
  964. const auto& fifo_temp_opt =
  965. opts.compaction_options_fifo.file_temperature_age_thresholds;
  966. ASSERT_EQ(fifo_temp_opt.size(), 2);
  967. ASSERT_EQ(fifo_temp_opt[0].temperature, Temperature::kWarm);
  968. ASSERT_EQ(fifo_temp_opt[0].age, 10);
  969. ASSERT_EQ(fifo_temp_opt[1].temperature, Temperature::kCold);
  970. ASSERT_EQ(fifo_temp_opt[1].age, 30000);
  971. }
  972. TEST_F(DBOptionsTest, OffpeakTimes) {
  973. Options options;
  974. options.create_if_missing = true;
  975. Random rnd(test::RandomSeed());
  976. auto verify_invalid = [&]() {
  977. Status s = DBImpl::TEST_ValidateOptions(options);
  978. ASSERT_NOK(s);
  979. ASSERT_TRUE(s.IsInvalidArgument());
  980. };
  981. auto verify_valid = [&]() {
  982. Status s = DBImpl::TEST_ValidateOptions(options);
  983. ASSERT_OK(s);
  984. ASSERT_FALSE(s.IsInvalidArgument());
  985. };
  986. std::vector<std::string> invalid_cases = {
  987. "06:30-",
  988. "-23:30", // Both need to be set
  989. "00:00-00:00",
  990. "06:30-06:30" // Start time cannot be the same as end time
  991. "12:30 PM-23:30",
  992. "12:01AM-11:00PM", // Invalid format
  993. "01:99-22:00", // Invalid value for minutes
  994. "00:00-24:00", // 24:00 is an invalid value
  995. "6-7",
  996. "6:-7",
  997. "06:31.42-7:00",
  998. "6.31:42-7:00",
  999. "6:0-7:",
  1000. "15:0.2-3:.7",
  1001. ":00-00:02",
  1002. "02:00-:00",
  1003. "random-value",
  1004. "No:No-Hi:Hi",
  1005. };
  1006. std::vector<std::string> valid_cases = {
  1007. "", // Not enabled. Valid case
  1008. "06:30-11:30",
  1009. "06:30-23:30",
  1010. "13:30-14:30",
  1011. "00:00-23:59", // Entire Day
  1012. "23:30-01:15", // From 11:30PM to 1:15AM next day. Valid case.
  1013. "1:0000000000000-2:000000000042", // Weird, but we can parse the int.
  1014. };
  1015. for (const std::string& invalid_case : invalid_cases) {
  1016. options.daily_offpeak_time_utc = invalid_case;
  1017. verify_invalid();
  1018. }
  1019. for (const std::string& valid_case : valid_cases) {
  1020. options.daily_offpeak_time_utc = valid_case;
  1021. verify_valid();
  1022. }
  1023. auto verify_offpeak_info = [&](bool expected_is_now_off_peak,
  1024. int expected_seconds_till_next_offpeak_start,
  1025. int now_utc_hour, int now_utc_minute,
  1026. int now_utc_second = 0) {
  1027. auto mock_clock = std::make_shared<MockSystemClock>(env_->GetSystemClock());
  1028. // Add some extra random days to current time
  1029. int days = rnd.Uniform(100);
  1030. mock_clock->SetCurrentTime(
  1031. days * OffpeakTimeOption::kSecondsPerDay +
  1032. now_utc_hour * OffpeakTimeOption::kSecondsPerHour +
  1033. now_utc_minute * OffpeakTimeOption::kSecondsPerMinute + now_utc_second);
  1034. Status s = DBImpl::TEST_ValidateOptions(options);
  1035. ASSERT_OK(s);
  1036. auto offpeak_option = OffpeakTimeOption(options.daily_offpeak_time_utc);
  1037. int64_t now;
  1038. ASSERT_OK(mock_clock.get()->GetCurrentTime(&now));
  1039. auto offpeak_info = offpeak_option.GetOffpeakTimeInfo(now);
  1040. ASSERT_EQ(expected_is_now_off_peak, offpeak_info.is_now_offpeak);
  1041. ASSERT_EQ(expected_seconds_till_next_offpeak_start,
  1042. offpeak_info.seconds_till_next_offpeak_start);
  1043. };
  1044. options.daily_offpeak_time_utc = "";
  1045. verify_offpeak_info(false, 0, 12, 30);
  1046. options.daily_offpeak_time_utc = "06:30-11:30";
  1047. verify_offpeak_info(false, 1 * OffpeakTimeOption::kSecondsPerHour, 5, 30);
  1048. verify_offpeak_info(true, 24 * OffpeakTimeOption::kSecondsPerHour, 6, 30);
  1049. verify_offpeak_info(true, 20 * OffpeakTimeOption::kSecondsPerHour, 10, 30);
  1050. verify_offpeak_info(true, 19 * OffpeakTimeOption::kSecondsPerHour, 11, 30);
  1051. verify_offpeak_info(false, 17 * OffpeakTimeOption::kSecondsPerHour, 13, 30);
  1052. options.daily_offpeak_time_utc = "23:30-04:30";
  1053. verify_offpeak_info(false, 17 * OffpeakTimeOption::kSecondsPerHour, 6, 30);
  1054. verify_offpeak_info(true, 24 * OffpeakTimeOption::kSecondsPerHour, 23, 30);
  1055. verify_offpeak_info(true,
  1056. 23 * OffpeakTimeOption::kSecondsPerHour +
  1057. 30 * OffpeakTimeOption::kSecondsPerMinute,
  1058. 0, 0);
  1059. verify_offpeak_info(true,
  1060. 22 * OffpeakTimeOption::kSecondsPerHour +
  1061. 30 * OffpeakTimeOption::kSecondsPerMinute,
  1062. 1, 0);
  1063. verify_offpeak_info(true, 19 * OffpeakTimeOption::kSecondsPerHour, 4, 30);
  1064. verify_offpeak_info(false,
  1065. 18 * OffpeakTimeOption::kSecondsPerHour +
  1066. 59 * OffpeakTimeOption::kSecondsPerMinute,
  1067. 4, 31);
  1068. // Entire day offpeak
  1069. options.daily_offpeak_time_utc = "00:00-23:59";
  1070. verify_offpeak_info(true, 24 * OffpeakTimeOption::kSecondsPerHour, 0, 0);
  1071. verify_offpeak_info(true, 12 * OffpeakTimeOption::kSecondsPerHour, 12, 00);
  1072. verify_offpeak_info(true, 1 * OffpeakTimeOption::kSecondsPerMinute, 23, 59);
  1073. verify_offpeak_info(true, 59, 23, 59, 1);
  1074. verify_offpeak_info(true, 1, 23, 59, 59);
  1075. // Start with a valid option
  1076. options.daily_offpeak_time_utc = "01:30-04:15";
  1077. DestroyAndReopen(options);
  1078. ASSERT_EQ("01:30-04:15", dbfull()->GetDBOptions().daily_offpeak_time_utc);
  1079. int may_schedule_compaction_called = 0;
  1080. SyncPoint::GetInstance()->SetCallBack(
  1081. "DBImpl::MaybeScheduleFlushOrCompaction:Start",
  1082. [&](void*) { may_schedule_compaction_called++; });
  1083. SyncPoint::GetInstance()->EnableProcessing();
  1084. // Make sure calling SetDBOptions with invalid option does not change the
  1085. // value nor call MaybeScheduleFlushOrCompaction()
  1086. for (std::string invalid_case : invalid_cases) {
  1087. ASSERT_NOK(
  1088. dbfull()->SetDBOptions({{"daily_offpeak_time_utc", invalid_case}}));
  1089. ASSERT_EQ("01:30-04:15", dbfull()
  1090. ->GetVersionSet()
  1091. ->offpeak_time_option()
  1092. .daily_offpeak_time_utc);
  1093. ASSERT_EQ(1 * kSecondInHour + 30 * kSecondInMinute,
  1094. dbfull()
  1095. ->GetVersionSet()
  1096. ->offpeak_time_option()
  1097. .daily_offpeak_start_time_utc);
  1098. ASSERT_EQ(4 * kSecondInHour + 15 * kSecondInMinute,
  1099. dbfull()
  1100. ->GetVersionSet()
  1101. ->offpeak_time_option()
  1102. .daily_offpeak_end_time_utc);
  1103. }
  1104. ASSERT_EQ(0, may_schedule_compaction_called);
  1105. // Changing to new valid values should call MaybeScheduleFlushOrCompaction()
  1106. // and sets the offpeak_time_option in VersionSet
  1107. int expected_count = 0;
  1108. for (std::string valid_case : valid_cases) {
  1109. if (dbfull()
  1110. ->GetVersionSet()
  1111. ->offpeak_time_option()
  1112. .daily_offpeak_time_utc != valid_case) {
  1113. expected_count++;
  1114. }
  1115. ASSERT_OK(dbfull()->SetDBOptions({{"daily_offpeak_time_utc", valid_case}}));
  1116. ASSERT_EQ(valid_case, dbfull()->GetDBOptions().daily_offpeak_time_utc);
  1117. ASSERT_EQ(valid_case, dbfull()
  1118. ->GetVersionSet()
  1119. ->offpeak_time_option()
  1120. .daily_offpeak_time_utc);
  1121. }
  1122. ASSERT_EQ(expected_count, may_schedule_compaction_called);
  1123. // Changing to the same value should not call MaybeScheduleFlushOrCompaction()
  1124. ASSERT_OK(
  1125. dbfull()->SetDBOptions({{"daily_offpeak_time_utc", "06:30-11:30"}}));
  1126. may_schedule_compaction_called = 0;
  1127. ASSERT_OK(
  1128. dbfull()->SetDBOptions({{"daily_offpeak_time_utc", "06:30-11:30"}}));
  1129. ASSERT_EQ(0, may_schedule_compaction_called);
  1130. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
  1131. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
  1132. Close();
  1133. }
  1134. TEST_F(DBOptionsTest, CompactionReadaheadSizeChange) {
  1135. for (bool use_direct_reads : {true, false}) {
  1136. SpecialEnv env(env_);
  1137. Options options;
  1138. options.env = &env;
  1139. options.use_direct_reads = use_direct_reads;
  1140. options.level0_file_num_compaction_trigger = 2;
  1141. const std::string kValue(1024, 'v');
  1142. Status s = TryReopen(options);
  1143. if (use_direct_reads && (s.IsNotSupported() || s.IsInvalidArgument())) {
  1144. continue;
  1145. } else {
  1146. ASSERT_OK(s);
  1147. }
  1148. ASSERT_EQ(1024 * 1024 * 2,
  1149. dbfull()->GetDBOptions().compaction_readahead_size);
  1150. ASSERT_OK(dbfull()->SetDBOptions({{"compaction_readahead_size", "256"}}));
  1151. ASSERT_EQ(256, dbfull()->GetDBOptions().compaction_readahead_size);
  1152. for (int i = 0; i < 1024; i++) {
  1153. ASSERT_OK(Put(Key(i), kValue));
  1154. }
  1155. ASSERT_OK(Flush());
  1156. for (int i = 0; i < 1024 * 2; i++) {
  1157. ASSERT_OK(Put(Key(i), kValue));
  1158. }
  1159. ASSERT_OK(Flush());
  1160. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  1161. ASSERT_EQ(256, env_->compaction_readahead_size_);
  1162. Close();
  1163. }
  1164. }
  1165. TEST_F(DBOptionsTest, FIFOTtlBackwardCompatible) {
  1166. Options options;
  1167. options.compaction_style = kCompactionStyleFIFO;
  1168. options.write_buffer_size = 10 << 10; // 10KB
  1169. options.create_if_missing = true;
  1170. options.env = CurrentOptions().env;
  1171. options.num_levels = 1;
  1172. ASSERT_OK(TryReopen(options));
  1173. Random rnd(301);
  1174. for (int i = 0; i < 10; i++) {
  1175. // Generate and flush a file about 10KB.
  1176. for (int j = 0; j < 10; j++) {
  1177. ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
  1178. }
  1179. ASSERT_OK(Flush());
  1180. }
  1181. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  1182. ASSERT_EQ(NumTableFilesAtLevel(0), 10);
  1183. // In release 6.0, ttl was promoted from a secondary level option under
  1184. // compaction_options_fifo to a top level option under ColumnFamilyOptions.
  1185. // We still need to handle old SetOptions calls but should ignore
  1186. // ttl under compaction_options_fifo.
  1187. ASSERT_OK(dbfull()->SetOptions(
  1188. {{"compaction_options_fifo",
  1189. "{allow_compaction=true;max_table_files_size=1024;ttl=731;file_"
  1190. "temperature_age_thresholds={temperature=kCold;age=12345}}"},
  1191. {"ttl", "60"}}));
  1192. ASSERT_EQ(dbfull()->GetOptions().compaction_options_fifo.allow_compaction,
  1193. true);
  1194. ASSERT_EQ(dbfull()->GetOptions().compaction_options_fifo.max_table_files_size,
  1195. 1024);
  1196. auto opts = dbfull()->GetOptions();
  1197. const auto& file_temp_age =
  1198. opts.compaction_options_fifo.file_temperature_age_thresholds;
  1199. ASSERT_EQ(file_temp_age.size(), 1);
  1200. ASSERT_EQ(file_temp_age[0].temperature, Temperature::kCold);
  1201. ASSERT_EQ(file_temp_age[0].age, 12345);
  1202. ASSERT_EQ(dbfull()->GetOptions().ttl, 60);
  1203. // Put ttl as the first option inside compaction_options_fifo. That works as
  1204. // it doesn't overwrite any other option.
  1205. ASSERT_OK(dbfull()->SetOptions(
  1206. {{"compaction_options_fifo",
  1207. "{ttl=985;allow_compaction=true;max_table_files_size=1024;}"},
  1208. {"ttl", "191"}}));
  1209. ASSERT_EQ(dbfull()->GetOptions().compaction_options_fifo.allow_compaction,
  1210. true);
  1211. ASSERT_EQ(dbfull()->GetOptions().compaction_options_fifo.max_table_files_size,
  1212. 1024);
  1213. ASSERT_EQ(file_temp_age.size(), 1);
  1214. ASSERT_EQ(file_temp_age[0].temperature, Temperature::kCold);
  1215. ASSERT_EQ(file_temp_age[0].age, 12345);
  1216. ASSERT_EQ(dbfull()->GetOptions().ttl, 191);
  1217. }
  1218. TEST_F(DBOptionsTest, ChangeCompression) {
  1219. if (!Snappy_Supported() || !LZ4_Supported()) {
  1220. return;
  1221. }
  1222. Options options;
  1223. options.write_buffer_size = 10 << 10; // 10KB
  1224. options.level0_file_num_compaction_trigger = 2;
  1225. options.create_if_missing = true;
  1226. options.compression = CompressionType::kLZ4Compression;
  1227. options.bottommost_compression = CompressionType::kNoCompression;
  1228. options.bottommost_compression_opts.level = 2;
  1229. options.bottommost_compression_opts.parallel_threads = 1;
  1230. options.env = CurrentOptions().env;
  1231. ASSERT_OK(TryReopen(options));
  1232. CompressionType compression_used = CompressionType::kLZ4Compression;
  1233. CompressionOptions compression_opt_used;
  1234. bool compacted = false;
  1235. SyncPoint::GetInstance()->SetCallBack(
  1236. "LevelCompactionPicker::PickCompaction:Return", [&](void* arg) {
  1237. Compaction* c = static_cast<Compaction*>(arg);
  1238. compression_used = c->output_compression();
  1239. compression_opt_used = c->output_compression_opts();
  1240. compacted = true;
  1241. });
  1242. SyncPoint::GetInstance()->EnableProcessing();
  1243. ASSERT_OK(Put("foo", "foofoofoo"));
  1244. ASSERT_OK(Put("bar", "foofoofoo"));
  1245. ASSERT_OK(Flush());
  1246. ASSERT_OK(Put("foo", "foofoofoo"));
  1247. ASSERT_OK(Put("bar", "foofoofoo"));
  1248. ASSERT_OK(Flush());
  1249. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  1250. ASSERT_TRUE(compacted);
  1251. ASSERT_EQ(CompressionType::kNoCompression, compression_used);
  1252. ASSERT_EQ(options.compression_opts.level, compression_opt_used.level);
  1253. ASSERT_EQ(options.compression_opts.parallel_threads,
  1254. compression_opt_used.parallel_threads);
  1255. compression_used = CompressionType::kLZ4Compression;
  1256. compacted = false;
  1257. ASSERT_OK(dbfull()->SetOptions(
  1258. {{"bottommost_compression", "kSnappyCompression"},
  1259. {"bottommost_compression_opts", "0:6:0:0:4:true"}}));
  1260. ASSERT_OK(Put("foo", "foofoofoo"));
  1261. ASSERT_OK(Put("bar", "foofoofoo"));
  1262. ASSERT_OK(Flush());
  1263. ASSERT_OK(Put("foo", "foofoofoo"));
  1264. ASSERT_OK(Put("bar", "foofoofoo"));
  1265. ASSERT_OK(Flush());
  1266. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  1267. ASSERT_TRUE(compacted);
  1268. ASSERT_EQ(CompressionType::kSnappyCompression, compression_used);
  1269. ASSERT_EQ(6, compression_opt_used.level);
  1270. // Right now parallel_level is not yet allowed to be changed.
  1271. SyncPoint::GetInstance()->DisableProcessing();
  1272. }
  1273. TEST_F(DBOptionsTest, BottommostCompressionOptsWithFallbackType) {
  1274. // Verify the bottommost compression options still take effect even when the
  1275. // bottommost compression type is left at its default value. Verify for both
  1276. // automatic and manual compaction.
  1277. if (!Snappy_Supported() || !LZ4_Supported()) {
  1278. return;
  1279. }
  1280. constexpr int kUpperCompressionLevel = 1;
  1281. constexpr int kBottommostCompressionLevel = 2;
  1282. constexpr int kNumL0Files = 2;
  1283. Options options = CurrentOptions();
  1284. options.level0_file_num_compaction_trigger = kNumL0Files;
  1285. options.compression = CompressionType::kLZ4Compression;
  1286. options.compression_opts.level = kUpperCompressionLevel;
  1287. options.bottommost_compression_opts.level = kBottommostCompressionLevel;
  1288. options.bottommost_compression_opts.enabled = true;
  1289. Reopen(options);
  1290. CompressionType compression_used = CompressionType::kDisableCompressionOption;
  1291. CompressionOptions compression_opt_used;
  1292. bool compacted = false;
  1293. SyncPoint::GetInstance()->SetCallBack(
  1294. "CompactionPicker::RegisterCompaction:Registered", [&](void* arg) {
  1295. Compaction* c = static_cast<Compaction*>(arg);
  1296. compression_used = c->output_compression();
  1297. compression_opt_used = c->output_compression_opts();
  1298. compacted = true;
  1299. });
  1300. SyncPoint::GetInstance()->EnableProcessing();
  1301. // First, verify for automatic compaction.
  1302. for (int i = 0; i < kNumL0Files; ++i) {
  1303. ASSERT_OK(Put("foo", "foofoofoo"));
  1304. ASSERT_OK(Put("bar", "foofoofoo"));
  1305. ASSERT_OK(Flush());
  1306. }
  1307. ASSERT_OK(dbfull()->TEST_WaitForCompact());
  1308. ASSERT_TRUE(compacted);
  1309. ASSERT_EQ(CompressionType::kLZ4Compression, compression_used);
  1310. ASSERT_EQ(kBottommostCompressionLevel, compression_opt_used.level);
  1311. // Second, verify for manual compaction.
  1312. compacted = false;
  1313. compression_used = CompressionType::kDisableCompressionOption;
  1314. compression_opt_used = CompressionOptions();
  1315. CompactRangeOptions cro;
  1316. cro.bottommost_level_compaction = BottommostLevelCompaction::kForceOptimized;
  1317. ASSERT_OK(dbfull()->CompactRange(cro, nullptr, nullptr));
  1318. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
  1319. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
  1320. ASSERT_TRUE(compacted);
  1321. ASSERT_EQ(CompressionType::kLZ4Compression, compression_used);
  1322. ASSERT_EQ(kBottommostCompressionLevel, compression_opt_used.level);
  1323. }
  1324. TEST_F(DBOptionsTest, FIFOTemperatureAgeThresholdValidation) {
  1325. Options options = CurrentOptions();
  1326. Destroy(options);
  1327. options.num_levels = 1;
  1328. options.compaction_style = kCompactionStyleFIFO;
  1329. options.max_open_files = -1;
  1330. // elements are not sorted
  1331. // During DB open
  1332. options.compaction_options_fifo.file_temperature_age_thresholds.push_back(
  1333. {Temperature::kCold, 1000});
  1334. options.compaction_options_fifo.file_temperature_age_thresholds.push_back(
  1335. {Temperature::kWarm, 500});
  1336. Status s = TryReopen(options);
  1337. ASSERT_TRUE(s.IsNotSupported());
  1338. ASSERT_TRUE(std::strstr(
  1339. s.getState(),
  1340. "Option file_temperature_age_thresholds requires elements to be sorted "
  1341. "in increasing order with respect to `age` field."));
  1342. // Dynamically set option
  1343. options.compaction_options_fifo.file_temperature_age_thresholds.pop_back();
  1344. ASSERT_OK(TryReopen(options));
  1345. s = db_->SetOptions({{"compaction_options_fifo",
  1346. "{file_temperature_age_thresholds={{temperature=kCold;"
  1347. "age=1000000}:{temperature=kWarm;age=1}}}"}});
  1348. ASSERT_TRUE(s.IsNotSupported());
  1349. ASSERT_TRUE(std::strstr(
  1350. s.getState(),
  1351. "Option file_temperature_age_thresholds requires elements to be sorted "
  1352. "in increasing order with respect to `age` field."));
  1353. // not single level
  1354. // During DB open
  1355. options.num_levels = 2;
  1356. s = TryReopen(options);
  1357. ASSERT_TRUE(s.IsNotSupported());
  1358. ASSERT_TRUE(std::strstr(s.getState(),
  1359. "Option file_temperature_age_thresholds is only "
  1360. "supported when num_levels = 1."));
  1361. // Dynamically set option
  1362. options.compaction_options_fifo.file_temperature_age_thresholds.clear();
  1363. DestroyAndReopen(options);
  1364. s = db_->SetOptions(
  1365. {{"compaction_options_fifo",
  1366. "{file_temperature_age_thresholds={temperature=kCold;age=1000}}"}});
  1367. ASSERT_TRUE(s.IsNotSupported());
  1368. ASSERT_TRUE(std::strstr(s.getState(),
  1369. "Option file_temperature_age_thresholds is only "
  1370. "supported when num_levels = 1."));
  1371. }
  1372. TEST_F(DBOptionsTest, TempOptionsFailTest) {
  1373. std::shared_ptr<FaultInjectionTestFS> fs;
  1374. std::unique_ptr<Env> env;
  1375. fs.reset(new FaultInjectionTestFS(env_->GetFileSystem()));
  1376. env = NewCompositeEnv(fs);
  1377. Options options = CurrentOptions();
  1378. options.env = env.get();
  1379. SyncPoint::GetInstance()->SetCallBack(
  1380. "PersistRocksDBOptions:create",
  1381. [&](void* /*arg*/) { fs->SetFilesystemActive(false); });
  1382. SyncPoint::GetInstance()->SetCallBack(
  1383. "PersistRocksDBOptions:written",
  1384. [&](void* /*arg*/) { fs->SetFilesystemActive(true); });
  1385. SyncPoint::GetInstance()->EnableProcessing();
  1386. ASSERT_NOK(TryReopen(options));
  1387. SyncPoint::GetInstance()->DisableProcessing();
  1388. std::vector<std::string> filenames;
  1389. ASSERT_OK(env_->GetChildren(dbname_, &filenames));
  1390. uint64_t number;
  1391. FileType type;
  1392. bool found_temp_file = false;
  1393. for (size_t i = 0; i < filenames.size(); i++) {
  1394. if (ParseFileName(filenames[i], &number, &type) && type == kTempFile) {
  1395. found_temp_file = true;
  1396. }
  1397. }
  1398. ASSERT_FALSE(found_temp_file);
  1399. }
  1400. TEST_F(DBOptionsTest, SetOptionsNoManifestWrite) {
  1401. ASSERT_OK(Put("x", "x"));
  1402. ASSERT_OK(Flush());
  1403. // In addition to checking manifest file, we want to ensure that SetOptions
  1404. // is essentially atomic, without releasing the DB mutex between applying
  1405. // the options to the cfd and installing new Version and SuperVersion. We
  1406. // probabilistically verify that by attempting to catch an inconsistency.
  1407. auto* const cfd =
  1408. static_cast<ColumnFamilyHandleImpl*>(db_->DefaultColumnFamily())->cfd();
  1409. SyncPoint::GetInstance()->DisableProcessing();
  1410. SyncPoint::GetInstance()->ClearAllCallBacks();
  1411. std::optional<std::thread> t;
  1412. SyncPoint::GetInstance()->SetCallBack(
  1413. "VersionSet::LogAndApply:WakeUpAndNotDone", [&](void* arg) {
  1414. auto* mu = static_cast<InstrumentedMutex*>(arg);
  1415. // Option not yet modified
  1416. ASSERT_FALSE(cfd->GetLatestMutableCFOptions().disable_auto_compactions);
  1417. ASSERT_FALSE(
  1418. cfd->current()->GetMutableCFOptions().disable_auto_compactions);
  1419. ASSERT_FALSE(
  1420. cfd->GetCurrentMutableCFOptions().disable_auto_compactions);
  1421. t = std::thread([mu, cfd]() {
  1422. InstrumentedMutexLock l(mu);
  1423. // Assuming above correctness, we can only acquire the mutex after
  1424. // options fully installed.
  1425. ASSERT_TRUE(
  1426. cfd->GetLatestMutableCFOptions().disable_auto_compactions);
  1427. ASSERT_TRUE(
  1428. cfd->current()->GetMutableCFOptions().disable_auto_compactions);
  1429. ASSERT_TRUE(
  1430. cfd->GetCurrentMutableCFOptions().disable_auto_compactions);
  1431. });
  1432. });
  1433. SyncPoint::GetInstance()->EnableProcessing();
  1434. // Baseline manifest file info
  1435. std::vector<std::string> live_files;
  1436. uint64_t orig_manifest_file_size;
  1437. ASSERT_OK(dbfull()->GetLiveFiles(live_files, &orig_manifest_file_size));
  1438. uint64_t orig_manifest_file_num = dbfull()->TEST_Current_Manifest_FileNo();
  1439. // Although this test mostly concerns SetOptions, we also include SetDBOptions
  1440. // just for the added scope
  1441. ASSERT_OK(db_->SetDBOptions({{"max_open_files", "100"}}));
  1442. ASSERT_OK(db_->SetOptions({{"disable_auto_compactions", "true"}}));
  1443. // Verify that our above check was activated and completed
  1444. ASSERT_TRUE(t.has_value());
  1445. t->join();
  1446. SyncPoint::GetInstance()->DisableProcessing();
  1447. SyncPoint::GetInstance()->ClearAllCallBacks();
  1448. // Verify manifest was not written to
  1449. uint64_t new_manifest_file_size;
  1450. ASSERT_OK(dbfull()->GetLiveFiles(live_files, &new_manifest_file_size));
  1451. uint64_t new_manifest_file_num = dbfull()->TEST_Current_Manifest_FileNo();
  1452. ASSERT_EQ(orig_manifest_file_num, new_manifest_file_num);
  1453. ASSERT_EQ(orig_manifest_file_size, new_manifest_file_size);
  1454. ASSERT_EQ(Get("x"), "x");
  1455. }
  1456. } // namespace ROCKSDB_NAMESPACE
  1457. int main(int argc, char** argv) {
  1458. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  1459. ::testing::InitGoogleTest(&argc, argv);
  1460. return RUN_ALL_TESTS();
  1461. }