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 #include "options/options_helper.h"
10 #include <unordered_set>
13 #include "options/cf_options.h"
14 #include "options/db_options.h"
15 #include "rocksdb/cache.h"
16 #include "rocksdb/compaction_filter.h"
17 #include "rocksdb/convenience.h"
18 #include "rocksdb/filter_policy.h"
19 #include "rocksdb/flush_block_policy.h"
20 #include "rocksdb/memtablerep.h"
21 #include "rocksdb/merge_operator.h"
22 #include "rocksdb/options.h"
23 #include "rocksdb/rate_limiter.h"
24 #include "rocksdb/slice_transform.h"
25 #include "rocksdb/table.h"
26 #include "rocksdb/utilities/object_registry.h"
27 #include "rocksdb/utilities/options_type.h"
28 #include "util/string_util.h"
30 namespace ROCKSDB_NAMESPACE
{
31 Status
ValidateOptions(const DBOptions
& db_opts
,
32 const ColumnFamilyOptions
& cf_opts
) {
35 auto db_cfg
= DBOptionsAsConfigurable(db_opts
);
36 auto cf_cfg
= CFOptionsAsConfigurable(cf_opts
);
37 s
= db_cfg
->ValidateOptions(db_opts
, cf_opts
);
38 if (s
.ok()) s
= cf_cfg
->ValidateOptions(db_opts
, cf_opts
);
40 s
= cf_opts
.table_factory
->ValidateOptions(db_opts
, cf_opts
);
45 DBOptions
BuildDBOptions(const ImmutableDBOptions
& immutable_db_options
,
46 const MutableDBOptions
& mutable_db_options
) {
49 options
.create_if_missing
= immutable_db_options
.create_if_missing
;
50 options
.create_missing_column_families
=
51 immutable_db_options
.create_missing_column_families
;
52 options
.error_if_exists
= immutable_db_options
.error_if_exists
;
53 options
.paranoid_checks
= immutable_db_options
.paranoid_checks
;
54 options
.track_and_verify_wals_in_manifest
=
55 immutable_db_options
.track_and_verify_wals_in_manifest
;
56 options
.env
= immutable_db_options
.env
;
57 options
.rate_limiter
= immutable_db_options
.rate_limiter
;
58 options
.sst_file_manager
= immutable_db_options
.sst_file_manager
;
59 options
.info_log
= immutable_db_options
.info_log
;
60 options
.info_log_level
= immutable_db_options
.info_log_level
;
61 options
.max_open_files
= mutable_db_options
.max_open_files
;
62 options
.max_file_opening_threads
=
63 immutable_db_options
.max_file_opening_threads
;
64 options
.max_total_wal_size
= mutable_db_options
.max_total_wal_size
;
65 options
.statistics
= immutable_db_options
.statistics
;
66 options
.use_fsync
= immutable_db_options
.use_fsync
;
67 options
.db_paths
= immutable_db_options
.db_paths
;
68 options
.db_log_dir
= immutable_db_options
.db_log_dir
;
69 options
.wal_dir
= immutable_db_options
.wal_dir
;
70 options
.delete_obsolete_files_period_micros
=
71 mutable_db_options
.delete_obsolete_files_period_micros
;
72 options
.max_background_jobs
= mutable_db_options
.max_background_jobs
;
73 options
.base_background_compactions
=
74 mutable_db_options
.base_background_compactions
;
75 options
.max_background_compactions
=
76 mutable_db_options
.max_background_compactions
;
77 options
.bytes_per_sync
= mutable_db_options
.bytes_per_sync
;
78 options
.wal_bytes_per_sync
= mutable_db_options
.wal_bytes_per_sync
;
79 options
.strict_bytes_per_sync
= mutable_db_options
.strict_bytes_per_sync
;
80 options
.max_subcompactions
= mutable_db_options
.max_subcompactions
;
81 options
.max_background_flushes
= mutable_db_options
.max_background_flushes
;
82 options
.max_log_file_size
= immutable_db_options
.max_log_file_size
;
83 options
.log_file_time_to_roll
= immutable_db_options
.log_file_time_to_roll
;
84 options
.keep_log_file_num
= immutable_db_options
.keep_log_file_num
;
85 options
.recycle_log_file_num
= immutable_db_options
.recycle_log_file_num
;
86 options
.max_manifest_file_size
= immutable_db_options
.max_manifest_file_size
;
87 options
.table_cache_numshardbits
=
88 immutable_db_options
.table_cache_numshardbits
;
89 options
.WAL_ttl_seconds
= immutable_db_options
.wal_ttl_seconds
;
90 options
.WAL_size_limit_MB
= immutable_db_options
.wal_size_limit_mb
;
91 options
.manifest_preallocation_size
=
92 immutable_db_options
.manifest_preallocation_size
;
93 options
.allow_mmap_reads
= immutable_db_options
.allow_mmap_reads
;
94 options
.allow_mmap_writes
= immutable_db_options
.allow_mmap_writes
;
95 options
.use_direct_reads
= immutable_db_options
.use_direct_reads
;
96 options
.use_direct_io_for_flush_and_compaction
=
97 immutable_db_options
.use_direct_io_for_flush_and_compaction
;
98 options
.allow_fallocate
= immutable_db_options
.allow_fallocate
;
99 options
.is_fd_close_on_exec
= immutable_db_options
.is_fd_close_on_exec
;
100 options
.stats_dump_period_sec
= mutable_db_options
.stats_dump_period_sec
;
101 options
.stats_persist_period_sec
=
102 mutable_db_options
.stats_persist_period_sec
;
103 options
.persist_stats_to_disk
= immutable_db_options
.persist_stats_to_disk
;
104 options
.stats_history_buffer_size
=
105 mutable_db_options
.stats_history_buffer_size
;
106 options
.advise_random_on_open
= immutable_db_options
.advise_random_on_open
;
107 options
.db_write_buffer_size
= immutable_db_options
.db_write_buffer_size
;
108 options
.write_buffer_manager
= immutable_db_options
.write_buffer_manager
;
109 options
.access_hint_on_compaction_start
=
110 immutable_db_options
.access_hint_on_compaction_start
;
111 options
.new_table_reader_for_compaction_inputs
=
112 immutable_db_options
.new_table_reader_for_compaction_inputs
;
113 options
.compaction_readahead_size
=
114 mutable_db_options
.compaction_readahead_size
;
115 options
.random_access_max_buffer_size
=
116 immutable_db_options
.random_access_max_buffer_size
;
117 options
.writable_file_max_buffer_size
=
118 mutable_db_options
.writable_file_max_buffer_size
;
119 options
.use_adaptive_mutex
= immutable_db_options
.use_adaptive_mutex
;
120 options
.listeners
= immutable_db_options
.listeners
;
121 options
.enable_thread_tracking
= immutable_db_options
.enable_thread_tracking
;
122 options
.delayed_write_rate
= mutable_db_options
.delayed_write_rate
;
123 options
.enable_pipelined_write
= immutable_db_options
.enable_pipelined_write
;
124 options
.unordered_write
= immutable_db_options
.unordered_write
;
125 options
.allow_concurrent_memtable_write
=
126 immutable_db_options
.allow_concurrent_memtable_write
;
127 options
.enable_write_thread_adaptive_yield
=
128 immutable_db_options
.enable_write_thread_adaptive_yield
;
129 options
.max_write_batch_group_size_bytes
=
130 immutable_db_options
.max_write_batch_group_size_bytes
;
131 options
.write_thread_max_yield_usec
=
132 immutable_db_options
.write_thread_max_yield_usec
;
133 options
.write_thread_slow_yield_usec
=
134 immutable_db_options
.write_thread_slow_yield_usec
;
135 options
.skip_stats_update_on_db_open
=
136 immutable_db_options
.skip_stats_update_on_db_open
;
137 options
.skip_checking_sst_file_sizes_on_db_open
=
138 immutable_db_options
.skip_checking_sst_file_sizes_on_db_open
;
139 options
.wal_recovery_mode
= immutable_db_options
.wal_recovery_mode
;
140 options
.allow_2pc
= immutable_db_options
.allow_2pc
;
141 options
.row_cache
= immutable_db_options
.row_cache
;
143 options
.wal_filter
= immutable_db_options
.wal_filter
;
144 #endif // ROCKSDB_LITE
145 options
.fail_if_options_file_error
=
146 immutable_db_options
.fail_if_options_file_error
;
147 options
.dump_malloc_stats
= immutable_db_options
.dump_malloc_stats
;
148 options
.avoid_flush_during_recovery
=
149 immutable_db_options
.avoid_flush_during_recovery
;
150 options
.avoid_flush_during_shutdown
=
151 mutable_db_options
.avoid_flush_during_shutdown
;
152 options
.allow_ingest_behind
=
153 immutable_db_options
.allow_ingest_behind
;
154 options
.preserve_deletes
=
155 immutable_db_options
.preserve_deletes
;
156 options
.two_write_queues
= immutable_db_options
.two_write_queues
;
157 options
.manual_wal_flush
= immutable_db_options
.manual_wal_flush
;
158 options
.atomic_flush
= immutable_db_options
.atomic_flush
;
159 options
.avoid_unnecessary_blocking_io
=
160 immutable_db_options
.avoid_unnecessary_blocking_io
;
161 options
.log_readahead_size
= immutable_db_options
.log_readahead_size
;
162 options
.file_checksum_gen_factory
=
163 immutable_db_options
.file_checksum_gen_factory
;
164 options
.best_efforts_recovery
= immutable_db_options
.best_efforts_recovery
;
165 options
.max_bgerror_resume_count
=
166 immutable_db_options
.max_bgerror_resume_count
;
167 options
.bgerror_resume_retry_interval
=
168 immutable_db_options
.bgerror_resume_retry_interval
;
169 options
.db_host_id
= immutable_db_options
.db_host_id
;
170 options
.allow_data_in_errors
= immutable_db_options
.allow_data_in_errors
;
174 ColumnFamilyOptions
BuildColumnFamilyOptions(
175 const ColumnFamilyOptions
& options
,
176 const MutableCFOptions
& mutable_cf_options
) {
177 ColumnFamilyOptions
cf_opts(options
);
179 // Memtable related options
180 cf_opts
.write_buffer_size
= mutable_cf_options
.write_buffer_size
;
181 cf_opts
.max_write_buffer_number
= mutable_cf_options
.max_write_buffer_number
;
182 cf_opts
.arena_block_size
= mutable_cf_options
.arena_block_size
;
183 cf_opts
.memtable_prefix_bloom_size_ratio
=
184 mutable_cf_options
.memtable_prefix_bloom_size_ratio
;
185 cf_opts
.memtable_whole_key_filtering
=
186 mutable_cf_options
.memtable_whole_key_filtering
;
187 cf_opts
.memtable_huge_page_size
= mutable_cf_options
.memtable_huge_page_size
;
188 cf_opts
.max_successive_merges
= mutable_cf_options
.max_successive_merges
;
189 cf_opts
.inplace_update_num_locks
=
190 mutable_cf_options
.inplace_update_num_locks
;
191 cf_opts
.prefix_extractor
= mutable_cf_options
.prefix_extractor
;
193 // Compaction related options
194 cf_opts
.disable_auto_compactions
=
195 mutable_cf_options
.disable_auto_compactions
;
196 cf_opts
.soft_pending_compaction_bytes_limit
=
197 mutable_cf_options
.soft_pending_compaction_bytes_limit
;
198 cf_opts
.hard_pending_compaction_bytes_limit
=
199 mutable_cf_options
.hard_pending_compaction_bytes_limit
;
200 cf_opts
.level0_file_num_compaction_trigger
=
201 mutable_cf_options
.level0_file_num_compaction_trigger
;
202 cf_opts
.level0_slowdown_writes_trigger
=
203 mutable_cf_options
.level0_slowdown_writes_trigger
;
204 cf_opts
.level0_stop_writes_trigger
=
205 mutable_cf_options
.level0_stop_writes_trigger
;
206 cf_opts
.max_compaction_bytes
= mutable_cf_options
.max_compaction_bytes
;
207 cf_opts
.target_file_size_base
= mutable_cf_options
.target_file_size_base
;
208 cf_opts
.target_file_size_multiplier
=
209 mutable_cf_options
.target_file_size_multiplier
;
210 cf_opts
.max_bytes_for_level_base
=
211 mutable_cf_options
.max_bytes_for_level_base
;
212 cf_opts
.max_bytes_for_level_multiplier
=
213 mutable_cf_options
.max_bytes_for_level_multiplier
;
214 cf_opts
.ttl
= mutable_cf_options
.ttl
;
215 cf_opts
.periodic_compaction_seconds
=
216 mutable_cf_options
.periodic_compaction_seconds
;
218 cf_opts
.max_bytes_for_level_multiplier_additional
.clear();
220 mutable_cf_options
.max_bytes_for_level_multiplier_additional
) {
221 cf_opts
.max_bytes_for_level_multiplier_additional
.emplace_back(value
);
224 cf_opts
.compaction_options_fifo
= mutable_cf_options
.compaction_options_fifo
;
225 cf_opts
.compaction_options_universal
=
226 mutable_cf_options
.compaction_options_universal
;
228 // Blob file related options
229 cf_opts
.enable_blob_files
= mutable_cf_options
.enable_blob_files
;
230 cf_opts
.min_blob_size
= mutable_cf_options
.min_blob_size
;
231 cf_opts
.blob_file_size
= mutable_cf_options
.blob_file_size
;
232 cf_opts
.blob_compression_type
= mutable_cf_options
.blob_compression_type
;
233 cf_opts
.enable_blob_garbage_collection
=
234 mutable_cf_options
.enable_blob_garbage_collection
;
235 cf_opts
.blob_garbage_collection_age_cutoff
=
236 mutable_cf_options
.blob_garbage_collection_age_cutoff
;
239 cf_opts
.max_sequential_skip_in_iterations
=
240 mutable_cf_options
.max_sequential_skip_in_iterations
;
241 cf_opts
.check_flush_compaction_key_order
=
242 mutable_cf_options
.check_flush_compaction_key_order
;
243 cf_opts
.paranoid_file_checks
= mutable_cf_options
.paranoid_file_checks
;
244 cf_opts
.report_bg_io_stats
= mutable_cf_options
.report_bg_io_stats
;
245 cf_opts
.compression
= mutable_cf_options
.compression
;
246 cf_opts
.compression_opts
= mutable_cf_options
.compression_opts
;
247 cf_opts
.bottommost_compression
= mutable_cf_options
.bottommost_compression
;
248 cf_opts
.bottommost_compression_opts
=
249 mutable_cf_options
.bottommost_compression_opts
;
250 cf_opts
.sample_for_compression
= mutable_cf_options
.sample_for_compression
;
252 cf_opts
.table_factory
= options
.table_factory
;
253 // TODO(yhchiang): find some way to handle the following derived options
259 std::map
<CompactionStyle
, std::string
>
260 OptionsHelper::compaction_style_to_string
= {
261 {kCompactionStyleLevel
, "kCompactionStyleLevel"},
262 {kCompactionStyleUniversal
, "kCompactionStyleUniversal"},
263 {kCompactionStyleFIFO
, "kCompactionStyleFIFO"},
264 {kCompactionStyleNone
, "kCompactionStyleNone"}};
266 std::map
<CompactionPri
, std::string
> OptionsHelper::compaction_pri_to_string
= {
267 {kByCompensatedSize
, "kByCompensatedSize"},
268 {kOldestLargestSeqFirst
, "kOldestLargestSeqFirst"},
269 {kOldestSmallestSeqFirst
, "kOldestSmallestSeqFirst"},
270 {kMinOverlappingRatio
, "kMinOverlappingRatio"}};
272 std::map
<CompactionStopStyle
, std::string
>
273 OptionsHelper::compaction_stop_style_to_string
= {
274 {kCompactionStopStyleSimilarSize
, "kCompactionStopStyleSimilarSize"},
275 {kCompactionStopStyleTotalSize
, "kCompactionStopStyleTotalSize"}};
277 std::unordered_map
<std::string
, ChecksumType
>
278 OptionsHelper::checksum_type_string_map
= {{"kNoChecksum", kNoChecksum
},
279 {"kCRC32c", kCRC32c
},
280 {"kxxHash", kxxHash
},
281 {"kxxHash64", kxxHash64
}};
283 std::unordered_map
<std::string
, CompressionType
>
284 OptionsHelper::compression_type_string_map
= {
285 {"kNoCompression", kNoCompression
},
286 {"kSnappyCompression", kSnappyCompression
},
287 {"kZlibCompression", kZlibCompression
},
288 {"kBZip2Compression", kBZip2Compression
},
289 {"kLZ4Compression", kLZ4Compression
},
290 {"kLZ4HCCompression", kLZ4HCCompression
},
291 {"kXpressCompression", kXpressCompression
},
293 {"kZSTDNotFinalCompression", kZSTDNotFinalCompression
},
294 {"kDisableCompressionOption", kDisableCompressionOption
}};
296 std::vector
<CompressionType
> GetSupportedCompressions() {
297 std::vector
<CompressionType
> supported_compressions
;
298 for (const auto& comp_to_name
: OptionsHelper::compression_type_string_map
) {
299 CompressionType t
= comp_to_name
.second
;
300 if (t
!= kDisableCompressionOption
&& CompressionTypeSupported(t
)) {
301 supported_compressions
.push_back(t
);
304 return supported_compressions
;
307 std::vector
<CompressionType
> GetSupportedDictCompressions() {
308 std::vector
<CompressionType
> dict_compression_types
;
309 for (const auto& comp_to_name
: OptionsHelper::compression_type_string_map
) {
310 CompressionType t
= comp_to_name
.second
;
311 if (t
!= kDisableCompressionOption
&& DictCompressionTypeSupported(t
)) {
312 dict_compression_types
.push_back(t
);
315 return dict_compression_types
;
319 bool ParseSliceTransformHelper(
320 const std::string
& kFixedPrefixName
, const std::string
& kCappedPrefixName
,
321 const std::string
& value
,
322 std::shared_ptr
<const SliceTransform
>* slice_transform
) {
323 const char* no_op_name
= "rocksdb.Noop";
324 size_t no_op_length
= strlen(no_op_name
);
325 auto& pe_value
= value
;
326 if (pe_value
.size() > kFixedPrefixName
.size() &&
327 pe_value
.compare(0, kFixedPrefixName
.size(), kFixedPrefixName
) == 0) {
328 int prefix_length
= ParseInt(trim(value
.substr(kFixedPrefixName
.size())));
329 slice_transform
->reset(NewFixedPrefixTransform(prefix_length
));
330 } else if (pe_value
.size() > kCappedPrefixName
.size() &&
331 pe_value
.compare(0, kCappedPrefixName
.size(), kCappedPrefixName
) ==
334 ParseInt(trim(pe_value
.substr(kCappedPrefixName
.size())));
335 slice_transform
->reset(NewCappedPrefixTransform(prefix_length
));
336 } else if (pe_value
.size() == no_op_length
&&
337 pe_value
.compare(0, no_op_length
, no_op_name
) == 0) {
338 const SliceTransform
* no_op_transform
= NewNoopTransform();
339 slice_transform
->reset(no_op_transform
);
340 } else if (value
== kNullptrString
) {
341 slice_transform
->reset();
349 bool ParseSliceTransform(
350 const std::string
& value
,
351 std::shared_ptr
<const SliceTransform
>* slice_transform
) {
352 // While we normally don't convert the string representation of a
353 // pointer-typed option into its instance, here we do so for backward
354 // compatibility as we allow this action in SetOption().
356 // TODO(yhchiang): A possible better place for these serialization /
357 // deserialization is inside the class definition of pointer-typed
358 // option itself, but this requires a bigger change of public API.
360 ParseSliceTransformHelper("fixed:", "capped:", value
, slice_transform
);
364 result
= ParseSliceTransformHelper(
365 "rocksdb.FixedPrefix.", "rocksdb.CappedPrefix.", value
, slice_transform
);
369 // TODO(yhchiang): we can further support other default
370 // SliceTransforms here.
374 static bool ParseOptionHelper(char* opt_address
, const OptionType
& opt_type
,
375 const std::string
& value
) {
377 case OptionType::kBoolean
:
378 *reinterpret_cast<bool*>(opt_address
) = ParseBoolean("", value
);
380 case OptionType::kInt
:
381 *reinterpret_cast<int*>(opt_address
) = ParseInt(value
);
383 case OptionType::kInt32T
:
384 *reinterpret_cast<int32_t*>(opt_address
) = ParseInt32(value
);
386 case OptionType::kInt64T
:
387 PutUnaligned(reinterpret_cast<int64_t*>(opt_address
), ParseInt64(value
));
389 case OptionType::kUInt
:
390 *reinterpret_cast<unsigned int*>(opt_address
) = ParseUint32(value
);
392 case OptionType::kUInt32T
:
393 *reinterpret_cast<uint32_t*>(opt_address
) = ParseUint32(value
);
395 case OptionType::kUInt64T
:
396 PutUnaligned(reinterpret_cast<uint64_t*>(opt_address
), ParseUint64(value
));
398 case OptionType::kSizeT
:
399 PutUnaligned(reinterpret_cast<size_t*>(opt_address
), ParseSizeT(value
));
401 case OptionType::kString
:
402 *reinterpret_cast<std::string
*>(opt_address
) = value
;
404 case OptionType::kDouble
:
405 *reinterpret_cast<double*>(opt_address
) = ParseDouble(value
);
407 case OptionType::kCompactionStyle
:
408 return ParseEnum
<CompactionStyle
>(
409 compaction_style_string_map
, value
,
410 reinterpret_cast<CompactionStyle
*>(opt_address
));
411 case OptionType::kCompactionPri
:
412 return ParseEnum
<CompactionPri
>(
413 compaction_pri_string_map
, value
,
414 reinterpret_cast<CompactionPri
*>(opt_address
));
415 case OptionType::kCompressionType
:
416 return ParseEnum
<CompressionType
>(
417 compression_type_string_map
, value
,
418 reinterpret_cast<CompressionType
*>(opt_address
));
419 case OptionType::kSliceTransform
:
420 return ParseSliceTransform(
421 value
, reinterpret_cast<std::shared_ptr
<const SliceTransform
>*>(
423 case OptionType::kChecksumType
:
424 return ParseEnum
<ChecksumType
>(
425 checksum_type_string_map
, value
,
426 reinterpret_cast<ChecksumType
*>(opt_address
));
427 case OptionType::kEncodingType
:
428 return ParseEnum
<EncodingType
>(
429 encoding_type_string_map
, value
,
430 reinterpret_cast<EncodingType
*>(opt_address
));
431 case OptionType::kCompactionStopStyle
:
432 return ParseEnum
<CompactionStopStyle
>(
433 compaction_stop_style_string_map
, value
,
434 reinterpret_cast<CompactionStopStyle
*>(opt_address
));
441 bool SerializeSingleOptionHelper(const char* opt_address
,
442 const OptionType opt_type
,
443 std::string
* value
) {
447 case OptionType::kBoolean
:
448 *value
= *(reinterpret_cast<const bool*>(opt_address
)) ? "true" : "false";
450 case OptionType::kInt
:
451 *value
= ToString(*(reinterpret_cast<const int*>(opt_address
)));
453 case OptionType::kInt32T
:
454 *value
= ToString(*(reinterpret_cast<const int32_t*>(opt_address
)));
456 case OptionType::kInt64T
:
459 GetUnaligned(reinterpret_cast<const int64_t*>(opt_address
), &v
);
460 *value
= ToString(v
);
463 case OptionType::kUInt
:
464 *value
= ToString(*(reinterpret_cast<const unsigned int*>(opt_address
)));
466 case OptionType::kUInt32T
:
467 *value
= ToString(*(reinterpret_cast<const uint32_t*>(opt_address
)));
469 case OptionType::kUInt64T
:
472 GetUnaligned(reinterpret_cast<const uint64_t*>(opt_address
), &v
);
473 *value
= ToString(v
);
476 case OptionType::kSizeT
:
479 GetUnaligned(reinterpret_cast<const size_t*>(opt_address
), &v
);
480 *value
= ToString(v
);
483 case OptionType::kDouble
:
484 *value
= ToString(*(reinterpret_cast<const double*>(opt_address
)));
486 case OptionType::kString
:
487 *value
= EscapeOptionString(
488 *(reinterpret_cast<const std::string
*>(opt_address
)));
490 case OptionType::kCompactionStyle
:
491 return SerializeEnum
<CompactionStyle
>(
492 compaction_style_string_map
,
493 *(reinterpret_cast<const CompactionStyle
*>(opt_address
)), value
);
494 case OptionType::kCompactionPri
:
495 return SerializeEnum
<CompactionPri
>(
496 compaction_pri_string_map
,
497 *(reinterpret_cast<const CompactionPri
*>(opt_address
)), value
);
498 case OptionType::kCompressionType
:
499 return SerializeEnum
<CompressionType
>(
500 compression_type_string_map
,
501 *(reinterpret_cast<const CompressionType
*>(opt_address
)), value
);
502 case OptionType::kSliceTransform
: {
503 const auto* slice_transform_ptr
=
504 reinterpret_cast<const std::shared_ptr
<const SliceTransform
>*>(
506 *value
= slice_transform_ptr
->get() ? slice_transform_ptr
->get()->Name()
510 case OptionType::kComparator
: {
511 // it's a const pointer of const Comparator*
512 const auto* ptr
= reinterpret_cast<const Comparator
* const*>(opt_address
);
513 // Since the user-specified comparator will be wrapped by
514 // InternalKeyComparator, we should persist the user-specified one
515 // instead of InternalKeyComparator.
516 if (*ptr
== nullptr) {
517 *value
= kNullptrString
;
519 const Comparator
* root_comp
= (*ptr
)->GetRootComparator();
520 if (root_comp
== nullptr) {
523 *value
= root_comp
->Name();
527 case OptionType::kCompactionFilter
: {
528 // it's a const pointer of const CompactionFilter*
530 reinterpret_cast<const CompactionFilter
* const*>(opt_address
);
531 *value
= *ptr
? (*ptr
)->Name() : kNullptrString
;
534 case OptionType::kCompactionFilterFactory
: {
536 reinterpret_cast<const std::shared_ptr
<CompactionFilterFactory
>*>(
538 *value
= ptr
->get() ? ptr
->get()->Name() : kNullptrString
;
541 case OptionType::kMemTableRepFactory
: {
543 reinterpret_cast<const std::shared_ptr
<MemTableRepFactory
>*>(
545 *value
= ptr
->get() ? ptr
->get()->Name() : kNullptrString
;
548 case OptionType::kMergeOperator
: {
550 reinterpret_cast<const std::shared_ptr
<MergeOperator
>*>(opt_address
);
551 *value
= ptr
->get() ? ptr
->get()->Name() : kNullptrString
;
554 case OptionType::kFilterPolicy
: {
556 reinterpret_cast<const std::shared_ptr
<FilterPolicy
>*>(opt_address
);
557 *value
= ptr
->get() ? ptr
->get()->Name() : kNullptrString
;
560 case OptionType::kChecksumType
:
561 return SerializeEnum
<ChecksumType
>(
562 checksum_type_string_map
,
563 *reinterpret_cast<const ChecksumType
*>(opt_address
), value
);
564 case OptionType::kFlushBlockPolicyFactory
: {
566 reinterpret_cast<const std::shared_ptr
<FlushBlockPolicyFactory
>*>(
568 *value
= ptr
->get() ? ptr
->get()->Name() : kNullptrString
;
571 case OptionType::kEncodingType
:
572 return SerializeEnum
<EncodingType
>(
573 encoding_type_string_map
,
574 *reinterpret_cast<const EncodingType
*>(opt_address
), value
);
575 case OptionType::kCompactionStopStyle
:
576 return SerializeEnum
<CompactionStopStyle
>(
577 compaction_stop_style_string_map
,
578 *reinterpret_cast<const CompactionStopStyle
*>(opt_address
), value
);
585 template <typename T
>
586 Status
ConfigureFromMap(
587 const ConfigOptions
& config_options
,
588 const std::unordered_map
<std::string
, std::string
>& opt_map
,
589 const std::string
& option_name
, Configurable
* config
, T
* new_opts
) {
590 Status s
= config
->ConfigureFromMap(config_options
, opt_map
);
592 *new_opts
= *(config
->GetOptions
<T
>(option_name
));
597 Status
GetMutableOptionsFromStrings(
598 const MutableCFOptions
& base_options
,
599 const std::unordered_map
<std::string
, std::string
>& options_map
,
600 Logger
* /*info_log*/, MutableCFOptions
* new_options
) {
602 *new_options
= base_options
;
603 ConfigOptions config_options
;
604 const auto config
= CFOptionsAsConfigurable(base_options
);
605 return ConfigureFromMap
<MutableCFOptions
>(config_options
, options_map
,
606 MutableCFOptions::kName(),
607 config
.get(), new_options
);
610 Status
GetMutableDBOptionsFromStrings(
611 const MutableDBOptions
& base_options
,
612 const std::unordered_map
<std::string
, std::string
>& options_map
,
613 MutableDBOptions
* new_options
) {
615 *new_options
= base_options
;
616 ConfigOptions config_options
;
618 auto config
= DBOptionsAsConfigurable(base_options
);
619 return ConfigureFromMap
<MutableDBOptions
>(config_options
, options_map
,
620 MutableDBOptions::kName(),
621 config
.get(), new_options
);
624 Status
StringToMap(const std::string
& opts_str
,
625 std::unordered_map
<std::string
, std::string
>* opts_map
) {
628 // opts_str = "write_buffer_size=1024;max_write_buffer_number=2;"
629 // "nested_opt={opt1=1;opt2=2};max_bytes_for_level_base=100"
631 std::string opts
= trim(opts_str
);
632 // If the input string starts and ends with "{...}", strip off the brackets
633 while (opts
.size() > 2 && opts
[0] == '{' && opts
[opts
.size() - 1] == '}') {
634 opts
= trim(opts
.substr(1, opts
.size() - 2));
637 while (pos
< opts
.size()) {
638 size_t eq_pos
= opts
.find('=', pos
);
639 if (eq_pos
== std::string::npos
) {
640 return Status::InvalidArgument("Mismatched key value pair, '=' expected");
642 std::string key
= trim(opts
.substr(pos
, eq_pos
- pos
));
644 return Status::InvalidArgument("Empty key found");
648 Status s
= OptionTypeInfo::NextToken(opts
, ';', eq_pos
+ 1, &pos
, &value
);
652 (*opts_map
)[key
] = value
;
653 if (pos
== std::string::npos
) {
664 Status
GetStringFromMutableDBOptions(const ConfigOptions
& config_options
,
665 const MutableDBOptions
& mutable_opts
,
666 std::string
* opt_string
) {
667 auto config
= DBOptionsAsConfigurable(mutable_opts
);
668 return config
->GetOptionString(config_options
, opt_string
);
671 Status
GetStringFromDBOptions(std::string
* opt_string
,
672 const DBOptions
& db_options
,
673 const std::string
& delimiter
) {
674 ConfigOptions config_options
;
675 config_options
.delimiter
= delimiter
;
676 return GetStringFromDBOptions(config_options
, db_options
, opt_string
);
679 Status
GetStringFromDBOptions(const ConfigOptions
& config_options
,
680 const DBOptions
& db_options
,
681 std::string
* opt_string
) {
684 auto config
= DBOptionsAsConfigurable(db_options
);
685 return config
->GetOptionString(config_options
, opt_string
);
688 Status
GetStringFromMutableCFOptions(const ConfigOptions
& config_options
,
689 const MutableCFOptions
& mutable_opts
,
690 std::string
* opt_string
) {
693 const auto config
= CFOptionsAsConfigurable(mutable_opts
);
694 return config
->GetOptionString(config_options
, opt_string
);
697 Status
GetStringFromColumnFamilyOptions(std::string
* opt_string
,
698 const ColumnFamilyOptions
& cf_options
,
699 const std::string
& delimiter
) {
700 ConfigOptions config_options
;
701 config_options
.delimiter
= delimiter
;
702 return GetStringFromColumnFamilyOptions(config_options
, cf_options
,
706 Status
GetStringFromColumnFamilyOptions(const ConfigOptions
& config_options
,
707 const ColumnFamilyOptions
& cf_options
,
708 std::string
* opt_string
) {
709 const auto config
= CFOptionsAsConfigurable(cf_options
);
710 return config
->GetOptionString(config_options
, opt_string
);
713 Status
GetStringFromCompressionType(std::string
* compression_str
,
714 CompressionType compression_type
) {
715 bool ok
= SerializeEnum
<CompressionType
>(compression_type_string_map
,
716 compression_type
, compression_str
);
720 return Status::InvalidArgument("Invalid compression types");
724 Status
GetColumnFamilyOptionsFromMap(
725 const ColumnFamilyOptions
& base_options
,
726 const std::unordered_map
<std::string
, std::string
>& opts_map
,
727 ColumnFamilyOptions
* new_options
, bool input_strings_escaped
,
728 bool ignore_unknown_options
) {
729 ConfigOptions config_options
;
730 config_options
.ignore_unknown_options
= ignore_unknown_options
;
731 config_options
.input_strings_escaped
= input_strings_escaped
;
732 return GetColumnFamilyOptionsFromMap(config_options
, base_options
, opts_map
,
736 Status
GetColumnFamilyOptionsFromMap(
737 const ConfigOptions
& config_options
,
738 const ColumnFamilyOptions
& base_options
,
739 const std::unordered_map
<std::string
, std::string
>& opts_map
,
740 ColumnFamilyOptions
* new_options
) {
743 *new_options
= base_options
;
745 const auto config
= CFOptionsAsConfigurable(base_options
);
746 Status s
= ConfigureFromMap
<ColumnFamilyOptions
>(
747 config_options
, opts_map
, OptionsHelper::kCFOptionsName
, config
.get(),
749 // Translate any errors (NotFound, NotSupported, to InvalidArgument
750 if (s
.ok() || s
.IsInvalidArgument()) {
753 return Status::InvalidArgument(s
.getState());
757 Status
GetColumnFamilyOptionsFromString(
758 const ColumnFamilyOptions
& base_options
,
759 const std::string
& opts_str
,
760 ColumnFamilyOptions
* new_options
) {
761 ConfigOptions config_options
;
762 config_options
.input_strings_escaped
= false;
763 config_options
.ignore_unknown_options
= false;
764 return GetColumnFamilyOptionsFromString(config_options
, base_options
,
765 opts_str
, new_options
);
768 Status
GetColumnFamilyOptionsFromString(const ConfigOptions
& config_options
,
769 const ColumnFamilyOptions
& base_options
,
770 const std::string
& opts_str
,
771 ColumnFamilyOptions
* new_options
) {
772 std::unordered_map
<std::string
, std::string
> opts_map
;
773 Status s
= StringToMap(opts_str
, &opts_map
);
775 *new_options
= base_options
;
778 return GetColumnFamilyOptionsFromMap(config_options
, base_options
, opts_map
,
782 Status
GetDBOptionsFromMap(
783 const DBOptions
& base_options
,
784 const std::unordered_map
<std::string
, std::string
>& opts_map
,
785 DBOptions
* new_options
, bool input_strings_escaped
,
786 bool ignore_unknown_options
) {
787 ConfigOptions config_options
;
788 config_options
.input_strings_escaped
= input_strings_escaped
;
789 config_options
.ignore_unknown_options
= ignore_unknown_options
;
790 return GetDBOptionsFromMap(config_options
, base_options
, opts_map
,
794 Status
GetDBOptionsFromMap(
795 const ConfigOptions
& config_options
, const DBOptions
& base_options
,
796 const std::unordered_map
<std::string
, std::string
>& opts_map
,
797 DBOptions
* new_options
) {
799 *new_options
= base_options
;
800 auto config
= DBOptionsAsConfigurable(base_options
);
801 Status s
= ConfigureFromMap
<DBOptions
>(config_options
, opts_map
,
802 OptionsHelper::kDBOptionsName
,
803 config
.get(), new_options
);
804 // Translate any errors (NotFound, NotSupported, to InvalidArgument
805 if (s
.ok() || s
.IsInvalidArgument()) {
808 return Status::InvalidArgument(s
.getState());
812 Status
GetDBOptionsFromString(const DBOptions
& base_options
,
813 const std::string
& opts_str
,
814 DBOptions
* new_options
) {
815 ConfigOptions config_options
;
816 config_options
.input_strings_escaped
= false;
817 config_options
.ignore_unknown_options
= false;
819 return GetDBOptionsFromString(config_options
, base_options
, opts_str
,
823 Status
GetDBOptionsFromString(const ConfigOptions
& config_options
,
824 const DBOptions
& base_options
,
825 const std::string
& opts_str
,
826 DBOptions
* new_options
) {
827 std::unordered_map
<std::string
, std::string
> opts_map
;
828 Status s
= StringToMap(opts_str
, &opts_map
);
830 *new_options
= base_options
;
833 return GetDBOptionsFromMap(config_options
, base_options
, opts_map
,
837 Status
GetOptionsFromString(const Options
& base_options
,
838 const std::string
& opts_str
, Options
* new_options
) {
839 ConfigOptions config_options
;
840 config_options
.input_strings_escaped
= false;
841 config_options
.ignore_unknown_options
= false;
843 return GetOptionsFromString(config_options
, base_options
, opts_str
,
847 Status
GetOptionsFromString(const ConfigOptions
& config_options
,
848 const Options
& base_options
,
849 const std::string
& opts_str
, Options
* new_options
) {
850 ColumnFamilyOptions new_cf_options
;
851 std::unordered_map
<std::string
, std::string
> unused_opts
;
852 std::unordered_map
<std::string
, std::string
> opts_map
;
854 *new_options
= base_options
;
855 Status s
= StringToMap(opts_str
, &opts_map
);
859 auto config
= DBOptionsAsConfigurable(base_options
);
860 s
= config
->ConfigureFromMap(config_options
, opts_map
, &unused_opts
);
863 DBOptions
* new_db_options
=
864 config
->GetOptions
<DBOptions
>(OptionsHelper::kDBOptionsName
);
865 if (!unused_opts
.empty()) {
866 s
= GetColumnFamilyOptionsFromMap(config_options
, base_options
,
867 unused_opts
, &new_cf_options
);
869 *new_options
= Options(*new_db_options
, new_cf_options
);
872 *new_options
= Options(*new_db_options
, base_options
);
875 // Translate any errors (NotFound, NotSupported, to InvalidArgument
876 if (s
.ok() || s
.IsInvalidArgument()) {
879 return Status::InvalidArgument(s
.getState());
883 std::unordered_map
<std::string
, EncodingType
>
884 OptionsHelper::encoding_type_string_map
= {{"kPlain", kPlain
},
885 {"kPrefix", kPrefix
}};
887 std::unordered_map
<std::string
, CompactionStyle
>
888 OptionsHelper::compaction_style_string_map
= {
889 {"kCompactionStyleLevel", kCompactionStyleLevel
},
890 {"kCompactionStyleUniversal", kCompactionStyleUniversal
},
891 {"kCompactionStyleFIFO", kCompactionStyleFIFO
},
892 {"kCompactionStyleNone", kCompactionStyleNone
}};
894 std::unordered_map
<std::string
, CompactionPri
>
895 OptionsHelper::compaction_pri_string_map
= {
896 {"kByCompensatedSize", kByCompensatedSize
},
897 {"kOldestLargestSeqFirst", kOldestLargestSeqFirst
},
898 {"kOldestSmallestSeqFirst", kOldestSmallestSeqFirst
},
899 {"kMinOverlappingRatio", kMinOverlappingRatio
}};
901 std::unordered_map
<std::string
, CompactionStopStyle
>
902 OptionsHelper::compaction_stop_style_string_map
= {
903 {"kCompactionStopStyleSimilarSize", kCompactionStopStyleSimilarSize
},
904 {"kCompactionStopStyleTotalSize", kCompactionStopStyleTotalSize
}};
906 Status
OptionTypeInfo::NextToken(const std::string
& opts
, char delimiter
,
907 size_t pos
, size_t* end
, std::string
* token
) {
908 while (pos
< opts
.size() && isspace(opts
[pos
])) {
911 // Empty value at the end
912 if (pos
>= opts
.size()) {
914 *end
= std::string::npos
;
916 } else if (opts
[pos
] == '{') {
918 size_t brace_pos
= pos
+ 1;
919 while (brace_pos
< opts
.size()) {
920 if (opts
[brace_pos
] == '{') {
922 } else if (opts
[brace_pos
] == '}') {
930 // found the matching closing brace
932 *token
= trim(opts
.substr(pos
+ 1, brace_pos
- pos
- 1));
933 // skip all whitespace and move to the next delimiter
934 // brace_pos points to the next position after the matching '}'
936 while (pos
< opts
.size() && isspace(opts
[pos
])) {
939 if (pos
< opts
.size() && opts
[pos
] != delimiter
) {
940 return Status::InvalidArgument("Unexpected chars after nested options");
944 return Status::InvalidArgument(
945 "Mismatched curly braces for nested options");
948 *end
= opts
.find(delimiter
, pos
);
949 if (*end
== std::string::npos
) {
950 // It either ends with a trailing semi-colon or the last key-value pair
951 *token
= trim(opts
.substr(pos
));
953 *token
= trim(opts
.substr(pos
, *end
- pos
));
959 Status
OptionTypeInfo::Parse(const ConfigOptions
& config_options
,
960 const std::string
& opt_name
,
961 const std::string
& value
, void* opt_ptr
) const {
962 if (IsDeprecated()) {
966 char* opt_addr
= reinterpret_cast<char*>(opt_ptr
) + offset_
;
967 const std::string
& opt_value
= config_options
.input_strings_escaped
968 ? UnescapeOptionString(value
)
971 if (opt_addr
== nullptr) {
972 return Status::NotFound("Could not find option", opt_name
);
973 } else if (parse_func_
!= nullptr) {
974 ConfigOptions copy
= config_options
;
975 copy
.invoke_prepare_options
= false;
976 return parse_func_(copy
, opt_name
, opt_value
, opt_addr
);
977 } else if (ParseOptionHelper(opt_addr
, type_
, opt_value
)) {
979 } else if (IsConfigurable()) {
980 // The option is <config>.<name>
981 Configurable
* config
= AsRawPointer
<Configurable
>(opt_ptr
);
982 if (opt_value
.empty()) {
984 } else if (config
== nullptr) {
985 return Status::NotFound("Could not find configurable: ", opt_name
);
987 ConfigOptions copy
= config_options
;
988 copy
.ignore_unknown_options
= false;
989 copy
.invoke_prepare_options
= false;
990 if (opt_value
.find("=") != std::string::npos
) {
991 return config
->ConfigureFromString(copy
, opt_value
);
993 return config
->ConfigureOption(copy
, opt_name
, opt_value
);
996 } else if (IsByName()) {
997 return Status::NotSupported("Deserializing the option " + opt_name
+
998 " is not supported");
1000 return Status::InvalidArgument("Error parsing:", opt_name
);
1002 } catch (std::exception
& e
) {
1003 return Status::InvalidArgument("Error parsing " + opt_name
+ ":" +
1004 std::string(e
.what()));
1008 Status
OptionTypeInfo::ParseStruct(
1009 const ConfigOptions
& config_options
, const std::string
& struct_name
,
1010 const std::unordered_map
<std::string
, OptionTypeInfo
>* struct_map
,
1011 const std::string
& opt_name
, const std::string
& opt_value
, char* opt_addr
) {
1014 if (opt_name
== struct_name
|| EndsWith(opt_name
, "." + struct_name
)) {
1015 // This option represents the entire struct
1016 std::unordered_map
<std::string
, std::string
> opt_map
;
1017 status
= StringToMap(opt_value
, &opt_map
);
1018 for (const auto& map_iter
: opt_map
) {
1022 const auto iter
= struct_map
->find(map_iter
.first
);
1023 if (iter
!= struct_map
->end()) {
1024 status
= iter
->second
.Parse(config_options
, map_iter
.first
,
1025 map_iter
.second
, opt_addr
);
1027 status
= Status::InvalidArgument("Unrecognized option",
1028 struct_name
+ "." + map_iter
.first
);
1031 } else if (StartsWith(opt_name
, struct_name
+ ".")) {
1032 // This option represents a nested field in the struct (e.g, struct.field)
1033 std::string elem_name
;
1034 const auto opt_info
=
1035 Find(opt_name
.substr(struct_name
.size() + 1), *struct_map
, &elem_name
);
1036 if (opt_info
!= nullptr) {
1037 status
= opt_info
->Parse(config_options
, elem_name
, opt_value
, opt_addr
);
1039 status
= Status::InvalidArgument("Unrecognized option", opt_name
);
1042 // This option represents a field in the struct (e.g. field)
1043 std::string elem_name
;
1044 const auto opt_info
= Find(opt_name
, *struct_map
, &elem_name
);
1045 if (opt_info
!= nullptr) {
1046 status
= opt_info
->Parse(config_options
, elem_name
, opt_value
, opt_addr
);
1048 status
= Status::InvalidArgument("Unrecognized option",
1049 struct_name
+ "." + opt_name
);
1055 Status
OptionTypeInfo::Serialize(const ConfigOptions
& config_options
,
1056 const std::string
& opt_name
,
1057 const void* const opt_ptr
,
1058 std::string
* opt_value
) const {
1059 // If the option is no longer used in rocksdb and marked as deprecated,
1060 // we skip it in the serialization.
1061 const char* opt_addr
= reinterpret_cast<const char*>(opt_ptr
) + offset_
;
1062 if (opt_addr
== nullptr || IsDeprecated()) {
1063 return Status::OK();
1064 } else if (IsEnabled(OptionTypeFlags::kDontSerialize
)) {
1065 return Status::NotSupported("Cannot serialize option: ", opt_name
);
1066 } else if (serialize_func_
!= nullptr) {
1067 return serialize_func_(config_options
, opt_name
, opt_addr
, opt_value
);
1068 } else if (SerializeSingleOptionHelper(opt_addr
, type_
, opt_value
)) {
1069 return Status::OK();
1070 } else if (IsCustomizable()) {
1071 const Customizable
* custom
= AsRawPointer
<Customizable
>(opt_ptr
);
1072 if (custom
== nullptr) {
1073 *opt_value
= kNullptrString
;
1074 } else if (IsEnabled(OptionTypeFlags::kStringNameOnly
) &&
1075 !config_options
.IsDetailed()) {
1076 *opt_value
= custom
->GetId();
1078 ConfigOptions embedded
= config_options
;
1079 embedded
.delimiter
= ";";
1080 *opt_value
= custom
->ToString(embedded
);
1082 return Status::OK();
1083 } else if (IsConfigurable()) {
1084 const Configurable
* config
= AsRawPointer
<Configurable
>(opt_ptr
);
1085 if (config
!= nullptr) {
1086 ConfigOptions embedded
= config_options
;
1087 embedded
.delimiter
= ";";
1088 *opt_value
= config
->ToString(embedded
);
1090 return Status::OK();
1092 return Status::InvalidArgument("Cannot serialize option: ", opt_name
);
1096 Status
OptionTypeInfo::SerializeStruct(
1097 const ConfigOptions
& config_options
, const std::string
& struct_name
,
1098 const std::unordered_map
<std::string
, OptionTypeInfo
>* struct_map
,
1099 const std::string
& opt_name
, const char* opt_addr
, std::string
* value
) {
1102 if (EndsWith(opt_name
, struct_name
)) {
1103 // We are going to write the struct as "{ prop1=value1; prop2=value2;}.
1104 // Set the delimiter to ";" so that the everything will be on one line.
1105 ConfigOptions embedded
= config_options
;
1106 embedded
.delimiter
= ";";
1108 // This option represents the entire struct
1110 for (const auto& iter
: *struct_map
) {
1112 const auto& opt_info
= iter
.second
;
1113 if (opt_info
.ShouldSerialize()) {
1114 status
= opt_info
.Serialize(embedded
, iter
.first
, opt_addr
, &single
);
1118 result
.append(iter
.first
+ "=" + single
+ embedded
.delimiter
);
1122 *value
= "{" + result
+ "}";
1123 } else if (StartsWith(opt_name
, struct_name
+ ".")) {
1124 // This option represents a nested field in the struct (e.g, struct.field)
1125 std::string elem_name
;
1126 const auto opt_info
=
1127 Find(opt_name
.substr(struct_name
.size() + 1), *struct_map
, &elem_name
);
1128 if (opt_info
!= nullptr) {
1129 status
= opt_info
->Serialize(config_options
, elem_name
, opt_addr
, value
);
1131 status
= Status::InvalidArgument("Unrecognized option", opt_name
);
1134 // This option represents a field in the struct (e.g. field)
1135 std::string elem_name
;
1136 const auto opt_info
= Find(opt_name
, *struct_map
, &elem_name
);
1137 if (opt_info
== nullptr) {
1138 status
= Status::InvalidArgument("Unrecognized option", opt_name
);
1139 } else if (opt_info
->ShouldSerialize()) {
1140 status
= opt_info
->Serialize(config_options
, opt_name
+ "." + elem_name
,
1147 template <typename T
>
1148 bool IsOptionEqual(const char* offset1
, const char* offset2
) {
1149 return (*reinterpret_cast<const T
*>(offset1
) ==
1150 *reinterpret_cast<const T
*>(offset2
));
1153 static bool AreEqualDoubles(const double a
, const double b
) {
1154 return (fabs(a
- b
) < 0.00001);
1157 static bool AreOptionsEqual(OptionType type
, const char* this_offset
,
1158 const char* that_offset
) {
1160 case OptionType::kBoolean
:
1161 return IsOptionEqual
<bool>(this_offset
, that_offset
);
1162 case OptionType::kInt
:
1163 return IsOptionEqual
<int>(this_offset
, that_offset
);
1164 case OptionType::kUInt
:
1165 return IsOptionEqual
<unsigned int>(this_offset
, that_offset
);
1166 case OptionType::kInt32T
:
1167 return IsOptionEqual
<int32_t>(this_offset
, that_offset
);
1168 case OptionType::kInt64T
: {
1170 GetUnaligned(reinterpret_cast<const int64_t*>(this_offset
), &v1
);
1171 GetUnaligned(reinterpret_cast<const int64_t*>(that_offset
), &v2
);
1174 case OptionType::kUInt32T
:
1175 return IsOptionEqual
<uint32_t>(this_offset
, that_offset
);
1176 case OptionType::kUInt64T
: {
1178 GetUnaligned(reinterpret_cast<const uint64_t*>(this_offset
), &v1
);
1179 GetUnaligned(reinterpret_cast<const uint64_t*>(that_offset
), &v2
);
1182 case OptionType::kSizeT
: {
1184 GetUnaligned(reinterpret_cast<const size_t*>(this_offset
), &v1
);
1185 GetUnaligned(reinterpret_cast<const size_t*>(that_offset
), &v2
);
1188 case OptionType::kString
:
1189 return IsOptionEqual
<std::string
>(this_offset
, that_offset
);
1190 case OptionType::kDouble
:
1191 return AreEqualDoubles(*reinterpret_cast<const double*>(this_offset
),
1192 *reinterpret_cast<const double*>(that_offset
));
1193 case OptionType::kCompactionStyle
:
1194 return IsOptionEqual
<CompactionStyle
>(this_offset
, that_offset
);
1195 case OptionType::kCompactionStopStyle
:
1196 return IsOptionEqual
<CompactionStopStyle
>(this_offset
, that_offset
);
1197 case OptionType::kCompactionPri
:
1198 return IsOptionEqual
<CompactionPri
>(this_offset
, that_offset
);
1199 case OptionType::kCompressionType
:
1200 return IsOptionEqual
<CompressionType
>(this_offset
, that_offset
);
1201 case OptionType::kChecksumType
:
1202 return IsOptionEqual
<ChecksumType
>(this_offset
, that_offset
);
1203 case OptionType::kEncodingType
:
1204 return IsOptionEqual
<EncodingType
>(this_offset
, that_offset
);
1210 bool OptionTypeInfo::AreEqual(const ConfigOptions
& config_options
,
1211 const std::string
& opt_name
,
1212 const void* const this_ptr
,
1213 const void* const that_ptr
,
1214 std::string
* mismatch
) const {
1215 auto level
= GetSanityLevel();
1216 if (!config_options
.IsCheckEnabled(level
)) {
1217 return true; // If the sanity level is not being checked, skip it
1219 const auto this_addr
= reinterpret_cast<const char*>(this_ptr
) + offset_
;
1220 const auto that_addr
= reinterpret_cast<const char*>(that_ptr
) + offset_
;
1221 if (this_addr
== nullptr || that_addr
== nullptr) {
1222 if (this_addr
== that_addr
) {
1225 } else if (equals_func_
!= nullptr) {
1226 if (equals_func_(config_options
, opt_name
, this_addr
, that_addr
,
1230 } else if (AreOptionsEqual(type_
, this_addr
, that_addr
)) {
1232 } else if (IsConfigurable()) {
1233 const auto* this_config
= AsRawPointer
<Configurable
>(this_ptr
);
1234 const auto* that_config
= AsRawPointer
<Configurable
>(that_ptr
);
1235 if (this_config
== that_config
) {
1237 } else if (this_config
!= nullptr && that_config
!= nullptr) {
1238 std::string bad_name
;
1240 if (level
< config_options
.sanity_level
) {
1241 ConfigOptions copy
= config_options
;
1242 copy
.sanity_level
= level
;
1243 matches
= this_config
->AreEquivalent(copy
, that_config
, &bad_name
);
1246 this_config
->AreEquivalent(config_options
, that_config
, &bad_name
);
1249 *mismatch
= opt_name
+ "." + bad_name
;
1254 if (mismatch
->empty()) {
1255 *mismatch
= opt_name
;
1260 bool OptionTypeInfo::StructsAreEqual(
1261 const ConfigOptions
& config_options
, const std::string
& struct_name
,
1262 const std::unordered_map
<std::string
, OptionTypeInfo
>* struct_map
,
1263 const std::string
& opt_name
, const char* this_addr
, const char* that_addr
,
1264 std::string
* mismatch
) {
1266 bool matches
= true;
1268 if (EndsWith(opt_name
, struct_name
)) {
1269 // This option represents the entire struct
1270 for (const auto& iter
: *struct_map
) {
1271 const auto& opt_info
= iter
.second
;
1273 matches
= opt_info
.AreEqual(config_options
, iter
.first
, this_addr
,
1274 that_addr
, &result
);
1276 *mismatch
= struct_name
+ "." + result
;
1280 } else if (StartsWith(opt_name
, struct_name
+ ".")) {
1281 // This option represents a nested field in the struct (e.g, struct.field)
1282 std::string elem_name
;
1283 const auto opt_info
=
1284 Find(opt_name
.substr(struct_name
.size() + 1), *struct_map
, &elem_name
);
1286 if (opt_info
== nullptr) {
1287 *mismatch
= opt_name
;
1289 } else if (!opt_info
->AreEqual(config_options
, elem_name
, this_addr
,
1290 that_addr
, &result
)) {
1292 *mismatch
= struct_name
+ "." + result
;
1295 // This option represents a field in the struct (e.g. field)
1296 std::string elem_name
;
1297 const auto opt_info
= Find(opt_name
, *struct_map
, &elem_name
);
1299 if (opt_info
== nullptr) {
1300 *mismatch
= struct_name
+ "." + opt_name
;
1302 } else if (!opt_info
->AreEqual(config_options
, elem_name
, this_addr
,
1303 that_addr
, &result
)) {
1305 *mismatch
= struct_name
+ "." + result
;
1311 bool MatchesOptionsTypeFromMap(
1312 const ConfigOptions
& config_options
,
1313 const std::unordered_map
<std::string
, OptionTypeInfo
>& type_map
,
1314 const void* const this_ptr
, const void* const that_ptr
,
1315 std::string
* mismatch
) {
1316 for (auto& pair
: type_map
) {
1317 // We skip checking deprecated variables as they might
1318 // contain random values since they might not be initialized
1319 if (config_options
.IsCheckEnabled(pair
.second
.GetSanityLevel())) {
1320 if (!pair
.second
.AreEqual(config_options
, pair
.first
, this_ptr
, that_ptr
,
1322 !pair
.second
.AreEqualByName(config_options
, pair
.first
, this_ptr
,
1331 bool OptionTypeInfo::AreEqualByName(const ConfigOptions
& config_options
,
1332 const std::string
& opt_name
,
1333 const void* const this_ptr
,
1334 const void* const that_ptr
) const {
1336 std::string that_value
;
1337 if (Serialize(config_options
, opt_name
, that_ptr
, &that_value
).ok()) {
1338 return AreEqualByName(config_options
, opt_name
, this_ptr
, that_value
);
1344 bool OptionTypeInfo::AreEqualByName(const ConfigOptions
& config_options
,
1345 const std::string
& opt_name
,
1346 const void* const opt_ptr
,
1347 const std::string
& that_value
) const {
1348 std::string this_value
;
1351 } else if (!Serialize(config_options
, opt_name
, opt_ptr
, &this_value
).ok()) {
1353 } else if (IsEnabled(OptionVerificationType::kByNameAllowFromNull
)) {
1354 if (that_value
== kNullptrString
) {
1357 } else if (IsEnabled(OptionVerificationType::kByNameAllowNull
)) {
1358 if (that_value
== kNullptrString
) {
1362 return (this_value
== that_value
);
1365 const OptionTypeInfo
* OptionTypeInfo::Find(
1366 const std::string
& opt_name
,
1367 const std::unordered_map
<std::string
, OptionTypeInfo
>& opt_map
,
1368 std::string
* elem_name
) {
1369 const auto iter
= opt_map
.find(opt_name
); // Look up the value in the map
1370 if (iter
!= opt_map
.end()) { // Found the option in the map
1371 *elem_name
= opt_name
; // Return the name
1372 return &(iter
->second
); // Return the contents of the iterator
1374 auto idx
= opt_name
.find("."); // Look for a separator
1375 if (idx
> 0 && idx
!= std::string::npos
) { // We found a separator
1377 opt_map
.find(opt_name
.substr(0, idx
)); // Look for the short name
1378 if (siter
!= opt_map
.end()) { // We found the short name
1379 if (siter
->second
.IsStruct() || // If the object is a struct
1380 siter
->second
.IsConfigurable()) { // or a Configurable
1381 *elem_name
= opt_name
.substr(idx
+ 1); // Return the rest
1382 return &(siter
->second
); // Return the contents of the iterator
1389 #endif // !ROCKSDB_LITE
1391 } // namespace ROCKSDB_NAMESPACE