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).
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.
12 #include "options/cf_options.h"
13 #include "options/db_options.h"
14 #include "options/options_helper.h"
15 #include "rocksdb/convenience.h"
16 #include "test_util/testharness.h"
19 bool FLAGS_enable_print
= false;
21 #include "util/gflags_compat.h"
22 using GFLAGS_NAMESPACE::ParseCommandLineFlags
;
23 DEFINE_bool(enable_print
, false, "Print options generated to console.");
26 namespace ROCKSDB_NAMESPACE
{
28 // Verify options are settable from options strings.
29 // We take the approach that depends on compiler behavior that copy constructor
30 // won't touch implicit padding bytes, so that the test is fragile.
31 // As a result, we only run the tests to verify new fields in options are
32 // settable through string on limited platforms as it depends on behavior of
35 #if defined OS_LINUX || defined OS_WIN
37 #ifndef ROCKSDB_UBSAN_RUN
39 class OptionsSettableTest
: public testing::Test
{
41 OptionsSettableTest() {}
44 const char kSpecialChar
= 'z';
45 using OffsetGap
= std::vector
<std::pair
<size_t, size_t>>;
47 void FillWithSpecialChar(char* start_ptr
, size_t total_size
,
48 const OffsetGap
& excluded
,
49 char special_char
= kSpecialChar
) {
51 // The excluded vector contains pairs of bytes, (first, second).
52 // The first bytes are all set to the special char (represented as 'c' below).
53 // The second bytes are simply skipped (padding bytes).
54 // ccccc[skipped]cccccccc[skiped]cccccccc[skipped]
55 for (auto& pair
: excluded
) {
56 std::memset(start_ptr
+ offset
, special_char
, pair
.first
- offset
);
57 offset
= pair
.first
+ pair
.second
;
59 // The rest of the structure is filled with the special characters.
60 // ccccc[skipped]cccccccc[skiped]cccccccc[skipped]cccccccccccccccc
61 std::memset(start_ptr
+ offset
, special_char
, total_size
- offset
);
64 int NumUnsetBytes(char* start_ptr
, size_t total_size
,
65 const OffsetGap
& excluded
) {
66 int total_unset_bytes_base
= 0;
68 for (auto& pair
: excluded
) {
69 // The first part of the structure contains memory spaces that can be
70 // set (pair.first), and memory spaces that cannot be set (pair.second).
71 // Therefore total_unset_bytes_base only agregates bytes set to kSpecialChar
72 // in the pair.first bytes, but skips the pair.second bytes (padding bytes).
73 for (char* ptr
= start_ptr
+ offset
; ptr
< start_ptr
+ pair
.first
; ptr
++) {
74 if (*ptr
== kSpecialChar
) {
75 total_unset_bytes_base
++;
78 offset
= pair
.first
+ pair
.second
;
80 // Then total_unset_bytes_base aggregates the bytes
81 // set to kSpecialChar in the rest of the structure
82 for (char* ptr
= start_ptr
+ offset
; ptr
< start_ptr
+ total_size
; ptr
++) {
83 if (*ptr
== kSpecialChar
) {
84 total_unset_bytes_base
++;
87 return total_unset_bytes_base
;
90 // Return true iff two structs are the same except excluded fields.
91 bool CompareBytes(char* start_ptr1
, char* start_ptr2
, size_t total_size
,
92 const OffsetGap
& excluded
) {
94 for (auto& pair
: excluded
) {
95 for (; offset
< pair
.first
; offset
++) {
96 if (*(start_ptr1
+ offset
) != *(start_ptr2
+ offset
)) {
100 offset
= pair
.first
+ pair
.second
;
102 for (; offset
< total_size
; offset
++) {
103 if (*(start_ptr1
+ offset
) != *(start_ptr2
+ offset
)) {
110 // If the test fails, likely a new option is added to BlockBasedTableOptions
111 // but it cannot be set through GetBlockBasedTableOptionsFromString(), or the
112 // test is not updated accordingly.
113 // After adding an option, we need to make sure it is settable by
114 // GetBlockBasedTableOptionsFromString() and add the option to the input string
115 // passed to the GetBlockBasedTableOptionsFromString() in this test.
116 // If it is a complicated type, you also need to add the field to
117 // kBbtoExcluded, and maybe add customized verification for it.
118 TEST_F(OptionsSettableTest
, BlockBasedTableOptionsAllFieldsSettable
) {
119 // Items in the form of <offset, size>. Need to be in ascending order
120 // and not overlapping. Need to update if new option to be excluded is added
121 // (e.g, pointer-type)
122 const OffsetGap kBbtoExcluded
= {
123 {offsetof(struct BlockBasedTableOptions
, flush_block_policy_factory
),
124 sizeof(std::shared_ptr
<FlushBlockPolicyFactory
>)},
125 {offsetof(struct BlockBasedTableOptions
, block_cache
),
126 sizeof(std::shared_ptr
<Cache
>)},
127 {offsetof(struct BlockBasedTableOptions
, persistent_cache
),
128 sizeof(std::shared_ptr
<PersistentCache
>)},
129 {offsetof(struct BlockBasedTableOptions
, block_cache_compressed
),
130 sizeof(std::shared_ptr
<Cache
>)},
131 {offsetof(struct BlockBasedTableOptions
, cache_usage_options
),
132 sizeof(CacheUsageOptions
)},
133 {offsetof(struct BlockBasedTableOptions
, filter_policy
),
134 sizeof(std::shared_ptr
<const FilterPolicy
>)},
137 // In this test, we catch a new option of BlockBasedTableOptions that is not
138 // settable through GetBlockBasedTableOptionsFromString().
139 // We count padding bytes of the option struct, and assert it to be the same
140 // as unset bytes of an option struct initialized by
141 // GetBlockBasedTableOptionsFromString().
143 char* bbto_ptr
= new char[sizeof(BlockBasedTableOptions
)];
145 // Count padding bytes by setting all bytes in the memory to a special char,
146 // copy a well constructed struct to this memory and see how many special
148 BlockBasedTableOptions
* bbto
= new (bbto_ptr
) BlockBasedTableOptions();
149 FillWithSpecialChar(bbto_ptr
, sizeof(BlockBasedTableOptions
), kBbtoExcluded
);
150 // It based on the behavior of compiler that padding bytes are not changed
151 // when copying the struct. It's prone to failure when compiler behavior
152 // changes. We verify there is unset bytes to detect the case.
153 *bbto
= BlockBasedTableOptions();
154 int unset_bytes_base
=
155 NumUnsetBytes(bbto_ptr
, sizeof(BlockBasedTableOptions
), kBbtoExcluded
);
156 ASSERT_GT(unset_bytes_base
, 0);
157 bbto
->~BlockBasedTableOptions();
159 // Construct the base option passed into
160 // GetBlockBasedTableOptionsFromString().
161 bbto
= new (bbto_ptr
) BlockBasedTableOptions();
162 FillWithSpecialChar(bbto_ptr
, sizeof(BlockBasedTableOptions
), kBbtoExcluded
);
163 // This option is not setable:
164 bbto
->use_delta_encoding
= true;
166 char* new_bbto_ptr
= new char[sizeof(BlockBasedTableOptions
)];
167 BlockBasedTableOptions
* new_bbto
=
168 new (new_bbto_ptr
) BlockBasedTableOptions();
169 FillWithSpecialChar(new_bbto_ptr
, sizeof(BlockBasedTableOptions
),
172 // Need to update the option string if a new option is added.
173 ASSERT_OK(GetBlockBasedTableOptionsFromString(
175 "cache_index_and_filter_blocks=1;"
176 "cache_index_and_filter_blocks_with_high_priority=true;"
177 "metadata_cache_options={top_level_index_pinning=kFallback;"
178 "partition_pinning=kAll;"
179 "unpartitioned_pinning=kFlushedAndSimilar;};"
180 "pin_l0_filter_and_index_blocks_in_cache=1;"
181 "pin_top_level_index_and_filter=1;"
182 "index_type=kHashSearch;"
183 "data_block_index_type=kDataBlockBinaryAndHash;"
184 "index_shortening=kNoShortening;"
185 "data_block_hash_table_util_ratio=0.75;"
186 "checksum=kxxHash;no_block_cache=1;"
187 "block_cache=1M;block_cache_compressed=1k;block_size=1024;"
188 "block_size_deviation=8;block_restart_interval=4; "
189 "metadata_block_size=1024;"
190 "partition_filters=false;"
191 "optimize_filters_for_memory=true;"
192 "index_block_restart_interval=4;"
193 "filter_policy=bloomfilter:4:true;whole_key_filtering=1;detect_filter_"
194 "construct_corruption=false;"
196 "verify_compression=true;read_amp_bytes_per_bit=0;"
197 "enable_index_compression=false;"
199 "max_auto_readahead_size=0;"
200 "prepopulate_block_cache=kDisable;"
201 "initial_auto_readahead_size=0;"
202 "num_file_reads_for_auto_readahead=0",
205 ASSERT_EQ(unset_bytes_base
,
206 NumUnsetBytes(new_bbto_ptr
, sizeof(BlockBasedTableOptions
),
209 ASSERT_TRUE(new_bbto
->block_cache
.get() != nullptr);
210 ASSERT_TRUE(new_bbto
->block_cache_compressed
.get() != nullptr);
211 ASSERT_TRUE(new_bbto
->filter_policy
.get() != nullptr);
213 bbto
->~BlockBasedTableOptions();
214 new_bbto
->~BlockBasedTableOptions();
217 delete[] new_bbto_ptr
;
220 // If the test fails, likely a new option is added to DBOptions
221 // but it cannot be set through GetDBOptionsFromString(), or the test is not
222 // updated accordingly.
223 // After adding an option, we need to make sure it is settable by
224 // GetDBOptionsFromString() and add the option to the input string passed to
225 // DBOptionsFromString()in this test.
226 // If it is a complicated type, you also need to add the field to
227 // kDBOptionsExcluded, and maybe add customized verification for it.
228 TEST_F(OptionsSettableTest
, DBOptionsAllFieldsSettable
) {
229 const OffsetGap kDBOptionsExcluded
= {
230 {offsetof(struct DBOptions
, env
), sizeof(Env
*)},
231 {offsetof(struct DBOptions
, rate_limiter
),
232 sizeof(std::shared_ptr
<RateLimiter
>)},
233 {offsetof(struct DBOptions
, sst_file_manager
),
234 sizeof(std::shared_ptr
<SstFileManager
>)},
235 {offsetof(struct DBOptions
, info_log
), sizeof(std::shared_ptr
<Logger
>)},
236 {offsetof(struct DBOptions
, statistics
),
237 sizeof(std::shared_ptr
<Statistics
>)},
238 {offsetof(struct DBOptions
, db_paths
), sizeof(std::vector
<DbPath
>)},
239 {offsetof(struct DBOptions
, db_log_dir
), sizeof(std::string
)},
240 {offsetof(struct DBOptions
, wal_dir
), sizeof(std::string
)},
241 {offsetof(struct DBOptions
, write_buffer_manager
),
242 sizeof(std::shared_ptr
<WriteBufferManager
>)},
243 {offsetof(struct DBOptions
, listeners
),
244 sizeof(std::vector
<std::shared_ptr
<EventListener
>>)},
245 {offsetof(struct DBOptions
, row_cache
), sizeof(std::shared_ptr
<Cache
>)},
246 {offsetof(struct DBOptions
, wal_filter
), sizeof(const WalFilter
*)},
247 {offsetof(struct DBOptions
, file_checksum_gen_factory
),
248 sizeof(std::shared_ptr
<FileChecksumGenFactory
>)},
249 {offsetof(struct DBOptions
, db_host_id
), sizeof(std::string
)},
250 {offsetof(struct DBOptions
, checksum_handoff_file_types
),
251 sizeof(FileTypeSet
)},
252 {offsetof(struct DBOptions
, compaction_service
),
253 sizeof(std::shared_ptr
<CompactionService
>)},
256 char* options_ptr
= new char[sizeof(DBOptions
)];
258 // Count padding bytes by setting all bytes in the memory to a special char,
259 // copy a well constructed struct to this memory and see how many special
261 DBOptions
* options
= new (options_ptr
) DBOptions();
262 FillWithSpecialChar(options_ptr
, sizeof(DBOptions
), kDBOptionsExcluded
);
263 // It based on the behavior of compiler that padding bytes are not changed
264 // when copying the struct. It's prone to failure when compiler behavior
265 // changes. We verify there is unset bytes to detect the case.
266 *options
= DBOptions();
267 int unset_bytes_base
=
268 NumUnsetBytes(options_ptr
, sizeof(DBOptions
), kDBOptionsExcluded
);
269 ASSERT_GT(unset_bytes_base
, 0);
270 options
->~DBOptions();
272 options
= new (options_ptr
) DBOptions();
273 FillWithSpecialChar(options_ptr
, sizeof(DBOptions
), kDBOptionsExcluded
);
275 char* new_options_ptr
= new char[sizeof(DBOptions
)];
276 DBOptions
* new_options
= new (new_options_ptr
) DBOptions();
277 FillWithSpecialChar(new_options_ptr
, sizeof(DBOptions
), kDBOptionsExcluded
);
279 // Need to update the option string if a new option is added.
281 GetDBOptionsFromString(*options
,
282 "wal_bytes_per_sync=4295048118;"
283 "delete_obsolete_files_period_micros=4294967758;"
284 "WAL_ttl_seconds=4295008036;"
285 "WAL_size_limit_MB=4295036161;"
286 "max_write_batch_group_size_bytes=1048576;"
287 "wal_dir=path/to/wal_dir;"
288 "db_write_buffer_size=2587;"
289 "max_subcompactions=64330;"
290 "table_cache_numshardbits=28;"
292 "max_file_opening_threads=35;"
293 "max_background_jobs=8;"
294 "max_background_compactions=33;"
296 "use_adaptive_mutex=false;"
297 "max_total_wal_size=4295005604;"
298 "compaction_readahead_size=0;"
299 "keep_log_file_num=4890;"
300 "skip_stats_update_on_db_open=false;"
301 "skip_checking_sst_file_sizes_on_db_open=false;"
302 "max_manifest_file_size=4295009941;"
303 "db_log_dir=path/to/db_log_dir;"
304 "writable_file_max_buffer_size=1048576;"
305 "paranoid_checks=true;"
306 "flush_verify_memtable_count=true;"
307 "track_and_verify_wals_in_manifest=true;"
308 "verify_sst_unique_id_in_manifest=true;"
309 "is_fd_close_on_exec=false;"
310 "bytes_per_sync=4295013613;"
311 "strict_bytes_per_sync=true;"
312 "enable_thread_tracking=false;"
313 "recycle_log_file_num=0;"
314 "create_missing_column_families=true;"
315 "log_file_time_to_roll=3097;"
316 "max_background_flushes=35;"
317 "create_if_missing=false;"
318 "error_if_exists=true;"
319 "delayed_write_rate=4294976214;"
320 "manifest_preallocation_size=1222;"
321 "allow_mmap_writes=false;"
322 "stats_dump_period_sec=70127;"
323 "stats_persist_period_sec=54321;"
324 "persist_stats_to_disk=true;"
325 "stats_history_buffer_size=14159;"
326 "allow_fallocate=true;"
327 "allow_mmap_reads=false;"
328 "use_direct_reads=false;"
329 "use_direct_io_for_flush_and_compaction=false;"
330 "max_log_file_size=4607;"
331 "random_access_max_buffer_size=1048576;"
332 "advise_random_on_open=true;"
333 "fail_if_options_file_error=false;"
334 "enable_pipelined_write=false;"
335 "unordered_write=false;"
336 "allow_concurrent_memtable_write=true;"
337 "wal_recovery_mode=kPointInTimeRecovery;"
338 "enable_write_thread_adaptive_yield=true;"
339 "write_thread_slow_yield_usec=5;"
340 "write_thread_max_yield_usec=1000;"
341 "access_hint_on_compaction_start=NONE;"
342 "info_log_level=DEBUG_LEVEL;"
343 "dump_malloc_stats=false;"
345 "avoid_flush_during_recovery=false;"
346 "avoid_flush_during_shutdown=false;"
347 "allow_ingest_behind=false;"
348 "concurrent_prepare=false;"
349 "two_write_queues=false;"
350 "manual_wal_flush=false;"
351 "wal_compression=kZSTD;"
352 "seq_per_batch=false;"
353 "atomic_flush=false;"
354 "avoid_unnecessary_blocking_io=false;"
355 "log_readahead_size=0;"
356 "write_dbid_to_manifest=false;"
357 "best_efforts_recovery=false;"
358 "max_bgerror_resume_count=2;"
359 "bgerror_resume_retry_interval=1000000;"
360 "db_host_id=hostname;"
361 "lowest_used_cache_tier=kNonVolatileBlockTier;"
362 "allow_data_in_errors=false;"
363 "enforce_single_del_contracts=false;",
366 ASSERT_EQ(unset_bytes_base
, NumUnsetBytes(new_options_ptr
, sizeof(DBOptions
),
367 kDBOptionsExcluded
));
369 options
->~DBOptions();
370 new_options
->~DBOptions();
372 delete[] options_ptr
;
373 delete[] new_options_ptr
;
376 // If the test fails, likely a new option is added to ColumnFamilyOptions
377 // but it cannot be set through GetColumnFamilyOptionsFromString(), or the
378 // test is not updated accordingly.
379 // After adding an option, we need to make sure it is settable by
380 // GetColumnFamilyOptionsFromString() and add the option to the input
381 // string passed to GetColumnFamilyOptionsFromString() in this test.
382 // If it is a complicated type, you also need to add the field to
383 // kColumnFamilyOptionsExcluded, and maybe add customized verification
385 TEST_F(OptionsSettableTest
, ColumnFamilyOptionsAllFieldsSettable
) {
386 // options in the excluded set need to appear in the same order as in
387 // ColumnFamilyOptions.
388 const OffsetGap kColumnFamilyOptionsExcluded
= {
389 {offsetof(struct ColumnFamilyOptions
, inplace_callback
),
390 sizeof(UpdateStatus(*)(char*, uint32_t*, Slice
, std::string
*))},
391 {offsetof(struct ColumnFamilyOptions
,
392 memtable_insert_with_hint_prefix_extractor
),
393 sizeof(std::shared_ptr
<const SliceTransform
>)},
394 {offsetof(struct ColumnFamilyOptions
, compression_per_level
),
395 sizeof(std::vector
<CompressionType
>)},
396 {offsetof(struct ColumnFamilyOptions
,
397 max_bytes_for_level_multiplier_additional
),
398 sizeof(std::vector
<int>)},
399 {offsetof(struct ColumnFamilyOptions
, memtable_factory
),
400 sizeof(std::shared_ptr
<MemTableRepFactory
>)},
401 {offsetof(struct ColumnFamilyOptions
,
402 table_properties_collector_factories
),
403 sizeof(ColumnFamilyOptions::TablePropertiesCollectorFactories
)},
404 {offsetof(struct ColumnFamilyOptions
, preclude_last_level_data_seconds
),
406 {offsetof(struct ColumnFamilyOptions
, preserve_internal_time_seconds
),
408 {offsetof(struct ColumnFamilyOptions
, blob_cache
),
409 sizeof(std::shared_ptr
<Cache
>)},
410 {offsetof(struct ColumnFamilyOptions
, comparator
), sizeof(Comparator
*)},
411 {offsetof(struct ColumnFamilyOptions
, merge_operator
),
412 sizeof(std::shared_ptr
<MergeOperator
>)},
413 {offsetof(struct ColumnFamilyOptions
, compaction_filter
),
414 sizeof(const CompactionFilter
*)},
415 {offsetof(struct ColumnFamilyOptions
, compaction_filter_factory
),
416 sizeof(std::shared_ptr
<CompactionFilterFactory
>)},
417 {offsetof(struct ColumnFamilyOptions
, prefix_extractor
),
418 sizeof(std::shared_ptr
<const SliceTransform
>)},
419 {offsetof(struct ColumnFamilyOptions
, snap_refresh_nanos
),
421 {offsetof(struct ColumnFamilyOptions
, table_factory
),
422 sizeof(std::shared_ptr
<TableFactory
>)},
423 {offsetof(struct ColumnFamilyOptions
, cf_paths
),
424 sizeof(std::vector
<DbPath
>)},
425 {offsetof(struct ColumnFamilyOptions
, compaction_thread_limiter
),
426 sizeof(std::shared_ptr
<ConcurrentTaskLimiter
>)},
427 {offsetof(struct ColumnFamilyOptions
, sst_partitioner_factory
),
428 sizeof(std::shared_ptr
<SstPartitionerFactory
>)},
431 char* options_ptr
= new char[sizeof(ColumnFamilyOptions
)];
433 // Count padding bytes by setting all bytes in the memory to a special char,
434 // copy a well constructed struct to this memory and see how many special
436 FillWithSpecialChar(options_ptr
, sizeof(ColumnFamilyOptions
),
437 kColumnFamilyOptionsExcluded
);
439 // Invoke a user-defined constructor in the hope that it does not overwrite
440 // padding bytes. Note that previously we relied on the implicitly-defined
441 // copy-assignment operator (i.e., `*options = ColumnFamilyOptions();`) here,
442 // which did in fact modify padding bytes.
443 ColumnFamilyOptions
* options
= new (options_ptr
) ColumnFamilyOptions();
445 int unset_bytes_base
= NumUnsetBytes(options_ptr
, sizeof(ColumnFamilyOptions
),
446 kColumnFamilyOptionsExcluded
);
447 ASSERT_GT(unset_bytes_base
, 0);
448 options
->~ColumnFamilyOptions();
450 options
= new (options_ptr
) ColumnFamilyOptions();
451 FillWithSpecialChar(options_ptr
, sizeof(ColumnFamilyOptions
),
452 kColumnFamilyOptionsExcluded
);
454 // Following options are not settable through
455 // GetColumnFamilyOptionsFromString():
456 options
->compaction_options_universal
= CompactionOptionsUniversal();
457 options
->num_levels
= 42; // Initialize options for MutableCF
458 options
->compaction_filter
= nullptr;
459 options
->sst_partitioner_factory
= nullptr;
461 char* new_options_ptr
= new char[sizeof(ColumnFamilyOptions
)];
462 ColumnFamilyOptions
* new_options
=
463 new (new_options_ptr
) ColumnFamilyOptions();
464 FillWithSpecialChar(new_options_ptr
, sizeof(ColumnFamilyOptions
),
465 kColumnFamilyOptionsExcluded
);
467 // Need to update the option string if a new option is added.
468 ASSERT_OK(GetColumnFamilyOptionsFromString(
470 "compaction_filter_factory=mpudlojcujCompactionFilterFactory;"
471 "table_factory=PlainTable;"
472 "prefix_extractor=rocksdb.CappedPrefix.13;"
473 "comparator=leveldb.BytewiseComparator;"
474 "compression_per_level=kBZip2Compression:kBZip2Compression:"
475 "kBZip2Compression:kNoCompression:kZlibCompression:kBZip2Compression:"
476 "kSnappyCompression;"
477 "max_bytes_for_level_base=986;"
478 "bloom_locality=8016;"
479 "target_file_size_base=4294976376;"
480 "memtable_huge_page_size=2557;"
481 "max_successive_merges=5497;"
482 "max_sequential_skip_in_iterations=4294971408;"
483 "arena_block_size=1893;"
484 "target_file_size_multiplier=35;"
485 "min_write_buffer_number_to_merge=9;"
486 "max_write_buffer_number=84;"
487 "write_buffer_size=1653;"
488 "max_compaction_bytes=64;"
489 "ignore_max_compaction_bytes_for_input=true;"
490 "max_bytes_for_level_multiplier=60;"
491 "memtable_factory=SkipListFactory;"
492 "compression=kNoCompression;"
493 "compression_opts=5:6:7:8:9:10:true:11:false;"
494 "bottommost_compression_opts=4:5:6:7:8:9:true:10:true;"
495 "bottommost_compression=kDisableCompressionOption;"
496 "level0_stop_writes_trigger=33;"
498 "level0_slowdown_writes_trigger=22;"
499 "level0_file_num_compaction_trigger=14;"
500 "compaction_filter=urxcqstuwnCompactionFilter;"
501 "soft_pending_compaction_bytes_limit=0;"
502 "max_write_buffer_number_to_maintain=84;"
503 "max_write_buffer_size_to_maintain=2147483648;"
504 "merge_operator=aabcxehazrMergeOperator;"
505 "memtable_prefix_bloom_size_ratio=0.4642;"
506 "memtable_whole_key_filtering=true;"
507 "memtable_insert_with_hint_prefix_extractor=rocksdb.CappedPrefix.13;"
508 "check_flush_compaction_key_order=false;"
509 "paranoid_file_checks=true;"
510 "force_consistency_checks=true;"
511 "inplace_update_num_locks=7429;"
512 "experimental_mempurge_threshold=0.0001;"
513 "optimize_filters_for_hits=false;"
514 "level_compaction_dynamic_level_bytes=false;"
515 "level_compaction_dynamic_file_size=true;"
516 "inplace_update_support=false;"
517 "compaction_style=kCompactionStyleFIFO;"
518 "compaction_pri=kMinOverlappingRatio;"
519 "hard_pending_compaction_bytes_limit=0;"
520 "disable_auto_compactions=false;"
521 "report_bg_io_stats=true;"
523 "periodic_compaction_seconds=3600;"
524 "sample_for_compression=0;"
525 "enable_blob_files=true;"
527 "blob_file_size=1000000;"
528 "blob_compression_type=kBZip2Compression;"
529 "enable_blob_garbage_collection=true;"
530 "blob_garbage_collection_age_cutoff=0.5;"
531 "blob_garbage_collection_force_threshold=0.75;"
532 "blob_compaction_readahead_size=262144;"
533 "blob_file_starting_level=1;"
534 "prepopulate_blob_cache=kDisable;"
535 "bottommost_temperature=kWarm;"
536 "last_level_temperature=kWarm;"
537 "preclude_last_level_data_seconds=86400;"
538 "preserve_internal_time_seconds=86400;"
539 "compaction_options_fifo={max_table_files_size=3;allow_"
540 "compaction=false;age_for_warm=1;};"
542 "memtable_protection_bytes_per_key=2;",
545 ASSERT_NE(new_options
->blob_cache
.get(), nullptr);
547 ASSERT_EQ(unset_bytes_base
,
548 NumUnsetBytes(new_options_ptr
, sizeof(ColumnFamilyOptions
),
549 kColumnFamilyOptionsExcluded
));
551 ColumnFamilyOptions rnd_filled_options
= *new_options
;
553 options
->~ColumnFamilyOptions();
554 new_options
->~ColumnFamilyOptions();
556 delete[] options_ptr
;
557 delete[] new_options_ptr
;
559 // Test copying to mutabable and immutable options and copy back the mutable
561 const OffsetGap kMutableCFOptionsExcluded
= {
562 {offsetof(struct MutableCFOptions
, prefix_extractor
),
563 sizeof(std::shared_ptr
<const SliceTransform
>)},
564 {offsetof(struct MutableCFOptions
,
565 max_bytes_for_level_multiplier_additional
),
566 sizeof(std::vector
<int>)},
567 {offsetof(struct MutableCFOptions
, compression_per_level
),
568 sizeof(std::vector
<CompressionType
>)},
569 {offsetof(struct MutableCFOptions
, max_file_size
),
570 sizeof(std::vector
<uint64_t>)},
573 // For all memory used for options, pre-fill every char. Otherwise, the
574 // padding bytes might be different so that byte-wise comparison doesn't
575 // general equal results even if objects are equal.
576 const char kMySpecialChar
= 'x';
577 char* mcfo1_ptr
= new char[sizeof(MutableCFOptions
)];
578 FillWithSpecialChar(mcfo1_ptr
, sizeof(MutableCFOptions
),
579 kMutableCFOptionsExcluded
, kMySpecialChar
);
580 char* mcfo2_ptr
= new char[sizeof(MutableCFOptions
)];
581 FillWithSpecialChar(mcfo2_ptr
, sizeof(MutableCFOptions
),
582 kMutableCFOptionsExcluded
, kMySpecialChar
);
584 // A clean column family options is constructed after filling the same special
585 // char as the initial one. So that the padding bytes are the same.
586 char* cfo_clean_ptr
= new char[sizeof(ColumnFamilyOptions
)];
587 FillWithSpecialChar(cfo_clean_ptr
, sizeof(ColumnFamilyOptions
),
588 kColumnFamilyOptionsExcluded
);
589 rnd_filled_options
.num_levels
= 66;
590 ColumnFamilyOptions
* cfo_clean
= new (cfo_clean_ptr
) ColumnFamilyOptions();
592 MutableCFOptions
* mcfo1
=
593 new (mcfo1_ptr
) MutableCFOptions(rnd_filled_options
);
594 ColumnFamilyOptions cfo_back
= BuildColumnFamilyOptions(*cfo_clean
, *mcfo1
);
595 MutableCFOptions
* mcfo2
= new (mcfo2_ptr
) MutableCFOptions(cfo_back
);
597 ASSERT_TRUE(CompareBytes(mcfo1_ptr
, mcfo2_ptr
, sizeof(MutableCFOptions
),
598 kMutableCFOptionsExcluded
));
600 cfo_clean
->~ColumnFamilyOptions();
601 mcfo1
->~MutableCFOptions();
602 mcfo2
->~MutableCFOptions();
605 delete[] cfo_clean_ptr
;
607 #endif // !ROCKSDB_UBSAN_RUN
609 #endif // OS_LINUX || OS_WIN
610 #endif // !ROCKSDB_LITE
612 } // namespace ROCKSDB_NAMESPACE
614 int main(int argc
, char** argv
) {
615 ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
616 ::testing::InitGoogleTest(&argc
, argv
);
618 ParseCommandLineFlags(&argc
, &argv
, true);
620 return RUN_ALL_TESTS();