options_settable_test.cc 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  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 <cstring>
  10. #include "options/cf_options.h"
  11. #include "options/db_options.h"
  12. #include "options/options_helper.h"
  13. #include "rocksdb/convenience.h"
  14. #include "test_util/testharness.h"
  15. #ifndef GFLAGS
  16. bool FLAGS_enable_print = false;
  17. #else
  18. #include "util/gflags_compat.h"
  19. using GFLAGS_NAMESPACE::ParseCommandLineFlags;
  20. DEFINE_bool(enable_print, false, "Print options generated to console.");
  21. #endif // GFLAGS
  22. namespace ROCKSDB_NAMESPACE {
  23. // Verify options are settable from options strings.
  24. // We take the approach that depends on compiler behavior that copy constructor
  25. // won't touch implicit padding bytes, so that the test is fragile.
  26. // As a result, we only run the tests to verify new fields in options are
  27. // settable through string on limited platforms as it depends on behavior of
  28. // compilers.
  29. #if defined OS_LINUX || defined OS_WIN
  30. #ifndef __clang__
  31. #ifndef ROCKSDB_UBSAN_RUN
  32. class OptionsSettableTest : public testing::Test {
  33. public:
  34. OptionsSettableTest() {}
  35. };
  36. const char kSpecialChar = 'z';
  37. using OffsetGap = std::vector<std::pair<size_t, size_t>>;
  38. void FillWithSpecialChar(char* start_ptr, size_t total_size,
  39. const OffsetGap& excluded,
  40. char special_char = kSpecialChar) {
  41. size_t offset = 0;
  42. // The excluded vector contains pairs of bytes, (first, second).
  43. // The first bytes are all set to the special char (represented as 'c' below).
  44. // The second bytes are simply skipped (padding bytes).
  45. // ccccc[skipped]cccccccc[skiped]cccccccc[skipped]
  46. for (auto& pair : excluded) {
  47. std::memset(start_ptr + offset, special_char, pair.first - offset);
  48. offset = pair.first + pair.second;
  49. }
  50. // The rest of the structure is filled with the special characters.
  51. // ccccc[skipped]cccccccc[skiped]cccccccc[skipped]cccccccccccccccc
  52. std::memset(start_ptr + offset, special_char, total_size - offset);
  53. }
  54. int NumUnsetBytes(char* start_ptr, size_t total_size,
  55. const OffsetGap& excluded) {
  56. int total_unset_bytes_base = 0;
  57. size_t offset = 0;
  58. for (auto& pair : excluded) {
  59. // The first part of the structure contains memory spaces that can be
  60. // set (pair.first), and memory spaces that cannot be set (pair.second).
  61. // Therefore total_unset_bytes_base only agregates bytes set to kSpecialChar
  62. // in the pair.first bytes, but skips the pair.second bytes (padding bytes).
  63. for (char* ptr = start_ptr + offset; ptr < start_ptr + pair.first; ptr++) {
  64. if (*ptr == kSpecialChar) {
  65. total_unset_bytes_base++;
  66. }
  67. }
  68. offset = pair.first + pair.second;
  69. }
  70. // Then total_unset_bytes_base aggregates the bytes
  71. // set to kSpecialChar in the rest of the structure
  72. for (char* ptr = start_ptr + offset; ptr < start_ptr + total_size; ptr++) {
  73. if (*ptr == kSpecialChar) {
  74. total_unset_bytes_base++;
  75. }
  76. }
  77. return total_unset_bytes_base;
  78. }
  79. // Return true iff two structs are the same except excluded fields.
  80. bool CompareBytes(char* start_ptr1, char* start_ptr2, size_t total_size,
  81. const OffsetGap& excluded) {
  82. size_t offset = 0;
  83. for (auto& pair : excluded) {
  84. for (; offset < pair.first; offset++) {
  85. if (*(start_ptr1 + offset) != *(start_ptr2 + offset)) {
  86. return false;
  87. }
  88. }
  89. offset = pair.first + pair.second;
  90. }
  91. for (; offset < total_size; offset++) {
  92. if (*(start_ptr1 + offset) != *(start_ptr2 + offset)) {
  93. return false;
  94. }
  95. }
  96. return true;
  97. }
  98. // If the test fails, likely a new option is added to BlockBasedTableOptions
  99. // but it cannot be set through GetBlockBasedTableOptionsFromString(), or the
  100. // test is not updated accordingly.
  101. // After adding an option, we need to make sure it is settable by
  102. // GetBlockBasedTableOptionsFromString() and add the option to the input string
  103. // passed to the GetBlockBasedTableOptionsFromString() in this test.
  104. // If it is a complicated type, you also need to add the field to
  105. // kBbtoExcluded, and maybe add customized verification for it.
  106. TEST_F(OptionsSettableTest, BlockBasedTableOptionsAllFieldsSettable) {
  107. // Items in the form of <offset, size>. Need to be in ascending order
  108. // and not overlapping. Need to update if new option to be excluded is added
  109. // (e.g, pointer-type)
  110. const OffsetGap kBbtoExcluded = {
  111. {offsetof(struct BlockBasedTableOptions, flush_block_policy_factory),
  112. sizeof(std::shared_ptr<FlushBlockPolicyFactory>)},
  113. {offsetof(struct BlockBasedTableOptions, block_cache),
  114. sizeof(std::shared_ptr<Cache>)},
  115. {offsetof(struct BlockBasedTableOptions, persistent_cache),
  116. sizeof(std::shared_ptr<PersistentCache>)},
  117. {offsetof(struct BlockBasedTableOptions, cache_usage_options),
  118. sizeof(CacheUsageOptions)},
  119. {offsetof(struct BlockBasedTableOptions, filter_policy),
  120. sizeof(std::shared_ptr<const FilterPolicy>)},
  121. {offsetof(struct BlockBasedTableOptions, user_defined_index_factory),
  122. sizeof(std::shared_ptr<UserDefinedIndexFactory>)},
  123. };
  124. // In this test, we catch a new option of BlockBasedTableOptions that is not
  125. // settable through GetBlockBasedTableOptionsFromString().
  126. // We count padding bytes of the option struct, and assert it to be the same
  127. // as unset bytes of an option struct initialized by
  128. // GetBlockBasedTableOptionsFromString().
  129. char* bbto_ptr = new char[sizeof(BlockBasedTableOptions)];
  130. // Count padding bytes by setting all bytes in the memory to a special char,
  131. // copy a well constructed struct to this memory and see how many special
  132. // bytes left.
  133. BlockBasedTableOptions* bbto = new (bbto_ptr) BlockBasedTableOptions();
  134. FillWithSpecialChar(bbto_ptr, sizeof(BlockBasedTableOptions), kBbtoExcluded);
  135. // It based on the behavior of compiler that padding bytes are not changed
  136. // when copying the struct. It's prone to failure when compiler behavior
  137. // changes. We verify there is unset bytes to detect the case.
  138. *bbto = BlockBasedTableOptions();
  139. int unset_bytes_base =
  140. NumUnsetBytes(bbto_ptr, sizeof(BlockBasedTableOptions), kBbtoExcluded);
  141. ASSERT_GT(unset_bytes_base, 0);
  142. bbto->~BlockBasedTableOptions();
  143. // Construct the base option passed into
  144. // GetBlockBasedTableOptionsFromString().
  145. bbto = new (bbto_ptr) BlockBasedTableOptions();
  146. FillWithSpecialChar(bbto_ptr, sizeof(BlockBasedTableOptions), kBbtoExcluded);
  147. char* new_bbto_ptr = new char[sizeof(BlockBasedTableOptions)];
  148. BlockBasedTableOptions* new_bbto =
  149. new (new_bbto_ptr) BlockBasedTableOptions();
  150. FillWithSpecialChar(new_bbto_ptr, sizeof(BlockBasedTableOptions),
  151. kBbtoExcluded);
  152. // Need to update the option string if a new option is added.
  153. ConfigOptions config_options;
  154. config_options.input_strings_escaped = false;
  155. config_options.ignore_unknown_options = false;
  156. config_options.invoke_prepare_options = false;
  157. config_options.ignore_unsupported_options = false;
  158. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  159. config_options, *bbto,
  160. "cache_index_and_filter_blocks=1;"
  161. "cache_index_and_filter_blocks_with_high_priority=true;"
  162. "metadata_cache_options={top_level_index_pinning=kFallback;"
  163. "partition_pinning=kAll;"
  164. "unpartitioned_pinning=kFlushedAndSimilar;};"
  165. "pin_l0_filter_and_index_blocks_in_cache=1;"
  166. "pin_top_level_index_and_filter=1;"
  167. "index_type=kHashSearch;"
  168. "data_block_index_type=kDataBlockBinaryAndHash;"
  169. "index_shortening=kNoShortening;"
  170. "data_block_hash_table_util_ratio=0.75;"
  171. "checksum=kxxHash;no_block_cache=1;"
  172. "block_cache=1M;block_cache_compressed=1k;block_size=1024;"
  173. "block_size_deviation=8;block_restart_interval=4; "
  174. "metadata_block_size=1024;"
  175. "partition_filters=false;"
  176. "decouple_partitioned_filters=true;"
  177. "optimize_filters_for_memory=true;"
  178. "use_delta_encoding=true;"
  179. "index_block_restart_interval=4;"
  180. "filter_policy=bloomfilter:4:true;whole_key_filtering=1;detect_filter_"
  181. "construct_corruption=false;"
  182. "format_version=1;"
  183. "verify_compression=true;read_amp_bytes_per_bit=0;"
  184. "enable_index_compression=false;"
  185. "block_align=true;"
  186. "super_block_alignment_size=65536;"
  187. "super_block_alignment_space_overhead_ratio=4096;"
  188. "max_auto_readahead_size=0;"
  189. "prepopulate_block_cache=kDisable;"
  190. "initial_auto_readahead_size=0;"
  191. "num_file_reads_for_auto_readahead=0;"
  192. "fail_if_no_udi_on_open=true",
  193. new_bbto));
  194. ASSERT_EQ(unset_bytes_base,
  195. NumUnsetBytes(new_bbto_ptr, sizeof(BlockBasedTableOptions),
  196. kBbtoExcluded));
  197. ASSERT_TRUE(new_bbto->block_cache.get() != nullptr);
  198. ASSERT_TRUE(new_bbto->filter_policy.get() != nullptr);
  199. bbto->~BlockBasedTableOptions();
  200. new_bbto->~BlockBasedTableOptions();
  201. delete[] bbto_ptr;
  202. delete[] new_bbto_ptr;
  203. }
  204. TEST_F(OptionsSettableTest, TablePropertiesAllFieldsSettable) {
  205. const OffsetGap kTablePropertiesExcluded = {
  206. {offsetof(struct TableProperties, db_id), sizeof(std::string)},
  207. {offsetof(struct TableProperties, db_session_id), sizeof(std::string)},
  208. {offsetof(struct TableProperties, db_host_id), sizeof(std::string)},
  209. {offsetof(struct TableProperties, column_family_name),
  210. sizeof(std::string)},
  211. {offsetof(struct TableProperties, filter_policy_name),
  212. sizeof(std::string)},
  213. {offsetof(struct TableProperties, comparator_name), sizeof(std::string)},
  214. {offsetof(struct TableProperties, merge_operator_name),
  215. sizeof(std::string)},
  216. {offsetof(struct TableProperties, prefix_extractor_name),
  217. sizeof(std::string)},
  218. {offsetof(struct TableProperties, property_collectors_names),
  219. sizeof(std::string)},
  220. {offsetof(struct TableProperties, compression_name), sizeof(std::string)},
  221. {offsetof(struct TableProperties, compression_options),
  222. sizeof(std::string)},
  223. {offsetof(struct TableProperties, seqno_to_time_mapping),
  224. sizeof(std::string)},
  225. {offsetof(struct TableProperties, user_collected_properties),
  226. sizeof(UserCollectedProperties)},
  227. {offsetof(struct TableProperties, readable_properties),
  228. sizeof(UserCollectedProperties)},
  229. };
  230. char* tp_ptr = new char[sizeof(TableProperties)];
  231. TableProperties* tp = new (tp_ptr) TableProperties();
  232. FillWithSpecialChar(tp_ptr, sizeof(TableProperties),
  233. kTablePropertiesExcluded);
  234. ASSERT_GT(
  235. NumUnsetBytes(tp_ptr, sizeof(TableProperties), kTablePropertiesExcluded),
  236. 0);
  237. char* new_tp_ptr = new char[sizeof(TableProperties)];
  238. TableProperties* new_tp = new (new_tp_ptr) TableProperties();
  239. FillWithSpecialChar(new_tp_ptr, sizeof(TableProperties),
  240. kTablePropertiesExcluded);
  241. // Need to update the option string if a new option is added.
  242. ConfigOptions config_options;
  243. config_options.input_strings_escaped = false;
  244. config_options.ignore_unknown_options = false;
  245. config_options.invoke_prepare_options = false;
  246. config_options.ignore_unsupported_options = false;
  247. ASSERT_OK(TableProperties::Parse(
  248. config_options,
  249. "readable_properties={7265616461626C655F6B6579="
  250. "7265616461626C655F76616C7565;};compression_options=;compression_name=;"
  251. "property_collectors_names=;prefix_extractor_name=;db_host_id="
  252. "64625F686F73745F6964;db_session_id=64625F73657373696F6E5F6964;creation_"
  253. "time=0;num_data_blocks=123;index_value_is_delta_encoded=0;top_level_"
  254. "index_size=0;data_size=100;uncompressed_data_size=1234;"
  255. "merge_operator_name=;index_partitions=0;file_"
  256. "creation_time=0;raw_value_size=0;index_size=200;user_collected_"
  257. "properties={757365725F6B6579=757365725F76616C7565;};tail_start_offset=0;"
  258. "seqno_to_time_mapping=;raw_key_size=0;slow_compression_estimated_data_"
  259. "size=0;filter_size=0;orig_file_number=3;num_deletions=0;num_range_"
  260. "deletions=0;format_version=0;comparator_name="
  261. "636F6D70617261746F725F6E616D65;num_filter_entries=0;db_id="
  262. "64625F686F73745F6964;column_family_id=2147483647;fixed_key_len=0;fast_"
  263. "compression_estimated_data_size=0;filter_policy_name="
  264. "66696C7465725F706F6C6963795F6E616D65;oldest_key_time=0;newest_key_time="
  265. "0;column_family_"
  266. "name=64656661756C74;user_defined_timestamps_persisted=1;num_entries=100;"
  267. "external_sst_file_global_seqno_offset=0;num_merge_operands=0;index_key_"
  268. "is_user_key=0;key_largest_seqno=18446744073709551615;key_smallest_seqno="
  269. "18;",
  270. new_tp));
  271. // All bytes are set from the parse
  272. ASSERT_EQ(NumUnsetBytes(new_tp_ptr, sizeof(TableProperties),
  273. kTablePropertiesExcluded),
  274. 0);
  275. ASSERT_EQ(new_tp->db_host_id, "db_host_id");
  276. ASSERT_EQ(new_tp->num_entries, 100);
  277. ASSERT_EQ(new_tp->num_data_blocks, 123);
  278. ASSERT_EQ(new_tp->user_collected_properties.size(), 1);
  279. ASSERT_EQ(new_tp->readable_properties.size(), 1);
  280. tp->~TableProperties();
  281. new_tp->~TableProperties();
  282. delete[] tp_ptr;
  283. delete[] new_tp_ptr;
  284. }
  285. // If the test fails, likely a new option is added to DBOptions
  286. // but it cannot be set through GetDBOptionsFromString(), or the test is not
  287. // updated accordingly.
  288. // After adding an option, we need to make sure it is settable by
  289. // GetDBOptionsFromString() and add the option to the input string passed to
  290. // DBOptionsFromString()in this test.
  291. // If it is a complicated type, you also need to add the field to
  292. // kDBOptionsExcluded, and maybe add customized verification for it.
  293. TEST_F(OptionsSettableTest, DBOptionsAllFieldsSettable) {
  294. const OffsetGap kDBOptionsExcluded = {
  295. {offsetof(struct DBOptions, env), sizeof(Env*)},
  296. {offsetof(struct DBOptions, rate_limiter),
  297. sizeof(std::shared_ptr<RateLimiter>)},
  298. {offsetof(struct DBOptions, sst_file_manager),
  299. sizeof(std::shared_ptr<SstFileManager>)},
  300. {offsetof(struct DBOptions, info_log), sizeof(std::shared_ptr<Logger>)},
  301. {offsetof(struct DBOptions, statistics),
  302. sizeof(std::shared_ptr<Statistics>)},
  303. {offsetof(struct DBOptions, db_paths), sizeof(std::vector<DbPath>)},
  304. {offsetof(struct DBOptions, db_log_dir), sizeof(std::string)},
  305. {offsetof(struct DBOptions, wal_dir), sizeof(std::string)},
  306. {offsetof(struct DBOptions, write_buffer_manager),
  307. sizeof(std::shared_ptr<WriteBufferManager>)},
  308. {offsetof(struct DBOptions, listeners),
  309. sizeof(std::vector<std::shared_ptr<EventListener>>)},
  310. {offsetof(struct DBOptions, row_cache), sizeof(std::shared_ptr<Cache>)},
  311. {offsetof(struct DBOptions, wal_filter), sizeof(const WalFilter*)},
  312. {offsetof(struct DBOptions, file_checksum_gen_factory),
  313. sizeof(std::shared_ptr<FileChecksumGenFactory>)},
  314. {offsetof(struct DBOptions, db_host_id), sizeof(std::string)},
  315. {offsetof(struct DBOptions, checksum_handoff_file_types),
  316. sizeof(FileTypeSet)},
  317. {offsetof(struct DBOptions, compaction_service),
  318. sizeof(std::shared_ptr<CompactionService>)},
  319. {offsetof(struct DBOptions, daily_offpeak_time_utc), sizeof(std::string)},
  320. {offsetof(struct DBOptions, calculate_sst_write_lifetime_hint_set),
  321. sizeof(CompactionStyleSet)},
  322. };
  323. char* options_ptr = new char[sizeof(DBOptions)];
  324. // Count padding bytes by setting all bytes in the memory to a special char,
  325. // copy a well constructed struct to this memory and see how many special
  326. // bytes left.
  327. DBOptions* options = new (options_ptr) DBOptions();
  328. FillWithSpecialChar(options_ptr, sizeof(DBOptions), kDBOptionsExcluded);
  329. // It based on the behavior of compiler that padding bytes are not changed
  330. // when copying the struct. It's prone to failure when compiler behavior
  331. // changes. We verify there is unset bytes to detect the case.
  332. *options = DBOptions();
  333. int unset_bytes_base =
  334. NumUnsetBytes(options_ptr, sizeof(DBOptions), kDBOptionsExcluded);
  335. ASSERT_GT(unset_bytes_base, 0);
  336. options->~DBOptions();
  337. // Now also check that BuildDBOptions populates everything
  338. FillWithSpecialChar(options_ptr, sizeof(DBOptions), kDBOptionsExcluded);
  339. BuildDBOptions({}, {}, *options);
  340. ASSERT_EQ(unset_bytes_base,
  341. NumUnsetBytes(options_ptr, sizeof(DBOptions), kDBOptionsExcluded));
  342. options = new (options_ptr) DBOptions();
  343. FillWithSpecialChar(options_ptr, sizeof(DBOptions), kDBOptionsExcluded);
  344. char* new_options_ptr = new char[sizeof(DBOptions)];
  345. DBOptions* new_options = new (new_options_ptr) DBOptions();
  346. FillWithSpecialChar(new_options_ptr, sizeof(DBOptions), kDBOptionsExcluded);
  347. // Need to update the option string if a new option is added.
  348. ConfigOptions config_options(*options);
  349. config_options.input_strings_escaped = false;
  350. config_options.ignore_unknown_options = false;
  351. ASSERT_OK(
  352. GetDBOptionsFromString(config_options, *options,
  353. "wal_bytes_per_sync=4295048118;"
  354. "delete_obsolete_files_period_micros=4294967758;"
  355. "WAL_ttl_seconds=4295008036;"
  356. "WAL_size_limit_MB=4295036161;"
  357. "max_write_batch_group_size_bytes=1048576;"
  358. "wal_dir=path/to/wal_dir;"
  359. "db_write_buffer_size=2587;"
  360. "max_subcompactions=64330;"
  361. "table_cache_numshardbits=28;"
  362. "max_open_files=72;"
  363. "max_file_opening_threads=35;"
  364. "max_background_jobs=8;"
  365. "max_background_compactions=33;"
  366. "use_fsync=true;"
  367. "use_adaptive_mutex=false;"
  368. "max_total_wal_size=4295005604;"
  369. "compaction_readahead_size=0;"
  370. "keep_log_file_num=4890;"
  371. "skip_stats_update_on_db_open=false;"
  372. "skip_checking_sst_file_sizes_on_db_open=false;"
  373. "max_manifest_file_size=4295009941;"
  374. "db_log_dir=path/to/db_log_dir;"
  375. "writable_file_max_buffer_size=1048576;"
  376. "paranoid_checks=true;"
  377. "flush_verify_memtable_count=true;"
  378. "compaction_verify_record_count=true;"
  379. "track_and_verify_wals_in_manifest=true;"
  380. "track_and_verify_wals=true;"
  381. "verify_sst_unique_id_in_manifest=true;"
  382. "is_fd_close_on_exec=false;"
  383. "bytes_per_sync=4295013613;"
  384. "strict_bytes_per_sync=true;"
  385. "enable_thread_tracking=false;"
  386. "recycle_log_file_num=0;"
  387. "create_missing_column_families=true;"
  388. "log_file_time_to_roll=3097;"
  389. "max_background_flushes=35;"
  390. "create_if_missing=false;"
  391. "error_if_exists=true;"
  392. "delayed_write_rate=4294976214;"
  393. "manifest_preallocation_size=1222;"
  394. "allow_mmap_writes=false;"
  395. "stats_dump_period_sec=70127;"
  396. "stats_persist_period_sec=54321;"
  397. "persist_stats_to_disk=true;"
  398. "stats_history_buffer_size=14159;"
  399. "allow_fallocate=true;"
  400. "allow_mmap_reads=false;"
  401. "use_direct_reads=false;"
  402. "use_direct_io_for_flush_and_compaction=false;"
  403. "max_log_file_size=4607;"
  404. "advise_random_on_open=true;"
  405. "enable_pipelined_write=false;"
  406. "unordered_write=false;"
  407. "allow_concurrent_memtable_write=true;"
  408. "wal_recovery_mode=kPointInTimeRecovery;"
  409. "enable_write_thread_adaptive_yield=true;"
  410. "write_thread_slow_yield_usec=5;"
  411. "write_thread_max_yield_usec=1000;"
  412. "info_log_level=DEBUG_LEVEL;"
  413. "dump_malloc_stats=false;"
  414. "allow_2pc=false;"
  415. "avoid_flush_during_recovery=false;"
  416. "avoid_flush_during_shutdown=false;"
  417. "allow_ingest_behind=false;"
  418. "concurrent_prepare=false;"
  419. "two_write_queues=false;"
  420. "manual_wal_flush=false;"
  421. "wal_compression=kZSTD;"
  422. "background_close_inactive_wals=true;"
  423. "seq_per_batch=false;"
  424. "atomic_flush=false;"
  425. "avoid_unnecessary_blocking_io=false;"
  426. "log_readahead_size=0;"
  427. "write_dbid_to_manifest=false;"
  428. "best_efforts_recovery=false;"
  429. "max_bgerror_resume_count=2;"
  430. "bgerror_resume_retry_interval=1000000;"
  431. "db_host_id=hostname;"
  432. "lowest_used_cache_tier=kNonVolatileBlockTier;"
  433. "allow_data_in_errors=false;"
  434. "enforce_single_del_contracts=false;"
  435. "daily_offpeak_time_utc=08:30-19:00;"
  436. "follower_refresh_catchup_period_ms=123;"
  437. "follower_catchup_retry_count=456;"
  438. "follower_catchup_retry_wait_ms=789;"
  439. "metadata_write_temperature=kCold;"
  440. "wal_write_temperature=kHot;"
  441. "background_close_inactive_wals=true;"
  442. "write_dbid_to_manifest=true;"
  443. "write_identity_file=true;"
  444. "prefix_seek_opt_in_only=true;",
  445. new_options));
  446. ASSERT_EQ(unset_bytes_base, NumUnsetBytes(new_options_ptr, sizeof(DBOptions),
  447. kDBOptionsExcluded));
  448. options->~DBOptions();
  449. new_options->~DBOptions();
  450. delete[] options_ptr;
  451. delete[] new_options_ptr;
  452. }
  453. // status check adds CXX flag -fno-elide-constructors which fails this test.
  454. #ifndef ROCKSDB_ASSERT_STATUS_CHECKED
  455. // If the test fails, likely a new option is added to ColumnFamilyOptions
  456. // but it cannot be set through GetColumnFamilyOptionsFromString(), or the
  457. // test is not updated accordingly.
  458. // After adding an option, we need to make sure it is settable by
  459. // GetColumnFamilyOptionsFromString() and add the option to the input
  460. // string passed to GetColumnFamilyOptionsFromString() in this test.
  461. // If it is a complicated type, you also need to add the field to
  462. // kColumnFamilyOptionsExcluded, and maybe add customized verification
  463. // for it.
  464. TEST_F(OptionsSettableTest, ColumnFamilyOptionsAllFieldsSettable) {
  465. // options in the excluded set need to appear in the same order as in
  466. // ColumnFamilyOptions.
  467. const OffsetGap kColumnFamilyOptionsExcluded = {
  468. {offsetof(struct ColumnFamilyOptions, inplace_callback),
  469. sizeof(UpdateStatus(*)(char*, uint32_t*, Slice, std::string*))},
  470. {offsetof(struct ColumnFamilyOptions,
  471. memtable_insert_with_hint_prefix_extractor),
  472. sizeof(std::shared_ptr<const SliceTransform>)},
  473. {offsetof(struct ColumnFamilyOptions, compression_per_level),
  474. sizeof(std::vector<CompressionType>)},
  475. {offsetof(struct ColumnFamilyOptions,
  476. max_bytes_for_level_multiplier_additional),
  477. sizeof(std::vector<int>)},
  478. {offsetof(struct ColumnFamilyOptions, compaction_options_fifo),
  479. sizeof(struct CompactionOptionsFIFO)},
  480. {offsetof(struct ColumnFamilyOptions, memtable_factory),
  481. sizeof(std::shared_ptr<MemTableRepFactory>)},
  482. {offsetof(struct ColumnFamilyOptions,
  483. table_properties_collector_factories),
  484. sizeof(ColumnFamilyOptions::TablePropertiesCollectorFactories)},
  485. {offsetof(struct ColumnFamilyOptions, preclude_last_level_data_seconds),
  486. sizeof(uint64_t)},
  487. {offsetof(struct ColumnFamilyOptions, preserve_internal_time_seconds),
  488. sizeof(uint64_t)},
  489. {offsetof(struct ColumnFamilyOptions, blob_cache),
  490. sizeof(std::shared_ptr<Cache>)},
  491. {offsetof(struct ColumnFamilyOptions, comparator), sizeof(Comparator*)},
  492. {offsetof(struct ColumnFamilyOptions, merge_operator),
  493. sizeof(std::shared_ptr<MergeOperator>)},
  494. {offsetof(struct ColumnFamilyOptions, compaction_filter),
  495. sizeof(const CompactionFilter*)},
  496. {offsetof(struct ColumnFamilyOptions, compaction_filter_factory),
  497. sizeof(std::shared_ptr<CompactionFilterFactory>)},
  498. {offsetof(struct ColumnFamilyOptions, compression_manager),
  499. sizeof(std::shared_ptr<CompressionManager>)},
  500. {offsetof(struct ColumnFamilyOptions, prefix_extractor),
  501. sizeof(std::shared_ptr<const SliceTransform>)},
  502. {offsetof(struct ColumnFamilyOptions, snap_refresh_nanos),
  503. sizeof(uint64_t)},
  504. {offsetof(struct ColumnFamilyOptions, table_factory),
  505. sizeof(std::shared_ptr<TableFactory>)},
  506. {offsetof(struct ColumnFamilyOptions, cf_paths),
  507. sizeof(std::vector<DbPath>)},
  508. {offsetof(struct ColumnFamilyOptions, compaction_thread_limiter),
  509. sizeof(std::shared_ptr<ConcurrentTaskLimiter>)},
  510. {offsetof(struct ColumnFamilyOptions, sst_partitioner_factory),
  511. sizeof(std::shared_ptr<SstPartitionerFactory>)},
  512. };
  513. char* options_ptr = new char[sizeof(ColumnFamilyOptions)];
  514. // Count padding bytes by setting all bytes in the memory to a special char,
  515. // copy a well constructed struct to this memory and see how many special
  516. // bytes left.
  517. FillWithSpecialChar(options_ptr, sizeof(ColumnFamilyOptions),
  518. kColumnFamilyOptionsExcluded);
  519. // Invoke a user-defined constructor in the hope that it does not overwrite
  520. // padding bytes. Note that previously we relied on the implicitly-defined
  521. // copy-assignment operator (i.e., `*options = ColumnFamilyOptions();`) here,
  522. // which did in fact modify padding bytes.
  523. ColumnFamilyOptions* options = new (options_ptr) ColumnFamilyOptions();
  524. int unset_bytes_base = NumUnsetBytes(options_ptr, sizeof(ColumnFamilyOptions),
  525. kColumnFamilyOptionsExcluded);
  526. ASSERT_GT(unset_bytes_base, 0);
  527. options->~ColumnFamilyOptions();
  528. options = new (options_ptr) ColumnFamilyOptions();
  529. FillWithSpecialChar(options_ptr, sizeof(ColumnFamilyOptions),
  530. kColumnFamilyOptionsExcluded);
  531. // Following options are not settable through
  532. // GetColumnFamilyOptionsFromString():
  533. options->compaction_options_universal = CompactionOptionsUniversal();
  534. options->num_levels = 42; // Initialize options for MutableCF
  535. options->compaction_filter = nullptr;
  536. options->sst_partitioner_factory = nullptr;
  537. char* new_options_ptr = new char[sizeof(ColumnFamilyOptions)];
  538. ColumnFamilyOptions* new_options =
  539. new (new_options_ptr) ColumnFamilyOptions();
  540. FillWithSpecialChar(new_options_ptr, sizeof(ColumnFamilyOptions),
  541. kColumnFamilyOptionsExcluded);
  542. // Need to update the option string if a new option is added.
  543. ConfigOptions config_options;
  544. config_options.input_strings_escaped = false;
  545. config_options.ignore_unknown_options = false;
  546. ASSERT_OK(GetColumnFamilyOptionsFromString(
  547. config_options, *options,
  548. "compaction_filter_factory=mpudlojcujCompactionFilterFactory;"
  549. "table_factory=PlainTable;"
  550. "prefix_extractor=rocksdb.CappedPrefix.13;"
  551. "comparator=leveldb.BytewiseComparator;"
  552. "compression_per_level=kBZip2Compression:kBZip2Compression:"
  553. "kBZip2Compression:kNoCompression:kZlibCompression:kBZip2Compression:"
  554. "kSnappyCompression;"
  555. "max_bytes_for_level_base=986;"
  556. "bloom_locality=8016;"
  557. "target_file_size_base=4294976376;"
  558. "memtable_huge_page_size=2557;"
  559. "max_successive_merges=5497;"
  560. "strict_max_successive_merges=true;"
  561. "max_sequential_skip_in_iterations=4294971408;"
  562. "arena_block_size=1893;"
  563. "target_file_size_multiplier=35;"
  564. "min_write_buffer_number_to_merge=9;"
  565. "max_write_buffer_number=84;"
  566. "write_buffer_size=1653;"
  567. "max_compaction_bytes=64;"
  568. "ignore_max_compaction_bytes_for_input=true;"
  569. "max_bytes_for_level_multiplier=60;"
  570. "memtable_factory=SkipListFactory;"
  571. "compression=kNoCompression;"
  572. "compression_opts={max_dict_buffer_bytes=5;use_zstd_dict_trainer=true;"
  573. "enabled=false;parallel_threads=6;zstd_max_train_bytes=7;strategy=8;max_"
  574. "dict_bytes=9;level=10;window_bits=11;max_compressed_bytes_per_kb=987;"
  575. "checksum=true};"
  576. "bottommost_compression_opts={max_dict_buffer_bytes=4;use_zstd_dict_"
  577. "trainer=true;enabled=true;parallel_threads=5;zstd_max_train_bytes=6;"
  578. "strategy=7;max_dict_bytes=8;level=9;window_bits=10;max_compressed_bytes_"
  579. "per_kb=876;checksum=true};"
  580. "bottommost_compression=kDisableCompressionOption;"
  581. "compression_manager=BuiltinV2;"
  582. "level0_stop_writes_trigger=33;"
  583. "num_levels=99;"
  584. "level0_slowdown_writes_trigger=22;"
  585. "level0_file_num_compaction_trigger=14;"
  586. "compaction_filter=urxcqstuwnCompactionFilter;"
  587. "soft_pending_compaction_bytes_limit=0;"
  588. "max_write_buffer_size_to_maintain=2147483648;"
  589. "merge_operator=aabcxehazrMergeOperator;"
  590. "memtable_prefix_bloom_size_ratio=0.4642;"
  591. "memtable_whole_key_filtering=true;"
  592. "memtable_insert_with_hint_prefix_extractor=rocksdb.CappedPrefix.13;"
  593. "check_flush_compaction_key_order=false;"
  594. "paranoid_file_checks=true;"
  595. "force_consistency_checks=true;"
  596. "inplace_update_num_locks=7429;"
  597. "experimental_mempurge_threshold=0.0001;"
  598. "optimize_filters_for_hits=false;"
  599. "level_compaction_dynamic_level_bytes=false;"
  600. "level_compaction_dynamic_file_size=true;"
  601. "inplace_update_support=false;"
  602. "compaction_style=kCompactionStyleFIFO;"
  603. "compaction_pri=kMinOverlappingRatio;"
  604. "hard_pending_compaction_bytes_limit=0;"
  605. "disable_auto_compactions=false;"
  606. "report_bg_io_stats=true;"
  607. "disallow_memtable_writes=true;"
  608. "ttl=60;"
  609. "periodic_compaction_seconds=3600;"
  610. "sample_for_compression=0;"
  611. "enable_blob_files=true;"
  612. "min_blob_size=256;"
  613. "blob_file_size=1000000;"
  614. "blob_compression_type=kBZip2Compression;"
  615. "enable_blob_garbage_collection=true;"
  616. "blob_garbage_collection_age_cutoff=0.5;"
  617. "blob_garbage_collection_force_threshold=0.75;"
  618. "blob_compaction_readahead_size=262144;"
  619. "blob_file_starting_level=1;"
  620. "prepopulate_blob_cache=kDisable;"
  621. "bottommost_temperature=kWarm;"
  622. "last_level_temperature=kWarm;"
  623. "default_write_temperature=kCold;"
  624. "default_temperature=kHot;"
  625. "preclude_last_level_data_seconds=86400;"
  626. "preserve_internal_time_seconds=86400;"
  627. "compaction_options_fifo={max_table_files_size=3;allow_"
  628. "compaction=true;age_for_warm=0;file_temperature_age_thresholds={{"
  629. "temperature=kCold;age=12345}};};"
  630. "blob_cache=1M;"
  631. "memtable_protection_bytes_per_key=2;"
  632. "persist_user_defined_timestamps=true;"
  633. "block_protection_bytes_per_key=1;"
  634. "memtable_max_range_deletions=999999;"
  635. "bottommost_file_compaction_delay=7200;"
  636. "uncache_aggressiveness=1234;"
  637. "paranoid_memory_checks=1;"
  638. "memtable_veirfy_per_key_checksum_on_seek=1;"
  639. "memtable_op_scan_flush_trigger=123;"
  640. "memtable_avg_op_scan_flush_trigger=12;"
  641. "cf_allow_ingest_behind=1;",
  642. new_options));
  643. ASSERT_NE(new_options->blob_cache.get(), nullptr);
  644. ASSERT_EQ(unset_bytes_base,
  645. NumUnsetBytes(new_options_ptr, sizeof(ColumnFamilyOptions),
  646. kColumnFamilyOptionsExcluded));
  647. // Custom verification since compaction_options_fifo was in
  648. // kColumnFamilyOptionsExcluded
  649. ASSERT_EQ(new_options->compaction_options_fifo.max_table_files_size, 3);
  650. ASSERT_EQ(new_options->compaction_options_fifo.allow_compaction, true);
  651. ASSERT_EQ(new_options->compaction_options_fifo.file_temperature_age_thresholds
  652. .size(),
  653. 1);
  654. ASSERT_EQ(
  655. new_options->compaction_options_fifo.file_temperature_age_thresholds[0]
  656. .temperature,
  657. Temperature::kCold);
  658. ASSERT_EQ(
  659. new_options->compaction_options_fifo.file_temperature_age_thresholds[0]
  660. .age,
  661. 12345);
  662. // TODO: try to enhance ObjectLibrary to support singletons
  663. // ASSERT_EQ(new_options->compression_manager,
  664. // GetBuiltinV2CompressionManager());
  665. ASSERT_STREQ(new_options->compression_manager->Name(),
  666. GetBuiltinV2CompressionManager()->Name());
  667. ColumnFamilyOptions rnd_filled_options = *new_options;
  668. options->~ColumnFamilyOptions();
  669. new_options->~ColumnFamilyOptions();
  670. delete[] options_ptr;
  671. delete[] new_options_ptr;
  672. // Test copying to mutabable and immutable options and copy back the mutable
  673. // part.
  674. const OffsetGap kMutableCFOptionsExcluded = {
  675. {offsetof(struct MutableCFOptions, prefix_extractor),
  676. sizeof(std::shared_ptr<const SliceTransform>)},
  677. {offsetof(struct MutableCFOptions,
  678. max_bytes_for_level_multiplier_additional),
  679. sizeof(std::vector<int>)},
  680. {offsetof(struct MutableCFOptions, compaction_options_fifo),
  681. sizeof(struct CompactionOptionsFIFO)},
  682. {offsetof(struct MutableCFOptions, compression_manager),
  683. sizeof(std::shared_ptr<CompressionManager>)},
  684. {offsetof(struct MutableCFOptions, compression_per_level),
  685. sizeof(std::vector<CompressionType>)},
  686. {offsetof(struct MutableCFOptions, max_file_size),
  687. sizeof(std::vector<uint64_t>)},
  688. };
  689. // For all memory used for options, pre-fill every char. Otherwise, the
  690. // padding bytes might be different so that byte-wise comparison doesn't
  691. // general equal results even if objects are equal.
  692. const char kMySpecialChar = 'x';
  693. char* mcfo1_ptr = new char[sizeof(MutableCFOptions)];
  694. FillWithSpecialChar(mcfo1_ptr, sizeof(MutableCFOptions),
  695. kMutableCFOptionsExcluded, kMySpecialChar);
  696. char* mcfo2_ptr = new char[sizeof(MutableCFOptions)];
  697. FillWithSpecialChar(mcfo2_ptr, sizeof(MutableCFOptions),
  698. kMutableCFOptionsExcluded, kMySpecialChar);
  699. // A clean column family options is constructed after filling the same special
  700. // char as the initial one. So that the padding bytes are the same.
  701. char* cfo_clean_ptr = new char[sizeof(ColumnFamilyOptions)];
  702. FillWithSpecialChar(cfo_clean_ptr, sizeof(ColumnFamilyOptions),
  703. kColumnFamilyOptionsExcluded);
  704. rnd_filled_options.num_levels = 66;
  705. ColumnFamilyOptions* cfo_clean = new (cfo_clean_ptr) ColumnFamilyOptions();
  706. MutableCFOptions* mcfo1 =
  707. new (mcfo1_ptr) MutableCFOptions(rnd_filled_options);
  708. ColumnFamilyOptions cfo_back = BuildColumnFamilyOptions(*cfo_clean, *mcfo1);
  709. MutableCFOptions* mcfo2 = new (mcfo2_ptr) MutableCFOptions(cfo_back);
  710. ASSERT_TRUE(CompareBytes(mcfo1_ptr, mcfo2_ptr, sizeof(MutableCFOptions),
  711. kMutableCFOptionsExcluded));
  712. cfo_clean->~ColumnFamilyOptions();
  713. mcfo1->~MutableCFOptions();
  714. mcfo2->~MutableCFOptions();
  715. delete[] mcfo1_ptr;
  716. delete[] mcfo2_ptr;
  717. delete[] cfo_clean_ptr;
  718. }
  719. #endif // !ROCKSDB_ASSERT_STATUS_CHECKED
  720. #endif // !ROCKSDB_UBSAN_RUN
  721. #endif // !__clang__
  722. #endif // OS_LINUX || OS_WIN
  723. } // namespace ROCKSDB_NAMESPACE
  724. int main(int argc, char** argv) {
  725. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  726. ::testing::InitGoogleTest(&argc, argv);
  727. #ifdef GFLAGS
  728. ParseCommandLineFlags(&argc, &argv, true);
  729. #endif // GFLAGS
  730. return RUN_ALL_TESTS();
  731. }