1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under the BSD-style license found in the
3 // LICENSE file in the root directory of this source tree. An additional grant
4 // of patent rights can be found in the PATENTS file in the same directory.
5 #include "options/options_helper.h"
10 #include <unordered_set>
12 #include "rocksdb/cache.h"
13 #include "rocksdb/compaction_filter.h"
14 #include "rocksdb/convenience.h"
15 #include "rocksdb/filter_policy.h"
16 #include "rocksdb/memtablerep.h"
17 #include "rocksdb/merge_operator.h"
18 #include "rocksdb/options.h"
19 #include "rocksdb/rate_limiter.h"
20 #include "rocksdb/slice_transform.h"
21 #include "rocksdb/table.h"
22 #include "table/block_based_table_factory.h"
23 #include "table/plain_table_factory.h"
24 #include "util/string_util.h"
28 DBOptions
BuildDBOptions(const ImmutableDBOptions
& immutable_db_options
,
29 const MutableDBOptions
& mutable_db_options
) {
32 options
.create_if_missing
= immutable_db_options
.create_if_missing
;
33 options
.create_missing_column_families
=
34 immutable_db_options
.create_missing_column_families
;
35 options
.error_if_exists
= immutable_db_options
.error_if_exists
;
36 options
.paranoid_checks
= immutable_db_options
.paranoid_checks
;
37 options
.env
= immutable_db_options
.env
;
38 options
.rate_limiter
= immutable_db_options
.rate_limiter
;
39 options
.sst_file_manager
= immutable_db_options
.sst_file_manager
;
40 options
.info_log
= immutable_db_options
.info_log
;
41 options
.info_log_level
= immutable_db_options
.info_log_level
;
42 options
.max_open_files
= immutable_db_options
.max_open_files
;
43 options
.max_file_opening_threads
=
44 immutable_db_options
.max_file_opening_threads
;
45 options
.max_total_wal_size
= mutable_db_options
.max_total_wal_size
;
46 options
.statistics
= immutable_db_options
.statistics
;
47 options
.use_fsync
= immutable_db_options
.use_fsync
;
48 options
.db_paths
= immutable_db_options
.db_paths
;
49 options
.db_log_dir
= immutable_db_options
.db_log_dir
;
50 options
.wal_dir
= immutable_db_options
.wal_dir
;
51 options
.delete_obsolete_files_period_micros
=
52 mutable_db_options
.delete_obsolete_files_period_micros
;
53 options
.base_background_compactions
=
54 mutable_db_options
.base_background_compactions
;
55 options
.max_background_compactions
=
56 mutable_db_options
.max_background_compactions
;
57 options
.max_subcompactions
= immutable_db_options
.max_subcompactions
;
58 options
.max_background_flushes
= immutable_db_options
.max_background_flushes
;
59 options
.max_log_file_size
= immutable_db_options
.max_log_file_size
;
60 options
.log_file_time_to_roll
= immutable_db_options
.log_file_time_to_roll
;
61 options
.keep_log_file_num
= immutable_db_options
.keep_log_file_num
;
62 options
.recycle_log_file_num
= immutable_db_options
.recycle_log_file_num
;
63 options
.max_manifest_file_size
= immutable_db_options
.max_manifest_file_size
;
64 options
.table_cache_numshardbits
=
65 immutable_db_options
.table_cache_numshardbits
;
66 options
.WAL_ttl_seconds
= immutable_db_options
.wal_ttl_seconds
;
67 options
.WAL_size_limit_MB
= immutable_db_options
.wal_size_limit_mb
;
68 options
.manifest_preallocation_size
=
69 immutable_db_options
.manifest_preallocation_size
;
70 options
.allow_mmap_reads
= immutable_db_options
.allow_mmap_reads
;
71 options
.allow_mmap_writes
= immutable_db_options
.allow_mmap_writes
;
72 options
.use_direct_reads
= immutable_db_options
.use_direct_reads
;
73 options
.use_direct_io_for_flush_and_compaction
=
74 immutable_db_options
.use_direct_io_for_flush_and_compaction
;
75 options
.allow_fallocate
= immutable_db_options
.allow_fallocate
;
76 options
.is_fd_close_on_exec
= immutable_db_options
.is_fd_close_on_exec
;
77 options
.stats_dump_period_sec
= mutable_db_options
.stats_dump_period_sec
;
78 options
.advise_random_on_open
= immutable_db_options
.advise_random_on_open
;
79 options
.db_write_buffer_size
= immutable_db_options
.db_write_buffer_size
;
80 options
.write_buffer_manager
= immutable_db_options
.write_buffer_manager
;
81 options
.access_hint_on_compaction_start
=
82 immutable_db_options
.access_hint_on_compaction_start
;
83 options
.new_table_reader_for_compaction_inputs
=
84 immutable_db_options
.new_table_reader_for_compaction_inputs
;
85 options
.compaction_readahead_size
=
86 immutable_db_options
.compaction_readahead_size
;
87 options
.random_access_max_buffer_size
=
88 immutable_db_options
.random_access_max_buffer_size
;
89 options
.writable_file_max_buffer_size
=
90 immutable_db_options
.writable_file_max_buffer_size
;
91 options
.use_adaptive_mutex
= immutable_db_options
.use_adaptive_mutex
;
92 options
.bytes_per_sync
= immutable_db_options
.bytes_per_sync
;
93 options
.wal_bytes_per_sync
= immutable_db_options
.wal_bytes_per_sync
;
94 options
.listeners
= immutable_db_options
.listeners
;
95 options
.enable_thread_tracking
= immutable_db_options
.enable_thread_tracking
;
96 options
.delayed_write_rate
= mutable_db_options
.delayed_write_rate
;
97 options
.allow_concurrent_memtable_write
=
98 immutable_db_options
.allow_concurrent_memtable_write
;
99 options
.enable_write_thread_adaptive_yield
=
100 immutable_db_options
.enable_write_thread_adaptive_yield
;
101 options
.write_thread_max_yield_usec
=
102 immutable_db_options
.write_thread_max_yield_usec
;
103 options
.write_thread_slow_yield_usec
=
104 immutable_db_options
.write_thread_slow_yield_usec
;
105 options
.skip_stats_update_on_db_open
=
106 immutable_db_options
.skip_stats_update_on_db_open
;
107 options
.wal_recovery_mode
= immutable_db_options
.wal_recovery_mode
;
108 options
.allow_2pc
= immutable_db_options
.allow_2pc
;
109 options
.row_cache
= immutable_db_options
.row_cache
;
111 options
.wal_filter
= immutable_db_options
.wal_filter
;
112 #endif // ROCKSDB_LITE
113 options
.fail_if_options_file_error
=
114 immutable_db_options
.fail_if_options_file_error
;
115 options
.dump_malloc_stats
= immutable_db_options
.dump_malloc_stats
;
116 options
.avoid_flush_during_recovery
=
117 immutable_db_options
.avoid_flush_during_recovery
;
118 options
.avoid_flush_during_shutdown
=
119 mutable_db_options
.avoid_flush_during_shutdown
;
124 ColumnFamilyOptions
BuildColumnFamilyOptions(
125 const ColumnFamilyOptions
& options
,
126 const MutableCFOptions
& mutable_cf_options
) {
127 ColumnFamilyOptions
cf_opts(options
);
129 // Memtable related options
130 cf_opts
.write_buffer_size
= mutable_cf_options
.write_buffer_size
;
131 cf_opts
.max_write_buffer_number
= mutable_cf_options
.max_write_buffer_number
;
132 cf_opts
.arena_block_size
= mutable_cf_options
.arena_block_size
;
133 cf_opts
.memtable_prefix_bloom_size_ratio
=
134 mutable_cf_options
.memtable_prefix_bloom_size_ratio
;
135 cf_opts
.memtable_huge_page_size
= mutable_cf_options
.memtable_huge_page_size
;
136 cf_opts
.max_successive_merges
= mutable_cf_options
.max_successive_merges
;
137 cf_opts
.inplace_update_num_locks
=
138 mutable_cf_options
.inplace_update_num_locks
;
140 // Compaction related options
141 cf_opts
.disable_auto_compactions
=
142 mutable_cf_options
.disable_auto_compactions
;
143 cf_opts
.level0_file_num_compaction_trigger
=
144 mutable_cf_options
.level0_file_num_compaction_trigger
;
145 cf_opts
.level0_slowdown_writes_trigger
=
146 mutable_cf_options
.level0_slowdown_writes_trigger
;
147 cf_opts
.level0_stop_writes_trigger
=
148 mutable_cf_options
.level0_stop_writes_trigger
;
149 cf_opts
.max_compaction_bytes
= mutable_cf_options
.max_compaction_bytes
;
150 cf_opts
.target_file_size_base
= mutable_cf_options
.target_file_size_base
;
151 cf_opts
.target_file_size_multiplier
=
152 mutable_cf_options
.target_file_size_multiplier
;
153 cf_opts
.max_bytes_for_level_base
=
154 mutable_cf_options
.max_bytes_for_level_base
;
155 cf_opts
.max_bytes_for_level_multiplier
=
156 mutable_cf_options
.max_bytes_for_level_multiplier
;
158 cf_opts
.max_bytes_for_level_multiplier_additional
.clear();
160 mutable_cf_options
.max_bytes_for_level_multiplier_additional
) {
161 cf_opts
.max_bytes_for_level_multiplier_additional
.emplace_back(value
);
165 cf_opts
.max_sequential_skip_in_iterations
=
166 mutable_cf_options
.max_sequential_skip_in_iterations
;
167 cf_opts
.paranoid_file_checks
= mutable_cf_options
.paranoid_file_checks
;
168 cf_opts
.report_bg_io_stats
= mutable_cf_options
.report_bg_io_stats
;
169 cf_opts
.compression
= mutable_cf_options
.compression
;
171 cf_opts
.table_factory
= options
.table_factory
;
172 // TODO(yhchiang): find some way to handle the following derived options
181 template <typename T
>
182 bool ParseEnum(const std::unordered_map
<std::string
, T
>& type_map
,
183 const std::string
& type
, T
* value
) {
184 auto iter
= type_map
.find(type
);
185 if (iter
!= type_map
.end()) {
186 *value
= iter
->second
;
192 template <typename T
>
193 bool SerializeEnum(const std::unordered_map
<std::string
, T
>& type_map
,
194 const T
& type
, std::string
* value
) {
195 for (const auto& pair
: type_map
) {
196 if (pair
.second
== type
) {
204 bool SerializeVectorCompressionType(const std::vector
<CompressionType
>& types
,
205 std::string
* value
) {
206 std::stringstream ss
;
208 for (size_t i
= 0; i
< types
.size(); ++i
) {
212 std::string string_type
;
213 result
= SerializeEnum
<CompressionType
>(compression_type_string_map
,
214 types
[i
], &string_type
);
215 if (result
== false) {
224 bool ParseVectorCompressionType(
225 const std::string
& value
,
226 std::vector
<CompressionType
>* compression_per_level
) {
227 compression_per_level
->clear();
229 while (start
< value
.size()) {
230 size_t end
= value
.find(':', start
);
232 CompressionType type
;
233 if (end
== std::string::npos
) {
234 is_ok
= ParseEnum
<CompressionType
>(compression_type_string_map
,
235 value
.substr(start
), &type
);
239 compression_per_level
->emplace_back(type
);
242 is_ok
= ParseEnum
<CompressionType
>(
243 compression_type_string_map
, value
.substr(start
, end
- start
), &type
);
247 compression_per_level
->emplace_back(type
);
254 bool ParseSliceTransformHelper(
255 const std::string
& kFixedPrefixName
, const std::string
& kCappedPrefixName
,
256 const std::string
& value
,
257 std::shared_ptr
<const SliceTransform
>* slice_transform
) {
259 auto& pe_value
= value
;
260 if (pe_value
.size() > kFixedPrefixName
.size() &&
261 pe_value
.compare(0, kFixedPrefixName
.size(), kFixedPrefixName
) == 0) {
262 int prefix_length
= ParseInt(trim(value
.substr(kFixedPrefixName
.size())));
263 slice_transform
->reset(NewFixedPrefixTransform(prefix_length
));
264 } else if (pe_value
.size() > kCappedPrefixName
.size() &&
265 pe_value
.compare(0, kCappedPrefixName
.size(), kCappedPrefixName
) ==
268 ParseInt(trim(pe_value
.substr(kCappedPrefixName
.size())));
269 slice_transform
->reset(NewCappedPrefixTransform(prefix_length
));
270 } else if (value
== kNullptrString
) {
271 slice_transform
->reset();
279 bool ParseSliceTransform(
280 const std::string
& value
,
281 std::shared_ptr
<const SliceTransform
>* slice_transform
) {
282 // While we normally don't convert the string representation of a
283 // pointer-typed option into its instance, here we do so for backward
284 // compatibility as we allow this action in SetOption().
286 // TODO(yhchiang): A possible better place for these serialization /
287 // deserialization is inside the class definition of pointer-typed
288 // option itself, but this requires a bigger change of public API.
290 ParseSliceTransformHelper("fixed:", "capped:", value
, slice_transform
);
294 result
= ParseSliceTransformHelper(
295 "rocksdb.FixedPrefix.", "rocksdb.CappedPrefix.", value
, slice_transform
);
299 // TODO(yhchiang): we can further support other default
300 // SliceTransforms here.
304 bool ParseOptionHelper(char* opt_address
, const OptionType
& opt_type
,
305 const std::string
& value
) {
307 case OptionType::kBoolean
:
308 *reinterpret_cast<bool*>(opt_address
) = ParseBoolean("", value
);
310 case OptionType::kInt
:
311 *reinterpret_cast<int*>(opt_address
) = ParseInt(value
);
313 case OptionType::kVectorInt
:
314 *reinterpret_cast<std::vector
<int>*>(opt_address
) = ParseVectorInt(value
);
316 case OptionType::kUInt
:
317 *reinterpret_cast<unsigned int*>(opt_address
) = ParseUint32(value
);
319 case OptionType::kUInt32T
:
320 *reinterpret_cast<uint32_t*>(opt_address
) = ParseUint32(value
);
322 case OptionType::kUInt64T
:
323 PutUnaligned(reinterpret_cast<uint64_t*>(opt_address
), ParseUint64(value
));
325 case OptionType::kSizeT
:
326 PutUnaligned(reinterpret_cast<size_t*>(opt_address
), ParseSizeT(value
));
328 case OptionType::kString
:
329 *reinterpret_cast<std::string
*>(opt_address
) = value
;
331 case OptionType::kDouble
:
332 *reinterpret_cast<double*>(opt_address
) = ParseDouble(value
);
334 case OptionType::kCompactionStyle
:
335 return ParseEnum
<CompactionStyle
>(
336 compaction_style_string_map
, value
,
337 reinterpret_cast<CompactionStyle
*>(opt_address
));
338 case OptionType::kCompactionPri
:
339 return ParseEnum
<CompactionPri
>(
340 compaction_pri_string_map
, value
,
341 reinterpret_cast<CompactionPri
*>(opt_address
));
342 case OptionType::kCompressionType
:
343 return ParseEnum
<CompressionType
>(
344 compression_type_string_map
, value
,
345 reinterpret_cast<CompressionType
*>(opt_address
));
346 case OptionType::kVectorCompressionType
:
347 return ParseVectorCompressionType(
348 value
, reinterpret_cast<std::vector
<CompressionType
>*>(opt_address
));
349 case OptionType::kSliceTransform
:
350 return ParseSliceTransform(
351 value
, reinterpret_cast<std::shared_ptr
<const SliceTransform
>*>(
353 case OptionType::kChecksumType
:
354 return ParseEnum
<ChecksumType
>(
355 checksum_type_string_map
, value
,
356 reinterpret_cast<ChecksumType
*>(opt_address
));
357 case OptionType::kBlockBasedTableIndexType
:
358 return ParseEnum
<BlockBasedTableOptions::IndexType
>(
359 block_base_table_index_type_string_map
, value
,
360 reinterpret_cast<BlockBasedTableOptions::IndexType
*>(opt_address
));
361 case OptionType::kEncodingType
:
362 return ParseEnum
<EncodingType
>(
363 encoding_type_string_map
, value
,
364 reinterpret_cast<EncodingType
*>(opt_address
));
365 case OptionType::kWALRecoveryMode
:
366 return ParseEnum
<WALRecoveryMode
>(
367 wal_recovery_mode_string_map
, value
,
368 reinterpret_cast<WALRecoveryMode
*>(opt_address
));
369 case OptionType::kAccessHint
:
370 return ParseEnum
<DBOptions::AccessHint
>(
371 access_hint_string_map
, value
,
372 reinterpret_cast<DBOptions::AccessHint
*>(opt_address
));
373 case OptionType::kInfoLogLevel
:
374 return ParseEnum
<InfoLogLevel
>(
375 info_log_level_string_map
, value
,
376 reinterpret_cast<InfoLogLevel
*>(opt_address
));
383 } // anonymouse namespace
385 bool SerializeSingleOptionHelper(const char* opt_address
,
386 const OptionType opt_type
,
387 std::string
* value
) {
391 case OptionType::kBoolean
:
392 *value
= *(reinterpret_cast<const bool*>(opt_address
)) ? "true" : "false";
394 case OptionType::kInt
:
395 *value
= ToString(*(reinterpret_cast<const int*>(opt_address
)));
397 case OptionType::kVectorInt
:
398 return SerializeIntVector(
399 *reinterpret_cast<const std::vector
<int>*>(opt_address
), value
);
400 case OptionType::kUInt
:
401 *value
= ToString(*(reinterpret_cast<const unsigned int*>(opt_address
)));
403 case OptionType::kUInt32T
:
404 *value
= ToString(*(reinterpret_cast<const uint32_t*>(opt_address
)));
406 case OptionType::kUInt64T
:
409 GetUnaligned(reinterpret_cast<const uint64_t*>(opt_address
), &v
);
410 *value
= ToString(v
);
413 case OptionType::kSizeT
:
416 GetUnaligned(reinterpret_cast<const size_t*>(opt_address
), &v
);
417 *value
= ToString(v
);
420 case OptionType::kDouble
:
421 *value
= ToString(*(reinterpret_cast<const double*>(opt_address
)));
423 case OptionType::kString
:
424 *value
= EscapeOptionString(
425 *(reinterpret_cast<const std::string
*>(opt_address
)));
427 case OptionType::kCompactionStyle
:
428 return SerializeEnum
<CompactionStyle
>(
429 compaction_style_string_map
,
430 *(reinterpret_cast<const CompactionStyle
*>(opt_address
)), value
);
431 case OptionType::kCompactionPri
:
432 return SerializeEnum
<CompactionPri
>(
433 compaction_pri_string_map
,
434 *(reinterpret_cast<const CompactionPri
*>(opt_address
)), value
);
435 case OptionType::kCompressionType
:
436 return SerializeEnum
<CompressionType
>(
437 compression_type_string_map
,
438 *(reinterpret_cast<const CompressionType
*>(opt_address
)), value
);
439 case OptionType::kVectorCompressionType
:
440 return SerializeVectorCompressionType(
441 *(reinterpret_cast<const std::vector
<CompressionType
>*>(opt_address
)),
444 case OptionType::kSliceTransform
: {
445 const auto* slice_transform_ptr
=
446 reinterpret_cast<const std::shared_ptr
<const SliceTransform
>*>(
448 *value
= slice_transform_ptr
->get() ? slice_transform_ptr
->get()->Name()
452 case OptionType::kTableFactory
: {
453 const auto* table_factory_ptr
=
454 reinterpret_cast<const std::shared_ptr
<const TableFactory
>*>(
456 *value
= table_factory_ptr
->get() ? table_factory_ptr
->get()->Name()
460 case OptionType::kComparator
: {
461 // it's a const pointer of const Comparator*
462 const auto* ptr
= reinterpret_cast<const Comparator
* const*>(opt_address
);
463 // Since the user-specified comparator will be wrapped by
464 // InternalKeyComparator, we should persist the user-specified one
465 // instead of InternalKeyComparator.
466 const auto* internal_comparator
=
467 dynamic_cast<const InternalKeyComparator
*>(*ptr
);
468 if (internal_comparator
!= nullptr) {
469 *value
= internal_comparator
->user_comparator()->Name();
471 *value
= *ptr
? (*ptr
)->Name() : kNullptrString
;
475 case OptionType::kCompactionFilter
: {
476 // it's a const pointer of const CompactionFilter*
478 reinterpret_cast<const CompactionFilter
* const*>(opt_address
);
479 *value
= *ptr
? (*ptr
)->Name() : kNullptrString
;
482 case OptionType::kCompactionFilterFactory
: {
484 reinterpret_cast<const std::shared_ptr
<CompactionFilterFactory
>*>(
486 *value
= ptr
->get() ? ptr
->get()->Name() : kNullptrString
;
489 case OptionType::kMemTableRepFactory
: {
491 reinterpret_cast<const std::shared_ptr
<MemTableRepFactory
>*>(
493 *value
= ptr
->get() ? ptr
->get()->Name() : kNullptrString
;
496 case OptionType::kMergeOperator
: {
498 reinterpret_cast<const std::shared_ptr
<MergeOperator
>*>(opt_address
);
499 *value
= ptr
->get() ? ptr
->get()->Name() : kNullptrString
;
502 case OptionType::kFilterPolicy
: {
504 reinterpret_cast<const std::shared_ptr
<FilterPolicy
>*>(opt_address
);
505 *value
= ptr
->get() ? ptr
->get()->Name() : kNullptrString
;
508 case OptionType::kChecksumType
:
509 return SerializeEnum
<ChecksumType
>(
510 checksum_type_string_map
,
511 *reinterpret_cast<const ChecksumType
*>(opt_address
), value
);
512 case OptionType::kBlockBasedTableIndexType
:
513 return SerializeEnum
<BlockBasedTableOptions::IndexType
>(
514 block_base_table_index_type_string_map
,
515 *reinterpret_cast<const BlockBasedTableOptions::IndexType
*>(
518 case OptionType::kFlushBlockPolicyFactory
: {
520 reinterpret_cast<const std::shared_ptr
<FlushBlockPolicyFactory
>*>(
522 *value
= ptr
->get() ? ptr
->get()->Name() : kNullptrString
;
525 case OptionType::kEncodingType
:
526 return SerializeEnum
<EncodingType
>(
527 encoding_type_string_map
,
528 *reinterpret_cast<const EncodingType
*>(opt_address
), value
);
529 case OptionType::kWALRecoveryMode
:
530 return SerializeEnum
<WALRecoveryMode
>(
531 wal_recovery_mode_string_map
,
532 *reinterpret_cast<const WALRecoveryMode
*>(opt_address
), value
);
533 case OptionType::kAccessHint
:
534 return SerializeEnum
<DBOptions::AccessHint
>(
535 access_hint_string_map
,
536 *reinterpret_cast<const DBOptions::AccessHint
*>(opt_address
), value
);
537 case OptionType::kInfoLogLevel
:
538 return SerializeEnum
<InfoLogLevel
>(
539 info_log_level_string_map
,
540 *reinterpret_cast<const InfoLogLevel
*>(opt_address
), value
);
547 Status
GetMutableOptionsFromStrings(
548 const MutableCFOptions
& base_options
,
549 const std::unordered_map
<std::string
, std::string
>& options_map
,
550 MutableCFOptions
* new_options
) {
552 *new_options
= base_options
;
553 for (const auto& o
: options_map
) {
555 auto iter
= cf_options_type_info
.find(o
.first
);
556 if (iter
== cf_options_type_info
.end()) {
557 return Status::InvalidArgument("Unrecognized option: " + o
.first
);
559 const auto& opt_info
= iter
->second
;
560 if (!opt_info
.is_mutable
) {
561 return Status::InvalidArgument("Option not changeable: " + o
.first
);
563 bool is_ok
= ParseOptionHelper(
564 reinterpret_cast<char*>(new_options
) + opt_info
.mutable_offset
,
565 opt_info
.type
, o
.second
);
567 return Status::InvalidArgument("Error parsing " + o
.first
);
569 } catch (std::exception
& e
) {
570 return Status::InvalidArgument("Error parsing " + o
.first
+ ":" +
571 std::string(e
.what()));
577 Status
GetMutableDBOptionsFromStrings(
578 const MutableDBOptions
& base_options
,
579 const std::unordered_map
<std::string
, std::string
>& options_map
,
580 MutableDBOptions
* new_options
) {
582 *new_options
= base_options
;
583 for (const auto& o
: options_map
) {
585 auto iter
= db_options_type_info
.find(o
.first
);
586 if (iter
== db_options_type_info
.end()) {
587 return Status::InvalidArgument("Unrecognized option: " + o
.first
);
589 const auto& opt_info
= iter
->second
;
590 if (!opt_info
.is_mutable
) {
591 return Status::InvalidArgument("Option not changeable: " + o
.first
);
593 bool is_ok
= ParseOptionHelper(
594 reinterpret_cast<char*>(new_options
) + opt_info
.mutable_offset
,
595 opt_info
.type
, o
.second
);
597 return Status::InvalidArgument("Error parsing " + o
.first
);
599 } catch (std::exception
& e
) {
600 return Status::InvalidArgument("Error parsing " + o
.first
+ ":" +
601 std::string(e
.what()));
607 Status
StringToMap(const std::string
& opts_str
,
608 std::unordered_map
<std::string
, std::string
>* opts_map
) {
611 // opts_str = "write_buffer_size=1024;max_write_buffer_number=2;"
612 // "nested_opt={opt1=1;opt2=2};max_bytes_for_level_base=100"
614 std::string opts
= trim(opts_str
);
615 while (pos
< opts
.size()) {
616 size_t eq_pos
= opts
.find('=', pos
);
617 if (eq_pos
== std::string::npos
) {
618 return Status::InvalidArgument("Mismatched key value pair, '=' expected");
620 std::string key
= trim(opts
.substr(pos
, eq_pos
- pos
));
622 return Status::InvalidArgument("Empty key found");
625 // skip space after '=' and look for '{' for possible nested options
627 while (pos
< opts
.size() && isspace(opts
[pos
])) {
630 // Empty value at the end
631 if (pos
>= opts
.size()) {
632 (*opts_map
)[key
] = "";
635 if (opts
[pos
] == '{') {
637 size_t brace_pos
= pos
+ 1;
638 while (brace_pos
< opts
.size()) {
639 if (opts
[brace_pos
] == '{') {
641 } else if (opts
[brace_pos
] == '}') {
649 // found the matching closing brace
651 (*opts_map
)[key
] = trim(opts
.substr(pos
+ 1, brace_pos
- pos
- 1));
652 // skip all whitespace and move to the next ';'
653 // brace_pos points to the next position after the matching '}'
655 while (pos
< opts
.size() && isspace(opts
[pos
])) {
658 if (pos
< opts
.size() && opts
[pos
] != ';') {
659 return Status::InvalidArgument(
660 "Unexpected chars after nested options");
664 return Status::InvalidArgument(
665 "Mismatched curly braces for nested options");
668 size_t sc_pos
= opts
.find(';', pos
);
669 if (sc_pos
== std::string::npos
) {
670 (*opts_map
)[key
] = trim(opts
.substr(pos
));
671 // It either ends with a trailing semi-colon or the last key-value pair
674 (*opts_map
)[key
] = trim(opts
.substr(pos
, sc_pos
- pos
));
683 Status
ParseColumnFamilyOption(const std::string
& name
,
684 const std::string
& org_value
,
685 ColumnFamilyOptions
* new_options
,
686 bool input_strings_escaped
= false) {
687 const std::string
& value
=
688 input_strings_escaped
? UnescapeOptionString(org_value
) : org_value
;
690 if (name
== "block_based_table_factory") {
692 BlockBasedTableOptions table_opt
, base_table_options
;
693 auto block_based_table_factory
= dynamic_cast<BlockBasedTableFactory
*>(
694 new_options
->table_factory
.get());
695 if (block_based_table_factory
!= nullptr) {
696 base_table_options
= block_based_table_factory
->table_options();
698 Status table_opt_s
= GetBlockBasedTableOptionsFromString(
699 base_table_options
, value
, &table_opt
);
700 if (!table_opt_s
.ok()) {
701 return Status::InvalidArgument(
702 "unable to parse the specified CF option " + name
);
704 new_options
->table_factory
.reset(NewBlockBasedTableFactory(table_opt
));
705 } else if (name
== "plain_table_factory") {
707 PlainTableOptions table_opt
, base_table_options
;
708 auto plain_table_factory
= dynamic_cast<PlainTableFactory
*>(
709 new_options
->table_factory
.get());
710 if (plain_table_factory
!= nullptr) {
711 base_table_options
= plain_table_factory
->table_options();
713 Status table_opt_s
= GetPlainTableOptionsFromString(
714 base_table_options
, value
, &table_opt
);
715 if (!table_opt_s
.ok()) {
716 return Status::InvalidArgument(
717 "unable to parse the specified CF option " + name
);
719 new_options
->table_factory
.reset(NewPlainTableFactory(table_opt
));
720 } else if (name
== "memtable") {
721 std::unique_ptr
<MemTableRepFactory
> new_mem_factory
;
722 Status mem_factory_s
=
723 GetMemTableRepFactoryFromString(value
, &new_mem_factory
);
724 if (!mem_factory_s
.ok()) {
725 return Status::InvalidArgument(
726 "unable to parse the specified CF option " + name
);
728 new_options
->memtable_factory
.reset(new_mem_factory
.release());
729 } else if (name
== "compression_opts") {
731 size_t end
= value
.find(':');
732 if (end
== std::string::npos
) {
733 return Status::InvalidArgument(
734 "unable to parse the specified CF option " + name
);
736 new_options
->compression_opts
.window_bits
=
737 ParseInt(value
.substr(start
, end
- start
));
739 end
= value
.find(':', start
);
740 if (end
== std::string::npos
) {
741 return Status::InvalidArgument(
742 "unable to parse the specified CF option " + name
);
744 new_options
->compression_opts
.level
=
745 ParseInt(value
.substr(start
, end
- start
));
747 if (start
>= value
.size()) {
748 return Status::InvalidArgument(
749 "unable to parse the specified CF option " + name
);
751 end
= value
.find(':', start
);
752 new_options
->compression_opts
.strategy
=
753 ParseInt(value
.substr(start
, value
.size() - start
));
754 // max_dict_bytes is optional for backwards compatibility
755 if (end
!= std::string::npos
) {
757 if (start
>= value
.size()) {
758 return Status::InvalidArgument(
759 "unable to parse the specified CF option " + name
);
761 new_options
->compression_opts
.max_dict_bytes
=
762 ParseInt(value
.substr(start
, value
.size() - start
));
764 } else if (name
== "compaction_options_fifo") {
765 new_options
->compaction_options_fifo
.max_table_files_size
=
768 auto iter
= cf_options_type_info
.find(name
);
769 if (iter
== cf_options_type_info
.end()) {
770 return Status::InvalidArgument(
771 "Unable to parse the specified CF option " + name
);
773 const auto& opt_info
= iter
->second
;
774 if (opt_info
.verification
!= OptionVerificationType::kDeprecated
&&
776 reinterpret_cast<char*>(new_options
) + opt_info
.offset
,
777 opt_info
.type
, value
)) {
780 switch (opt_info
.verification
) {
781 case OptionVerificationType::kByName
:
782 case OptionVerificationType::kByNameAllowNull
:
783 return Status::NotSupported(
784 "Deserializing the specified CF option " + name
+
785 " is not supported");
786 case OptionVerificationType::kDeprecated
:
789 return Status::InvalidArgument(
790 "Unable to parse the specified CF option " + name
);
793 } catch (const std::exception
&) {
794 return Status::InvalidArgument(
795 "unable to parse the specified option " + name
);
800 bool SerializeSingleDBOption(std::string
* opt_string
,
801 const DBOptions
& db_options
,
802 const std::string
& name
,
803 const std::string
& delimiter
) {
804 auto iter
= db_options_type_info
.find(name
);
805 if (iter
== db_options_type_info
.end()) {
808 auto& opt_info
= iter
->second
;
809 const char* opt_address
=
810 reinterpret_cast<const char*>(&db_options
) + opt_info
.offset
;
812 bool result
= SerializeSingleOptionHelper(opt_address
, opt_info
.type
, &value
);
814 *opt_string
= name
+ "=" + value
+ delimiter
;
819 Status
GetStringFromDBOptions(std::string
* opt_string
,
820 const DBOptions
& db_options
,
821 const std::string
& delimiter
) {
824 for (auto iter
= db_options_type_info
.begin();
825 iter
!= db_options_type_info
.end(); ++iter
) {
826 if (iter
->second
.verification
== OptionVerificationType::kDeprecated
) {
827 // If the option is no longer used in rocksdb and marked as deprecated,
828 // we skip it in the serialization.
831 std::string single_output
;
832 bool result
= SerializeSingleDBOption(&single_output
, db_options
,
833 iter
->first
, delimiter
);
836 opt_string
->append(single_output
);
842 bool SerializeSingleColumnFamilyOption(std::string
* opt_string
,
843 const ColumnFamilyOptions
& cf_options
,
844 const std::string
& name
,
845 const std::string
& delimiter
) {
846 auto iter
= cf_options_type_info
.find(name
);
847 if (iter
== cf_options_type_info
.end()) {
850 auto& opt_info
= iter
->second
;
851 const char* opt_address
=
852 reinterpret_cast<const char*>(&cf_options
) + opt_info
.offset
;
854 bool result
= SerializeSingleOptionHelper(opt_address
, opt_info
.type
, &value
);
856 *opt_string
= name
+ "=" + value
+ delimiter
;
861 Status
GetStringFromColumnFamilyOptions(std::string
* opt_string
,
862 const ColumnFamilyOptions
& cf_options
,
863 const std::string
& delimiter
) {
866 for (auto iter
= cf_options_type_info
.begin();
867 iter
!= cf_options_type_info
.end(); ++iter
) {
868 if (iter
->second
.verification
== OptionVerificationType::kDeprecated
) {
869 // If the option is no longer used in rocksdb and marked as deprecated,
870 // we skip it in the serialization.
873 std::string single_output
;
874 bool result
= SerializeSingleColumnFamilyOption(&single_output
, cf_options
,
875 iter
->first
, delimiter
);
877 opt_string
->append(single_output
);
879 return Status::InvalidArgument("failed to serialize %s\n",
880 iter
->first
.c_str());
887 Status
GetStringFromCompressionType(std::string
* compression_str
,
888 CompressionType compression_type
) {
889 bool ok
= SerializeEnum
<CompressionType
>(compression_type_string_map
,
890 compression_type
, compression_str
);
894 return Status::InvalidArgument("Invalid compression types");
898 std::vector
<CompressionType
> GetSupportedCompressions() {
899 std::vector
<CompressionType
> supported_compressions
;
900 for (const auto& comp_to_name
: compression_type_string_map
) {
901 CompressionType t
= comp_to_name
.second
;
902 if (t
!= kDisableCompressionOption
&& CompressionTypeSupported(t
)) {
903 supported_compressions
.push_back(t
);
906 return supported_compressions
;
909 bool SerializeSingleBlockBasedTableOption(
910 std::string
* opt_string
, const BlockBasedTableOptions
& bbt_options
,
911 const std::string
& name
, const std::string
& delimiter
) {
912 auto iter
= block_based_table_type_info
.find(name
);
913 if (iter
== block_based_table_type_info
.end()) {
916 auto& opt_info
= iter
->second
;
917 const char* opt_address
=
918 reinterpret_cast<const char*>(&bbt_options
) + opt_info
.offset
;
920 bool result
= SerializeSingleOptionHelper(opt_address
, opt_info
.type
, &value
);
922 *opt_string
= name
+ "=" + value
+ delimiter
;
927 Status
GetStringFromBlockBasedTableOptions(
928 std::string
* opt_string
, const BlockBasedTableOptions
& bbt_options
,
929 const std::string
& delimiter
) {
932 for (auto iter
= block_based_table_type_info
.begin();
933 iter
!= block_based_table_type_info
.end(); ++iter
) {
934 if (iter
->second
.verification
== OptionVerificationType::kDeprecated
) {
935 // If the option is no longer used in rocksdb and marked as deprecated,
936 // we skip it in the serialization.
939 std::string single_output
;
940 bool result
= SerializeSingleBlockBasedTableOption(
941 &single_output
, bbt_options
, iter
->first
, delimiter
);
944 opt_string
->append(single_output
);
950 Status
GetStringFromTableFactory(std::string
* opts_str
, const TableFactory
* tf
,
951 const std::string
& delimiter
) {
952 const auto* bbtf
= dynamic_cast<const BlockBasedTableFactory
*>(tf
);
954 if (bbtf
!= nullptr) {
955 return GetStringFromBlockBasedTableOptions(opts_str
, bbtf
->table_options(),
962 Status
ParseDBOption(const std::string
& name
,
963 const std::string
& org_value
,
964 DBOptions
* new_options
,
965 bool input_strings_escaped
= false) {
966 const std::string
& value
=
967 input_strings_escaped
? UnescapeOptionString(org_value
) : org_value
;
969 if (name
== "rate_limiter_bytes_per_sec") {
970 new_options
->rate_limiter
.reset(
971 NewGenericRateLimiter(static_cast<int64_t>(ParseUint64(value
))));
973 auto iter
= db_options_type_info
.find(name
);
974 if (iter
== db_options_type_info
.end()) {
975 return Status::InvalidArgument("Unrecognized option DBOptions:", name
);
977 const auto& opt_info
= iter
->second
;
978 if (opt_info
.verification
!= OptionVerificationType::kDeprecated
&&
980 reinterpret_cast<char*>(new_options
) + opt_info
.offset
,
981 opt_info
.type
, value
)) {
984 switch (opt_info
.verification
) {
985 case OptionVerificationType::kByName
:
986 case OptionVerificationType::kByNameAllowNull
:
987 return Status::NotSupported(
988 "Deserializing the specified DB option " + name
+
989 " is not supported");
990 case OptionVerificationType::kDeprecated
:
993 return Status::InvalidArgument(
994 "Unable to parse the specified DB option " + name
);
997 } catch (const std::exception
&) {
998 return Status::InvalidArgument("Unable to parse DBOptions:", name
);
1000 return Status::OK();
1003 std::string
ParseBlockBasedTableOption(const std::string
& name
,
1004 const std::string
& org_value
,
1005 BlockBasedTableOptions
* new_options
,
1006 bool input_strings_escaped
= false) {
1007 const std::string
& value
=
1008 input_strings_escaped
? UnescapeOptionString(org_value
) : org_value
;
1009 if (!input_strings_escaped
) {
1010 // if the input string is not escaped, it means this function is
1011 // invoked from SetOptions, which takes the old format.
1012 if (name
== "block_cache") {
1013 new_options
->block_cache
= NewLRUCache(ParseSizeT(value
));
1015 } else if (name
== "block_cache_compressed") {
1016 new_options
->block_cache_compressed
= NewLRUCache(ParseSizeT(value
));
1018 } else if (name
== "filter_policy") {
1019 // Expect the following format
1020 // bloomfilter:int:bool
1021 const std::string kName
= "bloomfilter:";
1022 if (value
.compare(0, kName
.size(), kName
) != 0) {
1023 return "Invalid filter policy name";
1025 size_t pos
= value
.find(':', kName
.size());
1026 if (pos
== std::string::npos
) {
1027 return "Invalid filter policy config, missing bits_per_key";
1030 ParseInt(trim(value
.substr(kName
.size(), pos
- kName
.size())));
1031 bool use_block_based_builder
=
1032 ParseBoolean("use_block_based_builder", trim(value
.substr(pos
+ 1)));
1033 new_options
->filter_policy
.reset(
1034 NewBloomFilterPolicy(bits_per_key
, use_block_based_builder
));
1038 const auto iter
= block_based_table_type_info
.find(name
);
1039 if (iter
== block_based_table_type_info
.end()) {
1040 return "Unrecognized option";
1042 const auto& opt_info
= iter
->second
;
1043 if (opt_info
.verification
!= OptionVerificationType::kDeprecated
&&
1044 !ParseOptionHelper(reinterpret_cast<char*>(new_options
) + opt_info
.offset
,
1045 opt_info
.type
, value
)) {
1046 return "Invalid value";
1051 std::string
ParsePlainTableOptions(const std::string
& name
,
1052 const std::string
& org_value
,
1053 PlainTableOptions
* new_options
,
1054 bool input_strings_escaped
= false) {
1055 const std::string
& value
=
1056 input_strings_escaped
? UnescapeOptionString(org_value
) : org_value
;
1057 const auto iter
= plain_table_type_info
.find(name
);
1058 if (iter
== plain_table_type_info
.end()) {
1059 return "Unrecognized option";
1061 const auto& opt_info
= iter
->second
;
1062 if (opt_info
.verification
!= OptionVerificationType::kDeprecated
&&
1063 !ParseOptionHelper(reinterpret_cast<char*>(new_options
) + opt_info
.offset
,
1064 opt_info
.type
, value
)) {
1065 return "Invalid value";
1070 Status
GetBlockBasedTableOptionsFromMap(
1071 const BlockBasedTableOptions
& table_options
,
1072 const std::unordered_map
<std::string
, std::string
>& opts_map
,
1073 BlockBasedTableOptions
* new_table_options
, bool input_strings_escaped
) {
1074 assert(new_table_options
);
1075 *new_table_options
= table_options
;
1076 for (const auto& o
: opts_map
) {
1077 auto error_message
= ParseBlockBasedTableOption(
1078 o
.first
, o
.second
, new_table_options
, input_strings_escaped
);
1079 if (error_message
!= "") {
1080 const auto iter
= block_based_table_type_info
.find(o
.first
);
1081 if (iter
== block_based_table_type_info
.end() ||
1082 !input_strings_escaped
|| // !input_strings_escaped indicates
1083 // the old API, where everything is
1085 (iter
->second
.verification
!= OptionVerificationType::kByName
&&
1086 iter
->second
.verification
!=
1087 OptionVerificationType::kByNameAllowNull
&&
1088 iter
->second
.verification
!= OptionVerificationType::kDeprecated
)) {
1089 // Restore "new_options" to the default "base_options".
1090 *new_table_options
= table_options
;
1091 return Status::InvalidArgument("Can't parse BlockBasedTableOptions:",
1092 o
.first
+ " " + error_message
);
1096 return Status::OK();
1099 Status
GetBlockBasedTableOptionsFromString(
1100 const BlockBasedTableOptions
& table_options
,
1101 const std::string
& opts_str
,
1102 BlockBasedTableOptions
* new_table_options
) {
1103 std::unordered_map
<std::string
, std::string
> opts_map
;
1104 Status s
= StringToMap(opts_str
, &opts_map
);
1108 return GetBlockBasedTableOptionsFromMap(table_options
, opts_map
,
1112 Status
GetPlainTableOptionsFromMap(
1113 const PlainTableOptions
& table_options
,
1114 const std::unordered_map
<std::string
, std::string
>& opts_map
,
1115 PlainTableOptions
* new_table_options
, bool input_strings_escaped
) {
1116 assert(new_table_options
);
1117 *new_table_options
= table_options
;
1118 for (const auto& o
: opts_map
) {
1119 auto error_message
= ParsePlainTableOptions(
1120 o
.first
, o
.second
, new_table_options
, input_strings_escaped
);
1121 if (error_message
!= "") {
1122 const auto iter
= plain_table_type_info
.find(o
.first
);
1123 if (iter
== plain_table_type_info
.end() ||
1124 !input_strings_escaped
|| // !input_strings_escaped indicates
1125 // the old API, where everything is
1127 (iter
->second
.verification
!= OptionVerificationType::kByName
&&
1128 iter
->second
.verification
!=
1129 OptionVerificationType::kByNameAllowNull
&&
1130 iter
->second
.verification
!= OptionVerificationType::kDeprecated
)) {
1131 // Restore "new_options" to the default "base_options".
1132 *new_table_options
= table_options
;
1133 return Status::InvalidArgument("Can't parse PlainTableOptions:",
1134 o
.first
+ " " + error_message
);
1138 return Status::OK();
1141 Status
GetPlainTableOptionsFromString(
1142 const PlainTableOptions
& table_options
,
1143 const std::string
& opts_str
,
1144 PlainTableOptions
* new_table_options
) {
1145 std::unordered_map
<std::string
, std::string
> opts_map
;
1146 Status s
= StringToMap(opts_str
, &opts_map
);
1150 return GetPlainTableOptionsFromMap(table_options
, opts_map
,
1154 Status
GetMemTableRepFactoryFromString(const std::string
& opts_str
,
1155 std::unique_ptr
<MemTableRepFactory
>* new_mem_factory
) {
1156 std::vector
<std::string
> opts_list
= StringSplit(opts_str
, ':');
1157 size_t len
= opts_list
.size();
1159 if (opts_list
.size() <= 0 || opts_list
.size() > 2) {
1160 return Status::InvalidArgument("Can't parse memtable_factory option ",
1164 MemTableRepFactory
* mem_factory
= nullptr;
1166 if (opts_list
[0] == "skip_list") {
1168 // skip_list:<lookahead>
1170 size_t lookahead
= ParseSizeT(opts_list
[1]);
1171 mem_factory
= new SkipListFactory(lookahead
);
1172 } else if (1 == len
) {
1173 mem_factory
= new SkipListFactory();
1175 } else if (opts_list
[0] == "prefix_hash") {
1177 // prfix_hash:<hash_bucket_count>
1179 size_t hash_bucket_count
= ParseSizeT(opts_list
[1]);
1180 mem_factory
= NewHashSkipListRepFactory(hash_bucket_count
);
1181 } else if (1 == len
) {
1182 mem_factory
= NewHashSkipListRepFactory();
1184 } else if (opts_list
[0] == "hash_linkedlist") {
1186 // hash_linkedlist:<hash_bucket_count>
1188 size_t hash_bucket_count
= ParseSizeT(opts_list
[1]);
1189 mem_factory
= NewHashLinkListRepFactory(hash_bucket_count
);
1190 } else if (1 == len
) {
1191 mem_factory
= NewHashLinkListRepFactory();
1193 } else if (opts_list
[0] == "vector") {
1197 size_t count
= ParseSizeT(opts_list
[1]);
1198 mem_factory
= new VectorRepFactory(count
);
1199 } else if (1 == len
) {
1200 mem_factory
= new VectorRepFactory();
1202 } else if (opts_list
[0] == "cuckoo") {
1204 // cuckoo:<write_buffer_size>
1206 size_t write_buffer_size
= ParseSizeT(opts_list
[1]);
1207 mem_factory
= NewHashCuckooRepFactory(write_buffer_size
);
1208 } else if (1 == len
) {
1209 return Status::InvalidArgument("Can't parse memtable_factory option ",
1213 return Status::InvalidArgument("Unrecognized memtable_factory option ",
1217 if (mem_factory
!= nullptr){
1218 new_mem_factory
->reset(mem_factory
);
1221 return Status::OK();
1224 Status
GetColumnFamilyOptionsFromMap(
1225 const ColumnFamilyOptions
& base_options
,
1226 const std::unordered_map
<std::string
, std::string
>& opts_map
,
1227 ColumnFamilyOptions
* new_options
, bool input_strings_escaped
) {
1228 return GetColumnFamilyOptionsFromMapInternal(
1229 base_options
, opts_map
, new_options
, input_strings_escaped
);
1232 Status
GetColumnFamilyOptionsFromMapInternal(
1233 const ColumnFamilyOptions
& base_options
,
1234 const std::unordered_map
<std::string
, std::string
>& opts_map
,
1235 ColumnFamilyOptions
* new_options
, bool input_strings_escaped
,
1236 std::vector
<std::string
>* unsupported_options_names
) {
1237 assert(new_options
);
1238 *new_options
= base_options
;
1239 if (unsupported_options_names
) {
1240 unsupported_options_names
->clear();
1242 for (const auto& o
: opts_map
) {
1243 auto s
= ParseColumnFamilyOption(o
.first
, o
.second
, new_options
,
1244 input_strings_escaped
);
1246 if (s
.IsNotSupported()) {
1247 // If the deserialization of the specified option is not supported
1248 // and an output vector of unsupported_options is provided, then
1249 // we log the name of the unsupported option and proceed.
1250 if (unsupported_options_names
!= nullptr) {
1251 unsupported_options_names
->push_back(o
.first
);
1253 // Note that we still return Status::OK in such case to maintain
1254 // the backward compatibility in the old public API defined in
1255 // rocksdb/convenience.h
1257 // Restore "new_options" to the default "base_options".
1258 *new_options
= base_options
;
1263 return Status::OK();
1266 Status
GetColumnFamilyOptionsFromString(
1267 const ColumnFamilyOptions
& base_options
,
1268 const std::string
& opts_str
,
1269 ColumnFamilyOptions
* new_options
) {
1270 std::unordered_map
<std::string
, std::string
> opts_map
;
1271 Status s
= StringToMap(opts_str
, &opts_map
);
1273 *new_options
= base_options
;
1276 return GetColumnFamilyOptionsFromMap(base_options
, opts_map
, new_options
);
1279 Status
GetDBOptionsFromMap(
1280 const DBOptions
& base_options
,
1281 const std::unordered_map
<std::string
, std::string
>& opts_map
,
1282 DBOptions
* new_options
, bool input_strings_escaped
) {
1283 return GetDBOptionsFromMapInternal(
1284 base_options
, opts_map
, new_options
, input_strings_escaped
);
1287 Status
GetDBOptionsFromMapInternal(
1288 const DBOptions
& base_options
,
1289 const std::unordered_map
<std::string
, std::string
>& opts_map
,
1290 DBOptions
* new_options
, bool input_strings_escaped
,
1291 std::vector
<std::string
>* unsupported_options_names
) {
1292 assert(new_options
);
1293 *new_options
= base_options
;
1294 if (unsupported_options_names
) {
1295 unsupported_options_names
->clear();
1297 for (const auto& o
: opts_map
) {
1298 auto s
= ParseDBOption(o
.first
, o
.second
,
1299 new_options
, input_strings_escaped
);
1301 if (s
.IsNotSupported()) {
1302 // If the deserialization of the specified option is not supported
1303 // and an output vector of unsupported_options is provided, then
1304 // we log the name of the unsupported option and proceed.
1305 if (unsupported_options_names
!= nullptr) {
1306 unsupported_options_names
->push_back(o
.first
);
1308 // Note that we still return Status::OK in such case to maintain
1309 // the backward compatibility in the old public API defined in
1310 // rocksdb/convenience.h
1312 // Restore "new_options" to the default "base_options".
1313 *new_options
= base_options
;
1318 return Status::OK();
1321 Status
GetDBOptionsFromString(
1322 const DBOptions
& base_options
,
1323 const std::string
& opts_str
,
1324 DBOptions
* new_options
) {
1325 std::unordered_map
<std::string
, std::string
> opts_map
;
1326 Status s
= StringToMap(opts_str
, &opts_map
);
1328 *new_options
= base_options
;
1331 return GetDBOptionsFromMap(base_options
, opts_map
, new_options
);
1334 Status
GetOptionsFromString(const Options
& base_options
,
1335 const std::string
& opts_str
, Options
* new_options
) {
1336 std::unordered_map
<std::string
, std::string
> opts_map
;
1337 Status s
= StringToMap(opts_str
, &opts_map
);
1341 DBOptions
new_db_options(base_options
);
1342 ColumnFamilyOptions
new_cf_options(base_options
);
1343 for (const auto& o
: opts_map
) {
1344 if (ParseDBOption(o
.first
, o
.second
, &new_db_options
).ok()) {
1345 } else if (ParseColumnFamilyOption(
1346 o
.first
, o
.second
, &new_cf_options
).ok()) {
1348 return Status::InvalidArgument("Can't parse option " + o
.first
);
1351 *new_options
= Options(new_db_options
, new_cf_options
);
1352 return Status::OK();
1355 Status
GetTableFactoryFromMap(
1356 const std::string
& factory_name
,
1357 const std::unordered_map
<std::string
, std::string
>& opt_map
,
1358 std::shared_ptr
<TableFactory
>* table_factory
) {
1360 if (factory_name
== BlockBasedTableFactory().Name()) {
1361 BlockBasedTableOptions bbt_opt
;
1362 s
= GetBlockBasedTableOptionsFromMap(BlockBasedTableOptions(), opt_map
,
1367 table_factory
->reset(new BlockBasedTableFactory(bbt_opt
));
1368 return Status::OK();
1369 } else if (factory_name
== PlainTableFactory().Name()) {
1370 PlainTableOptions pt_opt
;
1371 s
= GetPlainTableOptionsFromMap(PlainTableOptions(), opt_map
, &pt_opt
,
1376 table_factory
->reset(new PlainTableFactory(pt_opt
));
1377 return Status::OK();
1379 // Return OK for not supported table factories as TableFactory
1380 // Deserialization is optional.
1381 table_factory
->reset();
1382 return Status::OK();
1385 #endif // !ROCKSDB_LITE
1387 } // namespace rocksdb