options_test.cc 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004
  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 <cctype>
  10. #include <cinttypes>
  11. #include <cstring>
  12. #include <unordered_map>
  13. #include "cache/lru_cache.h"
  14. #include "cache/sharded_cache.h"
  15. #include "options/options_helper.h"
  16. #include "options/options_parser.h"
  17. #include "options/options_sanity_check.h"
  18. #include "port/port.h"
  19. #include "rocksdb/cache.h"
  20. #include "rocksdb/convenience.h"
  21. #include "rocksdb/memtablerep.h"
  22. #include "rocksdb/utilities/leveldb_options.h"
  23. #include "rocksdb/utilities/object_registry.h"
  24. #include "table/block_based/filter_policy_internal.h"
  25. #include "test_util/testharness.h"
  26. #include "test_util/testutil.h"
  27. #include "util/random.h"
  28. #include "util/stderr_logger.h"
  29. #include "util/string_util.h"
  30. #include "utilities/merge_operators/bytesxor.h"
  31. #ifndef GFLAGS
  32. bool FLAGS_enable_print = false;
  33. #else
  34. #include "util/gflags_compat.h"
  35. using GFLAGS_NAMESPACE::ParseCommandLineFlags;
  36. DEFINE_bool(enable_print, false, "Print options generated to console.");
  37. #endif // GFLAGS
  38. namespace ROCKSDB_NAMESPACE {
  39. class OptionsTest : public testing::Test {};
  40. #ifndef ROCKSDB_LITE // GetOptionsFromMap is not supported in ROCKSDB_LITE
  41. TEST_F(OptionsTest, GetOptionsFromMapTest) {
  42. std::unordered_map<std::string, std::string> cf_options_map = {
  43. {"write_buffer_size", "1"},
  44. {"max_write_buffer_number", "2"},
  45. {"min_write_buffer_number_to_merge", "3"},
  46. {"max_write_buffer_number_to_maintain", "99"},
  47. {"max_write_buffer_size_to_maintain", "-99999"},
  48. {"compression", "kSnappyCompression"},
  49. {"compression_per_level",
  50. "kNoCompression:"
  51. "kSnappyCompression:"
  52. "kZlibCompression:"
  53. "kBZip2Compression:"
  54. "kLZ4Compression:"
  55. "kLZ4HCCompression:"
  56. "kXpressCompression:"
  57. "kZSTD:"
  58. "kZSTDNotFinalCompression"},
  59. {"bottommost_compression", "kLZ4Compression"},
  60. {"bottommost_compression_opts", "5:6:7:8:9:true"},
  61. {"compression_opts", "4:5:6:7:8:true"},
  62. {"num_levels", "8"},
  63. {"level0_file_num_compaction_trigger", "8"},
  64. {"level0_slowdown_writes_trigger", "9"},
  65. {"level0_stop_writes_trigger", "10"},
  66. {"target_file_size_base", "12"},
  67. {"target_file_size_multiplier", "13"},
  68. {"max_bytes_for_level_base", "14"},
  69. {"level_compaction_dynamic_level_bytes", "true"},
  70. {"max_bytes_for_level_multiplier", "15.0"},
  71. {"max_bytes_for_level_multiplier_additional", "16:17:18"},
  72. {"max_compaction_bytes", "21"},
  73. {"soft_rate_limit", "1.1"},
  74. {"hard_rate_limit", "2.1"},
  75. {"hard_pending_compaction_bytes_limit", "211"},
  76. {"arena_block_size", "22"},
  77. {"disable_auto_compactions", "true"},
  78. {"compaction_style", "kCompactionStyleLevel"},
  79. {"compaction_pri", "kOldestSmallestSeqFirst"},
  80. {"verify_checksums_in_compaction", "false"},
  81. {"compaction_options_fifo", "23"},
  82. {"max_sequential_skip_in_iterations", "24"},
  83. {"inplace_update_support", "true"},
  84. {"report_bg_io_stats", "true"},
  85. {"compaction_measure_io_stats", "false"},
  86. {"inplace_update_num_locks", "25"},
  87. {"memtable_prefix_bloom_size_ratio", "0.26"},
  88. {"memtable_whole_key_filtering", "true"},
  89. {"memtable_huge_page_size", "28"},
  90. {"bloom_locality", "29"},
  91. {"max_successive_merges", "30"},
  92. {"min_partial_merge_operands", "31"},
  93. {"prefix_extractor", "fixed:31"},
  94. {"optimize_filters_for_hits", "true"},
  95. };
  96. std::unordered_map<std::string, std::string> db_options_map = {
  97. {"create_if_missing", "false"},
  98. {"create_missing_column_families", "true"},
  99. {"error_if_exists", "false"},
  100. {"paranoid_checks", "true"},
  101. {"max_open_files", "32"},
  102. {"max_total_wal_size", "33"},
  103. {"use_fsync", "true"},
  104. {"db_log_dir", "/db_log_dir"},
  105. {"wal_dir", "/wal_dir"},
  106. {"delete_obsolete_files_period_micros", "34"},
  107. {"max_background_compactions", "35"},
  108. {"max_background_flushes", "36"},
  109. {"max_log_file_size", "37"},
  110. {"log_file_time_to_roll", "38"},
  111. {"keep_log_file_num", "39"},
  112. {"recycle_log_file_num", "5"},
  113. {"max_manifest_file_size", "40"},
  114. {"table_cache_numshardbits", "41"},
  115. {"WAL_ttl_seconds", "43"},
  116. {"WAL_size_limit_MB", "44"},
  117. {"manifest_preallocation_size", "45"},
  118. {"allow_mmap_reads", "true"},
  119. {"allow_mmap_writes", "false"},
  120. {"use_direct_reads", "false"},
  121. {"use_direct_io_for_flush_and_compaction", "false"},
  122. {"is_fd_close_on_exec", "true"},
  123. {"skip_log_error_on_recovery", "false"},
  124. {"stats_dump_period_sec", "46"},
  125. {"stats_persist_period_sec", "57"},
  126. {"persist_stats_to_disk", "false"},
  127. {"stats_history_buffer_size", "69"},
  128. {"advise_random_on_open", "true"},
  129. {"use_adaptive_mutex", "false"},
  130. {"new_table_reader_for_compaction_inputs", "true"},
  131. {"compaction_readahead_size", "100"},
  132. {"random_access_max_buffer_size", "3145728"},
  133. {"writable_file_max_buffer_size", "314159"},
  134. {"bytes_per_sync", "47"},
  135. {"wal_bytes_per_sync", "48"},
  136. {"strict_bytes_per_sync", "true"},
  137. };
  138. ColumnFamilyOptions base_cf_opt;
  139. ColumnFamilyOptions new_cf_opt;
  140. ASSERT_OK(GetColumnFamilyOptionsFromMap(
  141. base_cf_opt, cf_options_map, &new_cf_opt));
  142. ASSERT_EQ(new_cf_opt.write_buffer_size, 1U);
  143. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 2);
  144. ASSERT_EQ(new_cf_opt.min_write_buffer_number_to_merge, 3);
  145. ASSERT_EQ(new_cf_opt.max_write_buffer_number_to_maintain, 99);
  146. ASSERT_EQ(new_cf_opt.max_write_buffer_size_to_maintain, -99999);
  147. ASSERT_EQ(new_cf_opt.compression, kSnappyCompression);
  148. ASSERT_EQ(new_cf_opt.compression_per_level.size(), 9U);
  149. ASSERT_EQ(new_cf_opt.compression_per_level[0], kNoCompression);
  150. ASSERT_EQ(new_cf_opt.compression_per_level[1], kSnappyCompression);
  151. ASSERT_EQ(new_cf_opt.compression_per_level[2], kZlibCompression);
  152. ASSERT_EQ(new_cf_opt.compression_per_level[3], kBZip2Compression);
  153. ASSERT_EQ(new_cf_opt.compression_per_level[4], kLZ4Compression);
  154. ASSERT_EQ(new_cf_opt.compression_per_level[5], kLZ4HCCompression);
  155. ASSERT_EQ(new_cf_opt.compression_per_level[6], kXpressCompression);
  156. ASSERT_EQ(new_cf_opt.compression_per_level[7], kZSTD);
  157. ASSERT_EQ(new_cf_opt.compression_per_level[8], kZSTDNotFinalCompression);
  158. ASSERT_EQ(new_cf_opt.compression_opts.window_bits, 4);
  159. ASSERT_EQ(new_cf_opt.compression_opts.level, 5);
  160. ASSERT_EQ(new_cf_opt.compression_opts.strategy, 6);
  161. ASSERT_EQ(new_cf_opt.compression_opts.max_dict_bytes, 7u);
  162. ASSERT_EQ(new_cf_opt.compression_opts.zstd_max_train_bytes, 8u);
  163. ASSERT_EQ(new_cf_opt.compression_opts.enabled, true);
  164. ASSERT_EQ(new_cf_opt.bottommost_compression, kLZ4Compression);
  165. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.window_bits, 5);
  166. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.level, 6);
  167. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.strategy, 7);
  168. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.max_dict_bytes, 8u);
  169. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.zstd_max_train_bytes, 9u);
  170. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.enabled, true);
  171. ASSERT_EQ(new_cf_opt.num_levels, 8);
  172. ASSERT_EQ(new_cf_opt.level0_file_num_compaction_trigger, 8);
  173. ASSERT_EQ(new_cf_opt.level0_slowdown_writes_trigger, 9);
  174. ASSERT_EQ(new_cf_opt.level0_stop_writes_trigger, 10);
  175. ASSERT_EQ(new_cf_opt.target_file_size_base, static_cast<uint64_t>(12));
  176. ASSERT_EQ(new_cf_opt.target_file_size_multiplier, 13);
  177. ASSERT_EQ(new_cf_opt.max_bytes_for_level_base, 14U);
  178. ASSERT_EQ(new_cf_opt.level_compaction_dynamic_level_bytes, true);
  179. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier, 15.0);
  180. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional.size(), 3U);
  181. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[0], 16);
  182. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[1], 17);
  183. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[2], 18);
  184. ASSERT_EQ(new_cf_opt.max_compaction_bytes, 21);
  185. ASSERT_EQ(new_cf_opt.hard_pending_compaction_bytes_limit, 211);
  186. ASSERT_EQ(new_cf_opt.arena_block_size, 22U);
  187. ASSERT_EQ(new_cf_opt.disable_auto_compactions, true);
  188. ASSERT_EQ(new_cf_opt.compaction_style, kCompactionStyleLevel);
  189. ASSERT_EQ(new_cf_opt.compaction_pri, kOldestSmallestSeqFirst);
  190. ASSERT_EQ(new_cf_opt.compaction_options_fifo.max_table_files_size,
  191. static_cast<uint64_t>(23));
  192. ASSERT_EQ(new_cf_opt.max_sequential_skip_in_iterations,
  193. static_cast<uint64_t>(24));
  194. ASSERT_EQ(new_cf_opt.inplace_update_support, true);
  195. ASSERT_EQ(new_cf_opt.inplace_update_num_locks, 25U);
  196. ASSERT_EQ(new_cf_opt.memtable_prefix_bloom_size_ratio, 0.26);
  197. ASSERT_EQ(new_cf_opt.memtable_whole_key_filtering, true);
  198. ASSERT_EQ(new_cf_opt.memtable_huge_page_size, 28U);
  199. ASSERT_EQ(new_cf_opt.bloom_locality, 29U);
  200. ASSERT_EQ(new_cf_opt.max_successive_merges, 30U);
  201. ASSERT_TRUE(new_cf_opt.prefix_extractor != nullptr);
  202. ASSERT_EQ(new_cf_opt.optimize_filters_for_hits, true);
  203. ASSERT_EQ(std::string(new_cf_opt.prefix_extractor->Name()),
  204. "rocksdb.FixedPrefix.31");
  205. cf_options_map["write_buffer_size"] = "hello";
  206. ASSERT_NOK(GetColumnFamilyOptionsFromMap(
  207. base_cf_opt, cf_options_map, &new_cf_opt));
  208. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt, new_cf_opt));
  209. cf_options_map["write_buffer_size"] = "1";
  210. ASSERT_OK(GetColumnFamilyOptionsFromMap(
  211. base_cf_opt, cf_options_map, &new_cf_opt));
  212. cf_options_map["unknown_option"] = "1";
  213. ASSERT_NOK(GetColumnFamilyOptionsFromMap(
  214. base_cf_opt, cf_options_map, &new_cf_opt));
  215. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt, new_cf_opt));
  216. ASSERT_OK(GetColumnFamilyOptionsFromMap(base_cf_opt, cf_options_map,
  217. &new_cf_opt,
  218. false, /* input_strings_escaped */
  219. true /* ignore_unknown_options */));
  220. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
  221. base_cf_opt, new_cf_opt, nullptr, /* new_opt_map */
  222. kSanityLevelLooselyCompatible /* from CheckOptionsCompatibility*/));
  223. ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
  224. base_cf_opt, new_cf_opt, nullptr, /* new_opt_map */
  225. kSanityLevelExactMatch /* default for VerifyCFOptions */));
  226. DBOptions base_db_opt;
  227. DBOptions new_db_opt;
  228. ASSERT_OK(GetDBOptionsFromMap(base_db_opt, db_options_map, &new_db_opt));
  229. ASSERT_EQ(new_db_opt.create_if_missing, false);
  230. ASSERT_EQ(new_db_opt.create_missing_column_families, true);
  231. ASSERT_EQ(new_db_opt.error_if_exists, false);
  232. ASSERT_EQ(new_db_opt.paranoid_checks, true);
  233. ASSERT_EQ(new_db_opt.max_open_files, 32);
  234. ASSERT_EQ(new_db_opt.max_total_wal_size, static_cast<uint64_t>(33));
  235. ASSERT_EQ(new_db_opt.use_fsync, true);
  236. ASSERT_EQ(new_db_opt.db_log_dir, "/db_log_dir");
  237. ASSERT_EQ(new_db_opt.wal_dir, "/wal_dir");
  238. ASSERT_EQ(new_db_opt.delete_obsolete_files_period_micros,
  239. static_cast<uint64_t>(34));
  240. ASSERT_EQ(new_db_opt.max_background_compactions, 35);
  241. ASSERT_EQ(new_db_opt.max_background_flushes, 36);
  242. ASSERT_EQ(new_db_opt.max_log_file_size, 37U);
  243. ASSERT_EQ(new_db_opt.log_file_time_to_roll, 38U);
  244. ASSERT_EQ(new_db_opt.keep_log_file_num, 39U);
  245. ASSERT_EQ(new_db_opt.recycle_log_file_num, 5U);
  246. ASSERT_EQ(new_db_opt.max_manifest_file_size, static_cast<uint64_t>(40));
  247. ASSERT_EQ(new_db_opt.table_cache_numshardbits, 41);
  248. ASSERT_EQ(new_db_opt.WAL_ttl_seconds, static_cast<uint64_t>(43));
  249. ASSERT_EQ(new_db_opt.WAL_size_limit_MB, static_cast<uint64_t>(44));
  250. ASSERT_EQ(new_db_opt.manifest_preallocation_size, 45U);
  251. ASSERT_EQ(new_db_opt.allow_mmap_reads, true);
  252. ASSERT_EQ(new_db_opt.allow_mmap_writes, false);
  253. ASSERT_EQ(new_db_opt.use_direct_reads, false);
  254. ASSERT_EQ(new_db_opt.use_direct_io_for_flush_and_compaction, false);
  255. ASSERT_EQ(new_db_opt.is_fd_close_on_exec, true);
  256. ASSERT_EQ(new_db_opt.skip_log_error_on_recovery, false);
  257. ASSERT_EQ(new_db_opt.stats_dump_period_sec, 46U);
  258. ASSERT_EQ(new_db_opt.stats_persist_period_sec, 57U);
  259. ASSERT_EQ(new_db_opt.persist_stats_to_disk, false);
  260. ASSERT_EQ(new_db_opt.stats_history_buffer_size, 69U);
  261. ASSERT_EQ(new_db_opt.advise_random_on_open, true);
  262. ASSERT_EQ(new_db_opt.use_adaptive_mutex, false);
  263. ASSERT_EQ(new_db_opt.new_table_reader_for_compaction_inputs, true);
  264. ASSERT_EQ(new_db_opt.compaction_readahead_size, 100);
  265. ASSERT_EQ(new_db_opt.random_access_max_buffer_size, 3145728);
  266. ASSERT_EQ(new_db_opt.writable_file_max_buffer_size, 314159);
  267. ASSERT_EQ(new_db_opt.bytes_per_sync, static_cast<uint64_t>(47));
  268. ASSERT_EQ(new_db_opt.wal_bytes_per_sync, static_cast<uint64_t>(48));
  269. ASSERT_EQ(new_db_opt.strict_bytes_per_sync, true);
  270. db_options_map["max_open_files"] = "hello";
  271. ASSERT_NOK(GetDBOptionsFromMap(base_db_opt, db_options_map, &new_db_opt));
  272. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(base_db_opt, new_db_opt));
  273. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(
  274. base_db_opt, new_db_opt, nullptr, /* new_opt_map */
  275. kSanityLevelLooselyCompatible /* from CheckOptionsCompatibility */));
  276. // unknow options should fail parsing without ignore_unknown_options = true
  277. db_options_map["unknown_db_option"] = "1";
  278. ASSERT_NOK(GetDBOptionsFromMap(base_db_opt, db_options_map, &new_db_opt));
  279. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(base_db_opt, new_db_opt));
  280. ASSERT_OK(GetDBOptionsFromMap(base_db_opt, db_options_map, &new_db_opt,
  281. false, /* input_strings_escaped */
  282. true /* ignore_unknown_options */));
  283. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(
  284. base_db_opt, new_db_opt, nullptr, /* new_opt_map */
  285. kSanityLevelLooselyCompatible /* from CheckOptionsCompatibility */));
  286. ASSERT_NOK(RocksDBOptionsParser::VerifyDBOptions(
  287. base_db_opt, new_db_opt, nullptr, /* new_opt_mat */
  288. kSanityLevelExactMatch /* default for VerifyDBOptions */));
  289. }
  290. #endif // !ROCKSDB_LITE
  291. #ifndef ROCKSDB_LITE // GetColumnFamilyOptionsFromString is not supported in
  292. // ROCKSDB_LITE
  293. TEST_F(OptionsTest, GetColumnFamilyOptionsFromStringTest) {
  294. ColumnFamilyOptions base_cf_opt;
  295. ColumnFamilyOptions new_cf_opt;
  296. base_cf_opt.table_factory.reset();
  297. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, "", &new_cf_opt));
  298. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  299. "write_buffer_size=5", &new_cf_opt));
  300. ASSERT_EQ(new_cf_opt.write_buffer_size, 5U);
  301. ASSERT_TRUE(new_cf_opt.table_factory == nullptr);
  302. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  303. "write_buffer_size=6;", &new_cf_opt));
  304. ASSERT_EQ(new_cf_opt.write_buffer_size, 6U);
  305. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  306. " write_buffer_size = 7 ", &new_cf_opt));
  307. ASSERT_EQ(new_cf_opt.write_buffer_size, 7U);
  308. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  309. " write_buffer_size = 8 ; ", &new_cf_opt));
  310. ASSERT_EQ(new_cf_opt.write_buffer_size, 8U);
  311. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  312. "write_buffer_size=9;max_write_buffer_number=10", &new_cf_opt));
  313. ASSERT_EQ(new_cf_opt.write_buffer_size, 9U);
  314. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 10);
  315. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  316. "write_buffer_size=11; max_write_buffer_number = 12 ;",
  317. &new_cf_opt));
  318. ASSERT_EQ(new_cf_opt.write_buffer_size, 11U);
  319. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 12);
  320. // Wrong name "max_write_buffer_number_"
  321. ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt,
  322. "write_buffer_size=13;max_write_buffer_number_=14;",
  323. &new_cf_opt));
  324. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt, new_cf_opt));
  325. // Comparator from object registry
  326. std::string kCompName = "reverse_comp";
  327. ObjectLibrary::Default()->Register<const Comparator>(
  328. kCompName,
  329. [](const std::string& /*name*/,
  330. std::unique_ptr<const Comparator>* /*guard*/,
  331. std::string* /* errmsg */) { return ReverseBytewiseComparator(); });
  332. ASSERT_OK(GetColumnFamilyOptionsFromString(
  333. base_cf_opt, "comparator=" + kCompName + ";", &new_cf_opt));
  334. ASSERT_EQ(new_cf_opt.comparator, ReverseBytewiseComparator());
  335. // MergeOperator from object registry
  336. std::unique_ptr<BytesXOROperator> bxo(new BytesXOROperator());
  337. std::string kMoName = bxo->Name();
  338. ObjectLibrary::Default()->Register<MergeOperator>(
  339. kMoName,
  340. [](const std::string& /*name*/, std::unique_ptr<MergeOperator>* guard,
  341. std::string* /* errmsg */) {
  342. guard->reset(new BytesXOROperator());
  343. return guard->get();
  344. });
  345. ASSERT_OK(GetColumnFamilyOptionsFromString(
  346. base_cf_opt, "merge_operator=" + kMoName + ";", &new_cf_opt));
  347. ASSERT_EQ(kMoName, std::string(new_cf_opt.merge_operator->Name()));
  348. // Wrong key/value pair
  349. ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt,
  350. "write_buffer_size=13;max_write_buffer_number;", &new_cf_opt));
  351. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt, new_cf_opt));
  352. // Error Paring value
  353. ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt,
  354. "write_buffer_size=13;max_write_buffer_number=;", &new_cf_opt));
  355. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt, new_cf_opt));
  356. // Missing option name
  357. ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt,
  358. "write_buffer_size=13; =100;", &new_cf_opt));
  359. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt, new_cf_opt));
  360. const uint64_t kilo = 1024UL;
  361. const uint64_t mega = 1024 * kilo;
  362. const uint64_t giga = 1024 * mega;
  363. const uint64_t tera = 1024 * giga;
  364. // Units (k)
  365. ASSERT_OK(GetColumnFamilyOptionsFromString(
  366. base_cf_opt, "max_write_buffer_number=15K", &new_cf_opt));
  367. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 15 * kilo);
  368. // Units (m)
  369. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  370. "max_write_buffer_number=16m;inplace_update_num_locks=17M",
  371. &new_cf_opt));
  372. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 16 * mega);
  373. ASSERT_EQ(new_cf_opt.inplace_update_num_locks, 17u * mega);
  374. // Units (g)
  375. ASSERT_OK(GetColumnFamilyOptionsFromString(
  376. base_cf_opt,
  377. "write_buffer_size=18g;prefix_extractor=capped:8;"
  378. "arena_block_size=19G",
  379. &new_cf_opt));
  380. ASSERT_EQ(new_cf_opt.write_buffer_size, 18 * giga);
  381. ASSERT_EQ(new_cf_opt.arena_block_size, 19 * giga);
  382. ASSERT_TRUE(new_cf_opt.prefix_extractor.get() != nullptr);
  383. std::string prefix_name(new_cf_opt.prefix_extractor->Name());
  384. ASSERT_EQ(prefix_name, "rocksdb.CappedPrefix.8");
  385. // Units (t)
  386. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  387. "write_buffer_size=20t;arena_block_size=21T", &new_cf_opt));
  388. ASSERT_EQ(new_cf_opt.write_buffer_size, 20 * tera);
  389. ASSERT_EQ(new_cf_opt.arena_block_size, 21 * tera);
  390. // Nested block based table options
  391. // Empty
  392. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  393. "write_buffer_size=10;max_write_buffer_number=16;"
  394. "block_based_table_factory={};arena_block_size=1024",
  395. &new_cf_opt));
  396. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  397. // Non-empty
  398. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  399. "write_buffer_size=10;max_write_buffer_number=16;"
  400. "block_based_table_factory={block_cache=1M;block_size=4;};"
  401. "arena_block_size=1024",
  402. &new_cf_opt));
  403. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  404. // Last one
  405. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  406. "write_buffer_size=10;max_write_buffer_number=16;"
  407. "block_based_table_factory={block_cache=1M;block_size=4;}",
  408. &new_cf_opt));
  409. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  410. // Mismatch curly braces
  411. ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt,
  412. "write_buffer_size=10;max_write_buffer_number=16;"
  413. "block_based_table_factory={{{block_size=4;};"
  414. "arena_block_size=1024",
  415. &new_cf_opt));
  416. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt, new_cf_opt));
  417. // Unexpected chars after closing curly brace
  418. ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt,
  419. "write_buffer_size=10;max_write_buffer_number=16;"
  420. "block_based_table_factory={block_size=4;}};"
  421. "arena_block_size=1024",
  422. &new_cf_opt));
  423. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt, new_cf_opt));
  424. ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt,
  425. "write_buffer_size=10;max_write_buffer_number=16;"
  426. "block_based_table_factory={block_size=4;}xdfa;"
  427. "arena_block_size=1024",
  428. &new_cf_opt));
  429. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt, new_cf_opt));
  430. ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt,
  431. "write_buffer_size=10;max_write_buffer_number=16;"
  432. "block_based_table_factory={block_size=4;}xdfa",
  433. &new_cf_opt));
  434. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt, new_cf_opt));
  435. // Invalid block based table option
  436. ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt,
  437. "write_buffer_size=10;max_write_buffer_number=16;"
  438. "block_based_table_factory={xx_block_size=4;}",
  439. &new_cf_opt));
  440. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt, new_cf_opt));
  441. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  442. "optimize_filters_for_hits=true",
  443. &new_cf_opt));
  444. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  445. "optimize_filters_for_hits=false",
  446. &new_cf_opt));
  447. ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt,
  448. "optimize_filters_for_hits=junk",
  449. &new_cf_opt));
  450. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt, new_cf_opt));
  451. // Nested plain table options
  452. // Empty
  453. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  454. "write_buffer_size=10;max_write_buffer_number=16;"
  455. "plain_table_factory={};arena_block_size=1024",
  456. &new_cf_opt));
  457. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  458. ASSERT_EQ(std::string(new_cf_opt.table_factory->Name()), "PlainTable");
  459. // Non-empty
  460. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  461. "write_buffer_size=10;max_write_buffer_number=16;"
  462. "plain_table_factory={user_key_len=66;bloom_bits_per_key=20;};"
  463. "arena_block_size=1024",
  464. &new_cf_opt));
  465. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  466. ASSERT_EQ(std::string(new_cf_opt.table_factory->Name()), "PlainTable");
  467. // memtable factory
  468. ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
  469. "write_buffer_size=10;max_write_buffer_number=16;"
  470. "memtable=skip_list:10;arena_block_size=1024",
  471. &new_cf_opt));
  472. ASSERT_TRUE(new_cf_opt.memtable_factory != nullptr);
  473. ASSERT_EQ(std::string(new_cf_opt.memtable_factory->Name()), "SkipListFactory");
  474. }
  475. #endif // !ROCKSDB_LITE
  476. #ifndef ROCKSDB_LITE // GetBlockBasedTableOptionsFromString is not supported
  477. TEST_F(OptionsTest, GetBlockBasedTableOptionsFromString) {
  478. BlockBasedTableOptions table_opt;
  479. BlockBasedTableOptions new_opt;
  480. // make sure default values are overwritten by something else
  481. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  482. table_opt,
  483. "cache_index_and_filter_blocks=1;index_type=kHashSearch;"
  484. "checksum=kxxHash;hash_index_allow_collision=1;no_block_cache=1;"
  485. "block_cache=1M;block_cache_compressed=1k;block_size=1024;"
  486. "block_size_deviation=8;block_restart_interval=4;"
  487. "format_version=5;whole_key_filtering=1;"
  488. "filter_policy=bloomfilter:4.567:false;",
  489. &new_opt));
  490. ASSERT_TRUE(new_opt.cache_index_and_filter_blocks);
  491. ASSERT_EQ(new_opt.index_type, BlockBasedTableOptions::kHashSearch);
  492. ASSERT_EQ(new_opt.checksum, ChecksumType::kxxHash);
  493. ASSERT_TRUE(new_opt.hash_index_allow_collision);
  494. ASSERT_TRUE(new_opt.no_block_cache);
  495. ASSERT_TRUE(new_opt.block_cache != nullptr);
  496. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 1024UL*1024UL);
  497. ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
  498. ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 1024UL);
  499. ASSERT_EQ(new_opt.block_size, 1024UL);
  500. ASSERT_EQ(new_opt.block_size_deviation, 8);
  501. ASSERT_EQ(new_opt.block_restart_interval, 4);
  502. ASSERT_EQ(new_opt.format_version, 5U);
  503. ASSERT_EQ(new_opt.whole_key_filtering, true);
  504. ASSERT_TRUE(new_opt.filter_policy != nullptr);
  505. const BloomFilterPolicy& bfp =
  506. dynamic_cast<const BloomFilterPolicy&>(*new_opt.filter_policy);
  507. EXPECT_EQ(bfp.GetMillibitsPerKey(), 4567);
  508. EXPECT_EQ(bfp.GetWholeBitsPerKey(), 5);
  509. // unknown option
  510. ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt,
  511. "cache_index_and_filter_blocks=1;index_type=kBinarySearch;"
  512. "bad_option=1",
  513. &new_opt));
  514. ASSERT_EQ(static_cast<bool>(table_opt.cache_index_and_filter_blocks),
  515. new_opt.cache_index_and_filter_blocks);
  516. ASSERT_EQ(table_opt.index_type, new_opt.index_type);
  517. // unrecognized index type
  518. ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt,
  519. "cache_index_and_filter_blocks=1;index_type=kBinarySearchXX",
  520. &new_opt));
  521. ASSERT_EQ(table_opt.cache_index_and_filter_blocks,
  522. new_opt.cache_index_and_filter_blocks);
  523. ASSERT_EQ(table_opt.index_type, new_opt.index_type);
  524. // unrecognized checksum type
  525. ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt,
  526. "cache_index_and_filter_blocks=1;checksum=kxxHashXX",
  527. &new_opt));
  528. ASSERT_EQ(table_opt.cache_index_and_filter_blocks,
  529. new_opt.cache_index_and_filter_blocks);
  530. ASSERT_EQ(table_opt.index_type, new_opt.index_type);
  531. // unrecognized filter policy name
  532. ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt,
  533. "cache_index_and_filter_blocks=1;"
  534. "filter_policy=bloomfilterxx:4:true",
  535. &new_opt));
  536. ASSERT_EQ(table_opt.cache_index_and_filter_blocks,
  537. new_opt.cache_index_and_filter_blocks);
  538. ASSERT_EQ(table_opt.filter_policy, new_opt.filter_policy);
  539. // unrecognized filter policy config
  540. ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt,
  541. "cache_index_and_filter_blocks=1;"
  542. "filter_policy=bloomfilter:4",
  543. &new_opt));
  544. ASSERT_EQ(table_opt.cache_index_and_filter_blocks,
  545. new_opt.cache_index_and_filter_blocks);
  546. ASSERT_EQ(table_opt.filter_policy, new_opt.filter_policy);
  547. // Check block cache options are overwritten when specified
  548. // in new format as a struct.
  549. ASSERT_OK(GetBlockBasedTableOptionsFromString(table_opt,
  550. "block_cache={capacity=1M;num_shard_bits=4;"
  551. "strict_capacity_limit=true;high_pri_pool_ratio=0.5;};"
  552. "block_cache_compressed={capacity=1M;num_shard_bits=4;"
  553. "strict_capacity_limit=true;high_pri_pool_ratio=0.5;}",
  554. &new_opt));
  555. ASSERT_TRUE(new_opt.block_cache != nullptr);
  556. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 1024UL*1024UL);
  557. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCache>(
  558. new_opt.block_cache)->GetNumShardBits(), 4);
  559. ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), true);
  560. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(
  561. new_opt.block_cache)->GetHighPriPoolRatio(), 0.5);
  562. ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
  563. ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 1024UL*1024UL);
  564. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCache>(
  565. new_opt.block_cache_compressed)->GetNumShardBits(), 4);
  566. ASSERT_EQ(new_opt.block_cache_compressed->HasStrictCapacityLimit(), true);
  567. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(
  568. new_opt.block_cache_compressed)->GetHighPriPoolRatio(),
  569. 0.5);
  570. // Set only block cache capacity. Check other values are
  571. // reset to default values.
  572. ASSERT_OK(GetBlockBasedTableOptionsFromString(table_opt,
  573. "block_cache={capacity=2M};"
  574. "block_cache_compressed={capacity=2M}",
  575. &new_opt));
  576. ASSERT_TRUE(new_opt.block_cache != nullptr);
  577. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 2*1024UL*1024UL);
  578. // Default values
  579. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCache>(
  580. new_opt.block_cache)->GetNumShardBits(),
  581. GetDefaultCacheShardBits(new_opt.block_cache->GetCapacity()));
  582. ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), false);
  583. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache)
  584. ->GetHighPriPoolRatio(),
  585. 0.5);
  586. ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
  587. ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 2*1024UL*1024UL);
  588. // Default values
  589. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCache>(
  590. new_opt.block_cache_compressed)->GetNumShardBits(),
  591. GetDefaultCacheShardBits(
  592. new_opt.block_cache_compressed->GetCapacity()));
  593. ASSERT_EQ(new_opt.block_cache_compressed->HasStrictCapacityLimit(), false);
  594. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache_compressed)
  595. ->GetHighPriPoolRatio(),
  596. 0.5);
  597. // Set couple of block cache options.
  598. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  599. table_opt,
  600. "block_cache={num_shard_bits=5;high_pri_pool_ratio=0.5;};"
  601. "block_cache_compressed={num_shard_bits=5;"
  602. "high_pri_pool_ratio=0.0;}",
  603. &new_opt));
  604. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 0);
  605. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCache>(
  606. new_opt.block_cache)->GetNumShardBits(), 5);
  607. ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), false);
  608. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(
  609. new_opt.block_cache)->GetHighPriPoolRatio(), 0.5);
  610. ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
  611. ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 0);
  612. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCache>(
  613. new_opt.block_cache_compressed)->GetNumShardBits(), 5);
  614. ASSERT_EQ(new_opt.block_cache_compressed->HasStrictCapacityLimit(), false);
  615. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache_compressed)
  616. ->GetHighPriPoolRatio(),
  617. 0.0);
  618. // Set couple of block cache options.
  619. ASSERT_OK(GetBlockBasedTableOptionsFromString(table_opt,
  620. "block_cache={capacity=1M;num_shard_bits=4;"
  621. "strict_capacity_limit=true;};"
  622. "block_cache_compressed={capacity=1M;num_shard_bits=4;"
  623. "strict_capacity_limit=true;}",
  624. &new_opt));
  625. ASSERT_TRUE(new_opt.block_cache != nullptr);
  626. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 1024UL*1024UL);
  627. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCache>(
  628. new_opt.block_cache)->GetNumShardBits(), 4);
  629. ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), true);
  630. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache)
  631. ->GetHighPriPoolRatio(),
  632. 0.5);
  633. ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
  634. ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 1024UL*1024UL);
  635. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCache>(
  636. new_opt.block_cache_compressed)->GetNumShardBits(), 4);
  637. ASSERT_EQ(new_opt.block_cache_compressed->HasStrictCapacityLimit(), true);
  638. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache_compressed)
  639. ->GetHighPriPoolRatio(),
  640. 0.5);
  641. }
  642. #endif // !ROCKSDB_LITE
  643. #ifndef ROCKSDB_LITE // GetPlainTableOptionsFromString is not supported
  644. TEST_F(OptionsTest, GetPlainTableOptionsFromString) {
  645. PlainTableOptions table_opt;
  646. PlainTableOptions new_opt;
  647. // make sure default values are overwritten by something else
  648. ASSERT_OK(GetPlainTableOptionsFromString(table_opt,
  649. "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
  650. "index_sparseness=8;huge_page_tlb_size=4;encoding_type=kPrefix;"
  651. "full_scan_mode=true;store_index_in_file=true",
  652. &new_opt));
  653. ASSERT_EQ(new_opt.user_key_len, 66u);
  654. ASSERT_EQ(new_opt.bloom_bits_per_key, 20);
  655. ASSERT_EQ(new_opt.hash_table_ratio, 0.5);
  656. ASSERT_EQ(new_opt.index_sparseness, 8);
  657. ASSERT_EQ(new_opt.huge_page_tlb_size, 4);
  658. ASSERT_EQ(new_opt.encoding_type, EncodingType::kPrefix);
  659. ASSERT_TRUE(new_opt.full_scan_mode);
  660. ASSERT_TRUE(new_opt.store_index_in_file);
  661. // unknown option
  662. ASSERT_NOK(GetPlainTableOptionsFromString(table_opt,
  663. "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
  664. "bad_option=1",
  665. &new_opt));
  666. // unrecognized EncodingType
  667. ASSERT_NOK(GetPlainTableOptionsFromString(table_opt,
  668. "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
  669. "encoding_type=kPrefixXX",
  670. &new_opt));
  671. }
  672. #endif // !ROCKSDB_LITE
  673. #ifndef ROCKSDB_LITE // GetMemTableRepFactoryFromString is not supported
  674. TEST_F(OptionsTest, GetMemTableRepFactoryFromString) {
  675. std::unique_ptr<MemTableRepFactory> new_mem_factory = nullptr;
  676. ASSERT_OK(GetMemTableRepFactoryFromString("skip_list", &new_mem_factory));
  677. ASSERT_OK(GetMemTableRepFactoryFromString("skip_list:16", &new_mem_factory));
  678. ASSERT_EQ(std::string(new_mem_factory->Name()), "SkipListFactory");
  679. ASSERT_NOK(GetMemTableRepFactoryFromString("skip_list:16:invalid_opt",
  680. &new_mem_factory));
  681. ASSERT_OK(GetMemTableRepFactoryFromString("prefix_hash", &new_mem_factory));
  682. ASSERT_OK(GetMemTableRepFactoryFromString("prefix_hash:1000",
  683. &new_mem_factory));
  684. ASSERT_EQ(std::string(new_mem_factory->Name()), "HashSkipListRepFactory");
  685. ASSERT_NOK(GetMemTableRepFactoryFromString("prefix_hash:1000:invalid_opt",
  686. &new_mem_factory));
  687. ASSERT_OK(GetMemTableRepFactoryFromString("hash_linkedlist",
  688. &new_mem_factory));
  689. ASSERT_OK(GetMemTableRepFactoryFromString("hash_linkedlist:1000",
  690. &new_mem_factory));
  691. ASSERT_EQ(std::string(new_mem_factory->Name()), "HashLinkListRepFactory");
  692. ASSERT_NOK(GetMemTableRepFactoryFromString("hash_linkedlist:1000:invalid_opt",
  693. &new_mem_factory));
  694. ASSERT_OK(GetMemTableRepFactoryFromString("vector", &new_mem_factory));
  695. ASSERT_OK(GetMemTableRepFactoryFromString("vector:1024", &new_mem_factory));
  696. ASSERT_EQ(std::string(new_mem_factory->Name()), "VectorRepFactory");
  697. ASSERT_NOK(GetMemTableRepFactoryFromString("vector:1024:invalid_opt",
  698. &new_mem_factory));
  699. ASSERT_NOK(GetMemTableRepFactoryFromString("cuckoo", &new_mem_factory));
  700. // CuckooHash memtable is already removed.
  701. ASSERT_NOK(GetMemTableRepFactoryFromString("cuckoo:1024", &new_mem_factory));
  702. ASSERT_NOK(GetMemTableRepFactoryFromString("bad_factory", &new_mem_factory));
  703. }
  704. #endif // !ROCKSDB_LITE
  705. #ifndef ROCKSDB_LITE // GetOptionsFromString is not supported in RocksDB Lite
  706. TEST_F(OptionsTest, GetOptionsFromStringTest) {
  707. Options base_options, new_options;
  708. base_options.write_buffer_size = 20;
  709. base_options.min_write_buffer_number_to_merge = 15;
  710. BlockBasedTableOptions block_based_table_options;
  711. block_based_table_options.cache_index_and_filter_blocks = true;
  712. base_options.table_factory.reset(
  713. NewBlockBasedTableFactory(block_based_table_options));
  714. // Register an Env with object registry.
  715. const static char* kCustomEnvName = "CustomEnv";
  716. class CustomEnv : public EnvWrapper {
  717. public:
  718. explicit CustomEnv(Env* _target) : EnvWrapper(_target) {}
  719. };
  720. ObjectLibrary::Default()->Register<Env>(
  721. kCustomEnvName,
  722. [](const std::string& /*name*/, std::unique_ptr<Env>* /*env_guard*/,
  723. std::string* /* errmsg */) {
  724. static CustomEnv env(Env::Default());
  725. return &env;
  726. });
  727. ASSERT_OK(GetOptionsFromString(
  728. base_options,
  729. "write_buffer_size=10;max_write_buffer_number=16;"
  730. "block_based_table_factory={block_cache=1M;block_size=4;};"
  731. "compression_opts=4:5:6;create_if_missing=true;max_open_files=1;"
  732. "bottommost_compression_opts=5:6:7;create_if_missing=true;max_open_files="
  733. "1;"
  734. "rate_limiter_bytes_per_sec=1024;env=CustomEnv",
  735. &new_options));
  736. ASSERT_EQ(new_options.compression_opts.window_bits, 4);
  737. ASSERT_EQ(new_options.compression_opts.level, 5);
  738. ASSERT_EQ(new_options.compression_opts.strategy, 6);
  739. ASSERT_EQ(new_options.compression_opts.max_dict_bytes, 0u);
  740. ASSERT_EQ(new_options.compression_opts.zstd_max_train_bytes, 0u);
  741. ASSERT_EQ(new_options.compression_opts.enabled, false);
  742. ASSERT_EQ(new_options.bottommost_compression, kDisableCompressionOption);
  743. ASSERT_EQ(new_options.bottommost_compression_opts.window_bits, 5);
  744. ASSERT_EQ(new_options.bottommost_compression_opts.level, 6);
  745. ASSERT_EQ(new_options.bottommost_compression_opts.strategy, 7);
  746. ASSERT_EQ(new_options.bottommost_compression_opts.max_dict_bytes, 0u);
  747. ASSERT_EQ(new_options.bottommost_compression_opts.zstd_max_train_bytes, 0u);
  748. ASSERT_EQ(new_options.bottommost_compression_opts.enabled, false);
  749. ASSERT_EQ(new_options.write_buffer_size, 10U);
  750. ASSERT_EQ(new_options.max_write_buffer_number, 16);
  751. BlockBasedTableOptions new_block_based_table_options =
  752. dynamic_cast<BlockBasedTableFactory*>(new_options.table_factory.get())
  753. ->table_options();
  754. ASSERT_EQ(new_block_based_table_options.block_cache->GetCapacity(), 1U << 20);
  755. ASSERT_EQ(new_block_based_table_options.block_size, 4U);
  756. // don't overwrite block based table options
  757. ASSERT_TRUE(new_block_based_table_options.cache_index_and_filter_blocks);
  758. ASSERT_EQ(new_options.create_if_missing, true);
  759. ASSERT_EQ(new_options.max_open_files, 1);
  760. ASSERT_TRUE(new_options.rate_limiter.get() != nullptr);
  761. Env* newEnv = new_options.env;
  762. ASSERT_OK(Env::LoadEnv(kCustomEnvName, &newEnv));
  763. ASSERT_EQ(newEnv, new_options.env);
  764. }
  765. TEST_F(OptionsTest, DBOptionsSerialization) {
  766. Options base_options, new_options;
  767. Random rnd(301);
  768. // Phase 1: Make big change in base_options
  769. test::RandomInitDBOptions(&base_options, &rnd);
  770. // Phase 2: obtain a string from base_option
  771. std::string base_options_file_content;
  772. ASSERT_OK(GetStringFromDBOptions(&base_options_file_content, base_options));
  773. // Phase 3: Set new_options from the derived string and expect
  774. // new_options == base_options
  775. ASSERT_OK(GetDBOptionsFromString(DBOptions(), base_options_file_content,
  776. &new_options));
  777. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(base_options, new_options));
  778. }
  779. TEST_F(OptionsTest, OptionsComposeDecompose) {
  780. // build an Options from DBOptions + CFOptions, then decompose it to verify
  781. // we get same constituent options.
  782. DBOptions base_db_opts;
  783. ColumnFamilyOptions base_cf_opts;
  784. Random rnd(301);
  785. test::RandomInitDBOptions(&base_db_opts, &rnd);
  786. test::RandomInitCFOptions(&base_cf_opts, base_db_opts, &rnd);
  787. Options base_opts(base_db_opts, base_cf_opts);
  788. DBOptions new_db_opts(base_opts);
  789. ColumnFamilyOptions new_cf_opts(base_opts);
  790. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(base_db_opts, new_db_opts));
  791. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opts, new_cf_opts));
  792. delete new_cf_opts.compaction_filter;
  793. }
  794. TEST_F(OptionsTest, ColumnFamilyOptionsSerialization) {
  795. Options options;
  796. ColumnFamilyOptions base_opt, new_opt;
  797. Random rnd(302);
  798. // Phase 1: randomly assign base_opt
  799. // custom type options
  800. test::RandomInitCFOptions(&base_opt, options, &rnd);
  801. // Phase 2: obtain a string from base_opt
  802. std::string base_options_file_content;
  803. ASSERT_OK(
  804. GetStringFromColumnFamilyOptions(&base_options_file_content, base_opt));
  805. // Phase 3: Set new_opt from the derived string and expect
  806. // new_opt == base_opt
  807. ASSERT_OK(GetColumnFamilyOptionsFromString(
  808. ColumnFamilyOptions(), base_options_file_content, &new_opt));
  809. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_opt, new_opt));
  810. if (base_opt.compaction_filter) {
  811. delete base_opt.compaction_filter;
  812. }
  813. }
  814. #endif // !ROCKSDB_LITE
  815. Status StringToMap(
  816. const std::string& opts_str,
  817. std::unordered_map<std::string, std::string>* opts_map);
  818. #ifndef ROCKSDB_LITE // StringToMap is not supported in ROCKSDB_LITE
  819. TEST_F(OptionsTest, StringToMapTest) {
  820. std::unordered_map<std::string, std::string> opts_map;
  821. // Regular options
  822. ASSERT_OK(StringToMap("k1=v1;k2=v2;k3=v3", &opts_map));
  823. ASSERT_EQ(opts_map["k1"], "v1");
  824. ASSERT_EQ(opts_map["k2"], "v2");
  825. ASSERT_EQ(opts_map["k3"], "v3");
  826. // Value with '='
  827. opts_map.clear();
  828. ASSERT_OK(StringToMap("k1==v1;k2=v2=;", &opts_map));
  829. ASSERT_EQ(opts_map["k1"], "=v1");
  830. ASSERT_EQ(opts_map["k2"], "v2=");
  831. // Overwrriten option
  832. opts_map.clear();
  833. ASSERT_OK(StringToMap("k1=v1;k1=v2;k3=v3", &opts_map));
  834. ASSERT_EQ(opts_map["k1"], "v2");
  835. ASSERT_EQ(opts_map["k3"], "v3");
  836. // Empty value
  837. opts_map.clear();
  838. ASSERT_OK(StringToMap("k1=v1;k2=;k3=v3;k4=", &opts_map));
  839. ASSERT_EQ(opts_map["k1"], "v1");
  840. ASSERT_TRUE(opts_map.find("k2") != opts_map.end());
  841. ASSERT_EQ(opts_map["k2"], "");
  842. ASSERT_EQ(opts_map["k3"], "v3");
  843. ASSERT_TRUE(opts_map.find("k4") != opts_map.end());
  844. ASSERT_EQ(opts_map["k4"], "");
  845. opts_map.clear();
  846. ASSERT_OK(StringToMap("k1=v1;k2=;k3=v3;k4= ", &opts_map));
  847. ASSERT_EQ(opts_map["k1"], "v1");
  848. ASSERT_TRUE(opts_map.find("k2") != opts_map.end());
  849. ASSERT_EQ(opts_map["k2"], "");
  850. ASSERT_EQ(opts_map["k3"], "v3");
  851. ASSERT_TRUE(opts_map.find("k4") != opts_map.end());
  852. ASSERT_EQ(opts_map["k4"], "");
  853. opts_map.clear();
  854. ASSERT_OK(StringToMap("k1=v1;k2=;k3=", &opts_map));
  855. ASSERT_EQ(opts_map["k1"], "v1");
  856. ASSERT_TRUE(opts_map.find("k2") != opts_map.end());
  857. ASSERT_EQ(opts_map["k2"], "");
  858. ASSERT_TRUE(opts_map.find("k3") != opts_map.end());
  859. ASSERT_EQ(opts_map["k3"], "");
  860. opts_map.clear();
  861. ASSERT_OK(StringToMap("k1=v1;k2=;k3=;", &opts_map));
  862. ASSERT_EQ(opts_map["k1"], "v1");
  863. ASSERT_TRUE(opts_map.find("k2") != opts_map.end());
  864. ASSERT_EQ(opts_map["k2"], "");
  865. ASSERT_TRUE(opts_map.find("k3") != opts_map.end());
  866. ASSERT_EQ(opts_map["k3"], "");
  867. // Regular nested options
  868. opts_map.clear();
  869. ASSERT_OK(StringToMap("k1=v1;k2={nk1=nv1;nk2=nv2};k3=v3", &opts_map));
  870. ASSERT_EQ(opts_map["k1"], "v1");
  871. ASSERT_EQ(opts_map["k2"], "nk1=nv1;nk2=nv2");
  872. ASSERT_EQ(opts_map["k3"], "v3");
  873. // Multi-level nested options
  874. opts_map.clear();
  875. ASSERT_OK(StringToMap("k1=v1;k2={nk1=nv1;nk2={nnk1=nnk2}};"
  876. "k3={nk1={nnk1={nnnk1=nnnv1;nnnk2;nnnv2}}};k4=v4",
  877. &opts_map));
  878. ASSERT_EQ(opts_map["k1"], "v1");
  879. ASSERT_EQ(opts_map["k2"], "nk1=nv1;nk2={nnk1=nnk2}");
  880. ASSERT_EQ(opts_map["k3"], "nk1={nnk1={nnnk1=nnnv1;nnnk2;nnnv2}}");
  881. ASSERT_EQ(opts_map["k4"], "v4");
  882. // Garbage inside curly braces
  883. opts_map.clear();
  884. ASSERT_OK(StringToMap("k1=v1;k2={dfad=};k3={=};k4=v4",
  885. &opts_map));
  886. ASSERT_EQ(opts_map["k1"], "v1");
  887. ASSERT_EQ(opts_map["k2"], "dfad=");
  888. ASSERT_EQ(opts_map["k3"], "=");
  889. ASSERT_EQ(opts_map["k4"], "v4");
  890. // Empty nested options
  891. opts_map.clear();
  892. ASSERT_OK(StringToMap("k1=v1;k2={};", &opts_map));
  893. ASSERT_EQ(opts_map["k1"], "v1");
  894. ASSERT_EQ(opts_map["k2"], "");
  895. opts_map.clear();
  896. ASSERT_OK(StringToMap("k1=v1;k2={{{{}}}{}{}};", &opts_map));
  897. ASSERT_EQ(opts_map["k1"], "v1");
  898. ASSERT_EQ(opts_map["k2"], "{{{}}}{}{}");
  899. // With random spaces
  900. opts_map.clear();
  901. ASSERT_OK(StringToMap(" k1 = v1 ; k2= {nk1=nv1; nk2={nnk1=nnk2}} ; "
  902. "k3={ { } }; k4= v4 ",
  903. &opts_map));
  904. ASSERT_EQ(opts_map["k1"], "v1");
  905. ASSERT_EQ(opts_map["k2"], "nk1=nv1; nk2={nnk1=nnk2}");
  906. ASSERT_EQ(opts_map["k3"], "{ }");
  907. ASSERT_EQ(opts_map["k4"], "v4");
  908. // Empty key
  909. ASSERT_NOK(StringToMap("k1=v1;k2=v2;=", &opts_map));
  910. ASSERT_NOK(StringToMap("=v1;k2=v2", &opts_map));
  911. ASSERT_NOK(StringToMap("k1=v1;k2v2;", &opts_map));
  912. ASSERT_NOK(StringToMap("k1=v1;k2=v2;fadfa", &opts_map));
  913. ASSERT_NOK(StringToMap("k1=v1;k2=v2;;", &opts_map));
  914. // Mismatch curly braces
  915. ASSERT_NOK(StringToMap("k1=v1;k2={;k3=v3", &opts_map));
  916. ASSERT_NOK(StringToMap("k1=v1;k2={{};k3=v3", &opts_map));
  917. ASSERT_NOK(StringToMap("k1=v1;k2={}};k3=v3", &opts_map));
  918. ASSERT_NOK(StringToMap("k1=v1;k2={{}{}}};k3=v3", &opts_map));
  919. // However this is valid!
  920. opts_map.clear();
  921. ASSERT_OK(StringToMap("k1=v1;k2=};k3=v3", &opts_map));
  922. ASSERT_EQ(opts_map["k1"], "v1");
  923. ASSERT_EQ(opts_map["k2"], "}");
  924. ASSERT_EQ(opts_map["k3"], "v3");
  925. // Invalid chars after closing curly brace
  926. ASSERT_NOK(StringToMap("k1=v1;k2={{}}{};k3=v3", &opts_map));
  927. ASSERT_NOK(StringToMap("k1=v1;k2={{}}cfda;k3=v3", &opts_map));
  928. ASSERT_NOK(StringToMap("k1=v1;k2={{}} cfda;k3=v3", &opts_map));
  929. ASSERT_NOK(StringToMap("k1=v1;k2={{}} cfda", &opts_map));
  930. ASSERT_NOK(StringToMap("k1=v1;k2={{}}{}", &opts_map));
  931. ASSERT_NOK(StringToMap("k1=v1;k2={{dfdl}adfa}{}", &opts_map));
  932. }
  933. #endif // ROCKSDB_LITE
  934. #ifndef ROCKSDB_LITE // StringToMap is not supported in ROCKSDB_LITE
  935. TEST_F(OptionsTest, StringToMapRandomTest) {
  936. std::unordered_map<std::string, std::string> opts_map;
  937. // Make sure segfault is not hit by semi-random strings
  938. std::vector<std::string> bases = {
  939. "a={aa={};tt={xxx={}}};c=defff",
  940. "a={aa={};tt={xxx={}}};c=defff;d={{}yxx{}3{xx}}",
  941. "abc={{}{}{}{{{}}}{{}{}{}{}{}{}{}"};
  942. for (std::string base : bases) {
  943. for (int rand_seed = 301; rand_seed < 401; rand_seed++) {
  944. Random rnd(rand_seed);
  945. for (int attempt = 0; attempt < 10; attempt++) {
  946. std::string str = base;
  947. // Replace random position to space
  948. size_t pos = static_cast<size_t>(
  949. rnd.Uniform(static_cast<int>(base.size())));
  950. str[pos] = ' ';
  951. Status s = StringToMap(str, &opts_map);
  952. ASSERT_TRUE(s.ok() || s.IsInvalidArgument());
  953. opts_map.clear();
  954. }
  955. }
  956. }
  957. // Random Construct a string
  958. std::vector<char> chars = {'{', '}', ' ', '=', ';', 'c'};
  959. for (int rand_seed = 301; rand_seed < 1301; rand_seed++) {
  960. Random rnd(rand_seed);
  961. int len = rnd.Uniform(30);
  962. std::string str = "";
  963. for (int attempt = 0; attempt < len; attempt++) {
  964. // Add a random character
  965. size_t pos = static_cast<size_t>(
  966. rnd.Uniform(static_cast<int>(chars.size())));
  967. str.append(1, chars[pos]);
  968. }
  969. Status s = StringToMap(str, &opts_map);
  970. ASSERT_TRUE(s.ok() || s.IsInvalidArgument());
  971. s = StringToMap("name=" + str, &opts_map);
  972. ASSERT_TRUE(s.ok() || s.IsInvalidArgument());
  973. opts_map.clear();
  974. }
  975. }
  976. TEST_F(OptionsTest, GetStringFromCompressionType) {
  977. std::string res;
  978. ASSERT_OK(GetStringFromCompressionType(&res, kNoCompression));
  979. ASSERT_EQ(res, "kNoCompression");
  980. ASSERT_OK(GetStringFromCompressionType(&res, kSnappyCompression));
  981. ASSERT_EQ(res, "kSnappyCompression");
  982. ASSERT_OK(GetStringFromCompressionType(&res, kDisableCompressionOption));
  983. ASSERT_EQ(res, "kDisableCompressionOption");
  984. ASSERT_OK(GetStringFromCompressionType(&res, kLZ4Compression));
  985. ASSERT_EQ(res, "kLZ4Compression");
  986. ASSERT_OK(GetStringFromCompressionType(&res, kZlibCompression));
  987. ASSERT_EQ(res, "kZlibCompression");
  988. ASSERT_NOK(
  989. GetStringFromCompressionType(&res, static_cast<CompressionType>(-10)));
  990. }
  991. #endif // !ROCKSDB_LITE
  992. TEST_F(OptionsTest, ConvertOptionsTest) {
  993. LevelDBOptions leveldb_opt;
  994. Options converted_opt = ConvertOptions(leveldb_opt);
  995. ASSERT_EQ(converted_opt.create_if_missing, leveldb_opt.create_if_missing);
  996. ASSERT_EQ(converted_opt.error_if_exists, leveldb_opt.error_if_exists);
  997. ASSERT_EQ(converted_opt.paranoid_checks, leveldb_opt.paranoid_checks);
  998. ASSERT_EQ(converted_opt.env, leveldb_opt.env);
  999. ASSERT_EQ(converted_opt.info_log.get(), leveldb_opt.info_log);
  1000. ASSERT_EQ(converted_opt.write_buffer_size, leveldb_opt.write_buffer_size);
  1001. ASSERT_EQ(converted_opt.max_open_files, leveldb_opt.max_open_files);
  1002. ASSERT_EQ(converted_opt.compression, leveldb_opt.compression);
  1003. std::shared_ptr<TableFactory> tb_guard = converted_opt.table_factory;
  1004. BlockBasedTableFactory* table_factory =
  1005. dynamic_cast<BlockBasedTableFactory*>(converted_opt.table_factory.get());
  1006. ASSERT_TRUE(table_factory != nullptr);
  1007. const BlockBasedTableOptions table_opt = table_factory->table_options();
  1008. ASSERT_EQ(table_opt.block_cache->GetCapacity(), 8UL << 20);
  1009. ASSERT_EQ(table_opt.block_size, leveldb_opt.block_size);
  1010. ASSERT_EQ(table_opt.block_restart_interval,
  1011. leveldb_opt.block_restart_interval);
  1012. ASSERT_EQ(table_opt.filter_policy.get(), leveldb_opt.filter_policy);
  1013. }
  1014. #ifndef ROCKSDB_LITE
  1015. class OptionsParserTest : public testing::Test {
  1016. public:
  1017. OptionsParserTest() {
  1018. env_.reset(new test::StringEnv(Env::Default()));
  1019. fs_.reset(new LegacyFileSystemWrapper(env_.get()));
  1020. }
  1021. protected:
  1022. std::unique_ptr<test::StringEnv> env_;
  1023. std::unique_ptr<LegacyFileSystemWrapper> fs_;
  1024. };
  1025. TEST_F(OptionsParserTest, Comment) {
  1026. DBOptions db_opt;
  1027. db_opt.max_open_files = 12345;
  1028. db_opt.max_background_flushes = 301;
  1029. db_opt.max_total_wal_size = 1024;
  1030. ColumnFamilyOptions cf_opt;
  1031. std::string options_file_content =
  1032. "# This is a testing option string.\n"
  1033. "# Currently we only support \"#\" styled comment.\n"
  1034. "\n"
  1035. "[Version]\n"
  1036. " rocksdb_version=3.14.0\n"
  1037. " options_file_version=1\n"
  1038. "[ DBOptions ]\n"
  1039. " # note that we don't support space around \"=\"\n"
  1040. " max_open_files=12345;\n"
  1041. " max_background_flushes=301 # comment after a statement is fine\n"
  1042. " # max_background_flushes=1000 # this line would be ignored\n"
  1043. " # max_background_compactions=2000 # so does this one\n"
  1044. " max_total_wal_size=1024 # keep_log_file_num=1000\n"
  1045. "[CFOptions \"default\"] # column family must be specified\n"
  1046. " # in the correct order\n"
  1047. " # if a section is blank, we will use the default\n";
  1048. const std::string kTestFileName = "test-rocksdb-options.ini";
  1049. env_->WriteToNewFile(kTestFileName, options_file_content);
  1050. RocksDBOptionsParser parser;
  1051. ASSERT_OK(
  1052. parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
  1053. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(*parser.db_opt(), db_opt));
  1054. ASSERT_EQ(parser.NumColumnFamilies(), 1U);
  1055. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
  1056. *parser.GetCFOptions("default"), cf_opt));
  1057. }
  1058. TEST_F(OptionsParserTest, ExtraSpace) {
  1059. std::string options_file_content =
  1060. "# This is a testing option string.\n"
  1061. "# Currently we only support \"#\" styled comment.\n"
  1062. "\n"
  1063. "[ Version ]\n"
  1064. " rocksdb_version = 3.14.0 \n"
  1065. " options_file_version=1 # some comment\n"
  1066. "[DBOptions ] # some comment\n"
  1067. "max_open_files=12345 \n"
  1068. " max_background_flushes = 301 \n"
  1069. " max_total_wal_size = 1024 # keep_log_file_num=1000\n"
  1070. " [CFOptions \"default\" ]\n"
  1071. " # if a section is blank, we will use the default\n";
  1072. const std::string kTestFileName = "test-rocksdb-options.ini";
  1073. env_->WriteToNewFile(kTestFileName, options_file_content);
  1074. RocksDBOptionsParser parser;
  1075. ASSERT_OK(
  1076. parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
  1077. }
  1078. TEST_F(OptionsParserTest, MissingDBOptions) {
  1079. std::string options_file_content =
  1080. "# This is a testing option string.\n"
  1081. "# Currently we only support \"#\" styled comment.\n"
  1082. "\n"
  1083. "[Version]\n"
  1084. " rocksdb_version=3.14.0\n"
  1085. " options_file_version=1\n"
  1086. "[CFOptions \"default\"]\n"
  1087. " # if a section is blank, we will use the default\n";
  1088. const std::string kTestFileName = "test-rocksdb-options.ini";
  1089. env_->WriteToNewFile(kTestFileName, options_file_content);
  1090. RocksDBOptionsParser parser;
  1091. ASSERT_NOK(
  1092. parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
  1093. }
  1094. TEST_F(OptionsParserTest, DoubleDBOptions) {
  1095. DBOptions db_opt;
  1096. db_opt.max_open_files = 12345;
  1097. db_opt.max_background_flushes = 301;
  1098. db_opt.max_total_wal_size = 1024;
  1099. ColumnFamilyOptions cf_opt;
  1100. std::string options_file_content =
  1101. "# This is a testing option string.\n"
  1102. "# Currently we only support \"#\" styled comment.\n"
  1103. "\n"
  1104. "[Version]\n"
  1105. " rocksdb_version=3.14.0\n"
  1106. " options_file_version=1\n"
  1107. "[DBOptions]\n"
  1108. " max_open_files=12345\n"
  1109. " max_background_flushes=301\n"
  1110. " max_total_wal_size=1024 # keep_log_file_num=1000\n"
  1111. "[DBOptions]\n"
  1112. "[CFOptions \"default\"]\n"
  1113. " # if a section is blank, we will use the default\n";
  1114. const std::string kTestFileName = "test-rocksdb-options.ini";
  1115. env_->WriteToNewFile(kTestFileName, options_file_content);
  1116. RocksDBOptionsParser parser;
  1117. ASSERT_NOK(
  1118. parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
  1119. }
  1120. TEST_F(OptionsParserTest, NoDefaultCFOptions) {
  1121. DBOptions db_opt;
  1122. db_opt.max_open_files = 12345;
  1123. db_opt.max_background_flushes = 301;
  1124. db_opt.max_total_wal_size = 1024;
  1125. ColumnFamilyOptions cf_opt;
  1126. std::string options_file_content =
  1127. "# This is a testing option string.\n"
  1128. "# Currently we only support \"#\" styled comment.\n"
  1129. "\n"
  1130. "[Version]\n"
  1131. " rocksdb_version=3.14.0\n"
  1132. " options_file_version=1\n"
  1133. "[DBOptions]\n"
  1134. " max_open_files=12345\n"
  1135. " max_background_flushes=301\n"
  1136. " max_total_wal_size=1024 # keep_log_file_num=1000\n"
  1137. "[CFOptions \"something_else\"]\n"
  1138. " # if a section is blank, we will use the default\n";
  1139. const std::string kTestFileName = "test-rocksdb-options.ini";
  1140. env_->WriteToNewFile(kTestFileName, options_file_content);
  1141. RocksDBOptionsParser parser;
  1142. ASSERT_NOK(
  1143. parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
  1144. }
  1145. TEST_F(OptionsParserTest, DefaultCFOptionsMustBeTheFirst) {
  1146. DBOptions db_opt;
  1147. db_opt.max_open_files = 12345;
  1148. db_opt.max_background_flushes = 301;
  1149. db_opt.max_total_wal_size = 1024;
  1150. ColumnFamilyOptions cf_opt;
  1151. std::string options_file_content =
  1152. "# This is a testing option string.\n"
  1153. "# Currently we only support \"#\" styled comment.\n"
  1154. "\n"
  1155. "[Version]\n"
  1156. " rocksdb_version=3.14.0\n"
  1157. " options_file_version=1\n"
  1158. "[DBOptions]\n"
  1159. " max_open_files=12345\n"
  1160. " max_background_flushes=301\n"
  1161. " max_total_wal_size=1024 # keep_log_file_num=1000\n"
  1162. "[CFOptions \"something_else\"]\n"
  1163. " # if a section is blank, we will use the default\n"
  1164. "[CFOptions \"default\"]\n"
  1165. " # if a section is blank, we will use the default\n";
  1166. const std::string kTestFileName = "test-rocksdb-options.ini";
  1167. env_->WriteToNewFile(kTestFileName, options_file_content);
  1168. RocksDBOptionsParser parser;
  1169. ASSERT_NOK(
  1170. parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
  1171. }
  1172. TEST_F(OptionsParserTest, DuplicateCFOptions) {
  1173. DBOptions db_opt;
  1174. db_opt.max_open_files = 12345;
  1175. db_opt.max_background_flushes = 301;
  1176. db_opt.max_total_wal_size = 1024;
  1177. ColumnFamilyOptions cf_opt;
  1178. std::string options_file_content =
  1179. "# This is a testing option string.\n"
  1180. "# Currently we only support \"#\" styled comment.\n"
  1181. "\n"
  1182. "[Version]\n"
  1183. " rocksdb_version=3.14.0\n"
  1184. " options_file_version=1\n"
  1185. "[DBOptions]\n"
  1186. " max_open_files=12345\n"
  1187. " max_background_flushes=301\n"
  1188. " max_total_wal_size=1024 # keep_log_file_num=1000\n"
  1189. "[CFOptions \"default\"]\n"
  1190. "[CFOptions \"something_else\"]\n"
  1191. "[CFOptions \"something_else\"]\n";
  1192. const std::string kTestFileName = "test-rocksdb-options.ini";
  1193. env_->WriteToNewFile(kTestFileName, options_file_content);
  1194. RocksDBOptionsParser parser;
  1195. ASSERT_NOK(
  1196. parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
  1197. }
  1198. TEST_F(OptionsParserTest, IgnoreUnknownOptions) {
  1199. for (int case_id = 0; case_id < 5; case_id++) {
  1200. DBOptions db_opt;
  1201. db_opt.max_open_files = 12345;
  1202. db_opt.max_background_flushes = 301;
  1203. db_opt.max_total_wal_size = 1024;
  1204. ColumnFamilyOptions cf_opt;
  1205. std::string version_string;
  1206. bool should_ignore = true;
  1207. if (case_id == 0) {
  1208. // same version
  1209. should_ignore = false;
  1210. version_string =
  1211. ToString(ROCKSDB_MAJOR) + "." + ToString(ROCKSDB_MINOR) + ".0";
  1212. } else if (case_id == 1) {
  1213. // higher minor version
  1214. should_ignore = true;
  1215. version_string =
  1216. ToString(ROCKSDB_MAJOR) + "." + ToString(ROCKSDB_MINOR + 1) + ".0";
  1217. } else if (case_id == 2) {
  1218. // higher major version.
  1219. should_ignore = true;
  1220. version_string = ToString(ROCKSDB_MAJOR + 1) + ".0.0";
  1221. } else if (case_id == 3) {
  1222. // lower minor version
  1223. #if ROCKSDB_MINOR == 0
  1224. continue;
  1225. #else
  1226. version_string =
  1227. ToString(ROCKSDB_MAJOR) + "." + ToString(ROCKSDB_MINOR - 1) + ".0";
  1228. should_ignore = false;
  1229. #endif
  1230. } else {
  1231. // lower major version
  1232. should_ignore = false;
  1233. version_string =
  1234. ToString(ROCKSDB_MAJOR - 1) + "." + ToString(ROCKSDB_MINOR) + ".0";
  1235. }
  1236. std::string options_file_content =
  1237. "# This is a testing option string.\n"
  1238. "# Currently we only support \"#\" styled comment.\n"
  1239. "\n"
  1240. "[Version]\n"
  1241. " rocksdb_version=" +
  1242. version_string +
  1243. "\n"
  1244. " options_file_version=1\n"
  1245. "[DBOptions]\n"
  1246. " max_open_files=12345\n"
  1247. " max_background_flushes=301\n"
  1248. " max_total_wal_size=1024 # keep_log_file_num=1000\n"
  1249. " unknown_db_option1=321\n"
  1250. " unknown_db_option2=false\n"
  1251. "[CFOptions \"default\"]\n"
  1252. " unknown_cf_option1=hello\n"
  1253. "[CFOptions \"something_else\"]\n"
  1254. " unknown_cf_option2=world\n"
  1255. " # if a section is blank, we will use the default\n";
  1256. const std::string kTestFileName = "test-rocksdb-options.ini";
  1257. env_->DeleteFile(kTestFileName);
  1258. env_->WriteToNewFile(kTestFileName, options_file_content);
  1259. RocksDBOptionsParser parser;
  1260. ASSERT_NOK(parser.Parse(kTestFileName, fs_.get(), false,
  1261. 4096 /* readahead_size */));
  1262. if (should_ignore) {
  1263. ASSERT_OK(parser.Parse(kTestFileName, fs_.get(),
  1264. true /* ignore_unknown_options */,
  1265. 4096 /* readahead_size */));
  1266. } else {
  1267. ASSERT_NOK(parser.Parse(kTestFileName, fs_.get(),
  1268. true /* ignore_unknown_options */,
  1269. 4096 /* readahead_size */));
  1270. }
  1271. }
  1272. }
  1273. TEST_F(OptionsParserTest, ParseVersion) {
  1274. DBOptions db_opt;
  1275. db_opt.max_open_files = 12345;
  1276. db_opt.max_background_flushes = 301;
  1277. db_opt.max_total_wal_size = 1024;
  1278. ColumnFamilyOptions cf_opt;
  1279. std::string file_template =
  1280. "# This is a testing option string.\n"
  1281. "# Currently we only support \"#\" styled comment.\n"
  1282. "\n"
  1283. "[Version]\n"
  1284. " rocksdb_version=3.13.1\n"
  1285. " options_file_version=%s\n"
  1286. "[DBOptions]\n"
  1287. "[CFOptions \"default\"]\n";
  1288. const int kLength = 1000;
  1289. char buffer[kLength];
  1290. RocksDBOptionsParser parser;
  1291. const std::vector<std::string> invalid_versions = {
  1292. "a.b.c", "3.2.2b", "3.-12", "3. 1", // only digits and dots are allowed
  1293. "1.2.3.4",
  1294. "1.2.3" // can only contains at most one dot.
  1295. "0", // options_file_version must be at least one
  1296. "3..2",
  1297. ".", ".1.2", // must have at least one digit before each dot
  1298. "1.2.", "1.", "2.34."}; // must have at least one digit after each dot
  1299. for (auto iv : invalid_versions) {
  1300. snprintf(buffer, kLength - 1, file_template.c_str(), iv.c_str());
  1301. parser.Reset();
  1302. env_->WriteToNewFile(iv, buffer);
  1303. ASSERT_NOK(parser.Parse(iv, fs_.get(), false, 0 /* readahead_size */));
  1304. }
  1305. const std::vector<std::string> valid_versions = {
  1306. "1.232", "100", "3.12", "1", "12.3 ", " 1.25 "};
  1307. for (auto vv : valid_versions) {
  1308. snprintf(buffer, kLength - 1, file_template.c_str(), vv.c_str());
  1309. parser.Reset();
  1310. env_->WriteToNewFile(vv, buffer);
  1311. ASSERT_OK(parser.Parse(vv, fs_.get(), false, 0 /* readahead_size */));
  1312. }
  1313. }
  1314. void VerifyCFPointerTypedOptions(
  1315. ColumnFamilyOptions* base_cf_opt, const ColumnFamilyOptions* new_cf_opt,
  1316. const std::unordered_map<std::string, std::string>* new_cf_opt_map) {
  1317. std::string name_buffer;
  1318. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt, *new_cf_opt,
  1319. new_cf_opt_map));
  1320. // change the name of merge operator back-and-forth
  1321. {
  1322. auto* merge_operator = dynamic_cast<test::ChanglingMergeOperator*>(
  1323. base_cf_opt->merge_operator.get());
  1324. if (merge_operator != nullptr) {
  1325. name_buffer = merge_operator->Name();
  1326. // change the name and expect non-ok status
  1327. merge_operator->SetName("some-other-name");
  1328. ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
  1329. *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  1330. // change the name back and expect ok status
  1331. merge_operator->SetName(name_buffer);
  1332. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt, *new_cf_opt,
  1333. new_cf_opt_map));
  1334. }
  1335. }
  1336. // change the name of the compaction filter factory back-and-forth
  1337. {
  1338. auto* compaction_filter_factory =
  1339. dynamic_cast<test::ChanglingCompactionFilterFactory*>(
  1340. base_cf_opt->compaction_filter_factory.get());
  1341. if (compaction_filter_factory != nullptr) {
  1342. name_buffer = compaction_filter_factory->Name();
  1343. // change the name and expect non-ok status
  1344. compaction_filter_factory->SetName("some-other-name");
  1345. ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
  1346. *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  1347. // change the name back and expect ok status
  1348. compaction_filter_factory->SetName(name_buffer);
  1349. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt, *new_cf_opt,
  1350. new_cf_opt_map));
  1351. }
  1352. }
  1353. // test by setting compaction_filter to nullptr
  1354. {
  1355. auto* tmp_compaction_filter = base_cf_opt->compaction_filter;
  1356. if (tmp_compaction_filter != nullptr) {
  1357. base_cf_opt->compaction_filter = nullptr;
  1358. // set compaction_filter to nullptr and expect non-ok status
  1359. ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
  1360. *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  1361. // set the value back and expect ok status
  1362. base_cf_opt->compaction_filter = tmp_compaction_filter;
  1363. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt, *new_cf_opt,
  1364. new_cf_opt_map));
  1365. }
  1366. }
  1367. // test by setting table_factory to nullptr
  1368. {
  1369. auto tmp_table_factory = base_cf_opt->table_factory;
  1370. if (tmp_table_factory != nullptr) {
  1371. base_cf_opt->table_factory.reset();
  1372. // set table_factory to nullptr and expect non-ok status
  1373. ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
  1374. *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  1375. // set the value back and expect ok status
  1376. base_cf_opt->table_factory = tmp_table_factory;
  1377. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt, *new_cf_opt,
  1378. new_cf_opt_map));
  1379. }
  1380. }
  1381. // test by setting memtable_factory to nullptr
  1382. {
  1383. auto tmp_memtable_factory = base_cf_opt->memtable_factory;
  1384. if (tmp_memtable_factory != nullptr) {
  1385. base_cf_opt->memtable_factory.reset();
  1386. // set memtable_factory to nullptr and expect non-ok status
  1387. ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
  1388. *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  1389. // set the value back and expect ok status
  1390. base_cf_opt->memtable_factory = tmp_memtable_factory;
  1391. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt, *new_cf_opt,
  1392. new_cf_opt_map));
  1393. }
  1394. }
  1395. }
  1396. TEST_F(OptionsParserTest, Readahead) {
  1397. DBOptions base_db_opt;
  1398. std::vector<ColumnFamilyOptions> base_cf_opts;
  1399. base_cf_opts.emplace_back();
  1400. base_cf_opts.emplace_back();
  1401. std::string one_mb_string = std::string(1024 * 1024, 'x');
  1402. std::vector<std::string> cf_names = {"default", one_mb_string};
  1403. const std::string kOptionsFileName = "test-persisted-options.ini";
  1404. ASSERT_OK(PersistRocksDBOptions(base_db_opt, cf_names, base_cf_opts,
  1405. kOptionsFileName, fs_.get()));
  1406. uint64_t file_size = 0;
  1407. ASSERT_OK(env_->GetFileSize(kOptionsFileName, &file_size));
  1408. assert(file_size > 0);
  1409. RocksDBOptionsParser parser;
  1410. env_->num_seq_file_read_ = 0;
  1411. size_t readahead_size = 128 * 1024;
  1412. ASSERT_OK(parser.Parse(kOptionsFileName, fs_.get(), false, readahead_size));
  1413. ASSERT_EQ(env_->num_seq_file_read_.load(),
  1414. (file_size - 1) / readahead_size + 1);
  1415. env_->num_seq_file_read_.store(0);
  1416. readahead_size = 1024 * 1024;
  1417. ASSERT_OK(parser.Parse(kOptionsFileName, fs_.get(), false, readahead_size));
  1418. ASSERT_EQ(env_->num_seq_file_read_.load(),
  1419. (file_size - 1) / readahead_size + 1);
  1420. // Tiny readahead. 8 KB is read each time.
  1421. env_->num_seq_file_read_.store(0);
  1422. ASSERT_OK(
  1423. parser.Parse(kOptionsFileName, fs_.get(), false, 1 /* readahead_size */));
  1424. ASSERT_GE(env_->num_seq_file_read_.load(), file_size / (8 * 1024));
  1425. ASSERT_LT(env_->num_seq_file_read_.load(), file_size / (8 * 1024) * 2);
  1426. // Disable readahead means 512KB readahead.
  1427. env_->num_seq_file_read_.store(0);
  1428. ASSERT_OK(
  1429. parser.Parse(kOptionsFileName, fs_.get(), false, 0 /* readahead_size */));
  1430. ASSERT_GE(env_->num_seq_file_read_.load(),
  1431. (file_size - 1) / (512 * 1024) + 1);
  1432. }
  1433. TEST_F(OptionsParserTest, DumpAndParse) {
  1434. DBOptions base_db_opt;
  1435. std::vector<ColumnFamilyOptions> base_cf_opts;
  1436. std::vector<std::string> cf_names = {"default", "cf1", "cf2", "cf3",
  1437. "c:f:4:4:4"
  1438. "p\\i\\k\\a\\chu\\\\\\",
  1439. "###rocksdb#1-testcf#2###"};
  1440. const int num_cf = static_cast<int>(cf_names.size());
  1441. Random rnd(302);
  1442. test::RandomInitDBOptions(&base_db_opt, &rnd);
  1443. base_db_opt.db_log_dir += "/#odd #but #could #happen #path #/\\\\#OMG";
  1444. BlockBasedTableOptions special_bbto;
  1445. special_bbto.cache_index_and_filter_blocks = true;
  1446. special_bbto.block_size = 999999;
  1447. for (int c = 0; c < num_cf; ++c) {
  1448. ColumnFamilyOptions cf_opt;
  1449. Random cf_rnd(0xFB + c);
  1450. test::RandomInitCFOptions(&cf_opt, base_db_opt, &cf_rnd);
  1451. if (c < 4) {
  1452. cf_opt.prefix_extractor.reset(test::RandomSliceTransform(&rnd, c));
  1453. }
  1454. if (c < 3) {
  1455. cf_opt.table_factory.reset(test::RandomTableFactory(&rnd, c));
  1456. } else if (c == 4) {
  1457. cf_opt.table_factory.reset(NewBlockBasedTableFactory(special_bbto));
  1458. }
  1459. base_cf_opts.emplace_back(cf_opt);
  1460. }
  1461. const std::string kOptionsFileName = "test-persisted-options.ini";
  1462. ASSERT_OK(PersistRocksDBOptions(base_db_opt, cf_names, base_cf_opts,
  1463. kOptionsFileName, fs_.get()));
  1464. RocksDBOptionsParser parser;
  1465. ASSERT_OK(
  1466. parser.Parse(kOptionsFileName, fs_.get(), false, 0 /* readahead_size */));
  1467. // Make sure block-based table factory options was deserialized correctly
  1468. std::shared_ptr<TableFactory> ttf = (*parser.cf_opts())[4].table_factory;
  1469. ASSERT_EQ(BlockBasedTableFactory::kName, std::string(ttf->Name()));
  1470. const BlockBasedTableOptions& parsed_bbto =
  1471. static_cast<BlockBasedTableFactory*>(ttf.get())->table_options();
  1472. ASSERT_EQ(special_bbto.block_size, parsed_bbto.block_size);
  1473. ASSERT_EQ(special_bbto.cache_index_and_filter_blocks,
  1474. parsed_bbto.cache_index_and_filter_blocks);
  1475. ASSERT_OK(RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
  1476. base_db_opt, cf_names, base_cf_opts, kOptionsFileName, fs_.get()));
  1477. ASSERT_OK(
  1478. RocksDBOptionsParser::VerifyDBOptions(*parser.db_opt(), base_db_opt));
  1479. for (int c = 0; c < num_cf; ++c) {
  1480. const auto* cf_opt = parser.GetCFOptions(cf_names[c]);
  1481. ASSERT_NE(cf_opt, nullptr);
  1482. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
  1483. base_cf_opts[c], *cf_opt, &(parser.cf_opt_maps()->at(c))));
  1484. }
  1485. // Further verify pointer-typed options
  1486. for (int c = 0; c < num_cf; ++c) {
  1487. const auto* cf_opt = parser.GetCFOptions(cf_names[c]);
  1488. ASSERT_NE(cf_opt, nullptr);
  1489. VerifyCFPointerTypedOptions(&base_cf_opts[c], cf_opt,
  1490. &(parser.cf_opt_maps()->at(c)));
  1491. }
  1492. ASSERT_EQ(parser.GetCFOptions("does not exist"), nullptr);
  1493. base_db_opt.max_open_files++;
  1494. ASSERT_NOK(RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
  1495. base_db_opt, cf_names, base_cf_opts, kOptionsFileName, fs_.get()));
  1496. for (int c = 0; c < num_cf; ++c) {
  1497. if (base_cf_opts[c].compaction_filter) {
  1498. delete base_cf_opts[c].compaction_filter;
  1499. }
  1500. }
  1501. }
  1502. TEST_F(OptionsParserTest, DifferentDefault) {
  1503. const std::string kOptionsFileName = "test-persisted-options.ini";
  1504. ColumnFamilyOptions cf_level_opts;
  1505. ASSERT_EQ(CompactionPri::kMinOverlappingRatio, cf_level_opts.compaction_pri);
  1506. cf_level_opts.OptimizeLevelStyleCompaction();
  1507. ColumnFamilyOptions cf_univ_opts;
  1508. cf_univ_opts.OptimizeUniversalStyleCompaction();
  1509. ASSERT_OK(PersistRocksDBOptions(DBOptions(), {"default", "universal"},
  1510. {cf_level_opts, cf_univ_opts},
  1511. kOptionsFileName, fs_.get()));
  1512. RocksDBOptionsParser parser;
  1513. ASSERT_OK(
  1514. parser.Parse(kOptionsFileName, fs_.get(), false, 0 /* readahead_size */));
  1515. {
  1516. Options old_default_opts;
  1517. old_default_opts.OldDefaults();
  1518. ASSERT_EQ(10 * 1048576, old_default_opts.max_bytes_for_level_base);
  1519. ASSERT_EQ(5000, old_default_opts.max_open_files);
  1520. ASSERT_EQ(2 * 1024U * 1024U, old_default_opts.delayed_write_rate);
  1521. ASSERT_EQ(WALRecoveryMode::kTolerateCorruptedTailRecords,
  1522. old_default_opts.wal_recovery_mode);
  1523. }
  1524. {
  1525. Options old_default_opts;
  1526. old_default_opts.OldDefaults(4, 6);
  1527. ASSERT_EQ(10 * 1048576, old_default_opts.max_bytes_for_level_base);
  1528. ASSERT_EQ(5000, old_default_opts.max_open_files);
  1529. }
  1530. {
  1531. Options old_default_opts;
  1532. old_default_opts.OldDefaults(4, 7);
  1533. ASSERT_NE(10 * 1048576, old_default_opts.max_bytes_for_level_base);
  1534. ASSERT_NE(4, old_default_opts.table_cache_numshardbits);
  1535. ASSERT_EQ(5000, old_default_opts.max_open_files);
  1536. ASSERT_EQ(2 * 1024U * 1024U, old_default_opts.delayed_write_rate);
  1537. }
  1538. {
  1539. ColumnFamilyOptions old_default_cf_opts;
  1540. old_default_cf_opts.OldDefaults();
  1541. ASSERT_EQ(2 * 1048576, old_default_cf_opts.target_file_size_base);
  1542. ASSERT_EQ(4 << 20, old_default_cf_opts.write_buffer_size);
  1543. ASSERT_EQ(2 * 1048576, old_default_cf_opts.target_file_size_base);
  1544. ASSERT_EQ(0, old_default_cf_opts.soft_pending_compaction_bytes_limit);
  1545. ASSERT_EQ(0, old_default_cf_opts.hard_pending_compaction_bytes_limit);
  1546. ASSERT_EQ(CompactionPri::kByCompensatedSize,
  1547. old_default_cf_opts.compaction_pri);
  1548. }
  1549. {
  1550. ColumnFamilyOptions old_default_cf_opts;
  1551. old_default_cf_opts.OldDefaults(4, 6);
  1552. ASSERT_EQ(2 * 1048576, old_default_cf_opts.target_file_size_base);
  1553. ASSERT_EQ(CompactionPri::kByCompensatedSize,
  1554. old_default_cf_opts.compaction_pri);
  1555. }
  1556. {
  1557. ColumnFamilyOptions old_default_cf_opts;
  1558. old_default_cf_opts.OldDefaults(4, 7);
  1559. ASSERT_NE(2 * 1048576, old_default_cf_opts.target_file_size_base);
  1560. ASSERT_EQ(CompactionPri::kByCompensatedSize,
  1561. old_default_cf_opts.compaction_pri);
  1562. }
  1563. {
  1564. Options old_default_opts;
  1565. old_default_opts.OldDefaults(5, 1);
  1566. ASSERT_EQ(2 * 1024U * 1024U, old_default_opts.delayed_write_rate);
  1567. }
  1568. {
  1569. Options old_default_opts;
  1570. old_default_opts.OldDefaults(5, 2);
  1571. ASSERT_EQ(16 * 1024U * 1024U, old_default_opts.delayed_write_rate);
  1572. ASSERT_TRUE(old_default_opts.compaction_pri ==
  1573. CompactionPri::kByCompensatedSize);
  1574. }
  1575. {
  1576. Options old_default_opts;
  1577. old_default_opts.OldDefaults(5, 18);
  1578. ASSERT_TRUE(old_default_opts.compaction_pri ==
  1579. CompactionPri::kByCompensatedSize);
  1580. }
  1581. Options small_opts;
  1582. small_opts.OptimizeForSmallDb();
  1583. ASSERT_EQ(2 << 20, small_opts.write_buffer_size);
  1584. ASSERT_EQ(5000, small_opts.max_open_files);
  1585. }
  1586. class OptionsSanityCheckTest : public OptionsParserTest {
  1587. public:
  1588. OptionsSanityCheckTest() {}
  1589. protected:
  1590. Status SanityCheckCFOptions(const ColumnFamilyOptions& cf_opts,
  1591. OptionsSanityCheckLevel level) {
  1592. return RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
  1593. DBOptions(), {"default"}, {cf_opts}, kOptionsFileName, fs_.get(),
  1594. level);
  1595. }
  1596. Status PersistCFOptions(const ColumnFamilyOptions& cf_opts) {
  1597. Status s = env_->DeleteFile(kOptionsFileName);
  1598. if (!s.ok()) {
  1599. return s;
  1600. }
  1601. return PersistRocksDBOptions(DBOptions(), {"default"}, {cf_opts},
  1602. kOptionsFileName, fs_.get());
  1603. }
  1604. const std::string kOptionsFileName = "OPTIONS";
  1605. };
  1606. TEST_F(OptionsSanityCheckTest, SanityCheck) {
  1607. ColumnFamilyOptions opts;
  1608. Random rnd(301);
  1609. // default ColumnFamilyOptions
  1610. {
  1611. ASSERT_OK(PersistCFOptions(opts));
  1612. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1613. }
  1614. // prefix_extractor
  1615. {
  1616. // Okay to change prefix_extractor form nullptr to non-nullptr
  1617. ASSERT_EQ(opts.prefix_extractor.get(), nullptr);
  1618. opts.prefix_extractor.reset(NewCappedPrefixTransform(10));
  1619. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
  1620. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone));
  1621. // persist the change
  1622. ASSERT_OK(PersistCFOptions(opts));
  1623. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1624. // use same prefix extractor but with different parameter
  1625. opts.prefix_extractor.reset(NewCappedPrefixTransform(15));
  1626. // expect pass only in kSanityLevelLooselyCompatible
  1627. ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1628. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
  1629. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone));
  1630. // repeat the test with FixedPrefixTransform
  1631. opts.prefix_extractor.reset(NewFixedPrefixTransform(10));
  1632. ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1633. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
  1634. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone));
  1635. // persist the change of prefix_extractor
  1636. ASSERT_OK(PersistCFOptions(opts));
  1637. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1638. // use same prefix extractor but with different parameter
  1639. opts.prefix_extractor.reset(NewFixedPrefixTransform(15));
  1640. // expect pass only in kSanityLevelLooselyCompatible
  1641. ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1642. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
  1643. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone));
  1644. // Change prefix extractor from non-nullptr to nullptr
  1645. opts.prefix_extractor.reset();
  1646. // expect pass as it's safe to change prefix_extractor
  1647. // from non-null to null
  1648. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
  1649. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone));
  1650. }
  1651. // persist the change
  1652. ASSERT_OK(PersistCFOptions(opts));
  1653. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1654. // table_factory
  1655. {
  1656. for (int tb = 0; tb <= 2; ++tb) {
  1657. // change the table factory
  1658. opts.table_factory.reset(test::RandomTableFactory(&rnd, tb));
  1659. ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
  1660. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone));
  1661. // persist the change
  1662. ASSERT_OK(PersistCFOptions(opts));
  1663. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1664. }
  1665. }
  1666. // merge_operator
  1667. {
  1668. // Test when going from nullptr -> merge operator
  1669. opts.merge_operator.reset(test::RandomMergeOperator(&rnd));
  1670. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
  1671. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone));
  1672. // persist the change
  1673. ASSERT_OK(PersistCFOptions(opts));
  1674. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1675. for (int test = 0; test < 5; ++test) {
  1676. // change the merge operator
  1677. opts.merge_operator.reset(test::RandomMergeOperator(&rnd));
  1678. ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
  1679. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone));
  1680. // persist the change
  1681. ASSERT_OK(PersistCFOptions(opts));
  1682. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1683. }
  1684. // Test when going from merge operator -> nullptr
  1685. opts.merge_operator = nullptr;
  1686. ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
  1687. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone));
  1688. // persist the change
  1689. ASSERT_OK(PersistCFOptions(opts));
  1690. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1691. }
  1692. // compaction_filter
  1693. {
  1694. for (int test = 0; test < 5; ++test) {
  1695. // change the compaction filter
  1696. opts.compaction_filter = test::RandomCompactionFilter(&rnd);
  1697. ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1698. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
  1699. // persist the change
  1700. ASSERT_OK(PersistCFOptions(opts));
  1701. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1702. delete opts.compaction_filter;
  1703. opts.compaction_filter = nullptr;
  1704. }
  1705. }
  1706. // compaction_filter_factory
  1707. {
  1708. for (int test = 0; test < 5; ++test) {
  1709. // change the compaction filter factory
  1710. opts.compaction_filter_factory.reset(
  1711. test::RandomCompactionFilterFactory(&rnd));
  1712. ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1713. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
  1714. // persist the change
  1715. ASSERT_OK(PersistCFOptions(opts));
  1716. ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
  1717. }
  1718. }
  1719. }
  1720. namespace {
  1721. bool IsEscapedString(const std::string& str) {
  1722. for (size_t i = 0; i < str.size(); ++i) {
  1723. if (str[i] == '\\') {
  1724. // since we already handle those two consecutive '\'s in
  1725. // the next if-then branch, any '\' appear at the end
  1726. // of an escaped string in such case is not valid.
  1727. if (i == str.size() - 1) {
  1728. return false;
  1729. }
  1730. if (str[i + 1] == '\\') {
  1731. // if there're two consecutive '\'s, skip the second one.
  1732. i++;
  1733. continue;
  1734. }
  1735. switch (str[i + 1]) {
  1736. case ':':
  1737. case '\\':
  1738. case '#':
  1739. continue;
  1740. default:
  1741. // if true, '\' together with str[i + 1] is not a valid escape.
  1742. if (UnescapeChar(str[i + 1]) == str[i + 1]) {
  1743. return false;
  1744. }
  1745. }
  1746. } else if (isSpecialChar(str[i]) && (i == 0 || str[i - 1] != '\\')) {
  1747. return false;
  1748. }
  1749. }
  1750. return true;
  1751. }
  1752. } // namespace
  1753. TEST_F(OptionsParserTest, IntegerParsing) {
  1754. ASSERT_EQ(ParseUint64("18446744073709551615"), 18446744073709551615U);
  1755. ASSERT_EQ(ParseUint32("4294967295"), 4294967295U);
  1756. ASSERT_EQ(ParseSizeT("18446744073709551615"), 18446744073709551615U);
  1757. ASSERT_EQ(ParseInt64("9223372036854775807"), 9223372036854775807);
  1758. ASSERT_EQ(ParseInt64("-9223372036854775808"), port::kMinInt64);
  1759. ASSERT_EQ(ParseInt32("2147483647"), 2147483647);
  1760. ASSERT_EQ(ParseInt32("-2147483648"), port::kMinInt32);
  1761. ASSERT_EQ(ParseInt("-32767"), -32767);
  1762. ASSERT_EQ(ParseDouble("-1.234567"), -1.234567);
  1763. }
  1764. TEST_F(OptionsParserTest, EscapeOptionString) {
  1765. ASSERT_EQ(UnescapeOptionString(
  1766. "This is a test string with \\# \\: and \\\\ escape chars."),
  1767. "This is a test string with # : and \\ escape chars.");
  1768. ASSERT_EQ(
  1769. EscapeOptionString("This is a test string with # : and \\ escape chars."),
  1770. "This is a test string with \\# \\: and \\\\ escape chars.");
  1771. std::string readible_chars =
  1772. "A String like this \"1234567890-=_)(*&^%$#@!ertyuiop[]{POIU"
  1773. "YTREWQasdfghjkl;':LKJHGFDSAzxcvbnm,.?>"
  1774. "<MNBVCXZ\\\" should be okay to \\#\\\\\\:\\#\\#\\#\\ "
  1775. "be serialized and deserialized";
  1776. std::string escaped_string = EscapeOptionString(readible_chars);
  1777. ASSERT_TRUE(IsEscapedString(escaped_string));
  1778. // This two transformations should be canceled and should output
  1779. // the original input.
  1780. ASSERT_EQ(UnescapeOptionString(escaped_string), readible_chars);
  1781. std::string all_chars;
  1782. for (unsigned char c = 0;; ++c) {
  1783. all_chars += c;
  1784. if (c == 255) {
  1785. break;
  1786. }
  1787. }
  1788. escaped_string = EscapeOptionString(all_chars);
  1789. ASSERT_TRUE(IsEscapedString(escaped_string));
  1790. ASSERT_EQ(UnescapeOptionString(escaped_string), all_chars);
  1791. ASSERT_EQ(RocksDBOptionsParser::TrimAndRemoveComment(
  1792. " A simple statement with a comment. # like this :)"),
  1793. "A simple statement with a comment.");
  1794. ASSERT_EQ(RocksDBOptionsParser::TrimAndRemoveComment(
  1795. "Escape \\# and # comment together ."),
  1796. "Escape \\# and");
  1797. }
  1798. #endif // !ROCKSDB_LITE
  1799. } // namespace ROCKSDB_NAMESPACE
  1800. int main(int argc, char** argv) {
  1801. ::testing::InitGoogleTest(&argc, argv);
  1802. #ifdef GFLAGS
  1803. ParseCommandLineFlags(&argc, &argv, true);
  1804. #endif // GFLAGS
  1805. return RUN_ALL_TESTS();
  1806. }