]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/options/options_settable_test.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rocksdb / options / options_settable_test.cc
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
10 #include <cstring>
11
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"
17
18 #ifndef GFLAGS
19 bool FLAGS_enable_print = false;
20 #else
21 #include "util/gflags_compat.h"
22 using GFLAGS_NAMESPACE::ParseCommandLineFlags;
23 DEFINE_bool(enable_print, false, "Print options generated to console.");
24 #endif // GFLAGS
25
26 namespace ROCKSDB_NAMESPACE {
27
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
33 // compilers.
34 #ifndef ROCKSDB_LITE
35 #if defined OS_LINUX || defined OS_WIN
36 #ifndef __clang__
37 #ifndef ROCKSDB_UBSAN_RUN
38
39 class OptionsSettableTest : public testing::Test {
40 public:
41 OptionsSettableTest() {}
42 };
43
44 const char kSpecialChar = 'z';
45 using OffsetGap = std::vector<std::pair<size_t, size_t>>;
46
47 void FillWithSpecialChar(char* start_ptr, size_t total_size,
48 const OffsetGap& excluded,
49 char special_char = kSpecialChar) {
50 size_t offset = 0;
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;
58 }
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);
62 }
63
64 int NumUnsetBytes(char* start_ptr, size_t total_size,
65 const OffsetGap& excluded) {
66 int total_unset_bytes_base = 0;
67 size_t offset = 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++;
76 }
77 }
78 offset = pair.first + pair.second;
79 }
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++;
85 }
86 }
87 return total_unset_bytes_base;
88 }
89
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) {
93 size_t offset = 0;
94 for (auto& pair : excluded) {
95 for (; offset < pair.first; offset++) {
96 if (*(start_ptr1 + offset) != *(start_ptr2 + offset)) {
97 return false;
98 }
99 }
100 offset = pair.first + pair.second;
101 }
102 for (; offset < total_size; offset++) {
103 if (*(start_ptr1 + offset) != *(start_ptr2 + offset)) {
104 return false;
105 }
106 }
107 return true;
108 }
109
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>)},
135 };
136
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().
142
143 char* bbto_ptr = new char[sizeof(BlockBasedTableOptions)];
144
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
147 // bytes left.
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();
158
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;
165
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),
170 kBbtoExcluded);
171
172 // Need to update the option string if a new option is added.
173 ASSERT_OK(GetBlockBasedTableOptionsFromString(
174 *bbto,
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;"
195 "format_version=1;"
196 "verify_compression=true;read_amp_bytes_per_bit=0;"
197 "enable_index_compression=false;"
198 "block_align=true;"
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",
203 new_bbto));
204
205 ASSERT_EQ(unset_bytes_base,
206 NumUnsetBytes(new_bbto_ptr, sizeof(BlockBasedTableOptions),
207 kBbtoExcluded));
208
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);
212
213 bbto->~BlockBasedTableOptions();
214 new_bbto->~BlockBasedTableOptions();
215
216 delete[] bbto_ptr;
217 delete[] new_bbto_ptr;
218 }
219
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>)},
254 };
255
256 char* options_ptr = new char[sizeof(DBOptions)];
257
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
260 // bytes left.
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();
271
272 options = new (options_ptr) DBOptions();
273 FillWithSpecialChar(options_ptr, sizeof(DBOptions), kDBOptionsExcluded);
274
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);
278
279 // Need to update the option string if a new option is added.
280 ASSERT_OK(
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;"
291 "max_open_files=72;"
292 "max_file_opening_threads=35;"
293 "max_background_jobs=8;"
294 "max_background_compactions=33;"
295 "use_fsync=true;"
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;"
344 "allow_2pc=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;",
364 new_options));
365
366 ASSERT_EQ(unset_bytes_base, NumUnsetBytes(new_options_ptr, sizeof(DBOptions),
367 kDBOptionsExcluded));
368
369 options->~DBOptions();
370 new_options->~DBOptions();
371
372 delete[] options_ptr;
373 delete[] new_options_ptr;
374 }
375
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
384 // for it.
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),
405 sizeof(uint64_t)},
406 {offsetof(struct ColumnFamilyOptions, preserve_internal_time_seconds),
407 sizeof(uint64_t)},
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),
420 sizeof(uint64_t)},
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>)},
429 };
430
431 char* options_ptr = new char[sizeof(ColumnFamilyOptions)];
432
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
435 // bytes left.
436 FillWithSpecialChar(options_ptr, sizeof(ColumnFamilyOptions),
437 kColumnFamilyOptionsExcluded);
438
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();
444
445 int unset_bytes_base = NumUnsetBytes(options_ptr, sizeof(ColumnFamilyOptions),
446 kColumnFamilyOptionsExcluded);
447 ASSERT_GT(unset_bytes_base, 0);
448 options->~ColumnFamilyOptions();
449
450 options = new (options_ptr) ColumnFamilyOptions();
451 FillWithSpecialChar(options_ptr, sizeof(ColumnFamilyOptions),
452 kColumnFamilyOptionsExcluded);
453
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;
460
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);
466
467 // Need to update the option string if a new option is added.
468 ASSERT_OK(GetColumnFamilyOptionsFromString(
469 *options,
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;"
497 "num_levels=99;"
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;"
522 "ttl=60;"
523 "periodic_compaction_seconds=3600;"
524 "sample_for_compression=0;"
525 "enable_blob_files=true;"
526 "min_blob_size=256;"
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;};"
541 "blob_cache=1M;"
542 "memtable_protection_bytes_per_key=2;",
543 new_options));
544
545 ASSERT_NE(new_options->blob_cache.get(), nullptr);
546
547 ASSERT_EQ(unset_bytes_base,
548 NumUnsetBytes(new_options_ptr, sizeof(ColumnFamilyOptions),
549 kColumnFamilyOptionsExcluded));
550
551 ColumnFamilyOptions rnd_filled_options = *new_options;
552
553 options->~ColumnFamilyOptions();
554 new_options->~ColumnFamilyOptions();
555
556 delete[] options_ptr;
557 delete[] new_options_ptr;
558
559 // Test copying to mutabable and immutable options and copy back the mutable
560 // part.
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>)},
571 };
572
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);
583
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();
591
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);
596
597 ASSERT_TRUE(CompareBytes(mcfo1_ptr, mcfo2_ptr, sizeof(MutableCFOptions),
598 kMutableCFOptionsExcluded));
599
600 cfo_clean->~ColumnFamilyOptions();
601 mcfo1->~MutableCFOptions();
602 mcfo2->~MutableCFOptions();
603 delete[] mcfo1_ptr;
604 delete[] mcfo2_ptr;
605 delete[] cfo_clean_ptr;
606 }
607 #endif // !ROCKSDB_UBSAN_RUN
608 #endif // !__clang__
609 #endif // OS_LINUX || OS_WIN
610 #endif // !ROCKSDB_LITE
611
612 } // namespace ROCKSDB_NAMESPACE
613
614 int main(int argc, char** argv) {
615 ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
616 ::testing::InitGoogleTest(&argc, argv);
617 #ifdef GFLAGS
618 ParseCommandLineFlags(&argc, &argv, true);
619 #endif // GFLAGS
620 return RUN_ALL_TESTS();
621 }