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