Coverage Report

Created: 2024-09-08 07:17

/src/rocksdb/options/options_helper.cc
Line
Count
Source (jump to first uncovered line)
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 <atomic>
8
#include <cassert>
9
#include <cctype>
10
#include <cstdlib>
11
#include <set>
12
#include <unordered_set>
13
#include <vector>
14
15
#include "options/cf_options.h"
16
#include "options/db_options.h"
17
#include "rocksdb/cache.h"
18
#include "rocksdb/compaction_filter.h"
19
#include "rocksdb/convenience.h"
20
#include "rocksdb/filter_policy.h"
21
#include "rocksdb/flush_block_policy.h"
22
#include "rocksdb/memtablerep.h"
23
#include "rocksdb/merge_operator.h"
24
#include "rocksdb/options.h"
25
#include "rocksdb/rate_limiter.h"
26
#include "rocksdb/slice_transform.h"
27
#include "rocksdb/table.h"
28
#include "rocksdb/utilities/object_registry.h"
29
#include "rocksdb/utilities/options_type.h"
30
#include "util/string_util.h"
31
32
namespace ROCKSDB_NAMESPACE {
33
ConfigOptions::ConfigOptions()
34
    : registry(ObjectRegistry::NewInstance())
35
19.3k
{
36
19.3k
  env = Env::Default();
37
19.3k
}
38
39
0
ConfigOptions::ConfigOptions(const DBOptions& db_opts) : env(db_opts.env) {
40
0
  registry = ObjectRegistry::NewInstance();
41
0
}
42
43
Status ValidateOptions(const DBOptions& db_opts,
44
11.4k
                       const ColumnFamilyOptions& cf_opts) {
45
11.4k
  Status s;
46
11.4k
  auto db_cfg = DBOptionsAsConfigurable(db_opts);
47
11.4k
  auto cf_cfg = CFOptionsAsConfigurable(cf_opts);
48
11.4k
  s = db_cfg->ValidateOptions(db_opts, cf_opts);
49
11.4k
  if (s.ok()) {
50
11.4k
    s = cf_cfg->ValidateOptions(db_opts, cf_opts);
51
11.4k
  }
52
11.4k
  return s;
53
11.4k
}
54
55
DBOptions BuildDBOptions(const ImmutableDBOptions& immutable_db_options,
56
52.1k
                         const MutableDBOptions& mutable_db_options) {
57
52.1k
  DBOptions options;
58
59
52.1k
  options.create_if_missing = immutable_db_options.create_if_missing;
60
52.1k
  options.create_missing_column_families =
61
52.1k
      immutable_db_options.create_missing_column_families;
62
52.1k
  options.error_if_exists = immutable_db_options.error_if_exists;
63
52.1k
  options.paranoid_checks = immutable_db_options.paranoid_checks;
64
52.1k
  options.flush_verify_memtable_count =
65
52.1k
      immutable_db_options.flush_verify_memtable_count;
66
52.1k
  options.compaction_verify_record_count =
67
52.1k
      immutable_db_options.compaction_verify_record_count;
68
52.1k
  options.track_and_verify_wals_in_manifest =
69
52.1k
      immutable_db_options.track_and_verify_wals_in_manifest;
70
52.1k
  options.verify_sst_unique_id_in_manifest =
71
52.1k
      immutable_db_options.verify_sst_unique_id_in_manifest;
72
52.1k
  options.env = immutable_db_options.env;
73
52.1k
  options.rate_limiter = immutable_db_options.rate_limiter;
74
52.1k
  options.sst_file_manager = immutable_db_options.sst_file_manager;
75
52.1k
  options.info_log = immutable_db_options.info_log;
76
52.1k
  options.info_log_level = immutable_db_options.info_log_level;
77
52.1k
  options.max_open_files = mutable_db_options.max_open_files;
78
52.1k
  options.max_file_opening_threads =
79
52.1k
      immutable_db_options.max_file_opening_threads;
80
52.1k
  options.max_total_wal_size = mutable_db_options.max_total_wal_size;
81
52.1k
  options.statistics = immutable_db_options.statistics;
82
52.1k
  options.use_fsync = immutable_db_options.use_fsync;
83
52.1k
  options.db_paths = immutable_db_options.db_paths;
84
52.1k
  options.db_log_dir = immutable_db_options.db_log_dir;
85
52.1k
  options.wal_dir = immutable_db_options.wal_dir;
86
52.1k
  options.delete_obsolete_files_period_micros =
87
52.1k
      mutable_db_options.delete_obsolete_files_period_micros;
88
52.1k
  options.max_background_jobs = mutable_db_options.max_background_jobs;
89
52.1k
  options.max_background_compactions =
90
52.1k
      mutable_db_options.max_background_compactions;
91
52.1k
  options.bytes_per_sync = mutable_db_options.bytes_per_sync;
92
52.1k
  options.wal_bytes_per_sync = mutable_db_options.wal_bytes_per_sync;
93
52.1k
  options.strict_bytes_per_sync = mutable_db_options.strict_bytes_per_sync;
94
52.1k
  options.max_subcompactions = mutable_db_options.max_subcompactions;
95
52.1k
  options.max_background_flushes = mutable_db_options.max_background_flushes;
96
52.1k
  options.max_log_file_size = immutable_db_options.max_log_file_size;
97
52.1k
  options.log_file_time_to_roll = immutable_db_options.log_file_time_to_roll;
98
52.1k
  options.keep_log_file_num = immutable_db_options.keep_log_file_num;
99
52.1k
  options.recycle_log_file_num = immutable_db_options.recycle_log_file_num;
100
52.1k
  options.max_manifest_file_size = immutable_db_options.max_manifest_file_size;
101
52.1k
  options.table_cache_numshardbits =
102
52.1k
      immutable_db_options.table_cache_numshardbits;
103
52.1k
  options.WAL_ttl_seconds = immutable_db_options.WAL_ttl_seconds;
104
52.1k
  options.WAL_size_limit_MB = immutable_db_options.WAL_size_limit_MB;
105
52.1k
  options.manifest_preallocation_size =
106
52.1k
      immutable_db_options.manifest_preallocation_size;
107
52.1k
  options.allow_mmap_reads = immutable_db_options.allow_mmap_reads;
108
52.1k
  options.allow_mmap_writes = immutable_db_options.allow_mmap_writes;
109
52.1k
  options.use_direct_reads = immutable_db_options.use_direct_reads;
110
52.1k
  options.use_direct_io_for_flush_and_compaction =
111
52.1k
      immutable_db_options.use_direct_io_for_flush_and_compaction;
112
52.1k
  options.allow_fallocate = immutable_db_options.allow_fallocate;
113
52.1k
  options.is_fd_close_on_exec = immutable_db_options.is_fd_close_on_exec;
114
52.1k
  options.stats_dump_period_sec = mutable_db_options.stats_dump_period_sec;
115
52.1k
  options.stats_persist_period_sec =
116
52.1k
      mutable_db_options.stats_persist_period_sec;
117
52.1k
  options.persist_stats_to_disk = immutable_db_options.persist_stats_to_disk;
118
52.1k
  options.stats_history_buffer_size =
119
52.1k
      mutable_db_options.stats_history_buffer_size;
120
52.1k
  options.advise_random_on_open = immutable_db_options.advise_random_on_open;
121
52.1k
  options.db_write_buffer_size = immutable_db_options.db_write_buffer_size;
122
52.1k
  options.write_buffer_manager = immutable_db_options.write_buffer_manager;
123
52.1k
  options.compaction_readahead_size =
124
52.1k
      mutable_db_options.compaction_readahead_size;
125
52.1k
  options.random_access_max_buffer_size =
126
52.1k
      immutable_db_options.random_access_max_buffer_size;
127
52.1k
  options.writable_file_max_buffer_size =
128
52.1k
      mutable_db_options.writable_file_max_buffer_size;
129
52.1k
  options.use_adaptive_mutex = immutable_db_options.use_adaptive_mutex;
130
52.1k
  options.listeners = immutable_db_options.listeners;
131
52.1k
  options.enable_thread_tracking = immutable_db_options.enable_thread_tracking;
132
52.1k
  options.delayed_write_rate = mutable_db_options.delayed_write_rate;
133
52.1k
  options.enable_pipelined_write = immutable_db_options.enable_pipelined_write;
134
52.1k
  options.unordered_write = immutable_db_options.unordered_write;
135
52.1k
  options.allow_concurrent_memtable_write =
136
52.1k
      immutable_db_options.allow_concurrent_memtable_write;
137
52.1k
  options.enable_write_thread_adaptive_yield =
138
52.1k
      immutable_db_options.enable_write_thread_adaptive_yield;
139
52.1k
  options.max_write_batch_group_size_bytes =
140
52.1k
      immutable_db_options.max_write_batch_group_size_bytes;
141
52.1k
  options.write_thread_max_yield_usec =
142
52.1k
      immutable_db_options.write_thread_max_yield_usec;
143
52.1k
  options.write_thread_slow_yield_usec =
144
52.1k
      immutable_db_options.write_thread_slow_yield_usec;
145
52.1k
  options.skip_stats_update_on_db_open =
146
52.1k
      immutable_db_options.skip_stats_update_on_db_open;
147
52.1k
  options.skip_checking_sst_file_sizes_on_db_open =
148
52.1k
      immutable_db_options.skip_checking_sst_file_sizes_on_db_open;
149
52.1k
  options.wal_recovery_mode = immutable_db_options.wal_recovery_mode;
150
52.1k
  options.allow_2pc = immutable_db_options.allow_2pc;
151
52.1k
  options.row_cache = immutable_db_options.row_cache;
152
52.1k
  options.wal_filter = immutable_db_options.wal_filter;
153
52.1k
  options.fail_if_options_file_error =
154
52.1k
      immutable_db_options.fail_if_options_file_error;
155
52.1k
  options.dump_malloc_stats = immutable_db_options.dump_malloc_stats;
156
52.1k
  options.avoid_flush_during_recovery =
157
52.1k
      immutable_db_options.avoid_flush_during_recovery;
158
52.1k
  options.avoid_flush_during_shutdown =
159
52.1k
      mutable_db_options.avoid_flush_during_shutdown;
160
52.1k
  options.allow_ingest_behind = immutable_db_options.allow_ingest_behind;
161
52.1k
  options.two_write_queues = immutable_db_options.two_write_queues;
162
52.1k
  options.manual_wal_flush = immutable_db_options.manual_wal_flush;
163
52.1k
  options.wal_compression = immutable_db_options.wal_compression;
164
52.1k
  options.atomic_flush = immutable_db_options.atomic_flush;
165
52.1k
  options.avoid_unnecessary_blocking_io =
166
52.1k
      immutable_db_options.avoid_unnecessary_blocking_io;
167
52.1k
  options.log_readahead_size = immutable_db_options.log_readahead_size;
168
52.1k
  options.file_checksum_gen_factory =
169
52.1k
      immutable_db_options.file_checksum_gen_factory;
170
52.1k
  options.best_efforts_recovery = immutable_db_options.best_efforts_recovery;
171
52.1k
  options.max_bgerror_resume_count =
172
52.1k
      immutable_db_options.max_bgerror_resume_count;
173
52.1k
  options.bgerror_resume_retry_interval =
174
52.1k
      immutable_db_options.bgerror_resume_retry_interval;
175
52.1k
  options.db_host_id = immutable_db_options.db_host_id;
176
52.1k
  options.allow_data_in_errors = immutable_db_options.allow_data_in_errors;
177
52.1k
  options.checksum_handoff_file_types =
178
52.1k
      immutable_db_options.checksum_handoff_file_types;
179
52.1k
  options.lowest_used_cache_tier = immutable_db_options.lowest_used_cache_tier;
180
52.1k
  options.enforce_single_del_contracts =
181
52.1k
      immutable_db_options.enforce_single_del_contracts;
182
52.1k
  options.daily_offpeak_time_utc = mutable_db_options.daily_offpeak_time_utc;
183
52.1k
  options.follower_refresh_catchup_period_ms =
184
52.1k
      immutable_db_options.follower_refresh_catchup_period_ms;
185
52.1k
  options.follower_catchup_retry_count =
186
52.1k
      immutable_db_options.follower_catchup_retry_count;
187
52.1k
  options.follower_catchup_retry_wait_ms =
188
52.1k
      immutable_db_options.follower_catchup_retry_wait_ms;
189
52.1k
  options.metadata_write_temperature =
190
52.1k
      immutable_db_options.metadata_write_temperature;
191
52.1k
  options.wal_write_temperature = immutable_db_options.wal_write_temperature;
192
52.1k
  return options;
193
52.1k
}
194
195
ColumnFamilyOptions BuildColumnFamilyOptions(
196
    const ColumnFamilyOptions& options,
197
12.5k
    const MutableCFOptions& mutable_cf_options) {
198
12.5k
  ColumnFamilyOptions cf_opts(options);
199
12.5k
  UpdateColumnFamilyOptions(mutable_cf_options, &cf_opts);
200
  // TODO(yhchiang): find some way to handle the following derived options
201
  // * max_file_size
202
12.5k
  return cf_opts;
203
12.5k
}
204
205
void UpdateColumnFamilyOptions(const MutableCFOptions& moptions,
206
25.1k
                               ColumnFamilyOptions* cf_opts) {
207
  // Memtable related options
208
25.1k
  cf_opts->write_buffer_size = moptions.write_buffer_size;
209
25.1k
  cf_opts->max_write_buffer_number = moptions.max_write_buffer_number;
210
25.1k
  cf_opts->arena_block_size = moptions.arena_block_size;
211
25.1k
  cf_opts->memtable_prefix_bloom_size_ratio =
212
25.1k
      moptions.memtable_prefix_bloom_size_ratio;
213
25.1k
  cf_opts->memtable_whole_key_filtering = moptions.memtable_whole_key_filtering;
214
25.1k
  cf_opts->memtable_huge_page_size = moptions.memtable_huge_page_size;
215
25.1k
  cf_opts->max_successive_merges = moptions.max_successive_merges;
216
25.1k
  cf_opts->strict_max_successive_merges = moptions.strict_max_successive_merges;
217
25.1k
  cf_opts->inplace_update_num_locks = moptions.inplace_update_num_locks;
218
25.1k
  cf_opts->prefix_extractor = moptions.prefix_extractor;
219
25.1k
  cf_opts->experimental_mempurge_threshold =
220
25.1k
      moptions.experimental_mempurge_threshold;
221
25.1k
  cf_opts->memtable_protection_bytes_per_key =
222
25.1k
      moptions.memtable_protection_bytes_per_key;
223
25.1k
  cf_opts->block_protection_bytes_per_key =
224
25.1k
      moptions.block_protection_bytes_per_key;
225
25.1k
  cf_opts->paranoid_memory_checks = moptions.paranoid_memory_checks;
226
25.1k
  cf_opts->bottommost_file_compaction_delay =
227
25.1k
      moptions.bottommost_file_compaction_delay;
228
229
  // Compaction related options
230
25.1k
  cf_opts->disable_auto_compactions = moptions.disable_auto_compactions;
231
25.1k
  cf_opts->soft_pending_compaction_bytes_limit =
232
25.1k
      moptions.soft_pending_compaction_bytes_limit;
233
25.1k
  cf_opts->hard_pending_compaction_bytes_limit =
234
25.1k
      moptions.hard_pending_compaction_bytes_limit;
235
25.1k
  cf_opts->level0_file_num_compaction_trigger =
236
25.1k
      moptions.level0_file_num_compaction_trigger;
237
25.1k
  cf_opts->level0_slowdown_writes_trigger =
238
25.1k
      moptions.level0_slowdown_writes_trigger;
239
25.1k
  cf_opts->level0_stop_writes_trigger = moptions.level0_stop_writes_trigger;
240
25.1k
  cf_opts->max_compaction_bytes = moptions.max_compaction_bytes;
241
25.1k
  cf_opts->target_file_size_base = moptions.target_file_size_base;
242
25.1k
  cf_opts->target_file_size_multiplier = moptions.target_file_size_multiplier;
243
25.1k
  cf_opts->max_bytes_for_level_base = moptions.max_bytes_for_level_base;
244
25.1k
  cf_opts->max_bytes_for_level_multiplier =
245
25.1k
      moptions.max_bytes_for_level_multiplier;
246
25.1k
  cf_opts->ttl = moptions.ttl;
247
25.1k
  cf_opts->periodic_compaction_seconds = moptions.periodic_compaction_seconds;
248
249
25.1k
  cf_opts->max_bytes_for_level_multiplier_additional.clear();
250
175k
  for (auto value : moptions.max_bytes_for_level_multiplier_additional) {
251
175k
    cf_opts->max_bytes_for_level_multiplier_additional.emplace_back(value);
252
175k
  }
253
254
25.1k
  cf_opts->compaction_options_fifo = moptions.compaction_options_fifo;
255
25.1k
  cf_opts->compaction_options_universal = moptions.compaction_options_universal;
256
257
  // Blob file related options
258
25.1k
  cf_opts->enable_blob_files = moptions.enable_blob_files;
259
25.1k
  cf_opts->min_blob_size = moptions.min_blob_size;
260
25.1k
  cf_opts->blob_file_size = moptions.blob_file_size;
261
25.1k
  cf_opts->blob_compression_type = moptions.blob_compression_type;
262
25.1k
  cf_opts->enable_blob_garbage_collection =
263
25.1k
      moptions.enable_blob_garbage_collection;
264
25.1k
  cf_opts->blob_garbage_collection_age_cutoff =
265
25.1k
      moptions.blob_garbage_collection_age_cutoff;
266
25.1k
  cf_opts->blob_garbage_collection_force_threshold =
267
25.1k
      moptions.blob_garbage_collection_force_threshold;
268
25.1k
  cf_opts->blob_compaction_readahead_size =
269
25.1k
      moptions.blob_compaction_readahead_size;
270
25.1k
  cf_opts->blob_file_starting_level = moptions.blob_file_starting_level;
271
25.1k
  cf_opts->prepopulate_blob_cache = moptions.prepopulate_blob_cache;
272
273
  // Misc options
274
25.1k
  cf_opts->max_sequential_skip_in_iterations =
275
25.1k
      moptions.max_sequential_skip_in_iterations;
276
25.1k
  cf_opts->paranoid_file_checks = moptions.paranoid_file_checks;
277
25.1k
  cf_opts->report_bg_io_stats = moptions.report_bg_io_stats;
278
25.1k
  cf_opts->compression = moptions.compression;
279
25.1k
  cf_opts->compression_opts = moptions.compression_opts;
280
25.1k
  cf_opts->bottommost_compression = moptions.bottommost_compression;
281
25.1k
  cf_opts->bottommost_compression_opts = moptions.bottommost_compression_opts;
282
25.1k
  cf_opts->sample_for_compression = moptions.sample_for_compression;
283
25.1k
  cf_opts->compression_per_level = moptions.compression_per_level;
284
25.1k
  cf_opts->last_level_temperature = moptions.last_level_temperature;
285
25.1k
  cf_opts->default_write_temperature = moptions.default_write_temperature;
286
25.1k
  cf_opts->memtable_max_range_deletions = moptions.memtable_max_range_deletions;
287
25.1k
  cf_opts->uncache_aggressiveness = moptions.uncache_aggressiveness;
288
25.1k
}
289
290
void UpdateColumnFamilyOptions(const ImmutableCFOptions& ioptions,
291
12.5k
                               ColumnFamilyOptions* cf_opts) {
292
12.5k
  cf_opts->compaction_style = ioptions.compaction_style;
293
12.5k
  cf_opts->compaction_pri = ioptions.compaction_pri;
294
12.5k
  cf_opts->comparator = ioptions.user_comparator;
295
12.5k
  cf_opts->merge_operator = ioptions.merge_operator;
296
12.5k
  cf_opts->compaction_filter = ioptions.compaction_filter;
297
12.5k
  cf_opts->compaction_filter_factory = ioptions.compaction_filter_factory;
298
12.5k
  cf_opts->min_write_buffer_number_to_merge =
299
12.5k
      ioptions.min_write_buffer_number_to_merge;
300
12.5k
  cf_opts->max_write_buffer_number_to_maintain =
301
12.5k
      ioptions.max_write_buffer_number_to_maintain;
302
12.5k
  cf_opts->max_write_buffer_size_to_maintain =
303
12.5k
      ioptions.max_write_buffer_size_to_maintain;
304
12.5k
  cf_opts->inplace_update_support = ioptions.inplace_update_support;
305
12.5k
  cf_opts->inplace_callback = ioptions.inplace_callback;
306
12.5k
  cf_opts->memtable_factory = ioptions.memtable_factory;
307
12.5k
  cf_opts->table_factory = ioptions.table_factory;
308
12.5k
  cf_opts->table_properties_collector_factories =
309
12.5k
      ioptions.table_properties_collector_factories;
310
12.5k
  cf_opts->bloom_locality = ioptions.bloom_locality;
311
12.5k
  cf_opts->level_compaction_dynamic_level_bytes =
312
12.5k
      ioptions.level_compaction_dynamic_level_bytes;
313
12.5k
  cf_opts->num_levels = ioptions.num_levels;
314
12.5k
  cf_opts->optimize_filters_for_hits = ioptions.optimize_filters_for_hits;
315
12.5k
  cf_opts->force_consistency_checks = ioptions.force_consistency_checks;
316
12.5k
  cf_opts->memtable_insert_with_hint_prefix_extractor =
317
12.5k
      ioptions.memtable_insert_with_hint_prefix_extractor;
318
12.5k
  cf_opts->cf_paths = ioptions.cf_paths;
319
12.5k
  cf_opts->compaction_thread_limiter = ioptions.compaction_thread_limiter;
320
12.5k
  cf_opts->sst_partitioner_factory = ioptions.sst_partitioner_factory;
321
12.5k
  cf_opts->blob_cache = ioptions.blob_cache;
322
12.5k
  cf_opts->preclude_last_level_data_seconds =
323
12.5k
      ioptions.preclude_last_level_data_seconds;
324
12.5k
  cf_opts->preserve_internal_time_seconds =
325
12.5k
      ioptions.preserve_internal_time_seconds;
326
12.5k
  cf_opts->persist_user_defined_timestamps =
327
12.5k
      ioptions.persist_user_defined_timestamps;
328
12.5k
  cf_opts->default_temperature = ioptions.default_temperature;
329
330
  // TODO(yhchiang): find some way to handle the following derived options
331
  // * max_file_size
332
12.5k
}
333
334
std::map<CompactionStyle, std::string>
335
    OptionsHelper::compaction_style_to_string = {
336
        {kCompactionStyleLevel, "kCompactionStyleLevel"},
337
        {kCompactionStyleUniversal, "kCompactionStyleUniversal"},
338
        {kCompactionStyleFIFO, "kCompactionStyleFIFO"},
339
        {kCompactionStyleNone, "kCompactionStyleNone"}};
340
341
std::map<CompactionPri, std::string> OptionsHelper::compaction_pri_to_string = {
342
    {kByCompensatedSize, "kByCompensatedSize"},
343
    {kOldestLargestSeqFirst, "kOldestLargestSeqFirst"},
344
    {kOldestSmallestSeqFirst, "kOldestSmallestSeqFirst"},
345
    {kMinOverlappingRatio, "kMinOverlappingRatio"},
346
    {kRoundRobin, "kRoundRobin"}};
347
348
std::map<CompactionStopStyle, std::string>
349
    OptionsHelper::compaction_stop_style_to_string = {
350
        {kCompactionStopStyleSimilarSize, "kCompactionStopStyleSimilarSize"},
351
        {kCompactionStopStyleTotalSize, "kCompactionStopStyleTotalSize"}};
352
353
std::map<Temperature, std::string> OptionsHelper::temperature_to_string = {
354
    {Temperature::kUnknown, "kUnknown"},
355
    {Temperature::kHot, "kHot"},
356
    {Temperature::kWarm, "kWarm"},
357
    {Temperature::kCold, "kCold"}};
358
359
std::unordered_map<std::string, ChecksumType>
360
    OptionsHelper::checksum_type_string_map = {{"kNoChecksum", kNoChecksum},
361
                                               {"kCRC32c", kCRC32c},
362
                                               {"kxxHash", kxxHash},
363
                                               {"kxxHash64", kxxHash64},
364
                                               {"kXXH3", kXXH3}};
365
366
std::unordered_map<std::string, CompressionType>
367
    OptionsHelper::compression_type_string_map = {
368
        {"kNoCompression", kNoCompression},
369
        {"kSnappyCompression", kSnappyCompression},
370
        {"kZlibCompression", kZlibCompression},
371
        {"kBZip2Compression", kBZip2Compression},
372
        {"kLZ4Compression", kLZ4Compression},
373
        {"kLZ4HCCompression", kLZ4HCCompression},
374
        {"kXpressCompression", kXpressCompression},
375
        {"kZSTD", kZSTD},
376
        {"kZSTDNotFinalCompression", kZSTDNotFinalCompression},
377
        {"kDisableCompressionOption", kDisableCompressionOption}};
378
379
0
std::vector<CompressionType> GetSupportedCompressions() {
380
  // std::set internally to deduplicate potential name aliases
381
0
  std::set<CompressionType> supported_compressions;
382
0
  for (const auto& comp_to_name : OptionsHelper::compression_type_string_map) {
383
0
    CompressionType t = comp_to_name.second;
384
0
    if (t != kDisableCompressionOption && CompressionTypeSupported(t)) {
385
0
      supported_compressions.insert(t);
386
0
    }
387
0
  }
388
0
  return std::vector<CompressionType>(supported_compressions.begin(),
389
0
                                      supported_compressions.end());
390
0
}
391
392
0
std::vector<CompressionType> GetSupportedDictCompressions() {
393
0
  std::set<CompressionType> dict_compression_types;
394
0
  for (const auto& comp_to_name : OptionsHelper::compression_type_string_map) {
395
0
    CompressionType t = comp_to_name.second;
396
0
    if (t != kDisableCompressionOption && DictCompressionTypeSupported(t)) {
397
0
      dict_compression_types.insert(t);
398
0
    }
399
0
  }
400
0
  return std::vector<CompressionType>(dict_compression_types.begin(),
401
0
                                      dict_compression_types.end());
402
0
}
403
404
0
std::vector<ChecksumType> GetSupportedChecksums() {
405
0
  std::set<ChecksumType> checksum_types;
406
0
  for (const auto& e : OptionsHelper::checksum_type_string_map) {
407
0
    checksum_types.insert(e.second);
408
0
  }
409
0
  return std::vector<ChecksumType>(checksum_types.begin(),
410
0
                                   checksum_types.end());
411
0
}
412
413
static bool ParseOptionHelper(void* opt_address, const OptionType& opt_type,
414
2.86M
                              const std::string& value) {
415
2.86M
  switch (opt_type) {
416
1.11M
    case OptionType::kBoolean:
417
1.11M
      *static_cast<bool*>(opt_address) = ParseBoolean("", value);
418
1.11M
      break;
419
509k
    case OptionType::kInt:
420
509k
      *static_cast<int*>(opt_address) = ParseInt(value);
421
509k
      break;
422
0
    case OptionType::kInt32T:
423
0
      *static_cast<int32_t*>(opt_address) = ParseInt32(value);
424
0
      break;
425
12.5k
    case OptionType::kInt64T:
426
12.5k
      PutUnaligned(static_cast<int64_t*>(opt_address), ParseInt64(value));
427
12.5k
      break;
428
73.8k
    case OptionType::kUInt:
429
73.8k
      *static_cast<unsigned int*>(opt_address) = ParseUint32(value);
430
73.8k
      break;
431
12.5k
    case OptionType::kUInt8T:
432
12.5k
      *static_cast<uint8_t*>(opt_address) = ParseUint8(value);
433
12.5k
      break;
434
149k
    case OptionType::kUInt32T:
435
149k
      *static_cast<uint32_t*>(opt_address) = ParseUint32(value);
436
149k
      break;
437
453k
    case OptionType::kUInt64T:
438
453k
      PutUnaligned(static_cast<uint64_t*>(opt_address), ParseUint64(value));
439
453k
      break;
440
268k
    case OptionType::kSizeT:
441
268k
      PutUnaligned(static_cast<size_t*>(opt_address), ParseSizeT(value));
442
268k
      break;
443
0
    case OptionType::kAtomicInt:
444
0
      static_cast<std::atomic<int>*>(opt_address)
445
0
          ->store(ParseInt(value), std::memory_order_release);
446
0
      break;
447
11.8k
    case OptionType::kString:
448
11.8k
      *static_cast<std::string*>(opt_address) = value;
449
11.8k
      break;
450
87.9k
    case OptionType::kDouble:
451
87.9k
      *static_cast<double*>(opt_address) = ParseDouble(value);
452
87.9k
      break;
453
12.5k
    case OptionType::kCompactionStyle:
454
12.5k
      return ParseEnum<CompactionStyle>(
455
12.5k
          compaction_style_string_map, value,
456
12.5k
          static_cast<CompactionStyle*>(opt_address));
457
12.5k
    case OptionType::kCompactionPri:
458
12.5k
      return ParseEnum<CompactionPri>(compaction_pri_string_map, value,
459
12.5k
                                      static_cast<CompactionPri*>(opt_address));
460
49.5k
    case OptionType::kCompressionType:
461
49.5k
      return ParseEnum<CompressionType>(
462
49.5k
          compression_type_string_map, value,
463
49.5k
          static_cast<CompressionType*>(opt_address));
464
25.1k
    case OptionType::kChecksumType:
465
25.1k
      return ParseEnum<ChecksumType>(checksum_type_string_map, value,
466
25.1k
                                     static_cast<ChecksumType*>(opt_address));
467
0
    case OptionType::kEncodingType:
468
0
      return ParseEnum<EncodingType>(encoding_type_string_map, value,
469
0
                                     static_cast<EncodingType*>(opt_address));
470
12.5k
    case OptionType::kCompactionStopStyle:
471
12.5k
      return ParseEnum<CompactionStopStyle>(
472
12.5k
          compaction_stop_style_string_map, value,
473
12.5k
          static_cast<CompactionStopStyle*>(opt_address));
474
0
    case OptionType::kEncodedString: {
475
0
      std::string* output_addr = static_cast<std::string*>(opt_address);
476
0
      (Slice(value)).DecodeHex(output_addr);
477
0
      break;
478
0
    }
479
61.3k
    case OptionType::kTemperature: {
480
61.3k
      return ParseEnum<Temperature>(temperature_string_map, value,
481
61.3k
                                    static_cast<Temperature*>(opt_address));
482
0
    }
483
0
    default:
484
0
      return false;
485
2.86M
  }
486
2.69M
  return true;
487
2.86M
}
488
489
bool SerializeSingleOptionHelper(const void* opt_address,
490
                                 const OptionType opt_type,
491
6.18M
                                 std::string* value) {
492
6.18M
  assert(value);
493
6.18M
  switch (opt_type) {
494
2.40M
    case OptionType::kBoolean:
495
2.40M
      *value = *(static_cast<const bool*>(opt_address)) ? "true" : "false";
496
2.40M
      break;
497
1.05M
    case OptionType::kInt:
498
1.05M
      *value = std::to_string(*(static_cast<const int*>(opt_address)));
499
1.05M
      break;
500
0
    case OptionType::kInt32T:
501
0
      *value = std::to_string(*(static_cast<const int32_t*>(opt_address)));
502
0
      break;
503
25.1k
    case OptionType::kInt64T:
504
25.1k
      {
505
25.1k
        int64_t v;
506
25.1k
        GetUnaligned(static_cast<const int64_t*>(opt_address), &v);
507
25.1k
        *value = std::to_string(v);
508
25.1k
      }
509
25.1k
      break;
510
147k
    case OptionType::kUInt:
511
147k
      *value = std::to_string(*(static_cast<const unsigned int*>(opt_address)));
512
147k
      break;
513
25.1k
    case OptionType::kUInt8T:
514
25.1k
      *value = std::to_string(*(static_cast<const uint8_t*>(opt_address)));
515
25.1k
      break;
516
375k
    case OptionType::kUInt32T:
517
375k
      *value = std::to_string(*(static_cast<const uint32_t*>(opt_address)));
518
375k
      break;
519
932k
    case OptionType::kUInt64T:
520
932k
      {
521
932k
        uint64_t v;
522
932k
        GetUnaligned(static_cast<const uint64_t*>(opt_address), &v);
523
932k
        *value = std::to_string(v);
524
932k
      }
525
932k
      break;
526
574k
    case OptionType::kSizeT:
527
574k
      {
528
574k
        size_t v;
529
574k
        GetUnaligned(static_cast<const size_t*>(opt_address), &v);
530
574k
        *value = std::to_string(v);
531
574k
      }
532
574k
      break;
533
188k
    case OptionType::kDouble:
534
188k
      *value = std::to_string(*(static_cast<const double*>(opt_address)));
535
188k
      break;
536
0
    case OptionType::kAtomicInt:
537
0
      *value = std::to_string(static_cast<const std::atomic<int>*>(opt_address)
538
0
                                  ->load(std::memory_order_acquire));
539
0
      break;
540
94.6k
    case OptionType::kString:
541
94.6k
      *value =
542
94.6k
          EscapeOptionString(*(static_cast<const std::string*>(opt_address)));
543
94.6k
      break;
544
25.1k
    case OptionType::kCompactionStyle:
545
25.1k
      return SerializeEnum<CompactionStyle>(
546
25.1k
          compaction_style_string_map,
547
25.1k
          *(static_cast<const CompactionStyle*>(opt_address)), value);
548
25.1k
    case OptionType::kCompactionPri:
549
25.1k
      return SerializeEnum<CompactionPri>(
550
25.1k
          compaction_pri_string_map,
551
25.1k
          *(static_cast<const CompactionPri*>(opt_address)), value);
552
99.0k
    case OptionType::kCompressionType:
553
99.0k
      return SerializeEnum<CompressionType>(
554
99.0k
          compression_type_string_map,
555
99.0k
          *(static_cast<const CompressionType*>(opt_address)), value);
556
0
      break;
557
62.8k
    case OptionType::kChecksumType:
558
62.8k
      return SerializeEnum<ChecksumType>(
559
62.8k
          checksum_type_string_map,
560
62.8k
          *static_cast<const ChecksumType*>(opt_address), value);
561
0
    case OptionType::kEncodingType:
562
0
      return SerializeEnum<EncodingType>(
563
0
          encoding_type_string_map,
564
0
          *static_cast<const EncodingType*>(opt_address), value);
565
25.1k
    case OptionType::kCompactionStopStyle:
566
25.1k
      return SerializeEnum<CompactionStopStyle>(
567
25.1k
          compaction_stop_style_string_map,
568
25.1k
          *static_cast<const CompactionStopStyle*>(opt_address), value);
569
0
    case OptionType::kEncodedString: {
570
0
      const auto* ptr = static_cast<const std::string*>(opt_address);
571
0
      *value = (Slice(*ptr)).ToString(true);
572
0
      break;
573
0
    }
574
122k
    case OptionType::kTemperature: {
575
122k
      return SerializeEnum<Temperature>(
576
122k
          temperature_string_map, *static_cast<const Temperature*>(opt_address),
577
122k
          value);
578
0
    }
579
0
    default:
580
0
      return false;
581
6.18M
  }
582
5.82M
  return true;
583
6.18M
}
584
585
template <typename T>
586
Status ConfigureFromMap(
587
    const ConfigOptions& config_options,
588
    const std::unordered_map<std::string, std::string>& opt_map,
589
24.3k
    const std::string& option_name, Configurable* config, T* new_opts) {
590
24.3k
  Status s = config->ConfigureFromMap(config_options, opt_map);
591
24.3k
  if (s.ok()) {
592
24.3k
    *new_opts = *(config->GetOptions<T>(option_name));
593
24.3k
  }
594
24.3k
  return s;
595
24.3k
}
rocksdb::Status rocksdb::ConfigureFromMap<rocksdb::ColumnFamilyOptions>(rocksdb::ConfigOptions const&, std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, rocksdb::Configurable*, rocksdb::ColumnFamilyOptions*)
Line
Count
Source
589
12.5k
    const std::string& option_name, Configurable* config, T* new_opts) {
590
12.5k
  Status s = config->ConfigureFromMap(config_options, opt_map);
591
12.5k
  if (s.ok()) {
592
12.5k
    *new_opts = *(config->GetOptions<T>(option_name));
593
12.5k
  }
594
12.5k
  return s;
595
12.5k
}
rocksdb::Status rocksdb::ConfigureFromMap<rocksdb::DBOptions>(rocksdb::ConfigOptions const&, std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, rocksdb::Configurable*, rocksdb::DBOptions*)
Line
Count
Source
589
11.8k
    const std::string& option_name, Configurable* config, T* new_opts) {
590
11.8k
  Status s = config->ConfigureFromMap(config_options, opt_map);
591
11.8k
  if (s.ok()) {
592
11.8k
    *new_opts = *(config->GetOptions<T>(option_name));
593
11.8k
  }
594
11.8k
  return s;
595
11.8k
}
596
597
598
Status StringToMap(const std::string& opts_str,
599
125k
                   std::unordered_map<std::string, std::string>* opts_map) {
600
125k
  assert(opts_map);
601
  // Example:
602
  //   opts_str = "write_buffer_size=1024;max_write_buffer_number=2;"
603
  //              "nested_opt={opt1=1;opt2=2};max_bytes_for_level_base=100"
604
125k
  size_t pos = 0;
605
125k
  std::string opts = trim(opts_str);
606
  // If the input string starts and ends with "{...}", strip off the brackets
607
188k
  while (opts.size() > 2 && opts[0] == '{' && opts[opts.size() - 1] == '}') {
608
62.8k
    opts = trim(opts.substr(1, opts.size() - 2));
609
62.8k
  }
610
611
1.05M
  while (pos < opts.size()) {
612
929k
    size_t eq_pos = opts.find_first_of("={};", pos);
613
929k
    if (eq_pos == std::string::npos) {
614
0
      return Status::InvalidArgument("Mismatched key value pair, '=' expected");
615
929k
    } else if (opts[eq_pos] != '=') {
616
0
      return Status::InvalidArgument("Unexpected char in key");
617
0
    }
618
619
929k
    std::string key = trim(opts.substr(pos, eq_pos - pos));
620
929k
    if (key.empty()) {
621
0
      return Status::InvalidArgument("Empty key found");
622
0
    }
623
624
929k
    std::string value;
625
929k
    Status s = OptionTypeInfo::NextToken(opts, ';', eq_pos + 1, &pos, &value);
626
929k
    if (!s.ok()) {
627
0
      return s;
628
929k
    } else {
629
929k
      (*opts_map)[key] = value;
630
929k
      if (pos == std::string::npos) {
631
0
        break;
632
929k
      } else {
633
929k
        pos++;
634
929k
      }
635
929k
    }
636
929k
  }
637
638
125k
  return Status::OK();
639
125k
}
640
641
642
Status GetStringFromDBOptions(std::string* opt_string,
643
                              const DBOptions& db_options,
644
0
                              const std::string& delimiter) {
645
0
  ConfigOptions config_options(db_options);
646
0
  config_options.delimiter = delimiter;
647
0
  return GetStringFromDBOptions(config_options, db_options, opt_string);
648
0
}
649
650
Status GetStringFromDBOptions(const ConfigOptions& config_options,
651
                              const DBOptions& db_options,
652
11.8k
                              std::string* opt_string) {
653
11.8k
  assert(opt_string);
654
11.8k
  opt_string->clear();
655
11.8k
  auto config = DBOptionsAsConfigurable(db_options);
656
11.8k
  return config->GetOptionString(config_options, opt_string);
657
11.8k
}
658
659
660
Status GetStringFromColumnFamilyOptions(std::string* opt_string,
661
                                        const ColumnFamilyOptions& cf_options,
662
0
                                        const std::string& delimiter) {
663
0
  ConfigOptions config_options;
664
0
  config_options.delimiter = delimiter;
665
0
  return GetStringFromColumnFamilyOptions(config_options, cf_options,
666
0
                                          opt_string);
667
0
}
668
669
Status GetStringFromColumnFamilyOptions(const ConfigOptions& config_options,
670
                                        const ColumnFamilyOptions& cf_options,
671
12.5k
                                        std::string* opt_string) {
672
12.5k
  const auto config = CFOptionsAsConfigurable(cf_options);
673
12.5k
  return config->GetOptionString(config_options, opt_string);
674
12.5k
}
675
676
Status GetStringFromCompressionType(std::string* compression_str,
677
0
                                    CompressionType compression_type) {
678
0
  bool ok = SerializeEnum<CompressionType>(compression_type_string_map,
679
0
                                           compression_type, compression_str);
680
0
  if (ok) {
681
0
    return Status::OK();
682
0
  } else {
683
0
    return Status::InvalidArgument("Invalid compression types");
684
0
  }
685
0
}
686
687
Status GetColumnFamilyOptionsFromMap(
688
    const ConfigOptions& config_options,
689
    const ColumnFamilyOptions& base_options,
690
    const std::unordered_map<std::string, std::string>& opts_map,
691
12.5k
    ColumnFamilyOptions* new_options) {
692
12.5k
  assert(new_options);
693
694
12.5k
  *new_options = base_options;
695
696
12.5k
  const auto config = CFOptionsAsConfigurable(base_options);
697
12.5k
  Status s = ConfigureFromMap<ColumnFamilyOptions>(
698
12.5k
      config_options, opts_map, OptionsHelper::kCFOptionsName, config.get(),
699
12.5k
      new_options);
700
  // Translate any errors (NotFound, NotSupported, to InvalidArgument
701
12.5k
  if (s.ok() || s.IsInvalidArgument()) {
702
12.5k
    return s;
703
12.5k
  } else {
704
0
    return Status::InvalidArgument(s.getState());
705
0
  }
706
12.5k
}
707
708
Status GetColumnFamilyOptionsFromString(const ConfigOptions& config_options,
709
                                        const ColumnFamilyOptions& base_options,
710
                                        const std::string& opts_str,
711
0
                                        ColumnFamilyOptions* new_options) {
712
0
  std::unordered_map<std::string, std::string> opts_map;
713
0
  Status s = StringToMap(opts_str, &opts_map);
714
0
  if (!s.ok()) {
715
0
    *new_options = base_options;
716
0
    return s;
717
0
  }
718
0
  return GetColumnFamilyOptionsFromMap(config_options, base_options, opts_map,
719
0
                                       new_options);
720
0
}
721
722
Status GetDBOptionsFromMap(
723
    const ConfigOptions& config_options, const DBOptions& base_options,
724
    const std::unordered_map<std::string, std::string>& opts_map,
725
11.8k
    DBOptions* new_options) {
726
11.8k
  assert(new_options);
727
11.8k
  *new_options = base_options;
728
11.8k
  auto config = DBOptionsAsConfigurable(base_options);
729
11.8k
  Status s = ConfigureFromMap<DBOptions>(config_options, opts_map,
730
11.8k
                                         OptionsHelper::kDBOptionsName,
731
11.8k
                                         config.get(), new_options);
732
  // Translate any errors (NotFound, NotSupported, to InvalidArgument
733
11.8k
  if (s.ok() || s.IsInvalidArgument()) {
734
11.8k
    return s;
735
11.8k
  } else {
736
0
    return Status::InvalidArgument(s.getState());
737
0
  }
738
11.8k
}
739
740
Status GetDBOptionsFromString(const ConfigOptions& config_options,
741
                              const DBOptions& base_options,
742
                              const std::string& opts_str,
743
0
                              DBOptions* new_options) {
744
0
  std::unordered_map<std::string, std::string> opts_map;
745
0
  Status s = StringToMap(opts_str, &opts_map);
746
0
  if (!s.ok()) {
747
0
    *new_options = base_options;
748
0
    return s;
749
0
  }
750
0
  return GetDBOptionsFromMap(config_options, base_options, opts_map,
751
0
                             new_options);
752
0
}
753
754
Status GetOptionsFromString(const Options& base_options,
755
0
                            const std::string& opts_str, Options* new_options) {
756
0
  ConfigOptions config_options(base_options);
757
0
  config_options.input_strings_escaped = false;
758
0
  config_options.ignore_unknown_options = false;
759
760
0
  return GetOptionsFromString(config_options, base_options, opts_str,
761
0
                              new_options);
762
0
}
763
764
Status GetOptionsFromString(const ConfigOptions& config_options,
765
                            const Options& base_options,
766
0
                            const std::string& opts_str, Options* new_options) {
767
0
  ColumnFamilyOptions new_cf_options;
768
0
  std::unordered_map<std::string, std::string> unused_opts;
769
0
  std::unordered_map<std::string, std::string> opts_map;
770
771
0
  assert(new_options);
772
0
  *new_options = base_options;
773
0
  Status s = StringToMap(opts_str, &opts_map);
774
0
  if (!s.ok()) {
775
0
    return s;
776
0
  }
777
0
  auto config = DBOptionsAsConfigurable(base_options);
778
0
  s = config->ConfigureFromMap(config_options, opts_map, &unused_opts);
779
780
0
  if (s.ok()) {
781
0
    DBOptions* new_db_options =
782
0
        config->GetOptions<DBOptions>(OptionsHelper::kDBOptionsName);
783
0
    if (!unused_opts.empty()) {
784
0
      s = GetColumnFamilyOptionsFromMap(config_options, base_options,
785
0
                                        unused_opts, &new_cf_options);
786
0
      if (s.ok()) {
787
0
        *new_options = Options(*new_db_options, new_cf_options);
788
0
      }
789
0
    } else {
790
0
      *new_options = Options(*new_db_options, base_options);
791
0
    }
792
0
  }
793
  // Translate any errors (NotFound, NotSupported, to InvalidArgument
794
0
  if (s.ok() || s.IsInvalidArgument()) {
795
0
    return s;
796
0
  } else {
797
0
    return Status::InvalidArgument(s.getState());
798
0
  }
799
0
}
800
801
std::unordered_map<std::string, EncodingType>
802
    OptionsHelper::encoding_type_string_map = {{"kPlain", kPlain},
803
                                               {"kPrefix", kPrefix}};
804
805
std::unordered_map<std::string, CompactionStyle>
806
    OptionsHelper::compaction_style_string_map = {
807
        {"kCompactionStyleLevel", kCompactionStyleLevel},
808
        {"kCompactionStyleUniversal", kCompactionStyleUniversal},
809
        {"kCompactionStyleFIFO", kCompactionStyleFIFO},
810
        {"kCompactionStyleNone", kCompactionStyleNone}};
811
812
std::unordered_map<std::string, CompactionPri>
813
    OptionsHelper::compaction_pri_string_map = {
814
        {"kByCompensatedSize", kByCompensatedSize},
815
        {"kOldestLargestSeqFirst", kOldestLargestSeqFirst},
816
        {"kOldestSmallestSeqFirst", kOldestSmallestSeqFirst},
817
        {"kMinOverlappingRatio", kMinOverlappingRatio},
818
        {"kRoundRobin", kRoundRobin}};
819
820
std::unordered_map<std::string, CompactionStopStyle>
821
    OptionsHelper::compaction_stop_style_string_map = {
822
        {"kCompactionStopStyleSimilarSize", kCompactionStopStyleSimilarSize},
823
        {"kCompactionStopStyleTotalSize", kCompactionStopStyleTotalSize}};
824
825
std::unordered_map<std::string, Temperature>
826
    OptionsHelper::temperature_string_map = {
827
        {"kUnknown", Temperature::kUnknown},
828
        {"kHot", Temperature::kHot},
829
        {"kWarm", Temperature::kWarm},
830
        {"kCold", Temperature::kCold}};
831
832
std::unordered_map<std::string, PrepopulateBlobCache>
833
    OptionsHelper::prepopulate_blob_cache_string_map = {
834
        {"kDisable", PrepopulateBlobCache::kDisable},
835
        {"kFlushOnly", PrepopulateBlobCache::kFlushOnly}};
836
837
Status OptionTypeInfo::NextToken(const std::string& opts, char delimiter,
838
1.01M
                                 size_t pos, size_t* end, std::string* token) {
839
1.01M
  while (pos < opts.size() && isspace(opts[pos])) {
840
0
    ++pos;
841
0
  }
842
  // Empty value at the end
843
1.01M
  if (pos >= opts.size()) {
844
0
    *token = "";
845
0
    *end = std::string::npos;
846
0
    return Status::OK();
847
1.01M
  } else if (opts[pos] == '{') {
848
12.5k
    int count = 1;
849
12.5k
    size_t brace_pos = pos + 1;
850
1.19M
    while (brace_pos < opts.size()) {
851
1.19M
      if (opts[brace_pos] == '{') {
852
0
        ++count;
853
1.19M
      } else if (opts[brace_pos] == '}') {
854
12.5k
        --count;
855
12.5k
        if (count == 0) {
856
12.5k
          break;
857
12.5k
        }
858
12.5k
      }
859
1.18M
      ++brace_pos;
860
1.18M
    }
861
    // found the matching closing brace
862
12.5k
    if (count == 0) {
863
12.5k
      *token = trim(opts.substr(pos + 1, brace_pos - pos - 1));
864
      // skip all whitespace and move to the next delimiter
865
      // brace_pos points to the next position after the matching '}'
866
12.5k
      pos = brace_pos + 1;
867
12.5k
      while (pos < opts.size() && isspace(opts[pos])) {
868
0
        ++pos;
869
0
      }
870
12.5k
      if (pos < opts.size() && opts[pos] != delimiter) {
871
0
        return Status::InvalidArgument("Unexpected chars after nested options");
872
0
      }
873
12.5k
      *end = pos;
874
12.5k
    } else {
875
0
      return Status::InvalidArgument(
876
0
          "Mismatched curly braces for nested options");
877
0
    }
878
1.00M
  } else {
879
1.00M
    *end = opts.find(delimiter, pos);
880
1.00M
    if (*end == std::string::npos) {
881
      // It either ends with a trailing semi-colon or the last key-value pair
882
12.5k
      *token = trim(opts.substr(pos));
883
992k
    } else {
884
992k
      *token = trim(opts.substr(pos, *end - pos));
885
992k
    }
886
1.00M
  }
887
1.01M
  return Status::OK();
888
1.01M
}
889
890
Status OptionTypeInfo::Parse(const ConfigOptions& config_options,
891
                             const std::string& opt_name,
892
3.40M
                             const std::string& value, void* opt_ptr) const {
893
3.40M
  if (IsDeprecated()) {
894
0
    return Status::OK();
895
0
  }
896
3.40M
  try {
897
3.40M
    const std::string& opt_value = config_options.input_strings_escaped
898
3.40M
                                       ? UnescapeOptionString(value)
899
3.40M
                                       : value;
900
901
3.40M
    if (opt_ptr == nullptr) {
902
0
      return Status::NotFound("Could not find option", opt_name);
903
3.40M
    } else if (parse_func_ != nullptr) {
904
536k
      ConfigOptions copy = config_options;
905
536k
      copy.invoke_prepare_options = false;
906
536k
      void* opt_addr = GetOffset(opt_ptr);
907
536k
      return parse_func_(copy, opt_name, opt_value, opt_addr);
908
2.86M
    } else if (ParseOptionHelper(GetOffset(opt_ptr), type_, opt_value)) {
909
2.86M
      return Status::OK();
910
2.86M
    } else if (IsConfigurable()) {
911
      // The option is <config>.<name>
912
0
      Configurable* config = AsRawPointer<Configurable>(opt_ptr);
913
0
      if (opt_value.empty()) {
914
0
        return Status::OK();
915
0
      } else if (config == nullptr) {
916
0
        return Status::NotFound("Could not find configurable: ", opt_name);
917
0
      } else {
918
0
        ConfigOptions copy = config_options;
919
0
        copy.ignore_unknown_options = false;
920
0
        copy.invoke_prepare_options = false;
921
0
        if (opt_value.find('=') != std::string::npos) {
922
0
          return config->ConfigureFromString(copy, opt_value);
923
0
        } else {
924
0
          return config->ConfigureOption(copy, opt_name, opt_value);
925
0
        }
926
0
      }
927
0
    } else if (IsByName()) {
928
0
      return Status::NotSupported("Deserializing the option " + opt_name +
929
0
                                  " is not supported");
930
0
    } else {
931
0
      return Status::InvalidArgument("Error parsing:", opt_name);
932
0
    }
933
3.40M
  } catch (std::exception& e) {
934
0
    return Status::InvalidArgument("Error parsing " + opt_name + ":" +
935
0
                                   std::string(e.what()));
936
0
  }
937
3.40M
}
938
939
Status OptionTypeInfo::ParseType(
940
    const ConfigOptions& config_options, const std::string& opts_str,
941
    const std::unordered_map<std::string, OptionTypeInfo>& type_map,
942
75.3k
    void* opt_addr, std::unordered_map<std::string, std::string>* unused) {
943
75.3k
  std::unordered_map<std::string, std::string> opts_map;
944
75.3k
  Status status = StringToMap(opts_str, &opts_map);
945
75.3k
  if (!status.ok()) {
946
0
    return status;
947
75.3k
  } else {
948
75.3k
    return ParseType(config_options, opts_map, type_map, opt_addr, unused);
949
75.3k
  }
950
75.3k
}
951
952
Status OptionTypeInfo::ParseType(
953
    const ConfigOptions& config_options,
954
    const std::unordered_map<std::string, std::string>& opts_map,
955
    const std::unordered_map<std::string, OptionTypeInfo>& type_map,
956
75.3k
    void* opt_addr, std::unordered_map<std::string, std::string>* unused) {
957
515k
  for (const auto& opts_iter : opts_map) {
958
515k
    std::string opt_name;
959
515k
    const auto* opt_info = Find(opts_iter.first, type_map, &opt_name);
960
515k
    if (opt_info != nullptr) {
961
515k
      Status status =
962
515k
          opt_info->Parse(config_options, opt_name, opts_iter.second, opt_addr);
963
515k
      if (!status.ok()) {
964
0
        return status;
965
0
      }
966
515k
    } else if (unused != nullptr) {
967
0
      (*unused)[opts_iter.first] = opts_iter.second;
968
0
    } else if (!config_options.ignore_unknown_options) {
969
0
      return Status::NotFound("Unrecognized option", opts_iter.first);
970
0
    }
971
515k
  }
972
75.3k
  return Status::OK();
973
75.3k
}
974
975
Status OptionTypeInfo::ParseStruct(
976
    const ConfigOptions& config_options, const std::string& struct_name,
977
    const std::unordered_map<std::string, OptionTypeInfo>* struct_map,
978
75.3k
    const std::string& opt_name, const std::string& opt_value, void* opt_addr) {
979
75.3k
  assert(struct_map);
980
75.3k
  Status status;
981
75.3k
  if (opt_name == struct_name || EndsWith(opt_name, "." + struct_name)) {
982
    // This option represents the entire struct
983
75.3k
    std::unordered_map<std::string, std::string> unused;
984
75.3k
    status =
985
75.3k
        ParseType(config_options, opt_value, *struct_map, opt_addr, &unused);
986
75.3k
    if (status.ok() && !unused.empty()) {
987
0
      status = Status::InvalidArgument(
988
0
          "Unrecognized option", struct_name + "." + unused.begin()->first);
989
0
    }
990
75.3k
  } else if (StartsWith(opt_name, struct_name + ".")) {
991
    // This option represents a nested field in the struct (e.g, struct.field)
992
0
    std::string elem_name;
993
0
    const auto opt_info =
994
0
        Find(opt_name.substr(struct_name.size() + 1), *struct_map, &elem_name);
995
0
    if (opt_info != nullptr) {
996
0
      status = opt_info->Parse(config_options, elem_name, opt_value, opt_addr);
997
0
    } else {
998
0
      status = Status::InvalidArgument("Unrecognized option", opt_name);
999
0
    }
1000
0
  } else {
1001
    // This option represents a field in the struct (e.g. field)
1002
0
    std::string elem_name;
1003
0
    const auto opt_info = Find(opt_name, *struct_map, &elem_name);
1004
0
    if (opt_info != nullptr) {
1005
0
      status = opt_info->Parse(config_options, elem_name, opt_value, opt_addr);
1006
0
    } else {
1007
0
      status = Status::InvalidArgument("Unrecognized option",
1008
0
                                       struct_name + "." + opt_name);
1009
0
    }
1010
0
  }
1011
75.3k
  return status;
1012
75.3k
}
1013
1014
Status OptionTypeInfo::Serialize(const ConfigOptions& config_options,
1015
                                 const std::string& opt_name,
1016
                                 const void* const opt_ptr,
1017
7.40M
                                 std::string* opt_value) const {
1018
  // If the option is no longer used in rocksdb and marked as deprecated,
1019
  // we skip it in the serialization.
1020
7.40M
  if (opt_ptr == nullptr || IsDeprecated()) {
1021
0
    return Status::OK();
1022
7.40M
  } else if (IsEnabled(OptionTypeFlags::kDontSerialize)) {
1023
0
    return Status::NotSupported("Cannot serialize option: ", opt_name);
1024
7.40M
  } else if (serialize_func_ != nullptr) {
1025
848k
    const void* opt_addr = GetOffset(opt_ptr);
1026
848k
    return serialize_func_(config_options, opt_name, opt_addr, opt_value);
1027
6.55M
  } else if (IsCustomizable()) {
1028
373k
    const Customizable* custom = AsRawPointer<Customizable>(opt_ptr);
1029
373k
    opt_value->clear();
1030
373k
    if (custom == nullptr) {
1031
      // We do not have a custom object to serialize.
1032
      // If the option is not mutable and we are doing only mutable options,
1033
      // we return an empty string (which will cause the option not to be
1034
      // printed). Otherwise, we return the "nullptr" string, which will result
1035
      // in "option=nullptr" being printed.
1036
260k
      if (IsMutable() || !config_options.mutable_options_only) {
1037
260k
        *opt_value = kNullptrString;
1038
260k
      } else {
1039
0
        *opt_value = "";
1040
0
      }
1041
260k
    } else if (IsEnabled(OptionTypeFlags::kStringNameOnly) &&
1042
113k
               !config_options.IsDetailed()) {
1043
12.5k
      if (!config_options.mutable_options_only || IsMutable()) {
1044
12.5k
        *opt_value = custom->GetId();
1045
12.5k
      }
1046
100k
    } else {
1047
100k
      ConfigOptions embedded = config_options;
1048
100k
      embedded.delimiter = ";";
1049
      // If this option is mutable, everything inside it should be considered
1050
      // mutable
1051
100k
      if (IsMutable()) {
1052
0
        embedded.mutable_options_only = false;
1053
0
      }
1054
100k
      std::string value = custom->ToString(embedded);
1055
100k
      if (!embedded.mutable_options_only ||
1056
100k
          value.find('=') != std::string::npos) {
1057
100k
        *opt_value = value;
1058
100k
      } else {
1059
0
        *opt_value = "";
1060
0
      }
1061
100k
    }
1062
373k
    return Status::OK();
1063
6.18M
  } else if (IsConfigurable()) {
1064
0
    const Configurable* config = AsRawPointer<Configurable>(opt_ptr);
1065
0
    if (config != nullptr) {
1066
0
      ConfigOptions embedded = config_options;
1067
0
      embedded.delimiter = ";";
1068
0
      *opt_value = config->ToString(embedded);
1069
0
    }
1070
0
    return Status::OK();
1071
6.18M
  } else if (config_options.mutable_options_only && !IsMutable()) {
1072
0
    return Status::OK();
1073
6.18M
  } else if (SerializeSingleOptionHelper(GetOffset(opt_ptr), type_,
1074
6.18M
                                         opt_value)) {
1075
6.18M
    return Status::OK();
1076
6.18M
  } else {
1077
0
    return Status::InvalidArgument("Cannot serialize option: ", opt_name);
1078
0
  }
1079
7.40M
}
1080
1081
Status OptionTypeInfo::SerializeType(
1082
    const ConfigOptions& config_options,
1083
    const std::unordered_map<std::string, OptionTypeInfo>& type_map,
1084
163k
    const void* opt_addr, std::string* result) {
1085
163k
  Status status;
1086
1.09M
  for (const auto& iter : type_map) {
1087
1.09M
    std::string single;
1088
1.09M
    const auto& opt_info = iter.second;
1089
1.09M
    if (opt_info.ShouldSerialize()) {
1090
1.06M
      status =
1091
1.06M
          opt_info.Serialize(config_options, iter.first, opt_addr, &single);
1092
1.06M
      if (!status.ok()) {
1093
0
        return status;
1094
1.06M
      } else {
1095
1.06M
        result->append(iter.first + "=" + single + config_options.delimiter);
1096
1.06M
      }
1097
1.06M
    }
1098
1.09M
  }
1099
163k
  return status;
1100
163k
}
1101
1102
Status OptionTypeInfo::SerializeStruct(
1103
    const ConfigOptions& config_options, const std::string& struct_name,
1104
    const std::unordered_map<std::string, OptionTypeInfo>* struct_map,
1105
163k
    const std::string& opt_name, const void* opt_addr, std::string* value) {
1106
163k
  assert(struct_map);
1107
163k
  Status status;
1108
163k
  if (EndsWith(opt_name, struct_name)) {
1109
    // We are going to write the struct as "{ prop1=value1; prop2=value2;}.
1110
    // Set the delimiter to ";" so that the everything will be on one line.
1111
163k
    ConfigOptions embedded = config_options;
1112
163k
    embedded.delimiter = ";";
1113
1114
    // This option represents the entire struct
1115
163k
    std::string result;
1116
163k
    status = SerializeType(embedded, *struct_map, opt_addr, &result);
1117
163k
    if (!status.ok()) {
1118
0
      return status;
1119
163k
    } else {
1120
163k
      *value = "{" + result + "}";
1121
163k
    }
1122
163k
  } else if (StartsWith(opt_name, struct_name + ".")) {
1123
    // This option represents a nested field in the struct (e.g, struct.field)
1124
0
    std::string elem_name;
1125
0
    const auto opt_info =
1126
0
        Find(opt_name.substr(struct_name.size() + 1), *struct_map, &elem_name);
1127
0
    if (opt_info != nullptr) {
1128
0
      status = opt_info->Serialize(config_options, elem_name, opt_addr, value);
1129
0
    } else {
1130
0
      status = Status::InvalidArgument("Unrecognized option", opt_name);
1131
0
    }
1132
0
  } else {
1133
    // This option represents a field in the struct (e.g. field)
1134
0
    std::string elem_name;
1135
0
    const auto opt_info = Find(opt_name, *struct_map, &elem_name);
1136
0
    if (opt_info == nullptr) {
1137
0
      status = Status::InvalidArgument("Unrecognized option", opt_name);
1138
0
    } else if (opt_info->ShouldSerialize()) {
1139
0
      status = opt_info->Serialize(config_options, opt_name + "." + elem_name,
1140
0
                                   opt_addr, value);
1141
0
    }
1142
0
  }
1143
163k
  return status;
1144
163k
}
1145
1146
template <typename T>
1147
1.57M
bool IsOptionEqual(const void* offset1, const void* offset2) {
1148
1.57M
  return (*static_cast<const T*>(offset1) == *static_cast<const T*>(offset2));
1149
1.57M
}
bool rocksdb::IsOptionEqual<bool>(void const*, void const*)
Line
Count
Source
1147
861k
bool IsOptionEqual(const void* offset1, const void* offset2) {
1148
861k
  return (*static_cast<const T*>(offset1) == *static_cast<const T*>(offset2));
1149
861k
}
bool rocksdb::IsOptionEqual<int>(void const*, void const*)
Line
Count
Source
1147
346k
bool IsOptionEqual(const void* offset1, const void* offset2) {
1148
346k
  return (*static_cast<const T*>(offset1) == *static_cast<const T*>(offset2));
1149
346k
}
bool rocksdb::IsOptionEqual<unsigned int>(void const*, void const*)
Line
Count
Source
1147
173k
bool IsOptionEqual(const void* offset1, const void* offset2) {
1148
173k
  return (*static_cast<const T*>(offset1) == *static_cast<const T*>(offset2));
1149
173k
}
bool rocksdb::IsOptionEqual<unsigned char>(void const*, void const*)
Line
Count
Source
1147
12.5k
bool IsOptionEqual(const void* offset1, const void* offset2) {
1148
12.5k
  return (*static_cast<const T*>(offset1) == *static_cast<const T*>(offset2));
1149
12.5k
}
Unexecuted instantiation: bool rocksdb::IsOptionEqual<std::__1::atomic<int> >(void const*, void const*)
bool rocksdb::IsOptionEqual<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(void const*, void const*)
Line
Count
Source
1147
35.4k
bool IsOptionEqual(const void* offset1, const void* offset2) {
1148
35.4k
  return (*static_cast<const T*>(offset1) == *static_cast<const T*>(offset2));
1149
35.4k
}
bool rocksdb::IsOptionEqual<rocksdb::CompactionStyle>(void const*, void const*)
Line
Count
Source
1147
12.5k
bool IsOptionEqual(const void* offset1, const void* offset2) {
1148
12.5k
  return (*static_cast<const T*>(offset1) == *static_cast<const T*>(offset2));
1149
12.5k
}
bool rocksdb::IsOptionEqual<rocksdb::CompactionStopStyle>(void const*, void const*)
Line
Count
Source
1147
12.5k
bool IsOptionEqual(const void* offset1, const void* offset2) {
1148
12.5k
  return (*static_cast<const T*>(offset1) == *static_cast<const T*>(offset2));
1149
12.5k
}
bool rocksdb::IsOptionEqual<rocksdb::CompactionPri>(void const*, void const*)
Line
Count
Source
1147
12.5k
bool IsOptionEqual(const void* offset1, const void* offset2) {
1148
12.5k
  return (*static_cast<const T*>(offset1) == *static_cast<const T*>(offset2));
1149
12.5k
}
bool rocksdb::IsOptionEqual<rocksdb::CompressionType>(void const*, void const*)
Line
Count
Source
1147
49.5k
bool IsOptionEqual(const void* offset1, const void* offset2) {
1148
49.5k
  return (*static_cast<const T*>(offset1) == *static_cast<const T*>(offset2));
1149
49.5k
}
bool rocksdb::IsOptionEqual<rocksdb::ChecksumType>(void const*, void const*)
Line
Count
Source
1147
12.5k
bool IsOptionEqual(const void* offset1, const void* offset2) {
1148
12.5k
  return (*static_cast<const T*>(offset1) == *static_cast<const T*>(offset2));
1149
12.5k
}
Unexecuted instantiation: bool rocksdb::IsOptionEqual<rocksdb::EncodingType>(void const*, void const*)
bool rocksdb::IsOptionEqual<rocksdb::Temperature>(void const*, void const*)
Line
Count
Source
1147
48.7k
bool IsOptionEqual(const void* offset1, const void* offset2) {
1148
48.7k
  return (*static_cast<const T*>(offset1) == *static_cast<const T*>(offset2));
1149
48.7k
}
1150
1151
75.3k
static bool AreEqualDoubles(const double a, const double b) {
1152
75.3k
  return (fabs(a - b) < 0.00001);
1153
75.3k
}
1154
1155
static bool AreOptionsEqual(OptionType type, const void* this_offset,
1156
2.45M
                            const void* that_offset) {
1157
2.45M
  switch (type) {
1158
861k
    case OptionType::kBoolean:
1159
861k
      return IsOptionEqual<bool>(this_offset, that_offset);
1160
346k
    case OptionType::kInt:
1161
346k
      return IsOptionEqual<int>(this_offset, that_offset);
1162
73.8k
    case OptionType::kUInt:
1163
73.8k
      return IsOptionEqual<unsigned int>(this_offset, that_offset);
1164
0
    case OptionType::kInt32T:
1165
0
      return IsOptionEqual<int32_t>(this_offset, that_offset);
1166
12.5k
    case OptionType::kInt64T: {
1167
12.5k
      int64_t v1, v2;
1168
12.5k
      GetUnaligned(static_cast<const int64_t*>(this_offset), &v1);
1169
12.5k
      GetUnaligned(static_cast<const int64_t*>(that_offset), &v2);
1170
12.5k
      return (v1 == v2);
1171
0
    }
1172
12.5k
    case OptionType::kUInt8T:
1173
12.5k
      return IsOptionEqual<uint8_t>(this_offset, that_offset);
1174
99.7k
    case OptionType::kUInt32T:
1175
99.7k
      return IsOptionEqual<uint32_t>(this_offset, that_offset);
1176
403k
    case OptionType::kUInt64T: {
1177
403k
      uint64_t v1, v2;
1178
403k
      GetUnaligned(static_cast<const uint64_t*>(this_offset), &v1);
1179
403k
      GetUnaligned(static_cast<const uint64_t*>(that_offset), &v2);
1180
403k
      return (v1 == v2);
1181
0
    }
1182
243k
    case OptionType::kSizeT: {
1183
243k
      size_t v1, v2;
1184
243k
      GetUnaligned(static_cast<const size_t*>(this_offset), &v1);
1185
243k
      GetUnaligned(static_cast<const size_t*>(that_offset), &v2);
1186
243k
      return (v1 == v2);
1187
0
    }
1188
0
    case OptionType::kAtomicInt:
1189
0
      return IsOptionEqual<std::atomic<int>>(this_offset, that_offset);
1190
35.4k
    case OptionType::kString:
1191
35.4k
      return IsOptionEqual<std::string>(this_offset, that_offset);
1192
75.3k
    case OptionType::kDouble:
1193
75.3k
      return AreEqualDoubles(*static_cast<const double*>(this_offset),
1194
75.3k
                             *static_cast<const double*>(that_offset));
1195
12.5k
    case OptionType::kCompactionStyle:
1196
12.5k
      return IsOptionEqual<CompactionStyle>(this_offset, that_offset);
1197
12.5k
    case OptionType::kCompactionStopStyle:
1198
12.5k
      return IsOptionEqual<CompactionStopStyle>(this_offset, that_offset);
1199
12.5k
    case OptionType::kCompactionPri:
1200
12.5k
      return IsOptionEqual<CompactionPri>(this_offset, that_offset);
1201
49.5k
    case OptionType::kCompressionType:
1202
49.5k
      return IsOptionEqual<CompressionType>(this_offset, that_offset);
1203
12.5k
    case OptionType::kChecksumType:
1204
12.5k
      return IsOptionEqual<ChecksumType>(this_offset, that_offset);
1205
0
    case OptionType::kEncodingType:
1206
0
      return IsOptionEqual<EncodingType>(this_offset, that_offset);
1207
0
    case OptionType::kEncodedString:
1208
0
      return IsOptionEqual<std::string>(this_offset, that_offset);
1209
48.7k
    case OptionType::kTemperature:
1210
48.7k
      return IsOptionEqual<Temperature>(this_offset, that_offset);
1211
137k
    default:
1212
137k
      return false;
1213
2.45M
  }  // End switch
1214
2.45M
}
1215
1216
bool OptionTypeInfo::AreEqual(const ConfigOptions& config_options,
1217
                              const std::string& opt_name,
1218
                              const void* const this_ptr,
1219
                              const void* const that_ptr,
1220
2.68M
                              std::string* mismatch) const {
1221
2.68M
  auto level = GetSanityLevel();
1222
2.68M
  if (!config_options.IsCheckEnabled(level)) {
1223
12.5k
    return true;  // If the sanity level is not being checked, skip it
1224
12.5k
  }
1225
2.67M
  if (this_ptr == nullptr || that_ptr == nullptr) {
1226
0
    if (this_ptr == that_ptr) {
1227
0
      return true;
1228
0
    }
1229
2.67M
  } else if (equals_func_ != nullptr) {
1230
223k
    const void* this_addr = GetOffset(this_ptr);
1231
223k
    const void* that_addr = GetOffset(that_ptr);
1232
223k
    if (equals_func_(config_options, opt_name, this_addr, that_addr,
1233
223k
                     mismatch)) {
1234
223k
      return true;
1235
223k
    }
1236
2.45M
  } else {
1237
2.45M
    const void* this_addr = GetOffset(this_ptr);
1238
2.45M
    const void* that_addr = GetOffset(that_ptr);
1239
2.45M
    if (AreOptionsEqual(type_, this_addr, that_addr)) {
1240
2.31M
      return true;
1241
2.31M
    } else if (IsConfigurable()) {
1242
137k
      const auto* this_config = AsRawPointer<Configurable>(this_ptr);
1243
137k
      const auto* that_config = AsRawPointer<Configurable>(that_ptr);
1244
137k
      if (this_config == that_config) {
1245
112k
        return true;
1246
112k
      } else if (this_config != nullptr && that_config != nullptr) {
1247
25.1k
        std::string bad_name;
1248
25.1k
        bool matches;
1249
25.1k
        if (level < config_options.sanity_level) {
1250
12.5k
          ConfigOptions copy = config_options;
1251
12.5k
          copy.sanity_level = level;
1252
12.5k
          matches = this_config->AreEquivalent(copy, that_config, &bad_name);
1253
12.5k
        } else {
1254
12.5k
          matches = this_config->AreEquivalent(config_options, that_config,
1255
12.5k
                                               &bad_name);
1256
12.5k
        }
1257
25.1k
        if (!matches) {
1258
0
          *mismatch = opt_name + "." + bad_name;
1259
0
        }
1260
25.1k
        return matches;
1261
25.1k
      }
1262
137k
    }
1263
2.45M
  }
1264
0
  if (mismatch->empty()) {
1265
0
    *mismatch = opt_name;
1266
0
  }
1267
0
  return false;
1268
2.67M
}
1269
1270
bool OptionTypeInfo::TypesAreEqual(
1271
    const ConfigOptions& config_options,
1272
    const std::unordered_map<std::string, OptionTypeInfo>& type_map,
1273
37.6k
    const void* this_addr, const void* that_addr, std::string* mismatch) {
1274
213k
  for (const auto& iter : type_map) {
1275
213k
    const auto& opt_info = iter.second;
1276
213k
    if (!opt_info.AreEqual(config_options, iter.first, this_addr, that_addr,
1277
213k
                           mismatch)) {
1278
0
      return false;
1279
0
    }
1280
213k
  }
1281
37.6k
  return true;
1282
37.6k
}
1283
1284
bool OptionTypeInfo::StructsAreEqual(
1285
    const ConfigOptions& config_options, const std::string& struct_name,
1286
    const std::unordered_map<std::string, OptionTypeInfo>* struct_map,
1287
    const std::string& opt_name, const void* this_addr, const void* that_addr,
1288
37.6k
    std::string* mismatch) {
1289
37.6k
  assert(struct_map);
1290
37.6k
  bool matches = true;
1291
37.6k
  std::string result;
1292
37.6k
  if (EndsWith(opt_name, struct_name)) {
1293
    // This option represents the entire struct
1294
37.6k
    matches = TypesAreEqual(config_options, *struct_map, this_addr, that_addr,
1295
37.6k
                            &result);
1296
37.6k
    if (!matches) {
1297
0
      *mismatch = struct_name + "." + result;
1298
0
      return false;
1299
0
    }
1300
37.6k
  } else if (StartsWith(opt_name, struct_name + ".")) {
1301
    // This option represents a nested field in the struct (e.g, struct.field)
1302
0
    std::string elem_name;
1303
0
    const auto opt_info =
1304
0
        Find(opt_name.substr(struct_name.size() + 1), *struct_map, &elem_name);
1305
0
    assert(opt_info);
1306
0
    if (opt_info == nullptr) {
1307
0
      *mismatch = opt_name;
1308
0
      matches = false;
1309
0
    } else if (!opt_info->AreEqual(config_options, elem_name, this_addr,
1310
0
                                   that_addr, &result)) {
1311
0
      matches = false;
1312
0
      *mismatch = struct_name + "." + result;
1313
0
    }
1314
0
  } else {
1315
    // This option represents a field in the struct (e.g. field)
1316
0
    std::string elem_name;
1317
0
    const auto opt_info = Find(opt_name, *struct_map, &elem_name);
1318
0
    assert(opt_info);
1319
0
    if (opt_info == nullptr) {
1320
0
      *mismatch = struct_name + "." + opt_name;
1321
0
      matches = false;
1322
0
    } else if (!opt_info->AreEqual(config_options, elem_name, this_addr,
1323
0
                                   that_addr, &result)) {
1324
0
      matches = false;
1325
0
      *mismatch = struct_name + "." + result;
1326
0
    }
1327
0
  }
1328
37.6k
  return matches;
1329
37.6k
}
1330
1331
bool MatchesOptionsTypeFromMap(
1332
    const ConfigOptions& config_options,
1333
    const std::unordered_map<std::string, OptionTypeInfo>& type_map,
1334
    const void* const this_ptr, const void* const that_ptr,
1335
0
    std::string* mismatch) {
1336
0
  for (auto& pair : type_map) {
1337
    // We skip checking deprecated variables as they might
1338
    // contain random values since they might not be initialized
1339
0
    if (config_options.IsCheckEnabled(pair.second.GetSanityLevel())) {
1340
0
      if (!pair.second.AreEqual(config_options, pair.first, this_ptr, that_ptr,
1341
0
                                mismatch) &&
1342
0
          !pair.second.AreEqualByName(config_options, pair.first, this_ptr,
1343
0
                                      that_ptr)) {
1344
0
        return false;
1345
0
      }
1346
0
    }
1347
0
  }
1348
0
  return true;
1349
0
}
1350
1351
bool OptionTypeInfo::AreEqualByName(const ConfigOptions& config_options,
1352
                                    const std::string& opt_name,
1353
                                    const void* const this_ptr,
1354
0
                                    const void* const that_ptr) const {
1355
0
  if (IsByName()) {
1356
0
    std::string that_value;
1357
0
    if (Serialize(config_options, opt_name, that_ptr, &that_value).ok()) {
1358
0
      return AreEqualByName(config_options, opt_name, this_ptr, that_value);
1359
0
    }
1360
0
  }
1361
0
  return false;
1362
0
}
1363
1364
bool OptionTypeInfo::AreEqualByName(const ConfigOptions& config_options,
1365
                                    const std::string& opt_name,
1366
                                    const void* const opt_ptr,
1367
0
                                    const std::string& that_value) const {
1368
0
  std::string this_value;
1369
0
  if (!IsByName()) {
1370
0
    return false;
1371
0
  } else if (!Serialize(config_options, opt_name, opt_ptr, &this_value).ok()) {
1372
0
    return false;
1373
0
  } else if (IsEnabled(OptionVerificationType::kByNameAllowFromNull)) {
1374
0
    if (that_value == kNullptrString) {
1375
0
      return true;
1376
0
    }
1377
0
  } else if (IsEnabled(OptionVerificationType::kByNameAllowNull)) {
1378
0
    if (that_value == kNullptrString) {
1379
0
      return true;
1380
0
    }
1381
0
  }
1382
0
  return (this_value == that_value);
1383
0
}
1384
1385
Status OptionTypeInfo::Prepare(const ConfigOptions& config_options,
1386
147k
                               const std::string& name, void* opt_ptr) const {
1387
147k
  if (ShouldPrepare()) {
1388
147k
    if (prepare_func_ != nullptr) {
1389
11.8k
      void* opt_addr = GetOffset(opt_ptr);
1390
11.8k
      return prepare_func_(config_options, name, opt_addr);
1391
135k
    } else if (IsConfigurable()) {
1392
135k
      Configurable* config = AsRawPointer<Configurable>(opt_ptr);
1393
135k
      if (config != nullptr) {
1394
25.1k
        return config->PrepareOptions(config_options);
1395
110k
      } else if (!CanBeNull()) {
1396
0
        return Status::NotFound("Missing configurable object", name);
1397
0
      }
1398
135k
    }
1399
147k
  }
1400
110k
  return Status::OK();
1401
147k
}
1402
1403
Status OptionTypeInfo::Validate(const DBOptions& db_opts,
1404
                                const ColumnFamilyOptions& cf_opts,
1405
                                const std::string& name,
1406
171k
                                const void* opt_ptr) const {
1407
171k
  if (ShouldValidate()) {
1408
171k
    if (validate_func_ != nullptr) {
1409
11.4k
      const void* opt_addr = GetOffset(opt_ptr);
1410
11.4k
      return validate_func_(db_opts, cf_opts, name, opt_addr);
1411
160k
    } else if (IsConfigurable()) {
1412
160k
      const Configurable* config = AsRawPointer<Configurable>(opt_ptr);
1413
160k
      if (config != nullptr) {
1414
45.8k
        return config->ValidateOptions(db_opts, cf_opts);
1415
114k
      } else if (!CanBeNull()) {
1416
0
        return Status::NotFound("Missing configurable object", name);
1417
0
      }
1418
160k
    }
1419
171k
  }
1420
114k
  return Status::OK();
1421
171k
}
1422
1423
const OptionTypeInfo* OptionTypeInfo::Find(
1424
    const std::string& opt_name,
1425
    const std::unordered_map<std::string, OptionTypeInfo>& opt_map,
1426
5.52M
    std::string* elem_name) {
1427
5.52M
  const auto iter = opt_map.find(opt_name);  // Look up the value in the map
1428
5.52M
  if (iter != opt_map.end()) {               // Found the option in the map
1429
3.31M
    *elem_name = opt_name;                   // Return the name
1430
3.31M
    return &(iter->second);  // Return the contents of the iterator
1431
3.31M
  } else {
1432
2.20M
    auto idx = opt_name.find('.');              // Look for a separator
1433
2.20M
    if (idx > 0 && idx != std::string::npos) {  // We found a separator
1434
0
      auto siter =
1435
0
          opt_map.find(opt_name.substr(0, idx));  // Look for the short name
1436
0
      if (siter != opt_map.end()) {               // We found the short name
1437
0
        if (siter->second.IsStruct() ||           // If the object is a struct
1438
0
            siter->second.IsConfigurable()) {     // or a Configurable
1439
0
          *elem_name = opt_name.substr(idx + 1);  // Return the rest
1440
0
          return &(siter->second);  // Return the contents of the iterator
1441
0
        }
1442
0
      }
1443
0
    }
1444
2.20M
  }
1445
2.20M
  return nullptr;
1446
5.52M
}
1447
1448
}  // namespace ROCKSDB_NAMESPACE