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"
11 #include <unordered_set>
14 #include "options/cf_options.h"
15 #include "options/db_options.h"
16 #include "rocksdb/cache.h"
17 #include "rocksdb/compaction_filter.h"
18 #include "rocksdb/convenience.h"
19 #include "rocksdb/filter_policy.h"
20 #include "rocksdb/flush_block_policy.h"
21 #include "rocksdb/memtablerep.h"
22 #include "rocksdb/merge_operator.h"
23 #include "rocksdb/options.h"
24 #include "rocksdb/rate_limiter.h"
25 #include "rocksdb/slice_transform.h"
26 #include "rocksdb/table.h"
27 #include "rocksdb/utilities/object_registry.h"
28 #include "rocksdb/utilities/options_type.h"
29 #include "util/string_util.h"
31 namespace ROCKSDB_NAMESPACE
{
32 ConfigOptions::ConfigOptions()
34 : registry(ObjectRegistry::NewInstance())
40 ConfigOptions::ConfigOptions(const DBOptions
& db_opts
) : env(db_opts
.env
) {
42 registry
= ObjectRegistry::NewInstance();
46 Status
ValidateOptions(const DBOptions
& db_opts
,
47 const ColumnFamilyOptions
& cf_opts
) {
50 auto db_cfg
= DBOptionsAsConfigurable(db_opts
);
51 auto cf_cfg
= CFOptionsAsConfigurable(cf_opts
);
52 s
= db_cfg
->ValidateOptions(db_opts
, cf_opts
);
53 if (s
.ok()) s
= cf_cfg
->ValidateOptions(db_opts
, cf_opts
);
55 s
= cf_opts
.table_factory
->ValidateOptions(db_opts
, cf_opts
);
60 DBOptions
BuildDBOptions(const ImmutableDBOptions
& immutable_db_options
,
61 const MutableDBOptions
& mutable_db_options
) {
64 options
.create_if_missing
= immutable_db_options
.create_if_missing
;
65 options
.create_missing_column_families
=
66 immutable_db_options
.create_missing_column_families
;
67 options
.error_if_exists
= immutable_db_options
.error_if_exists
;
68 options
.paranoid_checks
= immutable_db_options
.paranoid_checks
;
69 options
.flush_verify_memtable_count
=
70 immutable_db_options
.flush_verify_memtable_count
;
71 options
.track_and_verify_wals_in_manifest
=
72 immutable_db_options
.track_and_verify_wals_in_manifest
;
73 options
.verify_sst_unique_id_in_manifest
=
74 immutable_db_options
.verify_sst_unique_id_in_manifest
;
75 options
.env
= immutable_db_options
.env
;
76 options
.rate_limiter
= immutable_db_options
.rate_limiter
;
77 options
.sst_file_manager
= immutable_db_options
.sst_file_manager
;
78 options
.info_log
= immutable_db_options
.info_log
;
79 options
.info_log_level
= immutable_db_options
.info_log_level
;
80 options
.max_open_files
= mutable_db_options
.max_open_files
;
81 options
.max_file_opening_threads
=
82 immutable_db_options
.max_file_opening_threads
;
83 options
.max_total_wal_size
= mutable_db_options
.max_total_wal_size
;
84 options
.statistics
= immutable_db_options
.statistics
;
85 options
.use_fsync
= immutable_db_options
.use_fsync
;
86 options
.db_paths
= immutable_db_options
.db_paths
;
87 options
.db_log_dir
= immutable_db_options
.db_log_dir
;
88 options
.wal_dir
= immutable_db_options
.wal_dir
;
89 options
.delete_obsolete_files_period_micros
=
90 mutable_db_options
.delete_obsolete_files_period_micros
;
91 options
.max_background_jobs
= mutable_db_options
.max_background_jobs
;
92 options
.max_background_compactions
=
93 mutable_db_options
.max_background_compactions
;
94 options
.bytes_per_sync
= mutable_db_options
.bytes_per_sync
;
95 options
.wal_bytes_per_sync
= mutable_db_options
.wal_bytes_per_sync
;
96 options
.strict_bytes_per_sync
= mutable_db_options
.strict_bytes_per_sync
;
97 options
.max_subcompactions
= mutable_db_options
.max_subcompactions
;
98 options
.max_background_flushes
= mutable_db_options
.max_background_flushes
;
99 options
.max_log_file_size
= immutable_db_options
.max_log_file_size
;
100 options
.log_file_time_to_roll
= immutable_db_options
.log_file_time_to_roll
;
101 options
.keep_log_file_num
= immutable_db_options
.keep_log_file_num
;
102 options
.recycle_log_file_num
= immutable_db_options
.recycle_log_file_num
;
103 options
.max_manifest_file_size
= immutable_db_options
.max_manifest_file_size
;
104 options
.table_cache_numshardbits
=
105 immutable_db_options
.table_cache_numshardbits
;
106 options
.WAL_ttl_seconds
= immutable_db_options
.WAL_ttl_seconds
;
107 options
.WAL_size_limit_MB
= immutable_db_options
.WAL_size_limit_MB
;
108 options
.manifest_preallocation_size
=
109 immutable_db_options
.manifest_preallocation_size
;
110 options
.allow_mmap_reads
= immutable_db_options
.allow_mmap_reads
;
111 options
.allow_mmap_writes
= immutable_db_options
.allow_mmap_writes
;
112 options
.use_direct_reads
= immutable_db_options
.use_direct_reads
;
113 options
.use_direct_io_for_flush_and_compaction
=
114 immutable_db_options
.use_direct_io_for_flush_and_compaction
;
115 options
.allow_fallocate
= immutable_db_options
.allow_fallocate
;
116 options
.is_fd_close_on_exec
= immutable_db_options
.is_fd_close_on_exec
;
117 options
.stats_dump_period_sec
= mutable_db_options
.stats_dump_period_sec
;
118 options
.stats_persist_period_sec
=
119 mutable_db_options
.stats_persist_period_sec
;
120 options
.persist_stats_to_disk
= immutable_db_options
.persist_stats_to_disk
;
121 options
.stats_history_buffer_size
=
122 mutable_db_options
.stats_history_buffer_size
;
123 options
.advise_random_on_open
= immutable_db_options
.advise_random_on_open
;
124 options
.db_write_buffer_size
= immutable_db_options
.db_write_buffer_size
;
125 options
.write_buffer_manager
= immutable_db_options
.write_buffer_manager
;
126 options
.access_hint_on_compaction_start
=
127 immutable_db_options
.access_hint_on_compaction_start
;
128 options
.compaction_readahead_size
=
129 mutable_db_options
.compaction_readahead_size
;
130 options
.random_access_max_buffer_size
=
131 immutable_db_options
.random_access_max_buffer_size
;
132 options
.writable_file_max_buffer_size
=
133 mutable_db_options
.writable_file_max_buffer_size
;
134 options
.use_adaptive_mutex
= immutable_db_options
.use_adaptive_mutex
;
135 options
.listeners
= immutable_db_options
.listeners
;
136 options
.enable_thread_tracking
= immutable_db_options
.enable_thread_tracking
;
137 options
.delayed_write_rate
= mutable_db_options
.delayed_write_rate
;
138 options
.enable_pipelined_write
= immutable_db_options
.enable_pipelined_write
;
139 options
.unordered_write
= immutable_db_options
.unordered_write
;
140 options
.allow_concurrent_memtable_write
=
141 immutable_db_options
.allow_concurrent_memtable_write
;
142 options
.enable_write_thread_adaptive_yield
=
143 immutable_db_options
.enable_write_thread_adaptive_yield
;
144 options
.max_write_batch_group_size_bytes
=
145 immutable_db_options
.max_write_batch_group_size_bytes
;
146 options
.write_thread_max_yield_usec
=
147 immutable_db_options
.write_thread_max_yield_usec
;
148 options
.write_thread_slow_yield_usec
=
149 immutable_db_options
.write_thread_slow_yield_usec
;
150 options
.skip_stats_update_on_db_open
=
151 immutable_db_options
.skip_stats_update_on_db_open
;
152 options
.skip_checking_sst_file_sizes_on_db_open
=
153 immutable_db_options
.skip_checking_sst_file_sizes_on_db_open
;
154 options
.wal_recovery_mode
= immutable_db_options
.wal_recovery_mode
;
155 options
.allow_2pc
= immutable_db_options
.allow_2pc
;
156 options
.row_cache
= immutable_db_options
.row_cache
;
158 options
.wal_filter
= immutable_db_options
.wal_filter
;
159 #endif // ROCKSDB_LITE
160 options
.fail_if_options_file_error
=
161 immutable_db_options
.fail_if_options_file_error
;
162 options
.dump_malloc_stats
= immutable_db_options
.dump_malloc_stats
;
163 options
.avoid_flush_during_recovery
=
164 immutable_db_options
.avoid_flush_during_recovery
;
165 options
.avoid_flush_during_shutdown
=
166 mutable_db_options
.avoid_flush_during_shutdown
;
167 options
.allow_ingest_behind
= immutable_db_options
.allow_ingest_behind
;
168 options
.two_write_queues
= immutable_db_options
.two_write_queues
;
169 options
.manual_wal_flush
= immutable_db_options
.manual_wal_flush
;
170 options
.wal_compression
= immutable_db_options
.wal_compression
;
171 options
.atomic_flush
= immutable_db_options
.atomic_flush
;
172 options
.avoid_unnecessary_blocking_io
=
173 immutable_db_options
.avoid_unnecessary_blocking_io
;
174 options
.log_readahead_size
= immutable_db_options
.log_readahead_size
;
175 options
.file_checksum_gen_factory
=
176 immutable_db_options
.file_checksum_gen_factory
;
177 options
.best_efforts_recovery
= immutable_db_options
.best_efforts_recovery
;
178 options
.max_bgerror_resume_count
=
179 immutable_db_options
.max_bgerror_resume_count
;
180 options
.bgerror_resume_retry_interval
=
181 immutable_db_options
.bgerror_resume_retry_interval
;
182 options
.db_host_id
= immutable_db_options
.db_host_id
;
183 options
.allow_data_in_errors
= immutable_db_options
.allow_data_in_errors
;
184 options
.checksum_handoff_file_types
=
185 immutable_db_options
.checksum_handoff_file_types
;
186 options
.lowest_used_cache_tier
= immutable_db_options
.lowest_used_cache_tier
;
187 options
.enforce_single_del_contracts
=
188 immutable_db_options
.enforce_single_del_contracts
;
192 ColumnFamilyOptions
BuildColumnFamilyOptions(
193 const ColumnFamilyOptions
& options
,
194 const MutableCFOptions
& mutable_cf_options
) {
195 ColumnFamilyOptions
cf_opts(options
);
196 UpdateColumnFamilyOptions(mutable_cf_options
, &cf_opts
);
197 // TODO(yhchiang): find some way to handle the following derived options
202 void UpdateColumnFamilyOptions(const MutableCFOptions
& moptions
,
203 ColumnFamilyOptions
* cf_opts
) {
204 // Memtable related options
205 cf_opts
->write_buffer_size
= moptions
.write_buffer_size
;
206 cf_opts
->max_write_buffer_number
= moptions
.max_write_buffer_number
;
207 cf_opts
->arena_block_size
= moptions
.arena_block_size
;
208 cf_opts
->memtable_prefix_bloom_size_ratio
=
209 moptions
.memtable_prefix_bloom_size_ratio
;
210 cf_opts
->memtable_whole_key_filtering
= moptions
.memtable_whole_key_filtering
;
211 cf_opts
->memtable_huge_page_size
= moptions
.memtable_huge_page_size
;
212 cf_opts
->max_successive_merges
= moptions
.max_successive_merges
;
213 cf_opts
->inplace_update_num_locks
= moptions
.inplace_update_num_locks
;
214 cf_opts
->prefix_extractor
= moptions
.prefix_extractor
;
215 cf_opts
->experimental_mempurge_threshold
=
216 moptions
.experimental_mempurge_threshold
;
217 cf_opts
->memtable_protection_bytes_per_key
=
218 moptions
.memtable_protection_bytes_per_key
;
220 // Compaction related options
221 cf_opts
->disable_auto_compactions
= moptions
.disable_auto_compactions
;
222 cf_opts
->soft_pending_compaction_bytes_limit
=
223 moptions
.soft_pending_compaction_bytes_limit
;
224 cf_opts
->hard_pending_compaction_bytes_limit
=
225 moptions
.hard_pending_compaction_bytes_limit
;
226 cf_opts
->level0_file_num_compaction_trigger
=
227 moptions
.level0_file_num_compaction_trigger
;
228 cf_opts
->level0_slowdown_writes_trigger
=
229 moptions
.level0_slowdown_writes_trigger
;
230 cf_opts
->level0_stop_writes_trigger
= moptions
.level0_stop_writes_trigger
;
231 cf_opts
->max_compaction_bytes
= moptions
.max_compaction_bytes
;
232 cf_opts
->ignore_max_compaction_bytes_for_input
=
233 moptions
.ignore_max_compaction_bytes_for_input
;
234 cf_opts
->target_file_size_base
= moptions
.target_file_size_base
;
235 cf_opts
->target_file_size_multiplier
= moptions
.target_file_size_multiplier
;
236 cf_opts
->max_bytes_for_level_base
= moptions
.max_bytes_for_level_base
;
237 cf_opts
->max_bytes_for_level_multiplier
=
238 moptions
.max_bytes_for_level_multiplier
;
239 cf_opts
->ttl
= moptions
.ttl
;
240 cf_opts
->periodic_compaction_seconds
= moptions
.periodic_compaction_seconds
;
242 cf_opts
->max_bytes_for_level_multiplier_additional
.clear();
243 for (auto value
: moptions
.max_bytes_for_level_multiplier_additional
) {
244 cf_opts
->max_bytes_for_level_multiplier_additional
.emplace_back(value
);
247 cf_opts
->compaction_options_fifo
= moptions
.compaction_options_fifo
;
248 cf_opts
->compaction_options_universal
= moptions
.compaction_options_universal
;
250 // Blob file related options
251 cf_opts
->enable_blob_files
= moptions
.enable_blob_files
;
252 cf_opts
->min_blob_size
= moptions
.min_blob_size
;
253 cf_opts
->blob_file_size
= moptions
.blob_file_size
;
254 cf_opts
->blob_compression_type
= moptions
.blob_compression_type
;
255 cf_opts
->enable_blob_garbage_collection
=
256 moptions
.enable_blob_garbage_collection
;
257 cf_opts
->blob_garbage_collection_age_cutoff
=
258 moptions
.blob_garbage_collection_age_cutoff
;
259 cf_opts
->blob_garbage_collection_force_threshold
=
260 moptions
.blob_garbage_collection_force_threshold
;
261 cf_opts
->blob_compaction_readahead_size
=
262 moptions
.blob_compaction_readahead_size
;
263 cf_opts
->blob_file_starting_level
= moptions
.blob_file_starting_level
;
264 cf_opts
->prepopulate_blob_cache
= moptions
.prepopulate_blob_cache
;
267 cf_opts
->max_sequential_skip_in_iterations
=
268 moptions
.max_sequential_skip_in_iterations
;
269 cf_opts
->check_flush_compaction_key_order
=
270 moptions
.check_flush_compaction_key_order
;
271 cf_opts
->paranoid_file_checks
= moptions
.paranoid_file_checks
;
272 cf_opts
->report_bg_io_stats
= moptions
.report_bg_io_stats
;
273 cf_opts
->compression
= moptions
.compression
;
274 cf_opts
->compression_opts
= moptions
.compression_opts
;
275 cf_opts
->bottommost_compression
= moptions
.bottommost_compression
;
276 cf_opts
->bottommost_compression_opts
= moptions
.bottommost_compression_opts
;
277 cf_opts
->sample_for_compression
= moptions
.sample_for_compression
;
278 cf_opts
->compression_per_level
= moptions
.compression_per_level
;
279 cf_opts
->last_level_temperature
= moptions
.last_level_temperature
;
280 cf_opts
->bottommost_temperature
= moptions
.last_level_temperature
;
283 void UpdateColumnFamilyOptions(const ImmutableCFOptions
& ioptions
,
284 ColumnFamilyOptions
* cf_opts
) {
285 cf_opts
->compaction_style
= ioptions
.compaction_style
;
286 cf_opts
->compaction_pri
= ioptions
.compaction_pri
;
287 cf_opts
->comparator
= ioptions
.user_comparator
;
288 cf_opts
->merge_operator
= ioptions
.merge_operator
;
289 cf_opts
->compaction_filter
= ioptions
.compaction_filter
;
290 cf_opts
->compaction_filter_factory
= ioptions
.compaction_filter_factory
;
291 cf_opts
->min_write_buffer_number_to_merge
=
292 ioptions
.min_write_buffer_number_to_merge
;
293 cf_opts
->max_write_buffer_number_to_maintain
=
294 ioptions
.max_write_buffer_number_to_maintain
;
295 cf_opts
->max_write_buffer_size_to_maintain
=
296 ioptions
.max_write_buffer_size_to_maintain
;
297 cf_opts
->inplace_update_support
= ioptions
.inplace_update_support
;
298 cf_opts
->inplace_callback
= ioptions
.inplace_callback
;
299 cf_opts
->memtable_factory
= ioptions
.memtable_factory
;
300 cf_opts
->table_factory
= ioptions
.table_factory
;
301 cf_opts
->table_properties_collector_factories
=
302 ioptions
.table_properties_collector_factories
;
303 cf_opts
->bloom_locality
= ioptions
.bloom_locality
;
304 cf_opts
->level_compaction_dynamic_level_bytes
=
305 ioptions
.level_compaction_dynamic_level_bytes
;
306 cf_opts
->level_compaction_dynamic_file_size
=
307 ioptions
.level_compaction_dynamic_file_size
;
308 cf_opts
->num_levels
= ioptions
.num_levels
;
309 cf_opts
->optimize_filters_for_hits
= ioptions
.optimize_filters_for_hits
;
310 cf_opts
->force_consistency_checks
= ioptions
.force_consistency_checks
;
311 cf_opts
->memtable_insert_with_hint_prefix_extractor
=
312 ioptions
.memtable_insert_with_hint_prefix_extractor
;
313 cf_opts
->cf_paths
= ioptions
.cf_paths
;
314 cf_opts
->compaction_thread_limiter
= ioptions
.compaction_thread_limiter
;
315 cf_opts
->sst_partitioner_factory
= ioptions
.sst_partitioner_factory
;
316 cf_opts
->blob_cache
= ioptions
.blob_cache
;
317 cf_opts
->preclude_last_level_data_seconds
=
318 ioptions
.preclude_last_level_data_seconds
;
319 cf_opts
->preserve_internal_time_seconds
=
320 ioptions
.preserve_internal_time_seconds
;
322 // TODO(yhchiang): find some way to handle the following derived options
326 std::map
<CompactionStyle
, std::string
>
327 OptionsHelper::compaction_style_to_string
= {
328 {kCompactionStyleLevel
, "kCompactionStyleLevel"},
329 {kCompactionStyleUniversal
, "kCompactionStyleUniversal"},
330 {kCompactionStyleFIFO
, "kCompactionStyleFIFO"},
331 {kCompactionStyleNone
, "kCompactionStyleNone"}};
333 std::map
<CompactionPri
, std::string
> OptionsHelper::compaction_pri_to_string
= {
334 {kByCompensatedSize
, "kByCompensatedSize"},
335 {kOldestLargestSeqFirst
, "kOldestLargestSeqFirst"},
336 {kOldestSmallestSeqFirst
, "kOldestSmallestSeqFirst"},
337 {kMinOverlappingRatio
, "kMinOverlappingRatio"},
338 {kRoundRobin
, "kRoundRobin"}};
340 std::map
<CompactionStopStyle
, std::string
>
341 OptionsHelper::compaction_stop_style_to_string
= {
342 {kCompactionStopStyleSimilarSize
, "kCompactionStopStyleSimilarSize"},
343 {kCompactionStopStyleTotalSize
, "kCompactionStopStyleTotalSize"}};
345 std::map
<Temperature
, std::string
> OptionsHelper::temperature_to_string
= {
346 {Temperature::kUnknown
, "kUnknown"},
347 {Temperature::kHot
, "kHot"},
348 {Temperature::kWarm
, "kWarm"},
349 {Temperature::kCold
, "kCold"}};
351 std::unordered_map
<std::string
, ChecksumType
>
352 OptionsHelper::checksum_type_string_map
= {{"kNoChecksum", kNoChecksum
},
353 {"kCRC32c", kCRC32c
},
354 {"kxxHash", kxxHash
},
355 {"kxxHash64", kxxHash64
},
358 std::unordered_map
<std::string
, CompressionType
>
359 OptionsHelper::compression_type_string_map
= {
360 {"kNoCompression", kNoCompression
},
361 {"kSnappyCompression", kSnappyCompression
},
362 {"kZlibCompression", kZlibCompression
},
363 {"kBZip2Compression", kBZip2Compression
},
364 {"kLZ4Compression", kLZ4Compression
},
365 {"kLZ4HCCompression", kLZ4HCCompression
},
366 {"kXpressCompression", kXpressCompression
},
368 {"kZSTDNotFinalCompression", kZSTDNotFinalCompression
},
369 {"kDisableCompressionOption", kDisableCompressionOption
}};
371 std::vector
<CompressionType
> GetSupportedCompressions() {
372 // std::set internally to deduplicate potential name aliases
373 std::set
<CompressionType
> supported_compressions
;
374 for (const auto& comp_to_name
: OptionsHelper::compression_type_string_map
) {
375 CompressionType t
= comp_to_name
.second
;
376 if (t
!= kDisableCompressionOption
&& CompressionTypeSupported(t
)) {
377 supported_compressions
.insert(t
);
380 return std::vector
<CompressionType
>(supported_compressions
.begin(),
381 supported_compressions
.end());
384 std::vector
<CompressionType
> GetSupportedDictCompressions() {
385 std::set
<CompressionType
> dict_compression_types
;
386 for (const auto& comp_to_name
: OptionsHelper::compression_type_string_map
) {
387 CompressionType t
= comp_to_name
.second
;
388 if (t
!= kDisableCompressionOption
&& DictCompressionTypeSupported(t
)) {
389 dict_compression_types
.insert(t
);
392 return std::vector
<CompressionType
>(dict_compression_types
.begin(),
393 dict_compression_types
.end());
396 std::vector
<ChecksumType
> GetSupportedChecksums() {
397 std::set
<ChecksumType
> checksum_types
;
398 for (const auto& e
: OptionsHelper::checksum_type_string_map
) {
399 checksum_types
.insert(e
.second
);
401 return std::vector
<ChecksumType
>(checksum_types
.begin(),
402 checksum_types
.end());
406 static bool ParseOptionHelper(void* opt_address
, const OptionType
& opt_type
,
407 const std::string
& value
) {
409 case OptionType::kBoolean
:
410 *static_cast<bool*>(opt_address
) = ParseBoolean("", value
);
412 case OptionType::kInt
:
413 *static_cast<int*>(opt_address
) = ParseInt(value
);
415 case OptionType::kInt32T
:
416 *static_cast<int32_t*>(opt_address
) = ParseInt32(value
);
418 case OptionType::kInt64T
:
419 PutUnaligned(static_cast<int64_t*>(opt_address
), ParseInt64(value
));
421 case OptionType::kUInt
:
422 *static_cast<unsigned int*>(opt_address
) = ParseUint32(value
);
424 case OptionType::kUInt8T
:
425 *static_cast<uint8_t*>(opt_address
) = ParseUint8(value
);
427 case OptionType::kUInt32T
:
428 *static_cast<uint32_t*>(opt_address
) = ParseUint32(value
);
430 case OptionType::kUInt64T
:
431 PutUnaligned(static_cast<uint64_t*>(opt_address
), ParseUint64(value
));
433 case OptionType::kSizeT
:
434 PutUnaligned(static_cast<size_t*>(opt_address
), ParseSizeT(value
));
436 case OptionType::kString
:
437 *static_cast<std::string
*>(opt_address
) = value
;
439 case OptionType::kDouble
:
440 *static_cast<double*>(opt_address
) = ParseDouble(value
);
442 case OptionType::kCompactionStyle
:
443 return ParseEnum
<CompactionStyle
>(
444 compaction_style_string_map
, value
,
445 static_cast<CompactionStyle
*>(opt_address
));
446 case OptionType::kCompactionPri
:
447 return ParseEnum
<CompactionPri
>(compaction_pri_string_map
, value
,
448 static_cast<CompactionPri
*>(opt_address
));
449 case OptionType::kCompressionType
:
450 return ParseEnum
<CompressionType
>(
451 compression_type_string_map
, value
,
452 static_cast<CompressionType
*>(opt_address
));
453 case OptionType::kChecksumType
:
454 return ParseEnum
<ChecksumType
>(checksum_type_string_map
, value
,
455 static_cast<ChecksumType
*>(opt_address
));
456 case OptionType::kEncodingType
:
457 return ParseEnum
<EncodingType
>(encoding_type_string_map
, value
,
458 static_cast<EncodingType
*>(opt_address
));
459 case OptionType::kCompactionStopStyle
:
460 return ParseEnum
<CompactionStopStyle
>(
461 compaction_stop_style_string_map
, value
,
462 static_cast<CompactionStopStyle
*>(opt_address
));
463 case OptionType::kEncodedString
: {
464 std::string
* output_addr
= static_cast<std::string
*>(opt_address
);
465 (Slice(value
)).DecodeHex(output_addr
);
468 case OptionType::kTemperature
: {
469 return ParseEnum
<Temperature
>(temperature_string_map
, value
,
470 static_cast<Temperature
*>(opt_address
));
478 bool SerializeSingleOptionHelper(const void* opt_address
,
479 const OptionType opt_type
,
480 std::string
* value
) {
483 case OptionType::kBoolean
:
484 *value
= *(static_cast<const bool*>(opt_address
)) ? "true" : "false";
486 case OptionType::kInt
:
487 *value
= std::to_string(*(static_cast<const int*>(opt_address
)));
489 case OptionType::kInt32T
:
490 *value
= std::to_string(*(static_cast<const int32_t*>(opt_address
)));
492 case OptionType::kInt64T
:
495 GetUnaligned(static_cast<const int64_t*>(opt_address
), &v
);
496 *value
= std::to_string(v
);
499 case OptionType::kUInt
:
500 *value
= std::to_string(*(static_cast<const unsigned int*>(opt_address
)));
502 case OptionType::kUInt8T
:
503 *value
= std::to_string(*(static_cast<const uint8_t*>(opt_address
)));
505 case OptionType::kUInt32T
:
506 *value
= std::to_string(*(static_cast<const uint32_t*>(opt_address
)));
508 case OptionType::kUInt64T
:
511 GetUnaligned(static_cast<const uint64_t*>(opt_address
), &v
);
512 *value
= std::to_string(v
);
515 case OptionType::kSizeT
:
518 GetUnaligned(static_cast<const size_t*>(opt_address
), &v
);
519 *value
= std::to_string(v
);
522 case OptionType::kDouble
:
523 *value
= std::to_string(*(static_cast<const double*>(opt_address
)));
525 case OptionType::kString
:
527 EscapeOptionString(*(static_cast<const std::string
*>(opt_address
)));
529 case OptionType::kCompactionStyle
:
530 return SerializeEnum
<CompactionStyle
>(
531 compaction_style_string_map
,
532 *(static_cast<const CompactionStyle
*>(opt_address
)), value
);
533 case OptionType::kCompactionPri
:
534 return SerializeEnum
<CompactionPri
>(
535 compaction_pri_string_map
,
536 *(static_cast<const CompactionPri
*>(opt_address
)), value
);
537 case OptionType::kCompressionType
:
538 return SerializeEnum
<CompressionType
>(
539 compression_type_string_map
,
540 *(static_cast<const CompressionType
*>(opt_address
)), value
);
542 case OptionType::kChecksumType
:
543 return SerializeEnum
<ChecksumType
>(
544 checksum_type_string_map
,
545 *static_cast<const ChecksumType
*>(opt_address
), value
);
546 case OptionType::kEncodingType
:
547 return SerializeEnum
<EncodingType
>(
548 encoding_type_string_map
,
549 *static_cast<const EncodingType
*>(opt_address
), value
);
550 case OptionType::kCompactionStopStyle
:
551 return SerializeEnum
<CompactionStopStyle
>(
552 compaction_stop_style_string_map
,
553 *static_cast<const CompactionStopStyle
*>(opt_address
), value
);
554 case OptionType::kEncodedString
: {
555 const auto* ptr
= static_cast<const std::string
*>(opt_address
);
556 *value
= (Slice(*ptr
)).ToString(true);
559 case OptionType::kTemperature
: {
560 return SerializeEnum
<Temperature
>(
561 temperature_string_map
, *static_cast<const Temperature
*>(opt_address
),
570 template <typename T
>
571 Status
ConfigureFromMap(
572 const ConfigOptions
& config_options
,
573 const std::unordered_map
<std::string
, std::string
>& opt_map
,
574 const std::string
& option_name
, Configurable
* config
, T
* new_opts
) {
575 Status s
= config
->ConfigureFromMap(config_options
, opt_map
);
577 *new_opts
= *(config
->GetOptions
<T
>(option_name
));
583 Status
StringToMap(const std::string
& opts_str
,
584 std::unordered_map
<std::string
, std::string
>* opts_map
) {
587 // opts_str = "write_buffer_size=1024;max_write_buffer_number=2;"
588 // "nested_opt={opt1=1;opt2=2};max_bytes_for_level_base=100"
590 std::string opts
= trim(opts_str
);
591 // If the input string starts and ends with "{...}", strip off the brackets
592 while (opts
.size() > 2 && opts
[0] == '{' && opts
[opts
.size() - 1] == '}') {
593 opts
= trim(opts
.substr(1, opts
.size() - 2));
596 while (pos
< opts
.size()) {
597 size_t eq_pos
= opts
.find_first_of("={};", pos
);
598 if (eq_pos
== std::string::npos
) {
599 return Status::InvalidArgument("Mismatched key value pair, '=' expected");
600 } else if (opts
[eq_pos
] != '=') {
601 return Status::InvalidArgument("Unexpected char in key");
604 std::string key
= trim(opts
.substr(pos
, eq_pos
- pos
));
606 return Status::InvalidArgument("Empty key found");
610 Status s
= OptionTypeInfo::NextToken(opts
, ';', eq_pos
+ 1, &pos
, &value
);
614 (*opts_map
)[key
] = value
;
615 if (pos
== std::string::npos
) {
627 Status
GetStringFromDBOptions(std::string
* opt_string
,
628 const DBOptions
& db_options
,
629 const std::string
& delimiter
) {
630 ConfigOptions
config_options(db_options
);
631 config_options
.delimiter
= delimiter
;
632 return GetStringFromDBOptions(config_options
, db_options
, opt_string
);
635 Status
GetStringFromDBOptions(const ConfigOptions
& config_options
,
636 const DBOptions
& db_options
,
637 std::string
* opt_string
) {
640 auto config
= DBOptionsAsConfigurable(db_options
);
641 return config
->GetOptionString(config_options
, opt_string
);
645 Status
GetStringFromColumnFamilyOptions(std::string
* opt_string
,
646 const ColumnFamilyOptions
& cf_options
,
647 const std::string
& delimiter
) {
648 ConfigOptions config_options
;
649 config_options
.delimiter
= delimiter
;
650 return GetStringFromColumnFamilyOptions(config_options
, cf_options
,
654 Status
GetStringFromColumnFamilyOptions(const ConfigOptions
& config_options
,
655 const ColumnFamilyOptions
& cf_options
,
656 std::string
* opt_string
) {
657 const auto config
= CFOptionsAsConfigurable(cf_options
);
658 return config
->GetOptionString(config_options
, opt_string
);
661 Status
GetStringFromCompressionType(std::string
* compression_str
,
662 CompressionType compression_type
) {
663 bool ok
= SerializeEnum
<CompressionType
>(compression_type_string_map
,
664 compression_type
, compression_str
);
668 return Status::InvalidArgument("Invalid compression types");
672 Status
GetColumnFamilyOptionsFromMap(
673 const ColumnFamilyOptions
& base_options
,
674 const std::unordered_map
<std::string
, std::string
>& opts_map
,
675 ColumnFamilyOptions
* new_options
, bool input_strings_escaped
,
676 bool ignore_unknown_options
) {
677 ConfigOptions config_options
;
678 config_options
.ignore_unknown_options
= ignore_unknown_options
;
679 config_options
.input_strings_escaped
= input_strings_escaped
;
680 return GetColumnFamilyOptionsFromMap(config_options
, base_options
, opts_map
,
684 Status
GetColumnFamilyOptionsFromMap(
685 const ConfigOptions
& config_options
,
686 const ColumnFamilyOptions
& base_options
,
687 const std::unordered_map
<std::string
, std::string
>& opts_map
,
688 ColumnFamilyOptions
* new_options
) {
691 *new_options
= base_options
;
693 const auto config
= CFOptionsAsConfigurable(base_options
);
694 Status s
= ConfigureFromMap
<ColumnFamilyOptions
>(
695 config_options
, opts_map
, OptionsHelper::kCFOptionsName
, config
.get(),
697 // Translate any errors (NotFound, NotSupported, to InvalidArgument
698 if (s
.ok() || s
.IsInvalidArgument()) {
701 return Status::InvalidArgument(s
.getState());
705 Status
GetColumnFamilyOptionsFromString(
706 const ColumnFamilyOptions
& base_options
,
707 const std::string
& opts_str
,
708 ColumnFamilyOptions
* new_options
) {
709 ConfigOptions config_options
;
710 config_options
.input_strings_escaped
= false;
711 config_options
.ignore_unknown_options
= false;
712 return GetColumnFamilyOptionsFromString(config_options
, base_options
,
713 opts_str
, new_options
);
716 Status
GetColumnFamilyOptionsFromString(const ConfigOptions
& config_options
,
717 const ColumnFamilyOptions
& base_options
,
718 const std::string
& opts_str
,
719 ColumnFamilyOptions
* new_options
) {
720 std::unordered_map
<std::string
, std::string
> opts_map
;
721 Status s
= StringToMap(opts_str
, &opts_map
);
723 *new_options
= base_options
;
726 return GetColumnFamilyOptionsFromMap(config_options
, base_options
, opts_map
,
730 Status
GetDBOptionsFromMap(
731 const DBOptions
& base_options
,
732 const std::unordered_map
<std::string
, std::string
>& opts_map
,
733 DBOptions
* new_options
, bool input_strings_escaped
,
734 bool ignore_unknown_options
) {
735 ConfigOptions
config_options(base_options
);
736 config_options
.input_strings_escaped
= input_strings_escaped
;
737 config_options
.ignore_unknown_options
= ignore_unknown_options
;
738 return GetDBOptionsFromMap(config_options
, base_options
, opts_map
,
742 Status
GetDBOptionsFromMap(
743 const ConfigOptions
& config_options
, const DBOptions
& base_options
,
744 const std::unordered_map
<std::string
, std::string
>& opts_map
,
745 DBOptions
* new_options
) {
747 *new_options
= base_options
;
748 auto config
= DBOptionsAsConfigurable(base_options
);
749 Status s
= ConfigureFromMap
<DBOptions
>(config_options
, opts_map
,
750 OptionsHelper::kDBOptionsName
,
751 config
.get(), new_options
);
752 // Translate any errors (NotFound, NotSupported, to InvalidArgument
753 if (s
.ok() || s
.IsInvalidArgument()) {
756 return Status::InvalidArgument(s
.getState());
760 Status
GetDBOptionsFromString(const DBOptions
& base_options
,
761 const std::string
& opts_str
,
762 DBOptions
* new_options
) {
763 ConfigOptions
config_options(base_options
);
764 config_options
.input_strings_escaped
= false;
765 config_options
.ignore_unknown_options
= false;
767 return GetDBOptionsFromString(config_options
, base_options
, opts_str
,
771 Status
GetDBOptionsFromString(const ConfigOptions
& config_options
,
772 const DBOptions
& base_options
,
773 const std::string
& opts_str
,
774 DBOptions
* new_options
) {
775 std::unordered_map
<std::string
, std::string
> opts_map
;
776 Status s
= StringToMap(opts_str
, &opts_map
);
778 *new_options
= base_options
;
781 return GetDBOptionsFromMap(config_options
, base_options
, opts_map
,
785 Status
GetOptionsFromString(const Options
& base_options
,
786 const std::string
& opts_str
, Options
* new_options
) {
787 ConfigOptions
config_options(base_options
);
788 config_options
.input_strings_escaped
= false;
789 config_options
.ignore_unknown_options
= false;
791 return GetOptionsFromString(config_options
, base_options
, opts_str
,
795 Status
GetOptionsFromString(const ConfigOptions
& config_options
,
796 const Options
& base_options
,
797 const std::string
& opts_str
, Options
* new_options
) {
798 ColumnFamilyOptions new_cf_options
;
799 std::unordered_map
<std::string
, std::string
> unused_opts
;
800 std::unordered_map
<std::string
, std::string
> opts_map
;
803 *new_options
= base_options
;
804 Status s
= StringToMap(opts_str
, &opts_map
);
808 auto config
= DBOptionsAsConfigurable(base_options
);
809 s
= config
->ConfigureFromMap(config_options
, opts_map
, &unused_opts
);
812 DBOptions
* new_db_options
=
813 config
->GetOptions
<DBOptions
>(OptionsHelper::kDBOptionsName
);
814 if (!unused_opts
.empty()) {
815 s
= GetColumnFamilyOptionsFromMap(config_options
, base_options
,
816 unused_opts
, &new_cf_options
);
818 *new_options
= Options(*new_db_options
, new_cf_options
);
821 *new_options
= Options(*new_db_options
, base_options
);
824 // Translate any errors (NotFound, NotSupported, to InvalidArgument
825 if (s
.ok() || s
.IsInvalidArgument()) {
828 return Status::InvalidArgument(s
.getState());
832 std::unordered_map
<std::string
, EncodingType
>
833 OptionsHelper::encoding_type_string_map
= {{"kPlain", kPlain
},
834 {"kPrefix", kPrefix
}};
836 std::unordered_map
<std::string
, CompactionStyle
>
837 OptionsHelper::compaction_style_string_map
= {
838 {"kCompactionStyleLevel", kCompactionStyleLevel
},
839 {"kCompactionStyleUniversal", kCompactionStyleUniversal
},
840 {"kCompactionStyleFIFO", kCompactionStyleFIFO
},
841 {"kCompactionStyleNone", kCompactionStyleNone
}};
843 std::unordered_map
<std::string
, CompactionPri
>
844 OptionsHelper::compaction_pri_string_map
= {
845 {"kByCompensatedSize", kByCompensatedSize
},
846 {"kOldestLargestSeqFirst", kOldestLargestSeqFirst
},
847 {"kOldestSmallestSeqFirst", kOldestSmallestSeqFirst
},
848 {"kMinOverlappingRatio", kMinOverlappingRatio
},
849 {"kRoundRobin", kRoundRobin
}};
851 std::unordered_map
<std::string
, CompactionStopStyle
>
852 OptionsHelper::compaction_stop_style_string_map
= {
853 {"kCompactionStopStyleSimilarSize", kCompactionStopStyleSimilarSize
},
854 {"kCompactionStopStyleTotalSize", kCompactionStopStyleTotalSize
}};
856 std::unordered_map
<std::string
, Temperature
>
857 OptionsHelper::temperature_string_map
= {
858 {"kUnknown", Temperature::kUnknown
},
859 {"kHot", Temperature::kHot
},
860 {"kWarm", Temperature::kWarm
},
861 {"kCold", Temperature::kCold
}};
863 std::unordered_map
<std::string
, PrepopulateBlobCache
>
864 OptionsHelper::prepopulate_blob_cache_string_map
= {
865 {"kDisable", PrepopulateBlobCache::kDisable
},
866 {"kFlushOnly", PrepopulateBlobCache::kFlushOnly
}};
868 Status
OptionTypeInfo::NextToken(const std::string
& opts
, char delimiter
,
869 size_t pos
, size_t* end
, std::string
* token
) {
870 while (pos
< opts
.size() && isspace(opts
[pos
])) {
873 // Empty value at the end
874 if (pos
>= opts
.size()) {
876 *end
= std::string::npos
;
878 } else if (opts
[pos
] == '{') {
880 size_t brace_pos
= pos
+ 1;
881 while (brace_pos
< opts
.size()) {
882 if (opts
[brace_pos
] == '{') {
884 } else if (opts
[brace_pos
] == '}') {
892 // found the matching closing brace
894 *token
= trim(opts
.substr(pos
+ 1, brace_pos
- pos
- 1));
895 // skip all whitespace and move to the next delimiter
896 // brace_pos points to the next position after the matching '}'
898 while (pos
< opts
.size() && isspace(opts
[pos
])) {
901 if (pos
< opts
.size() && opts
[pos
] != delimiter
) {
902 return Status::InvalidArgument("Unexpected chars after nested options");
906 return Status::InvalidArgument(
907 "Mismatched curly braces for nested options");
910 *end
= opts
.find(delimiter
, pos
);
911 if (*end
== std::string::npos
) {
912 // It either ends with a trailing semi-colon or the last key-value pair
913 *token
= trim(opts
.substr(pos
));
915 *token
= trim(opts
.substr(pos
, *end
- pos
));
921 Status
OptionTypeInfo::Parse(const ConfigOptions
& config_options
,
922 const std::string
& opt_name
,
923 const std::string
& value
, void* opt_ptr
) const {
924 if (IsDeprecated()) {
928 const std::string
& opt_value
= config_options
.input_strings_escaped
929 ? UnescapeOptionString(value
)
932 if (opt_ptr
== nullptr) {
933 return Status::NotFound("Could not find option", opt_name
);
934 } else if (parse_func_
!= nullptr) {
935 ConfigOptions copy
= config_options
;
936 copy
.invoke_prepare_options
= false;
937 void* opt_addr
= GetOffset(opt_ptr
);
938 return parse_func_(copy
, opt_name
, opt_value
, opt_addr
);
939 } else if (ParseOptionHelper(GetOffset(opt_ptr
), type_
, opt_value
)) {
941 } else if (IsConfigurable()) {
942 // The option is <config>.<name>
943 Configurable
* config
= AsRawPointer
<Configurable
>(opt_ptr
);
944 if (opt_value
.empty()) {
946 } else if (config
== nullptr) {
947 return Status::NotFound("Could not find configurable: ", opt_name
);
949 ConfigOptions copy
= config_options
;
950 copy
.ignore_unknown_options
= false;
951 copy
.invoke_prepare_options
= false;
952 if (opt_value
.find("=") != std::string::npos
) {
953 return config
->ConfigureFromString(copy
, opt_value
);
955 return config
->ConfigureOption(copy
, opt_name
, opt_value
);
958 } else if (IsByName()) {
959 return Status::NotSupported("Deserializing the option " + opt_name
+
960 " is not supported");
962 return Status::InvalidArgument("Error parsing:", opt_name
);
964 } catch (std::exception
& e
) {
965 return Status::InvalidArgument("Error parsing " + opt_name
+ ":" +
966 std::string(e
.what()));
970 Status
OptionTypeInfo::ParseType(
971 const ConfigOptions
& config_options
, const std::string
& opts_str
,
972 const std::unordered_map
<std::string
, OptionTypeInfo
>& type_map
,
973 void* opt_addr
, std::unordered_map
<std::string
, std::string
>* unused
) {
974 std::unordered_map
<std::string
, std::string
> opts_map
;
975 Status status
= StringToMap(opts_str
, &opts_map
);
979 return ParseType(config_options
, opts_map
, type_map
, opt_addr
, unused
);
983 Status
OptionTypeInfo::ParseType(
984 const ConfigOptions
& config_options
,
985 const std::unordered_map
<std::string
, std::string
>& opts_map
,
986 const std::unordered_map
<std::string
, OptionTypeInfo
>& type_map
,
987 void* opt_addr
, std::unordered_map
<std::string
, std::string
>* unused
) {
988 for (const auto& opts_iter
: opts_map
) {
989 std::string opt_name
;
990 const auto* opt_info
= Find(opts_iter
.first
, type_map
, &opt_name
);
991 if (opt_info
!= nullptr) {
993 opt_info
->Parse(config_options
, opt_name
, opts_iter
.second
, opt_addr
);
997 } else if (unused
!= nullptr) {
998 (*unused
)[opts_iter
.first
] = opts_iter
.second
;
999 } else if (!config_options
.ignore_unknown_options
) {
1000 return Status::NotFound("Unrecognized option", opts_iter
.first
);
1003 return Status::OK();
1006 Status
OptionTypeInfo::ParseStruct(
1007 const ConfigOptions
& config_options
, const std::string
& struct_name
,
1008 const std::unordered_map
<std::string
, OptionTypeInfo
>* struct_map
,
1009 const std::string
& opt_name
, const std::string
& opt_value
, void* opt_addr
) {
1012 if (opt_name
== struct_name
|| EndsWith(opt_name
, "." + struct_name
)) {
1013 // This option represents the entire struct
1014 std::unordered_map
<std::string
, std::string
> unused
;
1016 ParseType(config_options
, opt_value
, *struct_map
, opt_addr
, &unused
);
1017 if (status
.ok() && !unused
.empty()) {
1018 status
= Status::InvalidArgument(
1019 "Unrecognized option", struct_name
+ "." + unused
.begin()->first
);
1021 } else if (StartsWith(opt_name
, struct_name
+ ".")) {
1022 // This option represents a nested field in the struct (e.g, struct.field)
1023 std::string elem_name
;
1024 const auto opt_info
=
1025 Find(opt_name
.substr(struct_name
.size() + 1), *struct_map
, &elem_name
);
1026 if (opt_info
!= nullptr) {
1027 status
= opt_info
->Parse(config_options
, elem_name
, opt_value
, opt_addr
);
1029 status
= Status::InvalidArgument("Unrecognized option", opt_name
);
1032 // This option represents a field in the struct (e.g. field)
1033 std::string elem_name
;
1034 const auto opt_info
= Find(opt_name
, *struct_map
, &elem_name
);
1035 if (opt_info
!= nullptr) {
1036 status
= opt_info
->Parse(config_options
, elem_name
, opt_value
, opt_addr
);
1038 status
= Status::InvalidArgument("Unrecognized option",
1039 struct_name
+ "." + opt_name
);
1045 Status
OptionTypeInfo::Serialize(const ConfigOptions
& config_options
,
1046 const std::string
& opt_name
,
1047 const void* const opt_ptr
,
1048 std::string
* opt_value
) const {
1049 // If the option is no longer used in rocksdb and marked as deprecated,
1050 // we skip it in the serialization.
1051 if (opt_ptr
== nullptr || IsDeprecated()) {
1052 return Status::OK();
1053 } else if (IsEnabled(OptionTypeFlags::kDontSerialize
)) {
1054 return Status::NotSupported("Cannot serialize option: ", opt_name
);
1055 } else if (serialize_func_
!= nullptr) {
1056 const void* opt_addr
= GetOffset(opt_ptr
);
1057 return serialize_func_(config_options
, opt_name
, opt_addr
, opt_value
);
1058 } else if (IsCustomizable()) {
1059 const Customizable
* custom
= AsRawPointer
<Customizable
>(opt_ptr
);
1061 if (custom
== nullptr) {
1062 // We do not have a custom object to serialize.
1063 // If the option is not mutable and we are doing only mutable options,
1064 // we return an empty string (which will cause the option not to be
1065 // printed). Otherwise, we return the "nullptr" string, which will result
1066 // in "option=nullptr" being printed.
1067 if (IsMutable() || !config_options
.mutable_options_only
) {
1068 *opt_value
= kNullptrString
;
1072 } else if (IsEnabled(OptionTypeFlags::kStringNameOnly
) &&
1073 !config_options
.IsDetailed()) {
1074 if (!config_options
.mutable_options_only
|| IsMutable()) {
1075 *opt_value
= custom
->GetId();
1078 ConfigOptions embedded
= config_options
;
1079 embedded
.delimiter
= ";";
1080 // If this option is mutable, everything inside it should be considered
1083 embedded
.mutable_options_only
= false;
1085 std::string value
= custom
->ToString(embedded
);
1086 if (!embedded
.mutable_options_only
||
1087 value
.find("=") != std::string::npos
) {
1093 return Status::OK();
1094 } else if (IsConfigurable()) {
1095 const Configurable
* config
= AsRawPointer
<Configurable
>(opt_ptr
);
1096 if (config
!= nullptr) {
1097 ConfigOptions embedded
= config_options
;
1098 embedded
.delimiter
= ";";
1099 *opt_value
= config
->ToString(embedded
);
1101 return Status::OK();
1102 } else if (config_options
.mutable_options_only
&& !IsMutable()) {
1103 return Status::OK();
1104 } else if (SerializeSingleOptionHelper(GetOffset(opt_ptr
), type_
,
1106 return Status::OK();
1108 return Status::InvalidArgument("Cannot serialize option: ", opt_name
);
1112 Status
OptionTypeInfo::SerializeType(
1113 const ConfigOptions
& config_options
,
1114 const std::unordered_map
<std::string
, OptionTypeInfo
>& type_map
,
1115 const void* opt_addr
, std::string
* result
) {
1117 for (const auto& iter
: type_map
) {
1119 const auto& opt_info
= iter
.second
;
1120 if (opt_info
.ShouldSerialize()) {
1122 opt_info
.Serialize(config_options
, iter
.first
, opt_addr
, &single
);
1126 result
->append(iter
.first
+ "=" + single
+ config_options
.delimiter
);
1133 Status
OptionTypeInfo::SerializeStruct(
1134 const ConfigOptions
& config_options
, const std::string
& struct_name
,
1135 const std::unordered_map
<std::string
, OptionTypeInfo
>* struct_map
,
1136 const std::string
& opt_name
, const void* opt_addr
, std::string
* value
) {
1139 if (EndsWith(opt_name
, struct_name
)) {
1140 // We are going to write the struct as "{ prop1=value1; prop2=value2;}.
1141 // Set the delimiter to ";" so that the everything will be on one line.
1142 ConfigOptions embedded
= config_options
;
1143 embedded
.delimiter
= ";";
1145 // This option represents the entire struct
1147 status
= SerializeType(embedded
, *struct_map
, opt_addr
, &result
);
1151 *value
= "{" + result
+ "}";
1153 } else if (StartsWith(opt_name
, struct_name
+ ".")) {
1154 // This option represents a nested field in the struct (e.g, struct.field)
1155 std::string elem_name
;
1156 const auto opt_info
=
1157 Find(opt_name
.substr(struct_name
.size() + 1), *struct_map
, &elem_name
);
1158 if (opt_info
!= nullptr) {
1159 status
= opt_info
->Serialize(config_options
, elem_name
, opt_addr
, value
);
1161 status
= Status::InvalidArgument("Unrecognized option", opt_name
);
1164 // This option represents a field in the struct (e.g. field)
1165 std::string elem_name
;
1166 const auto opt_info
= Find(opt_name
, *struct_map
, &elem_name
);
1167 if (opt_info
== nullptr) {
1168 status
= Status::InvalidArgument("Unrecognized option", opt_name
);
1169 } else if (opt_info
->ShouldSerialize()) {
1170 status
= opt_info
->Serialize(config_options
, opt_name
+ "." + elem_name
,
1177 template <typename T
>
1178 bool IsOptionEqual(const void* offset1
, const void* offset2
) {
1179 return (*static_cast<const T
*>(offset1
) == *static_cast<const T
*>(offset2
));
1182 static bool AreEqualDoubles(const double a
, const double b
) {
1183 return (fabs(a
- b
) < 0.00001);
1186 static bool AreOptionsEqual(OptionType type
, const void* this_offset
,
1187 const void* that_offset
) {
1189 case OptionType::kBoolean
:
1190 return IsOptionEqual
<bool>(this_offset
, that_offset
);
1191 case OptionType::kInt
:
1192 return IsOptionEqual
<int>(this_offset
, that_offset
);
1193 case OptionType::kUInt
:
1194 return IsOptionEqual
<unsigned int>(this_offset
, that_offset
);
1195 case OptionType::kInt32T
:
1196 return IsOptionEqual
<int32_t>(this_offset
, that_offset
);
1197 case OptionType::kInt64T
: {
1199 GetUnaligned(static_cast<const int64_t*>(this_offset
), &v1
);
1200 GetUnaligned(static_cast<const int64_t*>(that_offset
), &v2
);
1203 case OptionType::kUInt8T
:
1204 return IsOptionEqual
<uint8_t>(this_offset
, that_offset
);
1205 case OptionType::kUInt32T
:
1206 return IsOptionEqual
<uint32_t>(this_offset
, that_offset
);
1207 case OptionType::kUInt64T
: {
1209 GetUnaligned(static_cast<const uint64_t*>(this_offset
), &v1
);
1210 GetUnaligned(static_cast<const uint64_t*>(that_offset
), &v2
);
1213 case OptionType::kSizeT
: {
1215 GetUnaligned(static_cast<const size_t*>(this_offset
), &v1
);
1216 GetUnaligned(static_cast<const size_t*>(that_offset
), &v2
);
1219 case OptionType::kString
:
1220 return IsOptionEqual
<std::string
>(this_offset
, that_offset
);
1221 case OptionType::kDouble
:
1222 return AreEqualDoubles(*static_cast<const double*>(this_offset
),
1223 *static_cast<const double*>(that_offset
));
1224 case OptionType::kCompactionStyle
:
1225 return IsOptionEqual
<CompactionStyle
>(this_offset
, that_offset
);
1226 case OptionType::kCompactionStopStyle
:
1227 return IsOptionEqual
<CompactionStopStyle
>(this_offset
, that_offset
);
1228 case OptionType::kCompactionPri
:
1229 return IsOptionEqual
<CompactionPri
>(this_offset
, that_offset
);
1230 case OptionType::kCompressionType
:
1231 return IsOptionEqual
<CompressionType
>(this_offset
, that_offset
);
1232 case OptionType::kChecksumType
:
1233 return IsOptionEqual
<ChecksumType
>(this_offset
, that_offset
);
1234 case OptionType::kEncodingType
:
1235 return IsOptionEqual
<EncodingType
>(this_offset
, that_offset
);
1236 case OptionType::kEncodedString
:
1237 return IsOptionEqual
<std::string
>(this_offset
, that_offset
);
1238 case OptionType::kTemperature
:
1239 return IsOptionEqual
<Temperature
>(this_offset
, that_offset
);
1245 bool OptionTypeInfo::AreEqual(const ConfigOptions
& config_options
,
1246 const std::string
& opt_name
,
1247 const void* const this_ptr
,
1248 const void* const that_ptr
,
1249 std::string
* mismatch
) const {
1250 auto level
= GetSanityLevel();
1251 if (!config_options
.IsCheckEnabled(level
)) {
1252 return true; // If the sanity level is not being checked, skip it
1254 if (this_ptr
== nullptr || that_ptr
== nullptr) {
1255 if (this_ptr
== that_ptr
) {
1258 } else if (equals_func_
!= nullptr) {
1259 const void* this_addr
= GetOffset(this_ptr
);
1260 const void* that_addr
= GetOffset(that_ptr
);
1261 if (equals_func_(config_options
, opt_name
, this_addr
, that_addr
,
1266 const void* this_addr
= GetOffset(this_ptr
);
1267 const void* that_addr
= GetOffset(that_ptr
);
1268 if (AreOptionsEqual(type_
, this_addr
, that_addr
)) {
1270 } else if (IsConfigurable()) {
1271 const auto* this_config
= AsRawPointer
<Configurable
>(this_ptr
);
1272 const auto* that_config
= AsRawPointer
<Configurable
>(that_ptr
);
1273 if (this_config
== that_config
) {
1275 } else if (this_config
!= nullptr && that_config
!= nullptr) {
1276 std::string bad_name
;
1278 if (level
< config_options
.sanity_level
) {
1279 ConfigOptions copy
= config_options
;
1280 copy
.sanity_level
= level
;
1281 matches
= this_config
->AreEquivalent(copy
, that_config
, &bad_name
);
1283 matches
= this_config
->AreEquivalent(config_options
, that_config
,
1287 *mismatch
= opt_name
+ "." + bad_name
;
1293 if (mismatch
->empty()) {
1294 *mismatch
= opt_name
;
1299 bool OptionTypeInfo::TypesAreEqual(
1300 const ConfigOptions
& config_options
,
1301 const std::unordered_map
<std::string
, OptionTypeInfo
>& type_map
,
1302 const void* this_addr
, const void* that_addr
, std::string
* mismatch
) {
1303 for (const auto& iter
: type_map
) {
1304 const auto& opt_info
= iter
.second
;
1305 if (!opt_info
.AreEqual(config_options
, iter
.first
, this_addr
, that_addr
,
1313 bool OptionTypeInfo::StructsAreEqual(
1314 const ConfigOptions
& config_options
, const std::string
& struct_name
,
1315 const std::unordered_map
<std::string
, OptionTypeInfo
>* struct_map
,
1316 const std::string
& opt_name
, const void* this_addr
, const void* that_addr
,
1317 std::string
* mismatch
) {
1319 bool matches
= true;
1321 if (EndsWith(opt_name
, struct_name
)) {
1322 // This option represents the entire struct
1323 matches
= TypesAreEqual(config_options
, *struct_map
, this_addr
, that_addr
,
1326 *mismatch
= struct_name
+ "." + result
;
1329 } else if (StartsWith(opt_name
, struct_name
+ ".")) {
1330 // This option represents a nested field in the struct (e.g, struct.field)
1331 std::string elem_name
;
1332 const auto opt_info
=
1333 Find(opt_name
.substr(struct_name
.size() + 1), *struct_map
, &elem_name
);
1335 if (opt_info
== nullptr) {
1336 *mismatch
= opt_name
;
1338 } else if (!opt_info
->AreEqual(config_options
, elem_name
, this_addr
,
1339 that_addr
, &result
)) {
1341 *mismatch
= struct_name
+ "." + result
;
1344 // This option represents a field in the struct (e.g. field)
1345 std::string elem_name
;
1346 const auto opt_info
= Find(opt_name
, *struct_map
, &elem_name
);
1348 if (opt_info
== nullptr) {
1349 *mismatch
= struct_name
+ "." + opt_name
;
1351 } else if (!opt_info
->AreEqual(config_options
, elem_name
, this_addr
,
1352 that_addr
, &result
)) {
1354 *mismatch
= struct_name
+ "." + result
;
1360 bool MatchesOptionsTypeFromMap(
1361 const ConfigOptions
& config_options
,
1362 const std::unordered_map
<std::string
, OptionTypeInfo
>& type_map
,
1363 const void* const this_ptr
, const void* const that_ptr
,
1364 std::string
* mismatch
) {
1365 for (auto& pair
: type_map
) {
1366 // We skip checking deprecated variables as they might
1367 // contain random values since they might not be initialized
1368 if (config_options
.IsCheckEnabled(pair
.second
.GetSanityLevel())) {
1369 if (!pair
.second
.AreEqual(config_options
, pair
.first
, this_ptr
, that_ptr
,
1371 !pair
.second
.AreEqualByName(config_options
, pair
.first
, this_ptr
,
1380 bool OptionTypeInfo::AreEqualByName(const ConfigOptions
& config_options
,
1381 const std::string
& opt_name
,
1382 const void* const this_ptr
,
1383 const void* const that_ptr
) const {
1385 std::string that_value
;
1386 if (Serialize(config_options
, opt_name
, that_ptr
, &that_value
).ok()) {
1387 return AreEqualByName(config_options
, opt_name
, this_ptr
, that_value
);
1393 bool OptionTypeInfo::AreEqualByName(const ConfigOptions
& config_options
,
1394 const std::string
& opt_name
,
1395 const void* const opt_ptr
,
1396 const std::string
& that_value
) const {
1397 std::string this_value
;
1400 } else if (!Serialize(config_options
, opt_name
, opt_ptr
, &this_value
).ok()) {
1402 } else if (IsEnabled(OptionVerificationType::kByNameAllowFromNull
)) {
1403 if (that_value
== kNullptrString
) {
1406 } else if (IsEnabled(OptionVerificationType::kByNameAllowNull
)) {
1407 if (that_value
== kNullptrString
) {
1411 return (this_value
== that_value
);
1414 Status
OptionTypeInfo::Prepare(const ConfigOptions
& config_options
,
1415 const std::string
& name
, void* opt_ptr
) const {
1416 if (ShouldPrepare()) {
1417 if (prepare_func_
!= nullptr) {
1418 void* opt_addr
= GetOffset(opt_ptr
);
1419 return prepare_func_(config_options
, name
, opt_addr
);
1420 } else if (IsConfigurable()) {
1421 Configurable
* config
= AsRawPointer
<Configurable
>(opt_ptr
);
1422 if (config
!= nullptr) {
1423 return config
->PrepareOptions(config_options
);
1424 } else if (!CanBeNull()) {
1425 return Status::NotFound("Missing configurable object", name
);
1429 return Status::OK();
1432 Status
OptionTypeInfo::Validate(const DBOptions
& db_opts
,
1433 const ColumnFamilyOptions
& cf_opts
,
1434 const std::string
& name
,
1435 const void* opt_ptr
) const {
1436 if (ShouldValidate()) {
1437 if (validate_func_
!= nullptr) {
1438 const void* opt_addr
= GetOffset(opt_ptr
);
1439 return validate_func_(db_opts
, cf_opts
, name
, opt_addr
);
1440 } else if (IsConfigurable()) {
1441 const Configurable
* config
= AsRawPointer
<Configurable
>(opt_ptr
);
1442 if (config
!= nullptr) {
1443 return config
->ValidateOptions(db_opts
, cf_opts
);
1444 } else if (!CanBeNull()) {
1445 return Status::NotFound("Missing configurable object", name
);
1449 return Status::OK();
1452 const OptionTypeInfo
* OptionTypeInfo::Find(
1453 const std::string
& opt_name
,
1454 const std::unordered_map
<std::string
, OptionTypeInfo
>& opt_map
,
1455 std::string
* elem_name
) {
1456 const auto iter
= opt_map
.find(opt_name
); // Look up the value in the map
1457 if (iter
!= opt_map
.end()) { // Found the option in the map
1458 *elem_name
= opt_name
; // Return the name
1459 return &(iter
->second
); // Return the contents of the iterator
1461 auto idx
= opt_name
.find("."); // Look for a separator
1462 if (idx
> 0 && idx
!= std::string::npos
) { // We found a separator
1464 opt_map
.find(opt_name
.substr(0, idx
)); // Look for the short name
1465 if (siter
!= opt_map
.end()) { // We found the short name
1466 if (siter
->second
.IsStruct() || // If the object is a struct
1467 siter
->second
.IsConfigurable()) { // or a Configurable
1468 *elem_name
= opt_name
.substr(idx
+ 1); // Return the rest
1469 return &(siter
->second
); // Return the contents of the iterator
1476 #endif // !ROCKSDB_LITE
1478 } // namespace ROCKSDB_NAMESPACE