1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 #include "options/options_helper.h"
6 
7 #include <cassert>
8 #include <cctype>
9 #include <cstdlib>
10 #include <unordered_set>
11 #include <vector>
12 
13 #include "rocksdb/cache.h"
14 #include "rocksdb/compaction_filter.h"
15 #include "rocksdb/convenience.h"
16 #include "rocksdb/filter_policy.h"
17 #include "rocksdb/memtablerep.h"
18 #include "rocksdb/merge_operator.h"
19 #include "rocksdb/options.h"
20 #include "rocksdb/rate_limiter.h"
21 #include "rocksdb/slice_transform.h"
22 #include "rocksdb/table.h"
23 #include "rocksdb/utilities/object_registry.h"
24 #include "table/block_based/block_based_table_factory.h"
25 #include "table/plain/plain_table_factory.h"
26 #include "util/cast_util.h"
27 #include "util/string_util.h"
28 
29 namespace ROCKSDB_NAMESPACE {
30 
BuildDBOptions(const ImmutableDBOptions & immutable_db_options,const MutableDBOptions & mutable_db_options)31 DBOptions BuildDBOptions(const ImmutableDBOptions& immutable_db_options,
32                          const MutableDBOptions& mutable_db_options) {
33   DBOptions options;
34 
35   options.create_if_missing = immutable_db_options.create_if_missing;
36   options.create_missing_column_families =
37       immutable_db_options.create_missing_column_families;
38   options.error_if_exists = immutable_db_options.error_if_exists;
39   options.paranoid_checks = immutable_db_options.paranoid_checks;
40   options.env = immutable_db_options.env;
41   options.rate_limiter = immutable_db_options.rate_limiter;
42   options.sst_file_manager = immutable_db_options.sst_file_manager;
43   options.info_log = immutable_db_options.info_log;
44   options.info_log_level = immutable_db_options.info_log_level;
45   options.max_open_files = mutable_db_options.max_open_files;
46   options.max_file_opening_threads =
47       immutable_db_options.max_file_opening_threads;
48   options.max_total_wal_size = mutable_db_options.max_total_wal_size;
49   options.statistics = immutable_db_options.statistics;
50   options.use_fsync = immutable_db_options.use_fsync;
51   options.db_paths = immutable_db_options.db_paths;
52   options.db_log_dir = immutable_db_options.db_log_dir;
53   options.wal_dir = immutable_db_options.wal_dir;
54   options.delete_obsolete_files_period_micros =
55       mutable_db_options.delete_obsolete_files_period_micros;
56   options.max_background_jobs = mutable_db_options.max_background_jobs;
57   options.base_background_compactions =
58       mutable_db_options.base_background_compactions;
59   options.max_background_compactions =
60       mutable_db_options.max_background_compactions;
61   options.bytes_per_sync = mutable_db_options.bytes_per_sync;
62   options.wal_bytes_per_sync = mutable_db_options.wal_bytes_per_sync;
63   options.strict_bytes_per_sync = mutable_db_options.strict_bytes_per_sync;
64   options.max_subcompactions = immutable_db_options.max_subcompactions;
65   options.max_background_flushes = immutable_db_options.max_background_flushes;
66   options.max_log_file_size = immutable_db_options.max_log_file_size;
67   options.log_file_time_to_roll = immutable_db_options.log_file_time_to_roll;
68   options.keep_log_file_num = immutable_db_options.keep_log_file_num;
69   options.recycle_log_file_num = immutable_db_options.recycle_log_file_num;
70   options.max_manifest_file_size = immutable_db_options.max_manifest_file_size;
71   options.table_cache_numshardbits =
72       immutable_db_options.table_cache_numshardbits;
73   options.WAL_ttl_seconds = immutable_db_options.wal_ttl_seconds;
74   options.WAL_size_limit_MB = immutable_db_options.wal_size_limit_mb;
75   options.manifest_preallocation_size =
76       immutable_db_options.manifest_preallocation_size;
77   options.allow_mmap_reads = immutable_db_options.allow_mmap_reads;
78   options.allow_mmap_writes = immutable_db_options.allow_mmap_writes;
79   options.use_direct_reads = immutable_db_options.use_direct_reads;
80   options.use_direct_io_for_flush_and_compaction =
81       immutable_db_options.use_direct_io_for_flush_and_compaction;
82   options.allow_fallocate = immutable_db_options.allow_fallocate;
83   options.is_fd_close_on_exec = immutable_db_options.is_fd_close_on_exec;
84   options.stats_dump_period_sec = mutable_db_options.stats_dump_period_sec;
85   options.stats_persist_period_sec =
86       mutable_db_options.stats_persist_period_sec;
87   options.persist_stats_to_disk = immutable_db_options.persist_stats_to_disk;
88   options.stats_history_buffer_size =
89       mutable_db_options.stats_history_buffer_size;
90   options.advise_random_on_open = immutable_db_options.advise_random_on_open;
91   options.db_write_buffer_size = immutable_db_options.db_write_buffer_size;
92   options.write_buffer_manager = immutable_db_options.write_buffer_manager;
93   options.access_hint_on_compaction_start =
94       immutable_db_options.access_hint_on_compaction_start;
95   options.new_table_reader_for_compaction_inputs =
96       immutable_db_options.new_table_reader_for_compaction_inputs;
97   options.compaction_readahead_size =
98       mutable_db_options.compaction_readahead_size;
99   options.random_access_max_buffer_size =
100       immutable_db_options.random_access_max_buffer_size;
101   options.writable_file_max_buffer_size =
102       mutable_db_options.writable_file_max_buffer_size;
103   options.use_adaptive_mutex = immutable_db_options.use_adaptive_mutex;
104   options.listeners = immutable_db_options.listeners;
105   options.enable_thread_tracking = immutable_db_options.enable_thread_tracking;
106   options.delayed_write_rate = mutable_db_options.delayed_write_rate;
107   options.enable_pipelined_write = immutable_db_options.enable_pipelined_write;
108   options.unordered_write = immutable_db_options.unordered_write;
109   options.allow_concurrent_memtable_write =
110       immutable_db_options.allow_concurrent_memtable_write;
111   options.enable_write_thread_adaptive_yield =
112       immutable_db_options.enable_write_thread_adaptive_yield;
113   options.max_write_batch_group_size_bytes =
114       immutable_db_options.max_write_batch_group_size_bytes;
115   options.write_thread_max_yield_usec =
116       immutable_db_options.write_thread_max_yield_usec;
117   options.write_thread_slow_yield_usec =
118       immutable_db_options.write_thread_slow_yield_usec;
119   options.skip_stats_update_on_db_open =
120       immutable_db_options.skip_stats_update_on_db_open;
121   options.skip_checking_sst_file_sizes_on_db_open =
122       immutable_db_options.skip_checking_sst_file_sizes_on_db_open;
123   options.wal_recovery_mode = immutable_db_options.wal_recovery_mode;
124   options.allow_2pc = immutable_db_options.allow_2pc;
125   options.row_cache = immutable_db_options.row_cache;
126 #ifndef ROCKSDB_LITE
127   options.wal_filter = immutable_db_options.wal_filter;
128 #endif  // ROCKSDB_LITE
129   options.fail_if_options_file_error =
130       immutable_db_options.fail_if_options_file_error;
131   options.dump_malloc_stats = immutable_db_options.dump_malloc_stats;
132   options.avoid_flush_during_recovery =
133       immutable_db_options.avoid_flush_during_recovery;
134   options.avoid_flush_during_shutdown =
135       mutable_db_options.avoid_flush_during_shutdown;
136   options.allow_ingest_behind =
137       immutable_db_options.allow_ingest_behind;
138   options.preserve_deletes =
139       immutable_db_options.preserve_deletes;
140   options.two_write_queues = immutable_db_options.two_write_queues;
141   options.manual_wal_flush = immutable_db_options.manual_wal_flush;
142   options.atomic_flush = immutable_db_options.atomic_flush;
143   options.avoid_unnecessary_blocking_io =
144       immutable_db_options.avoid_unnecessary_blocking_io;
145   options.log_readahead_size = immutable_db_options.log_readahead_size;
146   options.file_checksum_gen_factory =
147       immutable_db_options.file_checksum_gen_factory;
148   options.best_efforts_recovery = immutable_db_options.best_efforts_recovery;
149   return options;
150 }
151 
BuildColumnFamilyOptions(const ColumnFamilyOptions & options,const MutableCFOptions & mutable_cf_options)152 ColumnFamilyOptions BuildColumnFamilyOptions(
153     const ColumnFamilyOptions& options,
154     const MutableCFOptions& mutable_cf_options) {
155   ColumnFamilyOptions cf_opts(options);
156 
157   // Memtable related options
158   cf_opts.write_buffer_size = mutable_cf_options.write_buffer_size;
159   cf_opts.max_write_buffer_number = mutable_cf_options.max_write_buffer_number;
160   cf_opts.arena_block_size = mutable_cf_options.arena_block_size;
161   cf_opts.memtable_prefix_bloom_size_ratio =
162       mutable_cf_options.memtable_prefix_bloom_size_ratio;
163   cf_opts.memtable_whole_key_filtering =
164       mutable_cf_options.memtable_whole_key_filtering;
165   cf_opts.memtable_huge_page_size = mutable_cf_options.memtable_huge_page_size;
166   cf_opts.max_successive_merges = mutable_cf_options.max_successive_merges;
167   cf_opts.inplace_update_num_locks =
168       mutable_cf_options.inplace_update_num_locks;
169   cf_opts.prefix_extractor = mutable_cf_options.prefix_extractor;
170 
171   // Compaction related options
172   cf_opts.disable_auto_compactions =
173       mutable_cf_options.disable_auto_compactions;
174   cf_opts.soft_pending_compaction_bytes_limit =
175       mutable_cf_options.soft_pending_compaction_bytes_limit;
176   cf_opts.hard_pending_compaction_bytes_limit =
177       mutable_cf_options.hard_pending_compaction_bytes_limit;
178   cf_opts.level0_file_num_compaction_trigger =
179       mutable_cf_options.level0_file_num_compaction_trigger;
180   cf_opts.level0_slowdown_writes_trigger =
181       mutable_cf_options.level0_slowdown_writes_trigger;
182   cf_opts.level0_stop_writes_trigger =
183       mutable_cf_options.level0_stop_writes_trigger;
184   cf_opts.max_compaction_bytes = mutable_cf_options.max_compaction_bytes;
185   cf_opts.target_file_size_base = mutable_cf_options.target_file_size_base;
186   cf_opts.target_file_size_multiplier =
187       mutable_cf_options.target_file_size_multiplier;
188   cf_opts.max_bytes_for_level_base =
189       mutable_cf_options.max_bytes_for_level_base;
190   cf_opts.max_bytes_for_level_multiplier =
191       mutable_cf_options.max_bytes_for_level_multiplier;
192   cf_opts.ttl = mutable_cf_options.ttl;
193   cf_opts.periodic_compaction_seconds =
194       mutable_cf_options.periodic_compaction_seconds;
195 
196   cf_opts.max_bytes_for_level_multiplier_additional.clear();
197   for (auto value :
198        mutable_cf_options.max_bytes_for_level_multiplier_additional) {
199     cf_opts.max_bytes_for_level_multiplier_additional.emplace_back(value);
200   }
201 
202   cf_opts.compaction_options_fifo = mutable_cf_options.compaction_options_fifo;
203   cf_opts.compaction_options_universal =
204       mutable_cf_options.compaction_options_universal;
205 
206   // Misc options
207   cf_opts.max_sequential_skip_in_iterations =
208       mutable_cf_options.max_sequential_skip_in_iterations;
209   cf_opts.paranoid_file_checks = mutable_cf_options.paranoid_file_checks;
210   cf_opts.report_bg_io_stats = mutable_cf_options.report_bg_io_stats;
211   cf_opts.compression = mutable_cf_options.compression;
212   cf_opts.sample_for_compression = mutable_cf_options.sample_for_compression;
213 
214   cf_opts.table_factory = options.table_factory;
215   // TODO(yhchiang): find some way to handle the following derived options
216   // * max_file_size
217 
218   return cf_opts;
219 }
220 
221 std::map<CompactionStyle, std::string>
222     OptionsHelper::compaction_style_to_string = {
223         {kCompactionStyleLevel, "kCompactionStyleLevel"},
224         {kCompactionStyleUniversal, "kCompactionStyleUniversal"},
225         {kCompactionStyleFIFO, "kCompactionStyleFIFO"},
226         {kCompactionStyleNone, "kCompactionStyleNone"}};
227 
228 std::map<CompactionPri, std::string> OptionsHelper::compaction_pri_to_string = {
229     {kByCompensatedSize, "kByCompensatedSize"},
230     {kOldestLargestSeqFirst, "kOldestLargestSeqFirst"},
231     {kOldestSmallestSeqFirst, "kOldestSmallestSeqFirst"},
232     {kMinOverlappingRatio, "kMinOverlappingRatio"}};
233 
234 std::map<CompactionStopStyle, std::string>
235     OptionsHelper::compaction_stop_style_to_string = {
236         {kCompactionStopStyleSimilarSize, "kCompactionStopStyleSimilarSize"},
237         {kCompactionStopStyleTotalSize, "kCompactionStopStyleTotalSize"}};
238 
239 std::unordered_map<std::string, ChecksumType>
240     OptionsHelper::checksum_type_string_map = {{"kNoChecksum", kNoChecksum},
241                                                {"kCRC32c", kCRC32c},
242                                                {"kxxHash", kxxHash},
243                                                {"kxxHash64", kxxHash64}};
244 
245 std::unordered_map<std::string, CompressionType>
246     OptionsHelper::compression_type_string_map = {
247         {"kNoCompression", kNoCompression},
248         {"kSnappyCompression", kSnappyCompression},
249         {"kZlibCompression", kZlibCompression},
250         {"kBZip2Compression", kBZip2Compression},
251         {"kLZ4Compression", kLZ4Compression},
252         {"kLZ4HCCompression", kLZ4HCCompression},
253         {"kXpressCompression", kXpressCompression},
254         {"kZSTD", kZSTD},
255         {"kZSTDNotFinalCompression", kZSTDNotFinalCompression},
256         {"kDisableCompressionOption", kDisableCompressionOption}};
257 #ifndef ROCKSDB_LITE
258 
259 const std::string kNameComparator = "comparator";
260 const std::string kNameEnv = "env";
261 const std::string kNameMergeOperator = "merge_operator";
262 
263 template <typename T>
264 Status GetStringFromStruct(
265     std::string* opt_string, const T& options,
266     const std::unordered_map<std::string, OptionTypeInfo>& type_info,
267     const std::string& delimiter);
268 
269 namespace {
270 template <typename T>
ParseEnum(const std::unordered_map<std::string,T> & type_map,const std::string & type,T * value)271 bool ParseEnum(const std::unordered_map<std::string, T>& type_map,
272                const std::string& type, T* value) {
273   auto iter = type_map.find(type);
274   if (iter != type_map.end()) {
275     *value = iter->second;
276     return true;
277   }
278   return false;
279 }
280 
281 template <typename T>
SerializeEnum(const std::unordered_map<std::string,T> & type_map,const T & type,std::string * value)282 bool SerializeEnum(const std::unordered_map<std::string, T>& type_map,
283                    const T& type, std::string* value) {
284   for (const auto& pair : type_map) {
285     if (pair.second == type) {
286       *value = pair.first;
287       return true;
288     }
289   }
290   return false;
291 }
292 
SerializeVectorCompressionType(const std::vector<CompressionType> & types,std::string * value)293 bool SerializeVectorCompressionType(const std::vector<CompressionType>& types,
294                                     std::string* value) {
295   std::stringstream ss;
296   bool result;
297   for (size_t i = 0; i < types.size(); ++i) {
298     if (i > 0) {
299       ss << ':';
300     }
301     std::string string_type;
302     result = SerializeEnum<CompressionType>(compression_type_string_map,
303                                             types[i], &string_type);
304     if (result == false) {
305       return result;
306     }
307     ss << string_type;
308   }
309   *value = ss.str();
310   return true;
311 }
312 
ParseVectorCompressionType(const std::string & value,std::vector<CompressionType> * compression_per_level)313 bool ParseVectorCompressionType(
314     const std::string& value,
315     std::vector<CompressionType>* compression_per_level) {
316   compression_per_level->clear();
317   size_t start = 0;
318   while (start < value.size()) {
319     size_t end = value.find(':', start);
320     bool is_ok;
321     CompressionType type;
322     if (end == std::string::npos) {
323       is_ok = ParseEnum<CompressionType>(compression_type_string_map,
324                                          value.substr(start), &type);
325       if (!is_ok) {
326         return false;
327       }
328       compression_per_level->emplace_back(type);
329       break;
330     } else {
331       is_ok = ParseEnum<CompressionType>(
332           compression_type_string_map, value.substr(start, end - start), &type);
333       if (!is_ok) {
334         return false;
335       }
336       compression_per_level->emplace_back(type);
337       start = end + 1;
338     }
339   }
340   return true;
341 }
342 
343 // This is to handle backward compatibility, where compaction_options_fifo
344 // could be assigned a single scalar value, say, like "23", which would be
345 // assigned to max_table_files_size.
FIFOCompactionOptionsSpecialCase(const std::string & opt_str,CompactionOptionsFIFO * options)346 bool FIFOCompactionOptionsSpecialCase(const std::string& opt_str,
347                                       CompactionOptionsFIFO* options) {
348   if (opt_str.find("=") != std::string::npos) {
349     // New format. Go do your new parsing using ParseStructOptions.
350     return false;
351   }
352 
353   // Old format. Parse just a single uint64_t value.
354   options->max_table_files_size = ParseUint64(opt_str);
355   return true;
356 }
357 
358 template <typename T>
SerializeStruct(const T & options,std::string * value,const std::unordered_map<std::string,OptionTypeInfo> & type_info_map)359 bool SerializeStruct(
360     const T& options, std::string* value,
361     const std::unordered_map<std::string, OptionTypeInfo>& type_info_map) {
362   std::string opt_str;
363   Status s = GetStringFromStruct(&opt_str, options, type_info_map, ";");
364   if (!s.ok()) {
365     return false;
366   }
367   *value = "{" + opt_str + "}";
368   return true;
369 }
370 
371 template <typename T>
ParseSingleStructOption(const std::string & opt_val_str,T * options,const std::unordered_map<std::string,OptionTypeInfo> & type_info_map)372 bool ParseSingleStructOption(
373     const std::string& opt_val_str, T* options,
374     const std::unordered_map<std::string, OptionTypeInfo>& type_info_map) {
375   size_t end = opt_val_str.find('=');
376   std::string key = opt_val_str.substr(0, end);
377   std::string value = opt_val_str.substr(end + 1);
378   auto iter = type_info_map.find(key);
379   if (iter == type_info_map.end()) {
380     return false;
381   }
382   const auto& opt_info = iter->second;
383   if (opt_info.verification == OptionVerificationType::kDeprecated) {
384     // Should also skip deprecated sub-options such as
385     // fifo_compaction_options_type_info.ttl
386     return true;
387   }
388   return ParseOptionHelper(
389       reinterpret_cast<char*>(options) + opt_info.mutable_offset, opt_info.type,
390       value);
391 }
392 
393 template <typename T>
ParseStructOptions(const std::string & opt_str,T * options,const std::unordered_map<std::string,OptionTypeInfo> & type_info_map)394 bool ParseStructOptions(
395     const std::string& opt_str, T* options,
396     const std::unordered_map<std::string, OptionTypeInfo>& type_info_map) {
397   assert(!opt_str.empty());
398 
399   size_t start = 0;
400   if (opt_str[0] == '{') {
401     start++;
402   }
403   while ((start != std::string::npos) && (start < opt_str.size())) {
404     if (opt_str[start] == '}') {
405       break;
406     }
407     size_t end = opt_str.find(';', start);
408     size_t len = (end == std::string::npos) ? end : end - start;
409     if (!ParseSingleStructOption(opt_str.substr(start, len), options,
410                                  type_info_map)) {
411       return false;
412     }
413     start = (end == std::string::npos) ? end : end + 1;
414   }
415   return true;
416 }
417 }  // anonymouse namespace
418 
ParseSliceTransformHelper(const std::string & kFixedPrefixName,const std::string & kCappedPrefixName,const std::string & value,std::shared_ptr<const SliceTransform> * slice_transform)419 bool ParseSliceTransformHelper(
420     const std::string& kFixedPrefixName, const std::string& kCappedPrefixName,
421     const std::string& value,
422     std::shared_ptr<const SliceTransform>* slice_transform) {
423   const char* no_op_name = "rocksdb.Noop";
424   size_t no_op_length = strlen(no_op_name);
425   auto& pe_value = value;
426   if (pe_value.size() > kFixedPrefixName.size() &&
427       pe_value.compare(0, kFixedPrefixName.size(), kFixedPrefixName) == 0) {
428     int prefix_length = ParseInt(trim(value.substr(kFixedPrefixName.size())));
429     slice_transform->reset(NewFixedPrefixTransform(prefix_length));
430   } else if (pe_value.size() > kCappedPrefixName.size() &&
431              pe_value.compare(0, kCappedPrefixName.size(), kCappedPrefixName) ==
432                  0) {
433     int prefix_length =
434         ParseInt(trim(pe_value.substr(kCappedPrefixName.size())));
435     slice_transform->reset(NewCappedPrefixTransform(prefix_length));
436   } else if (pe_value.size() == no_op_length &&
437              pe_value.compare(0, no_op_length, no_op_name) == 0) {
438     const SliceTransform* no_op_transform = NewNoopTransform();
439     slice_transform->reset(no_op_transform);
440   } else if (value == kNullptrString) {
441     slice_transform->reset();
442   } else {
443     return false;
444   }
445 
446   return true;
447 }
448 
ParseSliceTransform(const std::string & value,std::shared_ptr<const SliceTransform> * slice_transform)449 bool ParseSliceTransform(
450     const std::string& value,
451     std::shared_ptr<const SliceTransform>* slice_transform) {
452   // While we normally don't convert the string representation of a
453   // pointer-typed option into its instance, here we do so for backward
454   // compatibility as we allow this action in SetOption().
455 
456   // TODO(yhchiang): A possible better place for these serialization /
457   // deserialization is inside the class definition of pointer-typed
458   // option itself, but this requires a bigger change of public API.
459   bool result =
460       ParseSliceTransformHelper("fixed:", "capped:", value, slice_transform);
461   if (result) {
462     return result;
463   }
464   result = ParseSliceTransformHelper(
465       "rocksdb.FixedPrefix.", "rocksdb.CappedPrefix.", value, slice_transform);
466   if (result) {
467     return result;
468   }
469   // TODO(yhchiang): we can further support other default
470   //                 SliceTransforms here.
471   return false;
472 }
473 
ParseOptionHelper(char * opt_address,const OptionType & opt_type,const std::string & value)474 bool ParseOptionHelper(char* opt_address, const OptionType& opt_type,
475                        const std::string& value) {
476   switch (opt_type) {
477     case OptionType::kBoolean:
478       *reinterpret_cast<bool*>(opt_address) = ParseBoolean("", value);
479       break;
480     case OptionType::kInt:
481       *reinterpret_cast<int*>(opt_address) = ParseInt(value);
482       break;
483     case OptionType::kInt32T:
484       *reinterpret_cast<int32_t*>(opt_address) = ParseInt32(value);
485       break;
486     case OptionType::kInt64T:
487       PutUnaligned(reinterpret_cast<int64_t*>(opt_address), ParseInt64(value));
488       break;
489     case OptionType::kVectorInt:
490       *reinterpret_cast<std::vector<int>*>(opt_address) = ParseVectorInt(value);
491       break;
492     case OptionType::kUInt:
493       *reinterpret_cast<unsigned int*>(opt_address) = ParseUint32(value);
494       break;
495     case OptionType::kUInt32T:
496       *reinterpret_cast<uint32_t*>(opt_address) = ParseUint32(value);
497       break;
498     case OptionType::kUInt64T:
499       PutUnaligned(reinterpret_cast<uint64_t*>(opt_address), ParseUint64(value));
500       break;
501     case OptionType::kSizeT:
502       PutUnaligned(reinterpret_cast<size_t*>(opt_address), ParseSizeT(value));
503       break;
504     case OptionType::kString:
505       *reinterpret_cast<std::string*>(opt_address) = value;
506       break;
507     case OptionType::kDouble:
508       *reinterpret_cast<double*>(opt_address) = ParseDouble(value);
509       break;
510     case OptionType::kCompactionStyle:
511       return ParseEnum<CompactionStyle>(
512           compaction_style_string_map, value,
513           reinterpret_cast<CompactionStyle*>(opt_address));
514     case OptionType::kCompactionPri:
515       return ParseEnum<CompactionPri>(
516           compaction_pri_string_map, value,
517           reinterpret_cast<CompactionPri*>(opt_address));
518     case OptionType::kCompressionType:
519       return ParseEnum<CompressionType>(
520           compression_type_string_map, value,
521           reinterpret_cast<CompressionType*>(opt_address));
522     case OptionType::kVectorCompressionType:
523       return ParseVectorCompressionType(
524           value, reinterpret_cast<std::vector<CompressionType>*>(opt_address));
525     case OptionType::kSliceTransform:
526       return ParseSliceTransform(
527           value, reinterpret_cast<std::shared_ptr<const SliceTransform>*>(
528                      opt_address));
529     case OptionType::kChecksumType:
530       return ParseEnum<ChecksumType>(
531           checksum_type_string_map, value,
532           reinterpret_cast<ChecksumType*>(opt_address));
533     case OptionType::kBlockBasedTableIndexType:
534       return ParseEnum<BlockBasedTableOptions::IndexType>(
535           block_base_table_index_type_string_map, value,
536           reinterpret_cast<BlockBasedTableOptions::IndexType*>(opt_address));
537     case OptionType::kBlockBasedTableDataBlockIndexType:
538       return ParseEnum<BlockBasedTableOptions::DataBlockIndexType>(
539           block_base_table_data_block_index_type_string_map, value,
540           reinterpret_cast<BlockBasedTableOptions::DataBlockIndexType*>(
541               opt_address));
542     case OptionType::kBlockBasedTableIndexShorteningMode:
543       return ParseEnum<BlockBasedTableOptions::IndexShorteningMode>(
544           block_base_table_index_shortening_mode_string_map, value,
545           reinterpret_cast<BlockBasedTableOptions::IndexShorteningMode*>(
546               opt_address));
547     case OptionType::kEncodingType:
548       return ParseEnum<EncodingType>(
549           encoding_type_string_map, value,
550           reinterpret_cast<EncodingType*>(opt_address));
551     case OptionType::kWALRecoveryMode:
552       return ParseEnum<WALRecoveryMode>(
553           wal_recovery_mode_string_map, value,
554           reinterpret_cast<WALRecoveryMode*>(opt_address));
555     case OptionType::kAccessHint:
556       return ParseEnum<DBOptions::AccessHint>(
557           access_hint_string_map, value,
558           reinterpret_cast<DBOptions::AccessHint*>(opt_address));
559     case OptionType::kInfoLogLevel:
560       return ParseEnum<InfoLogLevel>(
561           info_log_level_string_map, value,
562           reinterpret_cast<InfoLogLevel*>(opt_address));
563     case OptionType::kCompactionOptionsFIFO: {
564       if (!FIFOCompactionOptionsSpecialCase(
565               value, reinterpret_cast<CompactionOptionsFIFO*>(opt_address))) {
566         return ParseStructOptions<CompactionOptionsFIFO>(
567             value, reinterpret_cast<CompactionOptionsFIFO*>(opt_address),
568             fifo_compaction_options_type_info);
569       }
570       return true;
571     }
572     case OptionType::kLRUCacheOptions: {
573       return ParseStructOptions<LRUCacheOptions>(value,
574           reinterpret_cast<LRUCacheOptions*>(opt_address),
575           lru_cache_options_type_info);
576     }
577     case OptionType::kCompactionOptionsUniversal:
578       return ParseStructOptions<CompactionOptionsUniversal>(
579           value, reinterpret_cast<CompactionOptionsUniversal*>(opt_address),
580           universal_compaction_options_type_info);
581     case OptionType::kCompactionStopStyle:
582       return ParseEnum<CompactionStopStyle>(
583           compaction_stop_style_string_map, value,
584           reinterpret_cast<CompactionStopStyle*>(opt_address));
585     default:
586       return false;
587   }
588   return true;
589 }
590 
SerializeSingleOptionHelper(const char * opt_address,const OptionType opt_type,std::string * value)591 bool SerializeSingleOptionHelper(const char* opt_address,
592                                  const OptionType opt_type,
593                                  std::string* value) {
594 
595   assert(value);
596   switch (opt_type) {
597     case OptionType::kBoolean:
598       *value = *(reinterpret_cast<const bool*>(opt_address)) ? "true" : "false";
599       break;
600     case OptionType::kInt:
601       *value = ToString(*(reinterpret_cast<const int*>(opt_address)));
602       break;
603     case OptionType::kInt32T:
604       *value = ToString(*(reinterpret_cast<const int32_t*>(opt_address)));
605       break;
606     case OptionType::kInt64T:
607       {
608         int64_t v;
609         GetUnaligned(reinterpret_cast<const int64_t*>(opt_address), &v);
610         *value = ToString(v);
611       }
612       break;
613     case OptionType::kVectorInt:
614       return SerializeIntVector(
615           *reinterpret_cast<const std::vector<int>*>(opt_address), value);
616     case OptionType::kUInt:
617       *value = ToString(*(reinterpret_cast<const unsigned int*>(opt_address)));
618       break;
619     case OptionType::kUInt32T:
620       *value = ToString(*(reinterpret_cast<const uint32_t*>(opt_address)));
621       break;
622     case OptionType::kUInt64T:
623       {
624         uint64_t v;
625         GetUnaligned(reinterpret_cast<const uint64_t*>(opt_address), &v);
626         *value = ToString(v);
627       }
628       break;
629     case OptionType::kSizeT:
630       {
631         size_t v;
632         GetUnaligned(reinterpret_cast<const size_t*>(opt_address), &v);
633         *value = ToString(v);
634       }
635       break;
636     case OptionType::kDouble:
637       *value = ToString(*(reinterpret_cast<const double*>(opt_address)));
638       break;
639     case OptionType::kString:
640       *value = EscapeOptionString(
641           *(reinterpret_cast<const std::string*>(opt_address)));
642       break;
643     case OptionType::kCompactionStyle:
644       return SerializeEnum<CompactionStyle>(
645           compaction_style_string_map,
646           *(reinterpret_cast<const CompactionStyle*>(opt_address)), value);
647     case OptionType::kCompactionPri:
648       return SerializeEnum<CompactionPri>(
649           compaction_pri_string_map,
650           *(reinterpret_cast<const CompactionPri*>(opt_address)), value);
651     case OptionType::kCompressionType:
652       return SerializeEnum<CompressionType>(
653           compression_type_string_map,
654           *(reinterpret_cast<const CompressionType*>(opt_address)), value);
655     case OptionType::kVectorCompressionType:
656       return SerializeVectorCompressionType(
657           *(reinterpret_cast<const std::vector<CompressionType>*>(opt_address)),
658           value);
659       break;
660     case OptionType::kSliceTransform: {
661       const auto* slice_transform_ptr =
662           reinterpret_cast<const std::shared_ptr<const SliceTransform>*>(
663               opt_address);
664       *value = slice_transform_ptr->get() ? slice_transform_ptr->get()->Name()
665                                           : kNullptrString;
666       break;
667     }
668     case OptionType::kTableFactory: {
669       const auto* table_factory_ptr =
670           reinterpret_cast<const std::shared_ptr<const TableFactory>*>(
671               opt_address);
672       *value = table_factory_ptr->get() ? table_factory_ptr->get()->Name()
673                                         : kNullptrString;
674       break;
675     }
676     case OptionType::kComparator: {
677       // it's a const pointer of const Comparator*
678       const auto* ptr = reinterpret_cast<const Comparator* const*>(opt_address);
679       // Since the user-specified comparator will be wrapped by
680       // InternalKeyComparator, we should persist the user-specified one
681       // instead of InternalKeyComparator.
682       if (*ptr == nullptr) {
683         *value = kNullptrString;
684       } else {
685         const Comparator* root_comp = (*ptr)->GetRootComparator();
686         if (root_comp == nullptr) {
687           root_comp = (*ptr);
688         }
689         *value = root_comp->Name();
690       }
691       break;
692     }
693     case OptionType::kCompactionFilter: {
694       // it's a const pointer of const CompactionFilter*
695       const auto* ptr =
696           reinterpret_cast<const CompactionFilter* const*>(opt_address);
697       *value = *ptr ? (*ptr)->Name() : kNullptrString;
698       break;
699     }
700     case OptionType::kCompactionFilterFactory: {
701       const auto* ptr =
702           reinterpret_cast<const std::shared_ptr<CompactionFilterFactory>*>(
703               opt_address);
704       *value = ptr->get() ? ptr->get()->Name() : kNullptrString;
705       break;
706     }
707     case OptionType::kMemTableRepFactory: {
708       const auto* ptr =
709           reinterpret_cast<const std::shared_ptr<MemTableRepFactory>*>(
710               opt_address);
711       *value = ptr->get() ? ptr->get()->Name() : kNullptrString;
712       break;
713     }
714     case OptionType::kMergeOperator: {
715       const auto* ptr =
716           reinterpret_cast<const std::shared_ptr<MergeOperator>*>(opt_address);
717       *value = ptr->get() ? ptr->get()->Name() : kNullptrString;
718       break;
719     }
720     case OptionType::kFilterPolicy: {
721       const auto* ptr =
722           reinterpret_cast<const std::shared_ptr<FilterPolicy>*>(opt_address);
723       *value = ptr->get() ? ptr->get()->Name() : kNullptrString;
724       break;
725     }
726     case OptionType::kChecksumType:
727       return SerializeEnum<ChecksumType>(
728           checksum_type_string_map,
729           *reinterpret_cast<const ChecksumType*>(opt_address), value);
730     case OptionType::kBlockBasedTableIndexType:
731       return SerializeEnum<BlockBasedTableOptions::IndexType>(
732           block_base_table_index_type_string_map,
733           *reinterpret_cast<const BlockBasedTableOptions::IndexType*>(
734               opt_address),
735           value);
736     case OptionType::kBlockBasedTableDataBlockIndexType:
737       return SerializeEnum<BlockBasedTableOptions::DataBlockIndexType>(
738           block_base_table_data_block_index_type_string_map,
739           *reinterpret_cast<const BlockBasedTableOptions::DataBlockIndexType*>(
740               opt_address),
741           value);
742     case OptionType::kBlockBasedTableIndexShorteningMode:
743       return SerializeEnum<BlockBasedTableOptions::IndexShorteningMode>(
744           block_base_table_index_shortening_mode_string_map,
745           *reinterpret_cast<const BlockBasedTableOptions::IndexShorteningMode*>(
746               opt_address),
747           value);
748     case OptionType::kFlushBlockPolicyFactory: {
749       const auto* ptr =
750           reinterpret_cast<const std::shared_ptr<FlushBlockPolicyFactory>*>(
751               opt_address);
752       *value = ptr->get() ? ptr->get()->Name() : kNullptrString;
753       break;
754     }
755     case OptionType::kEncodingType:
756       return SerializeEnum<EncodingType>(
757           encoding_type_string_map,
758           *reinterpret_cast<const EncodingType*>(opt_address), value);
759     case OptionType::kWALRecoveryMode:
760       return SerializeEnum<WALRecoveryMode>(
761           wal_recovery_mode_string_map,
762           *reinterpret_cast<const WALRecoveryMode*>(opt_address), value);
763     case OptionType::kAccessHint:
764       return SerializeEnum<DBOptions::AccessHint>(
765           access_hint_string_map,
766           *reinterpret_cast<const DBOptions::AccessHint*>(opt_address), value);
767     case OptionType::kInfoLogLevel:
768       return SerializeEnum<InfoLogLevel>(
769           info_log_level_string_map,
770           *reinterpret_cast<const InfoLogLevel*>(opt_address), value);
771     case OptionType::kCompactionOptionsFIFO:
772       return SerializeStruct<CompactionOptionsFIFO>(
773           *reinterpret_cast<const CompactionOptionsFIFO*>(opt_address), value,
774           fifo_compaction_options_type_info);
775     case OptionType::kCompactionOptionsUniversal:
776       return SerializeStruct<CompactionOptionsUniversal>(
777           *reinterpret_cast<const CompactionOptionsUniversal*>(opt_address),
778           value, universal_compaction_options_type_info);
779     case OptionType::kCompactionStopStyle:
780       return SerializeEnum<CompactionStopStyle>(
781           compaction_stop_style_string_map,
782           *reinterpret_cast<const CompactionStopStyle*>(opt_address), value);
783     default:
784       return false;
785   }
786   return true;
787 }
788 
GetMutableOptionsFromStrings(const MutableCFOptions & base_options,const std::unordered_map<std::string,std::string> & options_map,Logger * info_log,MutableCFOptions * new_options)789 Status GetMutableOptionsFromStrings(
790     const MutableCFOptions& base_options,
791     const std::unordered_map<std::string, std::string>& options_map,
792     Logger* info_log, MutableCFOptions* new_options) {
793   assert(new_options);
794   *new_options = base_options;
795   for (const auto& o : options_map) {
796     try {
797       auto iter = cf_options_type_info.find(o.first);
798       if (iter == cf_options_type_info.end()) {
799         return Status::InvalidArgument("Unrecognized option: " + o.first);
800       }
801       const auto& opt_info = iter->second;
802       if (!opt_info.is_mutable) {
803         return Status::InvalidArgument("Option not changeable: " + o.first);
804       }
805       if (opt_info.verification == OptionVerificationType::kDeprecated) {
806         // log warning when user tries to set a deprecated option but don't fail
807         // the call for compatibility.
808         ROCKS_LOG_WARN(info_log, "%s is a deprecated option and cannot be set",
809                        o.first.c_str());
810         continue;
811       }
812       bool is_ok = ParseOptionHelper(
813           reinterpret_cast<char*>(new_options) + opt_info.mutable_offset,
814           opt_info.type, o.second);
815       if (!is_ok) {
816         return Status::InvalidArgument("Error parsing " + o.first);
817       }
818     } catch (std::exception& e) {
819       return Status::InvalidArgument("Error parsing " + o.first + ":" +
820                                      std::string(e.what()));
821     }
822   }
823   return Status::OK();
824 }
825 
GetMutableDBOptionsFromStrings(const MutableDBOptions & base_options,const std::unordered_map<std::string,std::string> & options_map,MutableDBOptions * new_options)826 Status GetMutableDBOptionsFromStrings(
827     const MutableDBOptions& base_options,
828     const std::unordered_map<std::string, std::string>& options_map,
829     MutableDBOptions* new_options) {
830   assert(new_options);
831   *new_options = base_options;
832   for (const auto& o : options_map) {
833     try {
834       auto iter = db_options_type_info.find(o.first);
835       if (iter == db_options_type_info.end()) {
836         return Status::InvalidArgument("Unrecognized option: " + o.first);
837       }
838       const auto& opt_info = iter->second;
839       if (!opt_info.is_mutable) {
840         return Status::InvalidArgument("Option not changeable: " + o.first);
841       }
842       bool is_ok = ParseOptionHelper(
843           reinterpret_cast<char*>(new_options) + opt_info.mutable_offset,
844           opt_info.type, o.second);
845       if (!is_ok) {
846         return Status::InvalidArgument("Error parsing " + o.first);
847       }
848     } catch (std::exception& e) {
849       return Status::InvalidArgument("Error parsing " + o.first + ":" +
850                                      std::string(e.what()));
851     }
852   }
853   return Status::OK();
854 }
855 
StringToMap(const std::string & opts_str,std::unordered_map<std::string,std::string> * opts_map)856 Status StringToMap(const std::string& opts_str,
857                    std::unordered_map<std::string, std::string>* opts_map) {
858   assert(opts_map);
859   // Example:
860   //   opts_str = "write_buffer_size=1024;max_write_buffer_number=2;"
861   //              "nested_opt={opt1=1;opt2=2};max_bytes_for_level_base=100"
862   size_t pos = 0;
863   std::string opts = trim(opts_str);
864   while (pos < opts.size()) {
865     size_t eq_pos = opts.find('=', pos);
866     if (eq_pos == std::string::npos) {
867       return Status::InvalidArgument("Mismatched key value pair, '=' expected");
868     }
869     std::string key = trim(opts.substr(pos, eq_pos - pos));
870     if (key.empty()) {
871       return Status::InvalidArgument("Empty key found");
872     }
873 
874     // skip space after '=' and look for '{' for possible nested options
875     pos = eq_pos + 1;
876     while (pos < opts.size() && isspace(opts[pos])) {
877       ++pos;
878     }
879     // Empty value at the end
880     if (pos >= opts.size()) {
881       (*opts_map)[key] = "";
882       break;
883     }
884     if (opts[pos] == '{') {
885       int count = 1;
886       size_t brace_pos = pos + 1;
887       while (brace_pos < opts.size()) {
888         if (opts[brace_pos] == '{') {
889           ++count;
890         } else if (opts[brace_pos] == '}') {
891           --count;
892           if (count == 0) {
893             break;
894           }
895         }
896         ++brace_pos;
897       }
898       // found the matching closing brace
899       if (count == 0) {
900         (*opts_map)[key] = trim(opts.substr(pos + 1, brace_pos - pos - 1));
901         // skip all whitespace and move to the next ';'
902         // brace_pos points to the next position after the matching '}'
903         pos = brace_pos + 1;
904         while (pos < opts.size() && isspace(opts[pos])) {
905           ++pos;
906         }
907         if (pos < opts.size() && opts[pos] != ';') {
908           return Status::InvalidArgument(
909               "Unexpected chars after nested options");
910         }
911         ++pos;
912       } else {
913         return Status::InvalidArgument(
914             "Mismatched curly braces for nested options");
915       }
916     } else {
917       size_t sc_pos = opts.find(';', pos);
918       if (sc_pos == std::string::npos) {
919         (*opts_map)[key] = trim(opts.substr(pos));
920         // It either ends with a trailing semi-colon or the last key-value pair
921         break;
922       } else {
923         (*opts_map)[key] = trim(opts.substr(pos, sc_pos - pos));
924       }
925       pos = sc_pos + 1;
926     }
927   }
928 
929   return Status::OK();
930 }
931 
ParseCompressionOptions(const std::string & value,const std::string & name,CompressionOptions & compression_opts)932 Status ParseCompressionOptions(const std::string& value, const std::string& name,
933                               CompressionOptions& compression_opts) {
934   size_t start = 0;
935   size_t end = value.find(':');
936   if (end == std::string::npos) {
937     return Status::InvalidArgument("unable to parse the specified CF option " +
938                                    name);
939   }
940   compression_opts.window_bits = ParseInt(value.substr(start, end - start));
941   start = end + 1;
942   end = value.find(':', start);
943   if (end == std::string::npos) {
944     return Status::InvalidArgument("unable to parse the specified CF option " +
945                                    name);
946   }
947   compression_opts.level = ParseInt(value.substr(start, end - start));
948   start = end + 1;
949   if (start >= value.size()) {
950     return Status::InvalidArgument("unable to parse the specified CF option " +
951                                    name);
952   }
953   end = value.find(':', start);
954   compression_opts.strategy =
955       ParseInt(value.substr(start, value.size() - start));
956   // max_dict_bytes is optional for backwards compatibility
957   if (end != std::string::npos) {
958     start = end + 1;
959     if (start >= value.size()) {
960       return Status::InvalidArgument(
961           "unable to parse the specified CF option " + name);
962     }
963     compression_opts.max_dict_bytes =
964         ParseInt(value.substr(start, value.size() - start));
965     end = value.find(':', start);
966   }
967   // zstd_max_train_bytes is optional for backwards compatibility
968   if (end != std::string::npos) {
969     start = end + 1;
970     if (start >= value.size()) {
971       return Status::InvalidArgument(
972           "unable to parse the specified CF option " + name);
973     }
974     compression_opts.zstd_max_train_bytes =
975         ParseInt(value.substr(start, value.size() - start));
976     end = value.find(':', start);
977   }
978   // enabled is optional for backwards compatibility
979   if (end != std::string::npos) {
980     start = end + 1;
981     if (start >= value.size()) {
982       return Status::InvalidArgument(
983           "unable to parse the specified CF option " + name);
984     }
985     compression_opts.enabled =
986         ParseBoolean("", value.substr(start, value.size() - start));
987   }
988   return Status::OK();
989 }
990 
ParseColumnFamilyOption(const std::string & name,const std::string & org_value,ColumnFamilyOptions * new_options,bool input_strings_escaped=false)991 Status ParseColumnFamilyOption(const std::string& name,
992                                const std::string& org_value,
993                                ColumnFamilyOptions* new_options,
994                                bool input_strings_escaped = false) {
995   const std::string& value =
996       input_strings_escaped ? UnescapeOptionString(org_value) : org_value;
997   try {
998     if (name == "block_based_table_factory") {
999       // Nested options
1000       BlockBasedTableOptions table_opt, base_table_options;
1001       BlockBasedTableFactory* block_based_table_factory =
1002           static_cast_with_check<BlockBasedTableFactory, TableFactory>(
1003               new_options->table_factory.get());
1004       if (block_based_table_factory != nullptr) {
1005         base_table_options = block_based_table_factory->table_options();
1006       }
1007       Status table_opt_s = GetBlockBasedTableOptionsFromString(
1008           base_table_options, value, &table_opt);
1009       if (!table_opt_s.ok()) {
1010         return Status::InvalidArgument(
1011             "unable to parse the specified CF option " + name);
1012       }
1013       new_options->table_factory.reset(NewBlockBasedTableFactory(table_opt));
1014     } else if (name == "plain_table_factory") {
1015       // Nested options
1016       PlainTableOptions table_opt, base_table_options;
1017       PlainTableFactory* plain_table_factory =
1018           static_cast_with_check<PlainTableFactory, TableFactory>(
1019               new_options->table_factory.get());
1020       if (plain_table_factory != nullptr) {
1021         base_table_options = plain_table_factory->table_options();
1022       }
1023       Status table_opt_s = GetPlainTableOptionsFromString(
1024           base_table_options, value, &table_opt);
1025       if (!table_opt_s.ok()) {
1026         return Status::InvalidArgument(
1027             "unable to parse the specified CF option " + name);
1028       }
1029       new_options->table_factory.reset(NewPlainTableFactory(table_opt));
1030     } else if (name == "memtable") {
1031       std::unique_ptr<MemTableRepFactory> new_mem_factory;
1032       Status mem_factory_s =
1033           GetMemTableRepFactoryFromString(value, &new_mem_factory);
1034       if (!mem_factory_s.ok()) {
1035         return Status::InvalidArgument(
1036             "unable to parse the specified CF option " + name);
1037       }
1038       new_options->memtable_factory.reset(new_mem_factory.release());
1039     } else if (name == "bottommost_compression_opts") {
1040       Status s = ParseCompressionOptions(
1041           value, name, new_options->bottommost_compression_opts);
1042       if (!s.ok()) {
1043         return s;
1044       }
1045     } else if (name == "compression_opts") {
1046       Status s =
1047           ParseCompressionOptions(value, name, new_options->compression_opts);
1048       if (!s.ok()) {
1049         return s;
1050       }
1051     } else {
1052       if (name == kNameComparator) {
1053         // Try to get comparator from object registry first.
1054         // Only support static comparator for now.
1055         Status status = ObjectRegistry::NewInstance()->NewStaticObject(
1056             value, &new_options->comparator);
1057         if (status.ok()) {
1058           return status;
1059         }
1060       } else if (name == kNameMergeOperator) {
1061         // Try to get merge operator from object registry first.
1062         std::shared_ptr<MergeOperator> mo;
1063         Status status =
1064             ObjectRegistry::NewInstance()->NewSharedObject<MergeOperator>(
1065                 value, &new_options->merge_operator);
1066         // Only support static comparator for now.
1067         if (status.ok()) {
1068           return status;
1069         }
1070       }
1071 
1072       auto iter = cf_options_type_info.find(name);
1073       if (iter == cf_options_type_info.end()) {
1074         return Status::InvalidArgument(
1075             "Unable to parse the specified CF option " + name);
1076       }
1077       const auto& opt_info = iter->second;
1078       if (opt_info.verification != OptionVerificationType::kDeprecated &&
1079           ParseOptionHelper(
1080               reinterpret_cast<char*>(new_options) + opt_info.offset,
1081               opt_info.type, value)) {
1082         return Status::OK();
1083       }
1084       switch (opt_info.verification) {
1085         case OptionVerificationType::kByName:
1086         case OptionVerificationType::kByNameAllowNull:
1087         case OptionVerificationType::kByNameAllowFromNull:
1088           return Status::NotSupported(
1089               "Deserializing the specified CF option " + name +
1090                   " is not supported");
1091         case OptionVerificationType::kDeprecated:
1092           return Status::OK();
1093         default:
1094           return Status::InvalidArgument(
1095               "Unable to parse the specified CF option " + name);
1096       }
1097     }
1098   } catch (const std::exception&) {
1099     return Status::InvalidArgument(
1100         "unable to parse the specified option " + name);
1101   }
1102   return Status::OK();
1103 }
1104 
1105 template <typename T>
SerializeSingleStructOption(std::string * opt_string,const T & options,const std::unordered_map<std::string,OptionTypeInfo> & type_info,const std::string & name,const std::string & delimiter)1106 bool SerializeSingleStructOption(
1107     std::string* opt_string, const T& options,
1108     const std::unordered_map<std::string, OptionTypeInfo>& type_info,
1109     const std::string& name, const std::string& delimiter) {
1110   auto iter = type_info.find(name);
1111   if (iter == type_info.end()) {
1112     return false;
1113   }
1114   auto& opt_info = iter->second;
1115   const char* opt_address =
1116       reinterpret_cast<const char*>(&options) + opt_info.offset;
1117   std::string value;
1118   bool result = SerializeSingleOptionHelper(opt_address, opt_info.type, &value);
1119   if (result) {
1120     *opt_string = name + "=" + value + delimiter;
1121   }
1122   return result;
1123 }
1124 
1125 template <typename T>
GetStringFromStruct(std::string * opt_string,const T & options,const std::unordered_map<std::string,OptionTypeInfo> & type_info,const std::string & delimiter)1126 Status GetStringFromStruct(
1127     std::string* opt_string, const T& options,
1128     const std::unordered_map<std::string, OptionTypeInfo>& type_info,
1129     const std::string& delimiter) {
1130   assert(opt_string);
1131   opt_string->clear();
1132   for (auto iter = type_info.begin(); iter != type_info.end(); ++iter) {
1133     if (iter->second.verification == OptionVerificationType::kDeprecated) {
1134       // If the option is no longer used in rocksdb and marked as deprecated,
1135       // we skip it in the serialization.
1136       continue;
1137     }
1138     std::string single_output;
1139     bool result = SerializeSingleStructOption<T>(
1140         &single_output, options, type_info, iter->first, delimiter);
1141     if (result) {
1142       opt_string->append(single_output);
1143     } else {
1144       return Status::InvalidArgument("failed to serialize %s\n",
1145                                      iter->first.c_str());
1146     }
1147     assert(result);
1148   }
1149   return Status::OK();
1150 }
1151 
GetStringFromDBOptions(std::string * opt_string,const DBOptions & db_options,const std::string & delimiter)1152 Status GetStringFromDBOptions(std::string* opt_string,
1153                               const DBOptions& db_options,
1154                               const std::string& delimiter) {
1155   return GetStringFromStruct<DBOptions>(opt_string, db_options,
1156                                         db_options_type_info, delimiter);
1157 }
1158 
GetStringFromColumnFamilyOptions(std::string * opt_string,const ColumnFamilyOptions & cf_options,const std::string & delimiter)1159 Status GetStringFromColumnFamilyOptions(std::string* opt_string,
1160                                         const ColumnFamilyOptions& cf_options,
1161                                         const std::string& delimiter) {
1162   return GetStringFromStruct<ColumnFamilyOptions>(
1163       opt_string, cf_options, cf_options_type_info, delimiter);
1164 }
1165 
GetStringFromCompressionType(std::string * compression_str,CompressionType compression_type)1166 Status GetStringFromCompressionType(std::string* compression_str,
1167                                     CompressionType compression_type) {
1168   bool ok = SerializeEnum<CompressionType>(compression_type_string_map,
1169                                            compression_type, compression_str);
1170   if (ok) {
1171     return Status::OK();
1172   } else {
1173     return Status::InvalidArgument("Invalid compression types");
1174   }
1175 }
1176 
GetSupportedCompressions()1177 std::vector<CompressionType> GetSupportedCompressions() {
1178   std::vector<CompressionType> supported_compressions;
1179   for (const auto& comp_to_name : compression_type_string_map) {
1180     CompressionType t = comp_to_name.second;
1181     if (t != kDisableCompressionOption && CompressionTypeSupported(t)) {
1182       supported_compressions.push_back(t);
1183     }
1184   }
1185   return supported_compressions;
1186 }
1187 
ParseDBOption(const std::string & name,const std::string & org_value,DBOptions * new_options,bool input_strings_escaped=false)1188 Status ParseDBOption(const std::string& name,
1189                      const std::string& org_value,
1190                      DBOptions* new_options,
1191                      bool input_strings_escaped = false) {
1192   const std::string& value =
1193       input_strings_escaped ? UnescapeOptionString(org_value) : org_value;
1194   try {
1195     if (name == "rate_limiter_bytes_per_sec") {
1196       new_options->rate_limiter.reset(
1197           NewGenericRateLimiter(static_cast<int64_t>(ParseUint64(value))));
1198     } else if (name == kNameEnv) {
1199       // Currently `Env` can be deserialized from object registry only.
1200       Env* env = new_options->env;
1201       Status status = Env::LoadEnv(value, &env);
1202       // Only support static env for now.
1203       if (status.ok()) {
1204         new_options->env = env;
1205       }
1206     } else {
1207       auto iter = db_options_type_info.find(name);
1208       if (iter == db_options_type_info.end()) {
1209         return Status::InvalidArgument("Unrecognized option DBOptions:", name);
1210       }
1211       const auto& opt_info = iter->second;
1212       if (opt_info.verification != OptionVerificationType::kDeprecated &&
1213           ParseOptionHelper(
1214               reinterpret_cast<char*>(new_options) + opt_info.offset,
1215               opt_info.type, value)) {
1216         return Status::OK();
1217       }
1218       switch (opt_info.verification) {
1219         case OptionVerificationType::kByName:
1220         case OptionVerificationType::kByNameAllowNull:
1221           return Status::NotSupported(
1222               "Deserializing the specified DB option " + name +
1223                   " is not supported");
1224         case OptionVerificationType::kDeprecated:
1225           return Status::OK();
1226         default:
1227           return Status::InvalidArgument(
1228               "Unable to parse the specified DB option " + name);
1229       }
1230     }
1231   } catch (const std::exception&) {
1232     return Status::InvalidArgument("Unable to parse DBOptions:", name);
1233   }
1234   return Status::OK();
1235 }
1236 
GetColumnFamilyOptionsFromMap(const ColumnFamilyOptions & base_options,const std::unordered_map<std::string,std::string> & opts_map,ColumnFamilyOptions * new_options,bool input_strings_escaped,bool ignore_unknown_options)1237 Status GetColumnFamilyOptionsFromMap(
1238     const ColumnFamilyOptions& base_options,
1239     const std::unordered_map<std::string, std::string>& opts_map,
1240     ColumnFamilyOptions* new_options, bool input_strings_escaped,
1241     bool ignore_unknown_options) {
1242   return GetColumnFamilyOptionsFromMapInternal(
1243       base_options, opts_map, new_options, input_strings_escaped, nullptr,
1244       ignore_unknown_options);
1245 }
1246 
GetColumnFamilyOptionsFromMapInternal(const ColumnFamilyOptions & base_options,const std::unordered_map<std::string,std::string> & opts_map,ColumnFamilyOptions * new_options,bool input_strings_escaped,std::vector<std::string> * unsupported_options_names,bool ignore_unknown_options)1247 Status GetColumnFamilyOptionsFromMapInternal(
1248     const ColumnFamilyOptions& base_options,
1249     const std::unordered_map<std::string, std::string>& opts_map,
1250     ColumnFamilyOptions* new_options, bool input_strings_escaped,
1251     std::vector<std::string>* unsupported_options_names,
1252     bool ignore_unknown_options) {
1253   assert(new_options);
1254   *new_options = base_options;
1255   if (unsupported_options_names) {
1256     unsupported_options_names->clear();
1257   }
1258   for (const auto& o : opts_map) {
1259     auto s = ParseColumnFamilyOption(o.first, o.second, new_options,
1260                                  input_strings_escaped);
1261     if (!s.ok()) {
1262       if (s.IsNotSupported()) {
1263         // If the deserialization of the specified option is not supported
1264         // and an output vector of unsupported_options is provided, then
1265         // we log the name of the unsupported option and proceed.
1266         if (unsupported_options_names != nullptr) {
1267           unsupported_options_names->push_back(o.first);
1268         }
1269         // Note that we still return Status::OK in such case to maintain
1270         // the backward compatibility in the old public API defined in
1271         // rocksdb/convenience.h
1272       } else if (s.IsInvalidArgument() && ignore_unknown_options) {
1273         continue;
1274       } else {
1275         // Restore "new_options" to the default "base_options".
1276         *new_options = base_options;
1277         return s;
1278       }
1279     }
1280   }
1281   return Status::OK();
1282 }
1283 
GetColumnFamilyOptionsFromString(const ColumnFamilyOptions & base_options,const std::string & opts_str,ColumnFamilyOptions * new_options)1284 Status GetColumnFamilyOptionsFromString(
1285     const ColumnFamilyOptions& base_options,
1286     const std::string& opts_str,
1287     ColumnFamilyOptions* new_options) {
1288   std::unordered_map<std::string, std::string> opts_map;
1289   Status s = StringToMap(opts_str, &opts_map);
1290   if (!s.ok()) {
1291     *new_options = base_options;
1292     return s;
1293   }
1294   return GetColumnFamilyOptionsFromMap(base_options, opts_map, new_options);
1295 }
1296 
GetDBOptionsFromMap(const DBOptions & base_options,const std::unordered_map<std::string,std::string> & opts_map,DBOptions * new_options,bool input_strings_escaped,bool ignore_unknown_options)1297 Status GetDBOptionsFromMap(
1298     const DBOptions& base_options,
1299     const std::unordered_map<std::string, std::string>& opts_map,
1300     DBOptions* new_options, bool input_strings_escaped,
1301     bool ignore_unknown_options) {
1302   return GetDBOptionsFromMapInternal(base_options, opts_map, new_options,
1303                                      input_strings_escaped, nullptr,
1304                                      ignore_unknown_options);
1305 }
1306 
GetDBOptionsFromMapInternal(const DBOptions & base_options,const std::unordered_map<std::string,std::string> & opts_map,DBOptions * new_options,bool input_strings_escaped,std::vector<std::string> * unsupported_options_names,bool ignore_unknown_options)1307 Status GetDBOptionsFromMapInternal(
1308     const DBOptions& base_options,
1309     const std::unordered_map<std::string, std::string>& opts_map,
1310     DBOptions* new_options, bool input_strings_escaped,
1311     std::vector<std::string>* unsupported_options_names,
1312     bool ignore_unknown_options) {
1313   assert(new_options);
1314   *new_options = base_options;
1315   if (unsupported_options_names) {
1316     unsupported_options_names->clear();
1317   }
1318   for (const auto& o : opts_map) {
1319     auto s = ParseDBOption(o.first, o.second,
1320                            new_options, input_strings_escaped);
1321     if (!s.ok()) {
1322       if (s.IsNotSupported()) {
1323         // If the deserialization of the specified option is not supported
1324         // and an output vector of unsupported_options is provided, then
1325         // we log the name of the unsupported option and proceed.
1326         if (unsupported_options_names != nullptr) {
1327           unsupported_options_names->push_back(o.first);
1328         }
1329         // Note that we still return Status::OK in such case to maintain
1330         // the backward compatibility in the old public API defined in
1331         // rocksdb/convenience.h
1332       } else if (s.IsInvalidArgument() && ignore_unknown_options) {
1333         continue;
1334       } else {
1335         // Restore "new_options" to the default "base_options".
1336         *new_options = base_options;
1337         return s;
1338       }
1339     }
1340   }
1341   return Status::OK();
1342 }
1343 
GetDBOptionsFromString(const DBOptions & base_options,const std::string & opts_str,DBOptions * new_options)1344 Status GetDBOptionsFromString(
1345     const DBOptions& base_options,
1346     const std::string& opts_str,
1347     DBOptions* new_options) {
1348   std::unordered_map<std::string, std::string> opts_map;
1349   Status s = StringToMap(opts_str, &opts_map);
1350   if (!s.ok()) {
1351     *new_options = base_options;
1352     return s;
1353   }
1354   return GetDBOptionsFromMap(base_options, opts_map, new_options);
1355 }
1356 
GetOptionsFromString(const Options & base_options,const std::string & opts_str,Options * new_options)1357 Status GetOptionsFromString(const Options& base_options,
1358                             const std::string& opts_str, Options* new_options) {
1359   std::unordered_map<std::string, std::string> opts_map;
1360   Status s = StringToMap(opts_str, &opts_map);
1361   if (!s.ok()) {
1362     return s;
1363   }
1364   DBOptions new_db_options(base_options);
1365   ColumnFamilyOptions new_cf_options(base_options);
1366   for (const auto& o : opts_map) {
1367     if (ParseDBOption(o.first, o.second, &new_db_options).ok()) {
1368     } else if (ParseColumnFamilyOption(
1369         o.first, o.second, &new_cf_options).ok()) {
1370     } else {
1371       return Status::InvalidArgument("Can't parse option " + o.first);
1372     }
1373   }
1374   *new_options = Options(new_db_options, new_cf_options);
1375   return Status::OK();
1376 }
1377 
GetTableFactoryFromMap(const std::string & factory_name,const std::unordered_map<std::string,std::string> & opt_map,std::shared_ptr<TableFactory> * table_factory,bool ignore_unknown_options)1378 Status GetTableFactoryFromMap(
1379     const std::string& factory_name,
1380     const std::unordered_map<std::string, std::string>& opt_map,
1381     std::shared_ptr<TableFactory>* table_factory, bool ignore_unknown_options) {
1382   Status s;
1383   if (factory_name == BlockBasedTableFactory().Name()) {
1384     BlockBasedTableOptions bbt_opt;
1385     s = GetBlockBasedTableOptionsFromMap(BlockBasedTableOptions(), opt_map,
1386                                          &bbt_opt,
1387                                          true, /* input_strings_escaped */
1388                                          ignore_unknown_options);
1389     if (!s.ok()) {
1390       return s;
1391     }
1392     table_factory->reset(new BlockBasedTableFactory(bbt_opt));
1393     return Status::OK();
1394   } else if (factory_name == PlainTableFactory().Name()) {
1395     PlainTableOptions pt_opt;
1396     s = GetPlainTableOptionsFromMap(PlainTableOptions(), opt_map, &pt_opt,
1397                                     true, /* input_strings_escaped */
1398                                     ignore_unknown_options);
1399     if (!s.ok()) {
1400       return s;
1401     }
1402     table_factory->reset(new PlainTableFactory(pt_opt));
1403     return Status::OK();
1404   }
1405   // Return OK for not supported table factories as TableFactory
1406   // Deserialization is optional.
1407   table_factory->reset();
1408   return Status::OK();
1409 }
1410 
1411 std::unordered_map<std::string, OptionTypeInfo>
1412     OptionsHelper::db_options_type_info = {
1413         /*
1414          // not yet supported
1415           std::shared_ptr<Cache> row_cache;
1416           std::shared_ptr<DeleteScheduler> delete_scheduler;
1417           std::shared_ptr<Logger> info_log;
1418           std::shared_ptr<RateLimiter> rate_limiter;
1419           std::shared_ptr<Statistics> statistics;
1420           std::vector<DbPath> db_paths;
1421           std::vector<std::shared_ptr<EventListener>> listeners;
1422          */
1423         {"advise_random_on_open",
1424          {offsetof(struct DBOptions, advise_random_on_open),
1425           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1426         {"allow_mmap_reads",
1427          {offsetof(struct DBOptions, allow_mmap_reads), OptionType::kBoolean,
1428           OptionVerificationType::kNormal, false, 0}},
1429         {"allow_fallocate",
1430          {offsetof(struct DBOptions, allow_fallocate), OptionType::kBoolean,
1431           OptionVerificationType::kNormal, false, 0}},
1432         {"allow_mmap_writes",
1433          {offsetof(struct DBOptions, allow_mmap_writes), OptionType::kBoolean,
1434           OptionVerificationType::kNormal, false, 0}},
1435         {"use_direct_reads",
1436          {offsetof(struct DBOptions, use_direct_reads), OptionType::kBoolean,
1437           OptionVerificationType::kNormal, false, 0}},
1438         {"use_direct_writes",
1439          {0, OptionType::kBoolean, OptionVerificationType::kDeprecated, false,
1440           0}},
1441         {"use_direct_io_for_flush_and_compaction",
1442          {offsetof(struct DBOptions, use_direct_io_for_flush_and_compaction),
1443           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1444         {"allow_2pc",
1445          {offsetof(struct DBOptions, allow_2pc), OptionType::kBoolean,
1446           OptionVerificationType::kNormal, false, 0}},
1447         {"allow_os_buffer",
1448          {0, OptionType::kBoolean, OptionVerificationType::kDeprecated, true,
1449           0}},
1450         {"create_if_missing",
1451          {offsetof(struct DBOptions, create_if_missing), OptionType::kBoolean,
1452           OptionVerificationType::kNormal, false, 0}},
1453         {"create_missing_column_families",
1454          {offsetof(struct DBOptions, create_missing_column_families),
1455           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1456         {"disableDataSync",
1457          {0, OptionType::kBoolean, OptionVerificationType::kDeprecated, false,
1458           0}},
1459         {"disable_data_sync",  // for compatibility
1460          {0, OptionType::kBoolean, OptionVerificationType::kDeprecated, false,
1461           0}},
1462         {"enable_thread_tracking",
1463          {offsetof(struct DBOptions, enable_thread_tracking),
1464           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1465         {"error_if_exists",
1466          {offsetof(struct DBOptions, error_if_exists), OptionType::kBoolean,
1467           OptionVerificationType::kNormal, false, 0}},
1468         {"is_fd_close_on_exec",
1469          {offsetof(struct DBOptions, is_fd_close_on_exec), OptionType::kBoolean,
1470           OptionVerificationType::kNormal, false, 0}},
1471         {"paranoid_checks",
1472          {offsetof(struct DBOptions, paranoid_checks), OptionType::kBoolean,
1473           OptionVerificationType::kNormal, false, 0}},
1474         {"skip_log_error_on_recovery",
1475          {offsetof(struct DBOptions, skip_log_error_on_recovery),
1476           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1477         {"skip_stats_update_on_db_open",
1478          {offsetof(struct DBOptions, skip_stats_update_on_db_open),
1479           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1480         {"skip_checking_sst_file_sizes_on_db_open",
1481          {offsetof(struct DBOptions, skip_checking_sst_file_sizes_on_db_open),
1482           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1483         {"new_table_reader_for_compaction_inputs",
1484          {offsetof(struct DBOptions, new_table_reader_for_compaction_inputs),
1485           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1486         {"compaction_readahead_size",
1487          {offsetof(struct DBOptions, compaction_readahead_size),
1488           OptionType::kSizeT, OptionVerificationType::kNormal, true,
1489           offsetof(struct MutableDBOptions, compaction_readahead_size)}},
1490         {"random_access_max_buffer_size",
1491          {offsetof(struct DBOptions, random_access_max_buffer_size),
1492           OptionType::kSizeT, OptionVerificationType::kNormal, false, 0}},
1493         {"use_adaptive_mutex",
1494          {offsetof(struct DBOptions, use_adaptive_mutex), OptionType::kBoolean,
1495           OptionVerificationType::kNormal, false, 0}},
1496         {"use_fsync",
1497          {offsetof(struct DBOptions, use_fsync), OptionType::kBoolean,
1498           OptionVerificationType::kNormal, false, 0}},
1499         {"max_background_jobs",
1500          {offsetof(struct DBOptions, max_background_jobs), OptionType::kInt,
1501           OptionVerificationType::kNormal, true,
1502           offsetof(struct MutableDBOptions, max_background_jobs)}},
1503         {"max_background_compactions",
1504          {offsetof(struct DBOptions, max_background_compactions),
1505           OptionType::kInt, OptionVerificationType::kNormal, true,
1506           offsetof(struct MutableDBOptions, max_background_compactions)}},
1507         {"base_background_compactions",
1508          {offsetof(struct DBOptions, base_background_compactions),
1509           OptionType::kInt, OptionVerificationType::kNormal, true,
1510           offsetof(struct MutableDBOptions, base_background_compactions)}},
1511         {"max_background_flushes",
1512          {offsetof(struct DBOptions, max_background_flushes), OptionType::kInt,
1513           OptionVerificationType::kNormal, false, 0}},
1514         {"max_file_opening_threads",
1515          {offsetof(struct DBOptions, max_file_opening_threads),
1516           OptionType::kInt, OptionVerificationType::kNormal, false, 0}},
1517         {"max_open_files",
1518          {offsetof(struct DBOptions, max_open_files), OptionType::kInt,
1519           OptionVerificationType::kNormal, true,
1520           offsetof(struct MutableDBOptions, max_open_files)}},
1521         {"table_cache_numshardbits",
1522          {offsetof(struct DBOptions, table_cache_numshardbits),
1523           OptionType::kInt, OptionVerificationType::kNormal, false, 0}},
1524         {"db_write_buffer_size",
1525          {offsetof(struct DBOptions, db_write_buffer_size), OptionType::kSizeT,
1526           OptionVerificationType::kNormal, false, 0}},
1527         {"keep_log_file_num",
1528          {offsetof(struct DBOptions, keep_log_file_num), OptionType::kSizeT,
1529           OptionVerificationType::kNormal, false, 0}},
1530         {"recycle_log_file_num",
1531          {offsetof(struct DBOptions, recycle_log_file_num), OptionType::kSizeT,
1532           OptionVerificationType::kNormal, false, 0}},
1533         {"log_file_time_to_roll",
1534          {offsetof(struct DBOptions, log_file_time_to_roll), OptionType::kSizeT,
1535           OptionVerificationType::kNormal, false, 0}},
1536         {"manifest_preallocation_size",
1537          {offsetof(struct DBOptions, manifest_preallocation_size),
1538           OptionType::kSizeT, OptionVerificationType::kNormal, false, 0}},
1539         {"max_log_file_size",
1540          {offsetof(struct DBOptions, max_log_file_size), OptionType::kSizeT,
1541           OptionVerificationType::kNormal, false, 0}},
1542         {"db_log_dir",
1543          {offsetof(struct DBOptions, db_log_dir), OptionType::kString,
1544           OptionVerificationType::kNormal, false, 0}},
1545         {"wal_dir",
1546          {offsetof(struct DBOptions, wal_dir), OptionType::kString,
1547           OptionVerificationType::kNormal, false, 0}},
1548         {"max_subcompactions",
1549          {offsetof(struct DBOptions, max_subcompactions), OptionType::kUInt32T,
1550           OptionVerificationType::kNormal, false, 0}},
1551         {"WAL_size_limit_MB",
1552          {offsetof(struct DBOptions, WAL_size_limit_MB), OptionType::kUInt64T,
1553           OptionVerificationType::kNormal, false, 0}},
1554         {"WAL_ttl_seconds",
1555          {offsetof(struct DBOptions, WAL_ttl_seconds), OptionType::kUInt64T,
1556           OptionVerificationType::kNormal, false, 0}},
1557         {"bytes_per_sync",
1558          {offsetof(struct DBOptions, bytes_per_sync), OptionType::kUInt64T,
1559           OptionVerificationType::kNormal, true,
1560           offsetof(struct MutableDBOptions, bytes_per_sync)}},
1561         {"delayed_write_rate",
1562          {offsetof(struct DBOptions, delayed_write_rate), OptionType::kUInt64T,
1563           OptionVerificationType::kNormal, true,
1564           offsetof(struct MutableDBOptions, delayed_write_rate)}},
1565         {"delete_obsolete_files_period_micros",
1566          {offsetof(struct DBOptions, delete_obsolete_files_period_micros),
1567           OptionType::kUInt64T, OptionVerificationType::kNormal, true,
1568           offsetof(struct MutableDBOptions,
1569                    delete_obsolete_files_period_micros)}},
1570         {"max_manifest_file_size",
1571          {offsetof(struct DBOptions, max_manifest_file_size),
1572           OptionType::kUInt64T, OptionVerificationType::kNormal, false, 0}},
1573         {"max_total_wal_size",
1574          {offsetof(struct DBOptions, max_total_wal_size), OptionType::kUInt64T,
1575           OptionVerificationType::kNormal, true,
1576           offsetof(struct MutableDBOptions, max_total_wal_size)}},
1577         {"wal_bytes_per_sync",
1578          {offsetof(struct DBOptions, wal_bytes_per_sync), OptionType::kUInt64T,
1579           OptionVerificationType::kNormal, true,
1580           offsetof(struct MutableDBOptions, wal_bytes_per_sync)}},
1581         {"strict_bytes_per_sync",
1582          {offsetof(struct DBOptions, strict_bytes_per_sync),
1583           OptionType::kBoolean, OptionVerificationType::kNormal, true,
1584           offsetof(struct MutableDBOptions, strict_bytes_per_sync)}},
1585         {"stats_dump_period_sec",
1586          {offsetof(struct DBOptions, stats_dump_period_sec), OptionType::kUInt,
1587           OptionVerificationType::kNormal, true,
1588           offsetof(struct MutableDBOptions, stats_dump_period_sec)}},
1589         {"stats_persist_period_sec",
1590          {offsetof(struct DBOptions, stats_persist_period_sec),
1591           OptionType::kUInt, OptionVerificationType::kNormal, true,
1592           offsetof(struct MutableDBOptions, stats_persist_period_sec)}},
1593         {"persist_stats_to_disk",
1594          {offsetof(struct DBOptions, persist_stats_to_disk),
1595           OptionType::kBoolean, OptionVerificationType::kNormal, false,
1596           offsetof(struct ImmutableDBOptions, persist_stats_to_disk)}},
1597         {"stats_history_buffer_size",
1598          {offsetof(struct DBOptions, stats_history_buffer_size),
1599           OptionType::kSizeT, OptionVerificationType::kNormal, true,
1600           offsetof(struct MutableDBOptions, stats_history_buffer_size)}},
1601         {"fail_if_options_file_error",
1602          {offsetof(struct DBOptions, fail_if_options_file_error),
1603           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1604         {"enable_pipelined_write",
1605          {offsetof(struct DBOptions, enable_pipelined_write),
1606           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1607         {"unordered_write",
1608          {offsetof(struct DBOptions, unordered_write), OptionType::kBoolean,
1609           OptionVerificationType::kNormal, false, 0}},
1610         {"allow_concurrent_memtable_write",
1611          {offsetof(struct DBOptions, allow_concurrent_memtable_write),
1612           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1613         {"wal_recovery_mode",
1614          {offsetof(struct DBOptions, wal_recovery_mode),
1615           OptionType::kWALRecoveryMode, OptionVerificationType::kNormal, false,
1616           0}},
1617         {"enable_write_thread_adaptive_yield",
1618          {offsetof(struct DBOptions, enable_write_thread_adaptive_yield),
1619           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1620         {"write_thread_slow_yield_usec",
1621          {offsetof(struct DBOptions, write_thread_slow_yield_usec),
1622           OptionType::kUInt64T, OptionVerificationType::kNormal, false, 0}},
1623         {"max_write_batch_group_size_bytes",
1624          {offsetof(struct DBOptions, max_write_batch_group_size_bytes),
1625           OptionType::kUInt64T, OptionVerificationType::kNormal, false, 0}},
1626         {"write_thread_max_yield_usec",
1627          {offsetof(struct DBOptions, write_thread_max_yield_usec),
1628           OptionType::kUInt64T, OptionVerificationType::kNormal, false, 0}},
1629         {"access_hint_on_compaction_start",
1630          {offsetof(struct DBOptions, access_hint_on_compaction_start),
1631           OptionType::kAccessHint, OptionVerificationType::kNormal, false, 0}},
1632         {"info_log_level",
1633          {offsetof(struct DBOptions, info_log_level), OptionType::kInfoLogLevel,
1634           OptionVerificationType::kNormal, false, 0}},
1635         {"dump_malloc_stats",
1636          {offsetof(struct DBOptions, dump_malloc_stats), OptionType::kBoolean,
1637           OptionVerificationType::kNormal, false, 0}},
1638         {"avoid_flush_during_recovery",
1639          {offsetof(struct DBOptions, avoid_flush_during_recovery),
1640           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1641         {"avoid_flush_during_shutdown",
1642          {offsetof(struct DBOptions, avoid_flush_during_shutdown),
1643           OptionType::kBoolean, OptionVerificationType::kNormal, true,
1644           offsetof(struct MutableDBOptions, avoid_flush_during_shutdown)}},
1645         {"writable_file_max_buffer_size",
1646          {offsetof(struct DBOptions, writable_file_max_buffer_size),
1647           OptionType::kSizeT, OptionVerificationType::kNormal, true,
1648           offsetof(struct MutableDBOptions, writable_file_max_buffer_size)}},
1649         {"allow_ingest_behind",
1650          {offsetof(struct DBOptions, allow_ingest_behind), OptionType::kBoolean,
1651           OptionVerificationType::kNormal, false,
1652           offsetof(struct ImmutableDBOptions, allow_ingest_behind)}},
1653         {"preserve_deletes",
1654          {offsetof(struct DBOptions, preserve_deletes), OptionType::kBoolean,
1655           OptionVerificationType::kNormal, false,
1656           offsetof(struct ImmutableDBOptions, preserve_deletes)}},
1657         {"concurrent_prepare",  // Deprecated by two_write_queues
1658          {0, OptionType::kBoolean, OptionVerificationType::kDeprecated, false,
1659           0}},
1660         {"two_write_queues",
1661          {offsetof(struct DBOptions, two_write_queues), OptionType::kBoolean,
1662           OptionVerificationType::kNormal, false,
1663           offsetof(struct ImmutableDBOptions, two_write_queues)}},
1664         {"manual_wal_flush",
1665          {offsetof(struct DBOptions, manual_wal_flush), OptionType::kBoolean,
1666           OptionVerificationType::kNormal, false,
1667           offsetof(struct ImmutableDBOptions, manual_wal_flush)}},
1668         {"seq_per_batch",
1669          {0, OptionType::kBoolean, OptionVerificationType::kDeprecated, false,
1670           0}},
1671         {"atomic_flush",
1672          {offsetof(struct DBOptions, atomic_flush), OptionType::kBoolean,
1673           OptionVerificationType::kNormal, false,
1674           offsetof(struct ImmutableDBOptions, atomic_flush)}},
1675         {"avoid_unnecessary_blocking_io",
1676          {offsetof(struct DBOptions, avoid_unnecessary_blocking_io),
1677           OptionType::kBoolean, OptionVerificationType::kNormal, false,
1678           offsetof(struct ImmutableDBOptions, avoid_unnecessary_blocking_io)}},
1679         {"write_dbid_to_manifest",
1680          {offsetof(struct DBOptions, write_dbid_to_manifest),
1681           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1682         {"log_readahead_size",
1683          {offsetof(struct DBOptions, log_readahead_size), OptionType::kSizeT,
1684           OptionVerificationType::kNormal, false, 0}},
1685         {"best_efforts_recovery",
1686          {offsetof(struct DBOptions, best_efforts_recovery),
1687           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1688 };
1689 
1690 std::unordered_map<std::string, BlockBasedTableOptions::IndexType>
1691     OptionsHelper::block_base_table_index_type_string_map = {
1692         {"kBinarySearch", BlockBasedTableOptions::IndexType::kBinarySearch},
1693         {"kHashSearch", BlockBasedTableOptions::IndexType::kHashSearch},
1694         {"kTwoLevelIndexSearch",
1695          BlockBasedTableOptions::IndexType::kTwoLevelIndexSearch},
1696         {"kBinarySearchWithFirstKey",
1697          BlockBasedTableOptions::IndexType::kBinarySearchWithFirstKey}};
1698 
1699 std::unordered_map<std::string, BlockBasedTableOptions::DataBlockIndexType>
1700     OptionsHelper::block_base_table_data_block_index_type_string_map = {
1701         {"kDataBlockBinarySearch",
1702          BlockBasedTableOptions::DataBlockIndexType::kDataBlockBinarySearch},
1703         {"kDataBlockBinaryAndHash",
1704          BlockBasedTableOptions::DataBlockIndexType::kDataBlockBinaryAndHash}};
1705 
1706 std::unordered_map<std::string, BlockBasedTableOptions::IndexShorteningMode>
1707     OptionsHelper::block_base_table_index_shortening_mode_string_map = {
1708         {"kNoShortening",
1709          BlockBasedTableOptions::IndexShorteningMode::kNoShortening},
1710         {"kShortenSeparators",
1711          BlockBasedTableOptions::IndexShorteningMode::kShortenSeparators},
1712         {"kShortenSeparatorsAndSuccessor",
1713          BlockBasedTableOptions::IndexShorteningMode::
1714              kShortenSeparatorsAndSuccessor}};
1715 
1716 std::unordered_map<std::string, EncodingType>
1717     OptionsHelper::encoding_type_string_map = {{"kPlain", kPlain},
1718                                                {"kPrefix", kPrefix}};
1719 
1720 std::unordered_map<std::string, CompactionStyle>
1721     OptionsHelper::compaction_style_string_map = {
1722         {"kCompactionStyleLevel", kCompactionStyleLevel},
1723         {"kCompactionStyleUniversal", kCompactionStyleUniversal},
1724         {"kCompactionStyleFIFO", kCompactionStyleFIFO},
1725         {"kCompactionStyleNone", kCompactionStyleNone}};
1726 
1727 std::unordered_map<std::string, CompactionPri>
1728     OptionsHelper::compaction_pri_string_map = {
1729         {"kByCompensatedSize", kByCompensatedSize},
1730         {"kOldestLargestSeqFirst", kOldestLargestSeqFirst},
1731         {"kOldestSmallestSeqFirst", kOldestSmallestSeqFirst},
1732         {"kMinOverlappingRatio", kMinOverlappingRatio}};
1733 
1734 std::unordered_map<std::string, WALRecoveryMode>
1735     OptionsHelper::wal_recovery_mode_string_map = {
1736         {"kTolerateCorruptedTailRecords",
1737          WALRecoveryMode::kTolerateCorruptedTailRecords},
1738         {"kAbsoluteConsistency", WALRecoveryMode::kAbsoluteConsistency},
1739         {"kPointInTimeRecovery", WALRecoveryMode::kPointInTimeRecovery},
1740         {"kSkipAnyCorruptedRecords",
1741          WALRecoveryMode::kSkipAnyCorruptedRecords}};
1742 
1743 std::unordered_map<std::string, DBOptions::AccessHint>
1744     OptionsHelper::access_hint_string_map = {
1745         {"NONE", DBOptions::AccessHint::NONE},
1746         {"NORMAL", DBOptions::AccessHint::NORMAL},
1747         {"SEQUENTIAL", DBOptions::AccessHint::SEQUENTIAL},
1748         {"WILLNEED", DBOptions::AccessHint::WILLNEED}};
1749 
1750 std::unordered_map<std::string, InfoLogLevel>
1751     OptionsHelper::info_log_level_string_map = {
1752         {"DEBUG_LEVEL", InfoLogLevel::DEBUG_LEVEL},
1753         {"INFO_LEVEL", InfoLogLevel::INFO_LEVEL},
1754         {"WARN_LEVEL", InfoLogLevel::WARN_LEVEL},
1755         {"ERROR_LEVEL", InfoLogLevel::ERROR_LEVEL},
1756         {"FATAL_LEVEL", InfoLogLevel::FATAL_LEVEL},
1757         {"HEADER_LEVEL", InfoLogLevel::HEADER_LEVEL}};
1758 
1759 ColumnFamilyOptions OptionsHelper::dummy_cf_options;
1760 CompactionOptionsFIFO OptionsHelper::dummy_comp_options;
1761 LRUCacheOptions OptionsHelper::dummy_lru_cache_options;
1762 CompactionOptionsUniversal OptionsHelper::dummy_comp_options_universal;
1763 
1764 // offset_of is used to get the offset of a class data member
1765 // ex: offset_of(&ColumnFamilyOptions::num_levels)
1766 // This call will return the offset of num_levels in ColumnFamilyOptions class
1767 //
1768 // This is the same as offsetof() but allow us to work with non standard-layout
1769 // classes and structures
1770 // refs:
1771 // http://en.cppreference.com/w/cpp/concept/StandardLayoutType
1772 // https://gist.github.com/graphitemaster/494f21190bb2c63c5516
1773 template <typename T1>
offset_of(T1 ColumnFamilyOptions::* member)1774 int offset_of(T1 ColumnFamilyOptions::*member) {
1775   return int(size_t(&(OptionsHelper::dummy_cf_options.*member)) -
1776              size_t(&OptionsHelper::dummy_cf_options));
1777 }
1778 template <typename T1>
offset_of(T1 AdvancedColumnFamilyOptions::* member)1779 int offset_of(T1 AdvancedColumnFamilyOptions::*member) {
1780   return int(size_t(&(OptionsHelper::dummy_cf_options.*member)) -
1781              size_t(&OptionsHelper::dummy_cf_options));
1782 }
1783 template <typename T1>
offset_of(T1 CompactionOptionsFIFO::* member)1784 int offset_of(T1 CompactionOptionsFIFO::*member) {
1785   return int(size_t(&(OptionsHelper::dummy_comp_options.*member)) -
1786              size_t(&OptionsHelper::dummy_comp_options));
1787 }
1788 template <typename T1>
offset_of(T1 LRUCacheOptions::* member)1789 int offset_of(T1 LRUCacheOptions::*member) {
1790   return int(size_t(&(OptionsHelper::dummy_lru_cache_options.*member)) -
1791              size_t(&OptionsHelper::dummy_lru_cache_options));
1792 }
1793 template <typename T1>
offset_of(T1 CompactionOptionsUniversal::* member)1794 int offset_of(T1 CompactionOptionsUniversal::*member) {
1795   return int(size_t(&(OptionsHelper::dummy_comp_options_universal.*member)) -
1796              size_t(&OptionsHelper::dummy_comp_options_universal));
1797 }
1798 
1799 std::unordered_map<std::string, OptionTypeInfo>
1800     OptionsHelper::cf_options_type_info = {
1801         /* not yet supported
1802         CompressionOptions compression_opts;
1803         TablePropertiesCollectorFactories table_properties_collector_factories;
1804         typedef std::vector<std::shared_ptr<TablePropertiesCollectorFactory>>
1805             TablePropertiesCollectorFactories;
1806         UpdateStatus (*inplace_callback)(char* existing_value,
1807                                          uint34_t* existing_value_size,
1808                                          Slice delta_value,
1809                                          std::string* merged_value);
1810         std::vector<DbPath> cf_paths;
1811          */
1812         {"report_bg_io_stats",
1813          {offset_of(&ColumnFamilyOptions::report_bg_io_stats),
1814           OptionType::kBoolean, OptionVerificationType::kNormal, true,
1815           offsetof(struct MutableCFOptions, report_bg_io_stats)}},
1816         {"compaction_measure_io_stats",
1817          {0, OptionType::kBoolean, OptionVerificationType::kDeprecated, false,
1818           0}},
1819         {"disable_auto_compactions",
1820          {offset_of(&ColumnFamilyOptions::disable_auto_compactions),
1821           OptionType::kBoolean, OptionVerificationType::kNormal, true,
1822           offsetof(struct MutableCFOptions, disable_auto_compactions)}},
1823         {"filter_deletes",
1824          {0, OptionType::kBoolean, OptionVerificationType::kDeprecated, true,
1825           0}},
1826         {"inplace_update_support",
1827          {offset_of(&ColumnFamilyOptions::inplace_update_support),
1828           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1829         {"level_compaction_dynamic_level_bytes",
1830          {offset_of(&ColumnFamilyOptions::level_compaction_dynamic_level_bytes),
1831           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1832         {"optimize_filters_for_hits",
1833          {offset_of(&ColumnFamilyOptions::optimize_filters_for_hits),
1834           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1835         {"paranoid_file_checks",
1836          {offset_of(&ColumnFamilyOptions::paranoid_file_checks),
1837           OptionType::kBoolean, OptionVerificationType::kNormal, true,
1838           offsetof(struct MutableCFOptions, paranoid_file_checks)}},
1839         {"force_consistency_checks",
1840          {offset_of(&ColumnFamilyOptions::force_consistency_checks),
1841           OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
1842         {"purge_redundant_kvs_while_flush",
1843          {offset_of(&ColumnFamilyOptions::purge_redundant_kvs_while_flush),
1844           OptionType::kBoolean, OptionVerificationType::kDeprecated, false, 0}},
1845         {"verify_checksums_in_compaction",
1846          {0, OptionType::kBoolean, OptionVerificationType::kDeprecated, true,
1847           0}},
1848         {"soft_pending_compaction_bytes_limit",
1849          {offset_of(&ColumnFamilyOptions::soft_pending_compaction_bytes_limit),
1850           OptionType::kUInt64T, OptionVerificationType::kNormal, true,
1851           offsetof(struct MutableCFOptions,
1852                    soft_pending_compaction_bytes_limit)}},
1853         {"hard_pending_compaction_bytes_limit",
1854          {offset_of(&ColumnFamilyOptions::hard_pending_compaction_bytes_limit),
1855           OptionType::kUInt64T, OptionVerificationType::kNormal, true,
1856           offsetof(struct MutableCFOptions,
1857                    hard_pending_compaction_bytes_limit)}},
1858         {"hard_rate_limit",
1859          {0, OptionType::kDouble, OptionVerificationType::kDeprecated, true,
1860           0}},
1861         {"soft_rate_limit",
1862          {0, OptionType::kDouble, OptionVerificationType::kDeprecated, true,
1863           0}},
1864         {"max_compaction_bytes",
1865          {offset_of(&ColumnFamilyOptions::max_compaction_bytes),
1866           OptionType::kUInt64T, OptionVerificationType::kNormal, true,
1867           offsetof(struct MutableCFOptions, max_compaction_bytes)}},
1868         {"expanded_compaction_factor",
1869          {0, OptionType::kInt, OptionVerificationType::kDeprecated, true, 0}},
1870         {"level0_file_num_compaction_trigger",
1871          {offset_of(&ColumnFamilyOptions::level0_file_num_compaction_trigger),
1872           OptionType::kInt, OptionVerificationType::kNormal, true,
1873           offsetof(struct MutableCFOptions,
1874                    level0_file_num_compaction_trigger)}},
1875         {"level0_slowdown_writes_trigger",
1876          {offset_of(&ColumnFamilyOptions::level0_slowdown_writes_trigger),
1877           OptionType::kInt, OptionVerificationType::kNormal, true,
1878           offsetof(struct MutableCFOptions, level0_slowdown_writes_trigger)}},
1879         {"level0_stop_writes_trigger",
1880          {offset_of(&ColumnFamilyOptions::level0_stop_writes_trigger),
1881           OptionType::kInt, OptionVerificationType::kNormal, true,
1882           offsetof(struct MutableCFOptions, level0_stop_writes_trigger)}},
1883         {"max_grandparent_overlap_factor",
1884          {0, OptionType::kInt, OptionVerificationType::kDeprecated, true, 0}},
1885         {"max_mem_compaction_level",
1886          {0, OptionType::kInt, OptionVerificationType::kDeprecated, false, 0}},
1887         {"max_write_buffer_number",
1888          {offset_of(&ColumnFamilyOptions::max_write_buffer_number),
1889           OptionType::kInt, OptionVerificationType::kNormal, true,
1890           offsetof(struct MutableCFOptions, max_write_buffer_number)}},
1891         {"max_write_buffer_number_to_maintain",
1892          {offset_of(&ColumnFamilyOptions::max_write_buffer_number_to_maintain),
1893           OptionType::kInt, OptionVerificationType::kNormal, false, 0}},
1894         {"max_write_buffer_size_to_maintain",
1895          {offset_of(&ColumnFamilyOptions::max_write_buffer_size_to_maintain),
1896           OptionType::kInt64T, OptionVerificationType::kNormal, false, 0}},
1897         {"min_write_buffer_number_to_merge",
1898          {offset_of(&ColumnFamilyOptions::min_write_buffer_number_to_merge),
1899           OptionType::kInt, OptionVerificationType::kNormal, false, 0}},
1900         {"num_levels",
1901          {offset_of(&ColumnFamilyOptions::num_levels), OptionType::kInt,
1902           OptionVerificationType::kNormal, false, 0}},
1903         {"source_compaction_factor",
1904          {0, OptionType::kInt, OptionVerificationType::kDeprecated, true, 0}},
1905         {"target_file_size_multiplier",
1906          {offset_of(&ColumnFamilyOptions::target_file_size_multiplier),
1907           OptionType::kInt, OptionVerificationType::kNormal, true,
1908           offsetof(struct MutableCFOptions, target_file_size_multiplier)}},
1909         {"arena_block_size",
1910          {offset_of(&ColumnFamilyOptions::arena_block_size), OptionType::kSizeT,
1911           OptionVerificationType::kNormal, true,
1912           offsetof(struct MutableCFOptions, arena_block_size)}},
1913         {"inplace_update_num_locks",
1914          {offset_of(&ColumnFamilyOptions::inplace_update_num_locks),
1915           OptionType::kSizeT, OptionVerificationType::kNormal, true,
1916           offsetof(struct MutableCFOptions, inplace_update_num_locks)}},
1917         {"max_successive_merges",
1918          {offset_of(&ColumnFamilyOptions::max_successive_merges),
1919           OptionType::kSizeT, OptionVerificationType::kNormal, true,
1920           offsetof(struct MutableCFOptions, max_successive_merges)}},
1921         {"memtable_huge_page_size",
1922          {offset_of(&ColumnFamilyOptions::memtable_huge_page_size),
1923           OptionType::kSizeT, OptionVerificationType::kNormal, true,
1924           offsetof(struct MutableCFOptions, memtable_huge_page_size)}},
1925         {"memtable_prefix_bloom_huge_page_tlb_size",
1926          {0, OptionType::kSizeT, OptionVerificationType::kDeprecated, true, 0}},
1927         {"write_buffer_size",
1928          {offset_of(&ColumnFamilyOptions::write_buffer_size),
1929           OptionType::kSizeT, OptionVerificationType::kNormal, true,
1930           offsetof(struct MutableCFOptions, write_buffer_size)}},
1931         {"bloom_locality",
1932          {offset_of(&ColumnFamilyOptions::bloom_locality), OptionType::kUInt32T,
1933           OptionVerificationType::kNormal, false, 0}},
1934         {"memtable_prefix_bloom_bits",
1935          {0, OptionType::kUInt32T, OptionVerificationType::kDeprecated, true,
1936           0}},
1937         {"memtable_prefix_bloom_size_ratio",
1938          {offset_of(&ColumnFamilyOptions::memtable_prefix_bloom_size_ratio),
1939           OptionType::kDouble, OptionVerificationType::kNormal, true,
1940           offsetof(struct MutableCFOptions, memtable_prefix_bloom_size_ratio)}},
1941         {"memtable_prefix_bloom_probes",
1942          {0, OptionType::kUInt32T, OptionVerificationType::kDeprecated, true,
1943           0}},
1944         {"memtable_whole_key_filtering",
1945          {offset_of(&ColumnFamilyOptions::memtable_whole_key_filtering),
1946           OptionType::kBoolean, OptionVerificationType::kNormal, true,
1947           offsetof(struct MutableCFOptions, memtable_whole_key_filtering)}},
1948         {"min_partial_merge_operands",
1949          {0, OptionType::kUInt32T, OptionVerificationType::kDeprecated, true,
1950           0}},
1951         {"max_bytes_for_level_base",
1952          {offset_of(&ColumnFamilyOptions::max_bytes_for_level_base),
1953           OptionType::kUInt64T, OptionVerificationType::kNormal, true,
1954           offsetof(struct MutableCFOptions, max_bytes_for_level_base)}},
1955         {"snap_refresh_nanos",
1956          {0, OptionType::kUInt64T, OptionVerificationType::kDeprecated, true,
1957           0}},
1958         {"max_bytes_for_level_multiplier",
1959          {offset_of(&ColumnFamilyOptions::max_bytes_for_level_multiplier),
1960           OptionType::kDouble, OptionVerificationType::kNormal, true,
1961           offsetof(struct MutableCFOptions, max_bytes_for_level_multiplier)}},
1962         {"max_bytes_for_level_multiplier_additional",
1963          {offset_of(
1964               &ColumnFamilyOptions::max_bytes_for_level_multiplier_additional),
1965           OptionType::kVectorInt, OptionVerificationType::kNormal, true,
1966           offsetof(struct MutableCFOptions,
1967                    max_bytes_for_level_multiplier_additional)}},
1968         {"max_sequential_skip_in_iterations",
1969          {offset_of(&ColumnFamilyOptions::max_sequential_skip_in_iterations),
1970           OptionType::kUInt64T, OptionVerificationType::kNormal, true,
1971           offsetof(struct MutableCFOptions,
1972                    max_sequential_skip_in_iterations)}},
1973         {"target_file_size_base",
1974          {offset_of(&ColumnFamilyOptions::target_file_size_base),
1975           OptionType::kUInt64T, OptionVerificationType::kNormal, true,
1976           offsetof(struct MutableCFOptions, target_file_size_base)}},
1977         {"rate_limit_delay_max_milliseconds",
1978          {0, OptionType::kUInt, OptionVerificationType::kDeprecated, false, 0}},
1979         {"compression",
1980          {offset_of(&ColumnFamilyOptions::compression),
1981           OptionType::kCompressionType, OptionVerificationType::kNormal, true,
1982           offsetof(struct MutableCFOptions, compression)}},
1983         {"compression_per_level",
1984          {offset_of(&ColumnFamilyOptions::compression_per_level),
1985           OptionType::kVectorCompressionType, OptionVerificationType::kNormal,
1986           false, 0}},
1987         {"bottommost_compression",
1988          {offset_of(&ColumnFamilyOptions::bottommost_compression),
1989           OptionType::kCompressionType, OptionVerificationType::kNormal, false,
1990           0}},
1991         {kNameComparator,
1992          {offset_of(&ColumnFamilyOptions::comparator), OptionType::kComparator,
1993           OptionVerificationType::kByName, false, 0}},
1994         {"prefix_extractor",
1995          {offset_of(&ColumnFamilyOptions::prefix_extractor),
1996           OptionType::kSliceTransform, OptionVerificationType::kByNameAllowNull,
1997           true, offsetof(struct MutableCFOptions, prefix_extractor)}},
1998         {"memtable_insert_with_hint_prefix_extractor",
1999          {offset_of(
2000               &ColumnFamilyOptions::memtable_insert_with_hint_prefix_extractor),
2001           OptionType::kSliceTransform, OptionVerificationType::kByNameAllowNull,
2002           false, 0}},
2003         {"memtable_factory",
2004          {offset_of(&ColumnFamilyOptions::memtable_factory),
2005           OptionType::kMemTableRepFactory, OptionVerificationType::kByName,
2006           false, 0}},
2007         {"table_factory",
2008          {offset_of(&ColumnFamilyOptions::table_factory),
2009           OptionType::kTableFactory, OptionVerificationType::kByName, false,
2010           0}},
2011         {"compaction_filter",
2012          {offset_of(&ColumnFamilyOptions::compaction_filter),
2013           OptionType::kCompactionFilter, OptionVerificationType::kByName, false,
2014           0}},
2015         {"compaction_filter_factory",
2016          {offset_of(&ColumnFamilyOptions::compaction_filter_factory),
2017           OptionType::kCompactionFilterFactory, OptionVerificationType::kByName,
2018           false, 0}},
2019         {kNameMergeOperator,
2020          {offset_of(&ColumnFamilyOptions::merge_operator),
2021           OptionType::kMergeOperator,
2022           OptionVerificationType::kByNameAllowFromNull, false, 0}},
2023         {"compaction_style",
2024          {offset_of(&ColumnFamilyOptions::compaction_style),
2025           OptionType::kCompactionStyle, OptionVerificationType::kNormal, false,
2026           0}},
2027         {"compaction_pri",
2028          {offset_of(&ColumnFamilyOptions::compaction_pri),
2029           OptionType::kCompactionPri, OptionVerificationType::kNormal, false,
2030           0}},
2031         {"compaction_options_fifo",
2032          {offset_of(&ColumnFamilyOptions::compaction_options_fifo),
2033           OptionType::kCompactionOptionsFIFO, OptionVerificationType::kNormal,
2034           true, offsetof(struct MutableCFOptions, compaction_options_fifo)}},
2035         {"compaction_options_universal",
2036          {offset_of(&ColumnFamilyOptions::compaction_options_universal),
2037           OptionType::kCompactionOptionsUniversal,
2038           OptionVerificationType::kNormal, true,
2039           offsetof(struct MutableCFOptions, compaction_options_universal)}},
2040         {"ttl",
2041          {offset_of(&ColumnFamilyOptions::ttl), OptionType::kUInt64T,
2042           OptionVerificationType::kNormal, true,
2043           offsetof(struct MutableCFOptions, ttl)}},
2044         {"periodic_compaction_seconds",
2045          {offset_of(&ColumnFamilyOptions::periodic_compaction_seconds),
2046           OptionType::kUInt64T, OptionVerificationType::kNormal, true,
2047           offsetof(struct MutableCFOptions, periodic_compaction_seconds)}},
2048         {"sample_for_compression",
2049          {offset_of(&ColumnFamilyOptions::sample_for_compression),
2050           OptionType::kUInt64T, OptionVerificationType::kNormal, true,
2051           offsetof(struct MutableCFOptions, sample_for_compression)}}};
2052 
2053 std::unordered_map<std::string, OptionTypeInfo>
2054     OptionsHelper::fifo_compaction_options_type_info = {
2055         {"max_table_files_size",
2056          {offset_of(&CompactionOptionsFIFO::max_table_files_size),
2057           OptionType::kUInt64T, OptionVerificationType::kNormal, true,
2058           offsetof(struct CompactionOptionsFIFO, max_table_files_size)}},
2059         {"ttl",
2060          {0, OptionType::kUInt64T,
2061           OptionVerificationType::kDeprecated, false,
2062           0}},
2063         {"allow_compaction",
2064          {offset_of(&CompactionOptionsFIFO::allow_compaction),
2065           OptionType::kBoolean, OptionVerificationType::kNormal, true,
2066           offsetof(struct CompactionOptionsFIFO, allow_compaction)}}};
2067 
2068 std::unordered_map<std::string, OptionTypeInfo>
2069     OptionsHelper::universal_compaction_options_type_info = {
2070         {"size_ratio",
2071          {offset_of(&CompactionOptionsUniversal::size_ratio), OptionType::kUInt,
2072           OptionVerificationType::kNormal, true,
2073           offsetof(class CompactionOptionsUniversal, size_ratio)}},
2074         {"min_merge_width",
2075          {offset_of(&CompactionOptionsUniversal::min_merge_width),
2076           OptionType::kUInt, OptionVerificationType::kNormal, true,
2077           offsetof(class CompactionOptionsUniversal, min_merge_width)}},
2078         {"max_merge_width",
2079          {offset_of(&CompactionOptionsUniversal::max_merge_width),
2080           OptionType::kUInt, OptionVerificationType::kNormal, true,
2081           offsetof(class CompactionOptionsUniversal, max_merge_width)}},
2082         {"max_size_amplification_percent",
2083          {offset_of(
2084               &CompactionOptionsUniversal::max_size_amplification_percent),
2085           OptionType::kUInt, OptionVerificationType::kNormal, true,
2086           offsetof(class CompactionOptionsUniversal,
2087                    max_size_amplification_percent)}},
2088         {"compression_size_percent",
2089          {offset_of(&CompactionOptionsUniversal::compression_size_percent),
2090           OptionType::kInt, OptionVerificationType::kNormal, true,
2091           offsetof(class CompactionOptionsUniversal,
2092                    compression_size_percent)}},
2093         {"stop_style",
2094          {offset_of(&CompactionOptionsUniversal::stop_style),
2095           OptionType::kCompactionStopStyle, OptionVerificationType::kNormal,
2096           true, offsetof(class CompactionOptionsUniversal, stop_style)}},
2097         {"allow_trivial_move",
2098          {offset_of(&CompactionOptionsUniversal::allow_trivial_move),
2099           OptionType::kBoolean, OptionVerificationType::kNormal, true,
2100           offsetof(class CompactionOptionsUniversal, allow_trivial_move)}}};
2101 
2102 std::unordered_map<std::string, CompactionStopStyle>
2103     OptionsHelper::compaction_stop_style_string_map = {
2104         {"kCompactionStopStyleSimilarSize", kCompactionStopStyleSimilarSize},
2105         {"kCompactionStopStyleTotalSize", kCompactionStopStyleTotalSize}};
2106 
2107 std::unordered_map<std::string, OptionTypeInfo>
2108     OptionsHelper::lru_cache_options_type_info = {
2109         {"capacity",
2110          {offset_of(&LRUCacheOptions::capacity), OptionType::kSizeT,
2111           OptionVerificationType::kNormal, true,
2112           offsetof(struct LRUCacheOptions, capacity)}},
2113         {"num_shard_bits",
2114          {offset_of(&LRUCacheOptions::num_shard_bits), OptionType::kInt,
2115           OptionVerificationType::kNormal, true,
2116           offsetof(struct LRUCacheOptions, num_shard_bits)}},
2117         {"strict_capacity_limit",
2118          {offset_of(&LRUCacheOptions::strict_capacity_limit),
2119           OptionType::kBoolean, OptionVerificationType::kNormal, true,
2120           offsetof(struct LRUCacheOptions, strict_capacity_limit)}},
2121         {"high_pri_pool_ratio",
2122          {offset_of(&LRUCacheOptions::high_pri_pool_ratio), OptionType::kDouble,
2123           OptionVerificationType::kNormal, true,
2124           offsetof(struct LRUCacheOptions, high_pri_pool_ratio)}}};
2125 
2126 #endif  // !ROCKSDB_LITE
2127 
2128 }  // namespace ROCKSDB_NAMESPACE
2129