]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/options/options_helper.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / rocksdb / options / options_helper.cc
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"
6
7 #include <cassert>
8 #include <cctype>
9 #include <cstdlib>
10 #include <unordered_set>
11 #include <vector>
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"
25
26 namespace rocksdb {
27
28 DBOptions BuildDBOptions(const ImmutableDBOptions& immutable_db_options,
29 const MutableDBOptions& mutable_db_options) {
30 DBOptions options;
31
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;
110 #ifndef ROCKSDB_LITE
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;
120
121 return options;
122 }
123
124 ColumnFamilyOptions BuildColumnFamilyOptions(
125 const ColumnFamilyOptions& options,
126 const MutableCFOptions& mutable_cf_options) {
127 ColumnFamilyOptions cf_opts(options);
128
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;
139
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;
157
158 cf_opts.max_bytes_for_level_multiplier_additional.clear();
159 for (auto value :
160 mutable_cf_options.max_bytes_for_level_multiplier_additional) {
161 cf_opts.max_bytes_for_level_multiplier_additional.emplace_back(value);
162 }
163
164 // Misc options
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;
170
171 cf_opts.table_factory = options.table_factory;
172 // TODO(yhchiang): find some way to handle the following derived options
173 // * max_file_size
174
175 return cf_opts;
176 }
177
178 #ifndef ROCKSDB_LITE
179
180 namespace {
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;
187 return true;
188 }
189 return false;
190 }
191
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) {
197 *value = pair.first;
198 return true;
199 }
200 }
201 return false;
202 }
203
204 bool SerializeVectorCompressionType(const std::vector<CompressionType>& types,
205 std::string* value) {
206 std::stringstream ss;
207 bool result;
208 for (size_t i = 0; i < types.size(); ++i) {
209 if (i > 0) {
210 ss << ':';
211 }
212 std::string string_type;
213 result = SerializeEnum<CompressionType>(compression_type_string_map,
214 types[i], &string_type);
215 if (result == false) {
216 return result;
217 }
218 ss << string_type;
219 }
220 *value = ss.str();
221 return true;
222 }
223
224 bool ParseVectorCompressionType(
225 const std::string& value,
226 std::vector<CompressionType>* compression_per_level) {
227 compression_per_level->clear();
228 size_t start = 0;
229 while (start < value.size()) {
230 size_t end = value.find(':', start);
231 bool is_ok;
232 CompressionType type;
233 if (end == std::string::npos) {
234 is_ok = ParseEnum<CompressionType>(compression_type_string_map,
235 value.substr(start), &type);
236 if (!is_ok) {
237 return false;
238 }
239 compression_per_level->emplace_back(type);
240 break;
241 } else {
242 is_ok = ParseEnum<CompressionType>(
243 compression_type_string_map, value.substr(start, end - start), &type);
244 if (!is_ok) {
245 return false;
246 }
247 compression_per_level->emplace_back(type);
248 start = end + 1;
249 }
250 }
251 return true;
252 }
253
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) {
258
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) ==
266 0) {
267 int prefix_length =
268 ParseInt(trim(pe_value.substr(kCappedPrefixName.size())));
269 slice_transform->reset(NewCappedPrefixTransform(prefix_length));
270 } else if (value == kNullptrString) {
271 slice_transform->reset();
272 } else {
273 return false;
274 }
275
276 return true;
277 }
278
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().
285
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.
289 bool result =
290 ParseSliceTransformHelper("fixed:", "capped:", value, slice_transform);
291 if (result) {
292 return result;
293 }
294 result = ParseSliceTransformHelper(
295 "rocksdb.FixedPrefix.", "rocksdb.CappedPrefix.", value, slice_transform);
296 if (result) {
297 return result;
298 }
299 // TODO(yhchiang): we can further support other default
300 // SliceTransforms here.
301 return false;
302 }
303
304 bool ParseOptionHelper(char* opt_address, const OptionType& opt_type,
305 const std::string& value) {
306 switch (opt_type) {
307 case OptionType::kBoolean:
308 *reinterpret_cast<bool*>(opt_address) = ParseBoolean("", value);
309 break;
310 case OptionType::kInt:
311 *reinterpret_cast<int*>(opt_address) = ParseInt(value);
312 break;
313 case OptionType::kVectorInt:
314 *reinterpret_cast<std::vector<int>*>(opt_address) = ParseVectorInt(value);
315 break;
316 case OptionType::kUInt:
317 *reinterpret_cast<unsigned int*>(opt_address) = ParseUint32(value);
318 break;
319 case OptionType::kUInt32T:
320 *reinterpret_cast<uint32_t*>(opt_address) = ParseUint32(value);
321 break;
322 case OptionType::kUInt64T:
323 PutUnaligned(reinterpret_cast<uint64_t*>(opt_address), ParseUint64(value));
324 break;
325 case OptionType::kSizeT:
326 PutUnaligned(reinterpret_cast<size_t*>(opt_address), ParseSizeT(value));
327 break;
328 case OptionType::kString:
329 *reinterpret_cast<std::string*>(opt_address) = value;
330 break;
331 case OptionType::kDouble:
332 *reinterpret_cast<double*>(opt_address) = ParseDouble(value);
333 break;
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>*>(
352 opt_address));
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));
377 default:
378 return false;
379 }
380 return true;
381 }
382
383 } // anonymouse namespace
384
385 bool SerializeSingleOptionHelper(const char* opt_address,
386 const OptionType opt_type,
387 std::string* value) {
388
389 assert(value);
390 switch (opt_type) {
391 case OptionType::kBoolean:
392 *value = *(reinterpret_cast<const bool*>(opt_address)) ? "true" : "false";
393 break;
394 case OptionType::kInt:
395 *value = ToString(*(reinterpret_cast<const int*>(opt_address)));
396 break;
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)));
402 break;
403 case OptionType::kUInt32T:
404 *value = ToString(*(reinterpret_cast<const uint32_t*>(opt_address)));
405 break;
406 case OptionType::kUInt64T:
407 {
408 uint64_t v;
409 GetUnaligned(reinterpret_cast<const uint64_t*>(opt_address), &v);
410 *value = ToString(v);
411 }
412 break;
413 case OptionType::kSizeT:
414 {
415 size_t v;
416 GetUnaligned(reinterpret_cast<const size_t*>(opt_address), &v);
417 *value = ToString(v);
418 }
419 break;
420 case OptionType::kDouble:
421 *value = ToString(*(reinterpret_cast<const double*>(opt_address)));
422 break;
423 case OptionType::kString:
424 *value = EscapeOptionString(
425 *(reinterpret_cast<const std::string*>(opt_address)));
426 break;
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)),
442 value);
443 break;
444 case OptionType::kSliceTransform: {
445 const auto* slice_transform_ptr =
446 reinterpret_cast<const std::shared_ptr<const SliceTransform>*>(
447 opt_address);
448 *value = slice_transform_ptr->get() ? slice_transform_ptr->get()->Name()
449 : kNullptrString;
450 break;
451 }
452 case OptionType::kTableFactory: {
453 const auto* table_factory_ptr =
454 reinterpret_cast<const std::shared_ptr<const TableFactory>*>(
455 opt_address);
456 *value = table_factory_ptr->get() ? table_factory_ptr->get()->Name()
457 : kNullptrString;
458 break;
459 }
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();
470 } else {
471 *value = *ptr ? (*ptr)->Name() : kNullptrString;
472 }
473 break;
474 }
475 case OptionType::kCompactionFilter: {
476 // it's a const pointer of const CompactionFilter*
477 const auto* ptr =
478 reinterpret_cast<const CompactionFilter* const*>(opt_address);
479 *value = *ptr ? (*ptr)->Name() : kNullptrString;
480 break;
481 }
482 case OptionType::kCompactionFilterFactory: {
483 const auto* ptr =
484 reinterpret_cast<const std::shared_ptr<CompactionFilterFactory>*>(
485 opt_address);
486 *value = ptr->get() ? ptr->get()->Name() : kNullptrString;
487 break;
488 }
489 case OptionType::kMemTableRepFactory: {
490 const auto* ptr =
491 reinterpret_cast<const std::shared_ptr<MemTableRepFactory>*>(
492 opt_address);
493 *value = ptr->get() ? ptr->get()->Name() : kNullptrString;
494 break;
495 }
496 case OptionType::kMergeOperator: {
497 const auto* ptr =
498 reinterpret_cast<const std::shared_ptr<MergeOperator>*>(opt_address);
499 *value = ptr->get() ? ptr->get()->Name() : kNullptrString;
500 break;
501 }
502 case OptionType::kFilterPolicy: {
503 const auto* ptr =
504 reinterpret_cast<const std::shared_ptr<FilterPolicy>*>(opt_address);
505 *value = ptr->get() ? ptr->get()->Name() : kNullptrString;
506 break;
507 }
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*>(
516 opt_address),
517 value);
518 case OptionType::kFlushBlockPolicyFactory: {
519 const auto* ptr =
520 reinterpret_cast<const std::shared_ptr<FlushBlockPolicyFactory>*>(
521 opt_address);
522 *value = ptr->get() ? ptr->get()->Name() : kNullptrString;
523 break;
524 }
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);
541 default:
542 return false;
543 }
544 return true;
545 }
546
547 Status GetMutableOptionsFromStrings(
548 const MutableCFOptions& base_options,
549 const std::unordered_map<std::string, std::string>& options_map,
550 MutableCFOptions* new_options) {
551 assert(new_options);
552 *new_options = base_options;
553 for (const auto& o : options_map) {
554 try {
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);
558 }
559 const auto& opt_info = iter->second;
560 if (!opt_info.is_mutable) {
561 return Status::InvalidArgument("Option not changeable: " + o.first);
562 }
563 bool is_ok = ParseOptionHelper(
564 reinterpret_cast<char*>(new_options) + opt_info.mutable_offset,
565 opt_info.type, o.second);
566 if (!is_ok) {
567 return Status::InvalidArgument("Error parsing " + o.first);
568 }
569 } catch (std::exception& e) {
570 return Status::InvalidArgument("Error parsing " + o.first + ":" +
571 std::string(e.what()));
572 }
573 }
574 return Status::OK();
575 }
576
577 Status GetMutableDBOptionsFromStrings(
578 const MutableDBOptions& base_options,
579 const std::unordered_map<std::string, std::string>& options_map,
580 MutableDBOptions* new_options) {
581 assert(new_options);
582 *new_options = base_options;
583 for (const auto& o : options_map) {
584 try {
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);
588 }
589 const auto& opt_info = iter->second;
590 if (!opt_info.is_mutable) {
591 return Status::InvalidArgument("Option not changeable: " + o.first);
592 }
593 bool is_ok = ParseOptionHelper(
594 reinterpret_cast<char*>(new_options) + opt_info.mutable_offset,
595 opt_info.type, o.second);
596 if (!is_ok) {
597 return Status::InvalidArgument("Error parsing " + o.first);
598 }
599 } catch (std::exception& e) {
600 return Status::InvalidArgument("Error parsing " + o.first + ":" +
601 std::string(e.what()));
602 }
603 }
604 return Status::OK();
605 }
606
607 Status StringToMap(const std::string& opts_str,
608 std::unordered_map<std::string, std::string>* opts_map) {
609 assert(opts_map);
610 // Example:
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"
613 size_t pos = 0;
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");
619 }
620 std::string key = trim(opts.substr(pos, eq_pos - pos));
621 if (key.empty()) {
622 return Status::InvalidArgument("Empty key found");
623 }
624
625 // skip space after '=' and look for '{' for possible nested options
626 pos = eq_pos + 1;
627 while (pos < opts.size() && isspace(opts[pos])) {
628 ++pos;
629 }
630 // Empty value at the end
631 if (pos >= opts.size()) {
632 (*opts_map)[key] = "";
633 break;
634 }
635 if (opts[pos] == '{') {
636 int count = 1;
637 size_t brace_pos = pos + 1;
638 while (brace_pos < opts.size()) {
639 if (opts[brace_pos] == '{') {
640 ++count;
641 } else if (opts[brace_pos] == '}') {
642 --count;
643 if (count == 0) {
644 break;
645 }
646 }
647 ++brace_pos;
648 }
649 // found the matching closing brace
650 if (count == 0) {
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 '}'
654 pos = brace_pos + 1;
655 while (pos < opts.size() && isspace(opts[pos])) {
656 ++pos;
657 }
658 if (pos < opts.size() && opts[pos] != ';') {
659 return Status::InvalidArgument(
660 "Unexpected chars after nested options");
661 }
662 ++pos;
663 } else {
664 return Status::InvalidArgument(
665 "Mismatched curly braces for nested options");
666 }
667 } else {
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
672 break;
673 } else {
674 (*opts_map)[key] = trim(opts.substr(pos, sc_pos - pos));
675 }
676 pos = sc_pos + 1;
677 }
678 }
679
680 return Status::OK();
681 }
682
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;
689 try {
690 if (name == "block_based_table_factory") {
691 // Nested options
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();
697 }
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);
703 }
704 new_options->table_factory.reset(NewBlockBasedTableFactory(table_opt));
705 } else if (name == "plain_table_factory") {
706 // Nested options
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();
712 }
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);
718 }
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);
727 }
728 new_options->memtable_factory.reset(new_mem_factory.release());
729 } else if (name == "compression_opts") {
730 size_t start = 0;
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);
735 }
736 new_options->compression_opts.window_bits =
737 ParseInt(value.substr(start, end - start));
738 start = end + 1;
739 end = value.find(':', start);
740 if (end == std::string::npos) {
741 return Status::InvalidArgument(
742 "unable to parse the specified CF option " + name);
743 }
744 new_options->compression_opts.level =
745 ParseInt(value.substr(start, end - start));
746 start = end + 1;
747 if (start >= value.size()) {
748 return Status::InvalidArgument(
749 "unable to parse the specified CF option " + name);
750 }
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) {
756 start = end + 1;
757 if (start >= value.size()) {
758 return Status::InvalidArgument(
759 "unable to parse the specified CF option " + name);
760 }
761 new_options->compression_opts.max_dict_bytes =
762 ParseInt(value.substr(start, value.size() - start));
763 }
764 } else if (name == "compaction_options_fifo") {
765 new_options->compaction_options_fifo.max_table_files_size =
766 ParseUint64(value);
767 } else {
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);
772 }
773 const auto& opt_info = iter->second;
774 if (opt_info.verification != OptionVerificationType::kDeprecated &&
775 ParseOptionHelper(
776 reinterpret_cast<char*>(new_options) + opt_info.offset,
777 opt_info.type, value)) {
778 return Status::OK();
779 }
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:
787 return Status::OK();
788 default:
789 return Status::InvalidArgument(
790 "Unable to parse the specified CF option " + name);
791 }
792 }
793 } catch (const std::exception&) {
794 return Status::InvalidArgument(
795 "unable to parse the specified option " + name);
796 }
797 return Status::OK();
798 }
799
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()) {
806 return false;
807 }
808 auto& opt_info = iter->second;
809 const char* opt_address =
810 reinterpret_cast<const char*>(&db_options) + opt_info.offset;
811 std::string value;
812 bool result = SerializeSingleOptionHelper(opt_address, opt_info.type, &value);
813 if (result) {
814 *opt_string = name + "=" + value + delimiter;
815 }
816 return result;
817 }
818
819 Status GetStringFromDBOptions(std::string* opt_string,
820 const DBOptions& db_options,
821 const std::string& delimiter) {
822 assert(opt_string);
823 opt_string->clear();
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.
829 continue;
830 }
831 std::string single_output;
832 bool result = SerializeSingleDBOption(&single_output, db_options,
833 iter->first, delimiter);
834 assert(result);
835 if (result) {
836 opt_string->append(single_output);
837 }
838 }
839 return Status::OK();
840 }
841
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()) {
848 return false;
849 }
850 auto& opt_info = iter->second;
851 const char* opt_address =
852 reinterpret_cast<const char*>(&cf_options) + opt_info.offset;
853 std::string value;
854 bool result = SerializeSingleOptionHelper(opt_address, opt_info.type, &value);
855 if (result) {
856 *opt_string = name + "=" + value + delimiter;
857 }
858 return result;
859 }
860
861 Status GetStringFromColumnFamilyOptions(std::string* opt_string,
862 const ColumnFamilyOptions& cf_options,
863 const std::string& delimiter) {
864 assert(opt_string);
865 opt_string->clear();
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.
871 continue;
872 }
873 std::string single_output;
874 bool result = SerializeSingleColumnFamilyOption(&single_output, cf_options,
875 iter->first, delimiter);
876 if (result) {
877 opt_string->append(single_output);
878 } else {
879 return Status::InvalidArgument("failed to serialize %s\n",
880 iter->first.c_str());
881 }
882 assert(result);
883 }
884 return Status::OK();
885 }
886
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);
891 if (ok) {
892 return Status::OK();
893 } else {
894 return Status::InvalidArgument("Invalid compression types");
895 }
896 }
897
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);
904 }
905 }
906 return supported_compressions;
907 }
908
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()) {
914 return false;
915 }
916 auto& opt_info = iter->second;
917 const char* opt_address =
918 reinterpret_cast<const char*>(&bbt_options) + opt_info.offset;
919 std::string value;
920 bool result = SerializeSingleOptionHelper(opt_address, opt_info.type, &value);
921 if (result) {
922 *opt_string = name + "=" + value + delimiter;
923 }
924 return result;
925 }
926
927 Status GetStringFromBlockBasedTableOptions(
928 std::string* opt_string, const BlockBasedTableOptions& bbt_options,
929 const std::string& delimiter) {
930 assert(opt_string);
931 opt_string->clear();
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.
937 continue;
938 }
939 std::string single_output;
940 bool result = SerializeSingleBlockBasedTableOption(
941 &single_output, bbt_options, iter->first, delimiter);
942 assert(result);
943 if (result) {
944 opt_string->append(single_output);
945 }
946 }
947 return Status::OK();
948 }
949
950 Status GetStringFromTableFactory(std::string* opts_str, const TableFactory* tf,
951 const std::string& delimiter) {
952 const auto* bbtf = dynamic_cast<const BlockBasedTableFactory*>(tf);
953 opts_str->clear();
954 if (bbtf != nullptr) {
955 return GetStringFromBlockBasedTableOptions(opts_str, bbtf->table_options(),
956 delimiter);
957 }
958
959 return Status::OK();
960 }
961
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;
968 try {
969 if (name == "rate_limiter_bytes_per_sec") {
970 new_options->rate_limiter.reset(
971 NewGenericRateLimiter(static_cast<int64_t>(ParseUint64(value))));
972 } else {
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);
976 }
977 const auto& opt_info = iter->second;
978 if (opt_info.verification != OptionVerificationType::kDeprecated &&
979 ParseOptionHelper(
980 reinterpret_cast<char*>(new_options) + opt_info.offset,
981 opt_info.type, value)) {
982 return Status::OK();
983 }
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:
991 return Status::OK();
992 default:
993 return Status::InvalidArgument(
994 "Unable to parse the specified DB option " + name);
995 }
996 }
997 } catch (const std::exception&) {
998 return Status::InvalidArgument("Unable to parse DBOptions:", name);
999 }
1000 return Status::OK();
1001 }
1002
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));
1014 return "";
1015 } else if (name == "block_cache_compressed") {
1016 new_options->block_cache_compressed = NewLRUCache(ParseSizeT(value));
1017 return "";
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";
1024 }
1025 size_t pos = value.find(':', kName.size());
1026 if (pos == std::string::npos) {
1027 return "Invalid filter policy config, missing bits_per_key";
1028 }
1029 int 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));
1035 return "";
1036 }
1037 }
1038 const auto iter = block_based_table_type_info.find(name);
1039 if (iter == block_based_table_type_info.end()) {
1040 return "Unrecognized option";
1041 }
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";
1047 }
1048 return "";
1049 }
1050
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";
1060 }
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";
1066 }
1067 return "";
1068 }
1069
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
1084 // parsable.
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);
1093 }
1094 }
1095 }
1096 return Status::OK();
1097 }
1098
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);
1105 if (!s.ok()) {
1106 return s;
1107 }
1108 return GetBlockBasedTableOptionsFromMap(table_options, opts_map,
1109 new_table_options);
1110 }
1111
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
1126 // parsable.
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);
1135 }
1136 }
1137 }
1138 return Status::OK();
1139 }
1140
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);
1147 if (!s.ok()) {
1148 return s;
1149 }
1150 return GetPlainTableOptionsFromMap(table_options, opts_map,
1151 new_table_options);
1152 }
1153
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();
1158
1159 if (opts_list.size() <= 0 || opts_list.size() > 2) {
1160 return Status::InvalidArgument("Can't parse memtable_factory option ",
1161 opts_str);
1162 }
1163
1164 MemTableRepFactory* mem_factory = nullptr;
1165
1166 if (opts_list[0] == "skip_list") {
1167 // Expecting format
1168 // skip_list:<lookahead>
1169 if (2 == len) {
1170 size_t lookahead = ParseSizeT(opts_list[1]);
1171 mem_factory = new SkipListFactory(lookahead);
1172 } else if (1 == len) {
1173 mem_factory = new SkipListFactory();
1174 }
1175 } else if (opts_list[0] == "prefix_hash") {
1176 // Expecting format
1177 // prfix_hash:<hash_bucket_count>
1178 if (2 == len) {
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();
1183 }
1184 } else if (opts_list[0] == "hash_linkedlist") {
1185 // Expecting format
1186 // hash_linkedlist:<hash_bucket_count>
1187 if (2 == len) {
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();
1192 }
1193 } else if (opts_list[0] == "vector") {
1194 // Expecting format
1195 // vector:<count>
1196 if (2 == len) {
1197 size_t count = ParseSizeT(opts_list[1]);
1198 mem_factory = new VectorRepFactory(count);
1199 } else if (1 == len) {
1200 mem_factory = new VectorRepFactory();
1201 }
1202 } else if (opts_list[0] == "cuckoo") {
1203 // Expecting format
1204 // cuckoo:<write_buffer_size>
1205 if (2 == len) {
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 ",
1210 opts_str);
1211 }
1212 } else {
1213 return Status::InvalidArgument("Unrecognized memtable_factory option ",
1214 opts_str);
1215 }
1216
1217 if (mem_factory != nullptr){
1218 new_mem_factory->reset(mem_factory);
1219 }
1220
1221 return Status::OK();
1222 }
1223
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);
1230 }
1231
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();
1241 }
1242 for (const auto& o : opts_map) {
1243 auto s = ParseColumnFamilyOption(o.first, o.second, new_options,
1244 input_strings_escaped);
1245 if (!s.ok()) {
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);
1252 }
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
1256 } else {
1257 // Restore "new_options" to the default "base_options".
1258 *new_options = base_options;
1259 return s;
1260 }
1261 }
1262 }
1263 return Status::OK();
1264 }
1265
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);
1272 if (!s.ok()) {
1273 *new_options = base_options;
1274 return s;
1275 }
1276 return GetColumnFamilyOptionsFromMap(base_options, opts_map, new_options);
1277 }
1278
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);
1285 }
1286
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();
1296 }
1297 for (const auto& o : opts_map) {
1298 auto s = ParseDBOption(o.first, o.second,
1299 new_options, input_strings_escaped);
1300 if (!s.ok()) {
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);
1307 }
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
1311 } else {
1312 // Restore "new_options" to the default "base_options".
1313 *new_options = base_options;
1314 return s;
1315 }
1316 }
1317 }
1318 return Status::OK();
1319 }
1320
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);
1327 if (!s.ok()) {
1328 *new_options = base_options;
1329 return s;
1330 }
1331 return GetDBOptionsFromMap(base_options, opts_map, new_options);
1332 }
1333
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);
1338 if (!s.ok()) {
1339 return s;
1340 }
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()) {
1347 } else {
1348 return Status::InvalidArgument("Can't parse option " + o.first);
1349 }
1350 }
1351 *new_options = Options(new_db_options, new_cf_options);
1352 return Status::OK();
1353 }
1354
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) {
1359 Status s;
1360 if (factory_name == BlockBasedTableFactory().Name()) {
1361 BlockBasedTableOptions bbt_opt;
1362 s = GetBlockBasedTableOptionsFromMap(BlockBasedTableOptions(), opt_map,
1363 &bbt_opt, true);
1364 if (!s.ok()) {
1365 return s;
1366 }
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,
1372 true);
1373 if (!s.ok()) {
1374 return s;
1375 }
1376 table_factory->reset(new PlainTableFactory(pt_opt));
1377 return Status::OK();
1378 }
1379 // Return OK for not supported table factories as TableFactory
1380 // Deserialization is optional.
1381 table_factory->reset();
1382 return Status::OK();
1383 }
1384
1385 #endif // !ROCKSDB_LITE
1386
1387 } // namespace rocksdb