Coverage Report

Created: 2026-04-10 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rocksdb/options/configurable.cc
Line
Count
Source
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
6
#include "rocksdb/configurable.h"
7
8
#include "logging/logging.h"
9
#include "options/configurable_helper.h"
10
#include "options/options_helper.h"
11
#include "rocksdb/customizable.h"
12
#include "rocksdb/status.h"
13
#include "rocksdb/utilities/object_registry.h"
14
#include "rocksdb/utilities/options_type.h"
15
#include "util/coding.h"
16
#include "util/string_util.h"
17
18
namespace ROCKSDB_NAMESPACE {
19
20
namespace {
21
2.77M
intptr_t GetOffset(const Configurable* holder, void* field) {
22
2.77M
  return reinterpret_cast<intptr_t>(field) -
23
2.77M
         reinterpret_cast<intptr_t>(static_cast<const void*>(holder));
24
2.77M
}
25
26
49.3M
void* ApplyOffset(const Configurable* holder, intptr_t offset) {
27
49.3M
  return reinterpret_cast<void*>(
28
49.3M
      reinterpret_cast<intptr_t>(static_cast<const void*>(holder)) + offset);
29
49.3M
}
30
}  // namespace
31
32
void Configurable::RegisterOptions(
33
    const std::string& name, void* opt_ptr,
34
2.77M
    const std::unordered_map<std::string, OptionTypeInfo>* type_map) {
35
2.77M
  RegisteredOptions opts;
36
2.77M
  opts.name = name;
37
2.77M
  opts.type_map = type_map;
38
2.77M
  opts.opt_offset = GetOffset(this, opt_ptr);
39
2.77M
  options_.emplace_back(opts);
40
2.77M
}
41
42
//*************************************************************************
43
//
44
//       Methods for Initializing and Validating Configurable Objects
45
//
46
//*************************************************************************
47
48
454k
Status Configurable::PrepareOptions(const ConfigOptions& opts) {
49
  // We ignore the invoke_prepare_options here intentionally,
50
  // as if you are here, you must have called PrepareOptions explicitly.
51
454k
  Status status = Status::OK();
52
454k
  for (const auto& opt_iter : options_) {
53
454k
    if (opt_iter.type_map != nullptr) {
54
20.5M
      for (const auto& map_iter : *(opt_iter.type_map)) {
55
20.5M
        auto& opt_info = map_iter.second;
56
20.5M
        if (opt_info.ShouldPrepare()) {
57
1.21M
          status = opt_info.Prepare(opts, map_iter.first,
58
1.21M
                                    ApplyOffset(this, opt_iter.opt_offset));
59
1.21M
          if (!status.ok()) {
60
0
            return status;
61
0
          }
62
1.21M
        }
63
20.5M
      }
64
454k
    }
65
454k
  }
66
454k
  return status;
67
454k
}
68
69
Status Configurable::ValidateOptions(const DBOptions& db_opts,
70
402k
                                     const ColumnFamilyOptions& cf_opts) const {
71
402k
  Status status;
72
402k
  for (const auto& opt_iter : options_) {
73
344k
    if (opt_iter.type_map != nullptr) {
74
16.1M
      for (const auto& map_iter : *(opt_iter.type_map)) {
75
16.1M
        auto& opt_info = map_iter.second;
76
16.1M
        if (opt_info.ShouldValidate()) {
77
976k
          status = opt_info.Validate(db_opts, cf_opts, map_iter.first,
78
976k
                                     ApplyOffset(this, opt_iter.opt_offset));
79
976k
          if (!status.ok()) {
80
0
            return status;
81
0
          }
82
976k
        }
83
16.1M
      }
84
344k
    }
85
344k
  }
86
402k
  return status;
87
402k
}
88
89
/*********************************************************************************/
90
/*                                                                               */
91
/*       Methods for Retrieving Options from Configurables */
92
/*                                                                               */
93
/*********************************************************************************/
94
95
1.45M
const void* Configurable::GetOptionsPtr(const std::string& name) const {
96
1.80M
  for (const auto& o : options_) {
97
1.80M
    if (o.name == name) {
98
1.45M
      return ApplyOffset(this, o.opt_offset);
99
1.45M
    }
100
1.80M
  }
101
0
  return nullptr;
102
1.45M
}
103
104
34.9M
std::string Configurable::GetOptionName(const std::string& opt_name) const {
105
34.9M
  return opt_name;
106
34.9M
}
107
108
const OptionTypeInfo* ConfigurableHelper::FindOption(
109
    const Configurable& configurable, const std::string& short_name,
110
0
    std::string* opt_name, void** opt_ptr) {
111
0
  for (const auto& iter : configurable.options_) {
112
0
    if (iter.type_map != nullptr) {
113
0
      const auto opt_info =
114
0
          OptionTypeInfo::Find(short_name, *(iter.type_map), opt_name);
115
0
      if (opt_info != nullptr) {
116
0
        *opt_ptr = ApplyOffset(&configurable, iter.opt_offset);
117
0
        return opt_info;
118
0
      }
119
0
    }
120
0
  }
121
0
  return nullptr;
122
0
}
123
124
//*************************************************************************
125
//
126
//       Methods for Configuring Options from Strings/Name-Value Pairs/Maps
127
//
128
//*************************************************************************
129
130
Status Configurable::ConfigureFromMap(
131
    const ConfigOptions& config_options,
132
691k
    const std::unordered_map<std::string, std::string>& opts_map) {
133
691k
  Status s = ConfigureFromMap(config_options, opts_map, nullptr);
134
691k
  return s;
135
691k
}
136
137
Status Configurable::ConfigureFromMap(
138
    const ConfigOptions& config_options,
139
    const std::unordered_map<std::string, std::string>& opts_map,
140
691k
    std::unordered_map<std::string, std::string>* unused) {
141
691k
  return ConfigureOptions(config_options, opts_map, unused);
142
691k
}
143
144
Status Configurable::ConfigureOptions(
145
    const ConfigOptions& config_options,
146
    const std::unordered_map<std::string, std::string>& opts_map,
147
691k
    std::unordered_map<std::string, std::string>* unused) {
148
691k
  std::string curr_opts;
149
691k
  Status s;
150
691k
  if (!opts_map.empty()) {
151
    // There are options in the map.
152
    // Save the current configuration in curr_opts and then configure the
153
    // options, but do not prepare them now.  We will do all the prepare when
154
    // the configuration is complete.
155
278k
    ConfigOptions copy = config_options;
156
278k
    copy.invoke_prepare_options = false;
157
278k
    if (!config_options.ignore_unknown_options) {
158
      // If we are not ignoring unused, get the defaults in case we need to
159
      // reset
160
278k
      copy.depth = ConfigOptions::kDepthDetailed;
161
278k
      copy.delimiter = "; ";
162
278k
      GetOptionString(copy, &curr_opts).PermitUncheckedError();
163
278k
    }
164
165
278k
    s = ConfigurableHelper::ConfigureOptions(copy, *this, opts_map, unused);
166
278k
  }
167
691k
  if (config_options.invoke_prepare_options && s.ok()) {
168
0
    s = PrepareOptions(config_options);
169
0
  }
170
691k
  if (!s.ok() && !curr_opts.empty()) {
171
0
    ConfigOptions reset = config_options;
172
0
    reset.ignore_unknown_options = true;
173
0
    reset.invoke_prepare_options = true;
174
0
    reset.ignore_unsupported_options = true;
175
    // There are some options to reset from this current error
176
0
    ConfigureFromString(reset, curr_opts).PermitUncheckedError();
177
0
  }
178
691k
  return s;
179
691k
}
180
181
Status Configurable::ParseStringOptions(const ConfigOptions& /*config_options*/,
182
0
                                        const std::string& /*opts_str*/) {
183
0
  return Status::OK();
184
0
}
185
186
Status Configurable::ConfigureFromString(const ConfigOptions& config_options,
187
0
                                         const std::string& opts_str) {
188
0
  Status s;
189
0
  if (!opts_str.empty()) {
190
0
    if (opts_str.find(';') != std::string::npos ||
191
0
        opts_str.find('=') != std::string::npos) {
192
0
      std::unordered_map<std::string, std::string> opt_map;
193
0
      s = StringToMap(opts_str, &opt_map);
194
0
      if (s.ok()) {
195
0
        s = ConfigureFromMap(config_options, opt_map, nullptr);
196
0
      }
197
0
    } else {
198
0
      s = ParseStringOptions(config_options, opts_str);
199
0
      if (s.ok() && config_options.invoke_prepare_options) {
200
0
        s = PrepareOptions(config_options);
201
0
      }
202
0
    }
203
0
  } else if (config_options.invoke_prepare_options) {
204
0
    s = PrepareOptions(config_options);
205
0
  } else {
206
0
    s = Status::OK();
207
0
  }
208
0
  return s;
209
0
}
210
211
/**
212
 * Sets the value of the named property to the input value, returning OK on
213
 * succcess.
214
 */
215
Status Configurable::ConfigureOption(const ConfigOptions& config_options,
216
                                     const std::string& name,
217
0
                                     const std::string& value) {
218
0
  return ConfigurableHelper::ConfigureSingleOption(config_options, *this, name,
219
0
                                                   value);
220
0
}
221
222
/**
223
 * Looks for the named option amongst the options for this type and sets
224
 * the value for it to be the input value.
225
 * If the name was found, found_option will be set to true and the resulting
226
 * status should be returned.
227
 */
228
229
Status Configurable::ParseOption(const ConfigOptions& config_options,
230
                                 const OptionTypeInfo& opt_info,
231
                                 const std::string& opt_name,
232
20.0M
                                 const std::string& opt_value, void* opt_ptr) {
233
20.0M
  if (opt_info.IsMutable()) {
234
8.30M
    if (config_options.mutable_options_only) {
235
      // This option is mutable. Treat all of its children as mutable as well
236
0
      ConfigOptions copy = config_options;
237
0
      copy.mutable_options_only = false;
238
0
      return opt_info.Parse(copy, opt_name, opt_value, opt_ptr);
239
8.30M
    } else {
240
8.30M
      return opt_info.Parse(config_options, opt_name, opt_value, opt_ptr);
241
8.30M
    }
242
11.7M
  } else if (config_options.mutable_options_only) {
243
0
    return Status::InvalidArgument("Option not changeable: " + opt_name);
244
11.7M
  } else {
245
11.7M
    return opt_info.Parse(config_options, opt_name, opt_value, opt_ptr);
246
11.7M
  }
247
20.0M
}
248
249
Status ConfigurableHelper::ConfigureOptions(
250
    const ConfigOptions& config_options, Configurable& configurable,
251
    const std::unordered_map<std::string, std::string>& opts_map,
252
278k
    std::unordered_map<std::string, std::string>* unused) {
253
278k
  std::unordered_map<std::string, std::string> remaining = opts_map;
254
278k
  Status s = Status::OK();
255
278k
  if (!opts_map.empty()) {
256
454k
    for (const auto& iter : configurable.options_) {
257
454k
      if (iter.type_map != nullptr) {
258
454k
        s = ConfigureSomeOptions(config_options, configurable, *(iter.type_map),
259
454k
                                 &remaining,
260
454k
                                 ApplyOffset(&configurable, iter.opt_offset));
261
454k
        if (remaining.empty()) {  // Are there more options left?
262
278k
          break;
263
278k
        } else if (!s.ok()) {
264
0
          break;
265
0
        }
266
454k
      }
267
454k
    }
268
278k
  }
269
278k
  if (unused != nullptr && !remaining.empty()) {
270
0
    unused->insert(remaining.begin(), remaining.end());
271
0
  }
272
278k
  if (config_options.ignore_unknown_options) {
273
0
    s = Status::OK();
274
278k
  } else if (s.ok() && unused == nullptr && !remaining.empty()) {
275
0
    s = Status::NotFound("Extra option not recognized",
276
0
                         remaining.begin()->first);
277
0
  }
278
278k
  return s;
279
278k
}
280
281
/**
282
 * Updates the object with the named-value property values, returning OK on
283
 * succcess. Any properties that were found are removed from the options list;
284
 * upon return only options that were not found in this opt_map remain.
285
286
 * Returns:
287
 * -  OK if ignore_unknown_options is set
288
 * - InvalidArgument, if any option was invalid
289
 * - NotSupported, if any option is unsupported and ignore_unsupported_options
290
 is OFF
291
 * - OK, if no option was invalid or not supported (or ignored)
292
 */
293
Status ConfigurableHelper::ConfigureSomeOptions(
294
    const ConfigOptions& config_options, Configurable& configurable,
295
    const std::unordered_map<std::string, OptionTypeInfo>& type_map,
296
454k
    std::unordered_map<std::string, std::string>* options, void* opt_ptr) {
297
454k
  Status result = Status::OK();  // The last non-OK result (if any)
298
454k
  Status notsup = Status::OK();  // The last NotSupported result (if any)
299
454k
  std::string elem_name;
300
454k
  int found = 1;
301
454k
  std::unordered_set<std::string> unsupported;
302
  // While there are unused properties and we processed at least one,
303
  // go through the remaining unused properties and attempt to configure them.
304
1.08M
  while (found > 0 && !options->empty()) {
305
630k
    found = 0;
306
630k
    notsup = Status::OK();
307
35.6M
    for (auto it = options->begin(); it != options->end();) {
308
34.9M
      const std::string& opt_name = configurable.GetOptionName(it->first);
309
34.9M
      const std::string& opt_value = it->second;
310
34.9M
      const auto opt_info =
311
34.9M
          OptionTypeInfo::Find(opt_name, type_map, &elem_name);
312
34.9M
      if (opt_info == nullptr) {  // Did not find the option.  Skip it
313
14.9M
        ++it;
314
20.0M
      } else {
315
20.0M
        Status s = ConfigureOption(config_options, configurable, *opt_info,
316
20.0M
                                   opt_name, elem_name, opt_value, opt_ptr);
317
20.0M
        if (s.IsNotFound()) {
318
0
          ++it;
319
20.0M
        } else if (s.IsNotSupported()) {
320
0
          notsup = s;
321
0
          unsupported.insert(it->first);
322
0
          ++it;  // Skip it for now
323
20.0M
        } else {
324
20.0M
          found++;
325
20.0M
          it = options->erase(it);
326
20.0M
          if (!s.ok()) {
327
0
            result = s;
328
0
          }
329
20.0M
        }
330
20.0M
      }
331
34.9M
    }  // End for all remaining options
332
630k
  }  // End while found one or options remain
333
334
  // Now that we have been through the list, remove any unsupported
335
454k
  for (const auto& u : unsupported) {
336
0
    auto it = options->find(u);
337
0
    if (it != options->end()) {
338
0
      options->erase(it);
339
0
    }
340
0
  }
341
454k
  if (config_options.ignore_unknown_options) {
342
0
    if (!result.ok()) {
343
0
      result.PermitUncheckedError();
344
0
    }
345
0
    if (!notsup.ok()) {
346
0
      notsup.PermitUncheckedError();
347
0
    }
348
0
    return Status::OK();
349
454k
  } else if (!result.ok()) {
350
0
    if (!notsup.ok()) {
351
0
      notsup.PermitUncheckedError();
352
0
    }
353
0
    return result;
354
454k
  } else if (config_options.ignore_unsupported_options) {
355
454k
    if (!notsup.ok()) {
356
0
      notsup.PermitUncheckedError();
357
0
    }
358
454k
    return Status::OK();
359
454k
  } else {
360
0
    return notsup;
361
0
  }
362
454k
}
363
364
Status ConfigurableHelper::ConfigureSingleOption(
365
    const ConfigOptions& config_options, Configurable& configurable,
366
0
    const std::string& name, const std::string& value) {
367
0
  const std::string& opt_name = configurable.GetOptionName(name);
368
0
  std::string elem_name;
369
0
  void* opt_ptr = nullptr;
370
0
  const auto opt_info =
371
0
      FindOption(configurable, opt_name, &elem_name, &opt_ptr);
372
0
  if (opt_info == nullptr) {
373
0
    return Status::NotFound("Could not find option", name);
374
0
  } else {
375
0
    return ConfigureOption(config_options, configurable, *opt_info, opt_name,
376
0
                           elem_name, value, opt_ptr);
377
0
  }
378
0
}
379
Status ConfigurableHelper::ConfigureCustomizableOption(
380
    const ConfigOptions& config_options, Configurable& configurable,
381
    const OptionTypeInfo& opt_info, const std::string& opt_name,
382
1.48M
    const std::string& name, const std::string& value, void* opt_ptr) {
383
1.48M
  Customizable* custom = opt_info.AsRawPointer<Customizable>(opt_ptr);
384
1.48M
  ConfigOptions copy = config_options;
385
1.48M
  if (opt_info.IsMutable()) {
386
    // This option is mutable. Pass that property on to any subsequent calls
387
309k
    copy.mutable_options_only = false;
388
309k
  }
389
390
1.48M
  if (opt_info.IsMutable() || !config_options.mutable_options_only) {
391
    // Either the option is mutable, or we are processing all of the options
392
1.48M
    if (opt_name == name || name == OptionTypeInfo::kIdPropName() ||
393
1.48M
        EndsWith(opt_name, OptionTypeInfo::kIdPropSuffix())) {
394
1.48M
      return configurable.ParseOption(copy, opt_info, name, value, opt_ptr);
395
1.48M
    } else if (value.empty()) {
396
0
      return Status::OK();
397
0
    } else if (custom == nullptr || !StartsWith(name, custom->GetId() + ".")) {
398
0
      return configurable.ParseOption(copy, opt_info, name, value, opt_ptr);
399
0
    } else if (value.find('=') != std::string::npos) {
400
0
      return custom->ConfigureFromString(copy, value);
401
0
    } else {
402
0
      return custom->ConfigureOption(copy, name, value);
403
0
    }
404
1.48M
  } else {
405
    // We are processing immutable options, which means that we cannot change
406
    // the Customizable object itself, but could change its mutable properties.
407
    // Check to make sure that nothing is trying to change the Customizable
408
0
    if (custom == nullptr) {
409
      // We do not have a Customizable to configure.  This is OK if the
410
      // value is empty (nothing being configured) but an error otherwise
411
0
      if (value.empty()) {
412
0
        return Status::OK();
413
0
      } else {
414
0
        return Status::InvalidArgument("Option not changeable: " + opt_name);
415
0
      }
416
0
    } else if (EndsWith(opt_name, OptionTypeInfo::kIdPropSuffix()) ||
417
0
               name == OptionTypeInfo::kIdPropName()) {
418
      // We have a property of the form "id=value" or "table.id=value"
419
      // This is OK if we ID/value matches the current customizable object
420
0
      if (custom->GetId() == value) {
421
0
        return Status::OK();
422
0
      } else {
423
0
        return Status::InvalidArgument("Option not changeable: " + opt_name);
424
0
      }
425
0
    } else if (opt_name == name) {
426
      // The properties are of one of forms:
427
      //    name = { id = id; prop1 = value1; ... }
428
      //    name = { prop1=value1; prop2=value2; ... }
429
      //    name = ID
430
      // Convert the value to a map and extract the ID
431
      // If the ID does not match that of the current customizable, return an
432
      // error. Otherwise, update the current customizable via the properties
433
      // map
434
0
      std::unordered_map<std::string, std::string> props;
435
0
      std::string id;
436
0
      Status s =
437
0
          Configurable::GetOptionsMap(value, custom->GetId(), &id, &props);
438
0
      if (!s.ok()) {
439
0
        return s;
440
0
      } else if (custom->GetId() != id) {
441
0
        return Status::InvalidArgument("Option not changeable: " + opt_name);
442
0
      } else if (props.empty()) {
443
0
        return Status::OK();
444
0
      } else {
445
0
        return custom->ConfigureFromMap(copy, props);
446
0
      }
447
0
    } else {
448
      // Attempting to configure one of the properties of the customizable
449
      // Let it through
450
0
      return custom->ConfigureOption(copy, name, value);
451
0
    }
452
0
  }
453
1.48M
}
454
455
Status ConfigurableHelper::ConfigureOption(
456
    const ConfigOptions& config_options, Configurable& configurable,
457
    const OptionTypeInfo& opt_info, const std::string& opt_name,
458
20.0M
    const std::string& name, const std::string& value, void* opt_ptr) {
459
20.0M
  if (opt_info.IsCustomizable()) {
460
1.48M
    return ConfigureCustomizableOption(config_options, configurable, opt_info,
461
1.48M
                                       opt_name, name, value, opt_ptr);
462
18.5M
  } else if (opt_name == name) {
463
18.5M
    return configurable.ParseOption(config_options, opt_info, opt_name, value,
464
18.5M
                                    opt_ptr);
465
18.5M
  } else if (opt_info.IsStruct() || opt_info.IsConfigurable()) {
466
0
    return configurable.ParseOption(config_options, opt_info, name, value,
467
0
                                    opt_ptr);
468
0
  } else {
469
0
    return Status::NotFound("Unknown how to configure option", name);
470
0
  }
471
20.0M
}
472
473
//*******************************************************************************
474
//
475
//       Methods for Converting Options into strings
476
//
477
//*******************************************************************************
478
479
Status Configurable::GetOptionString(const ConfigOptions& config_options,
480
763k
                                     std::string* result) const {
481
763k
  assert(result);
482
763k
  result->clear();
483
763k
  return ConfigurableHelper::SerializeOptions(config_options, *this, "",
484
763k
                                              result);
485
763k
}
486
487
std::string Configurable::ToString(const ConfigOptions& config_options,
488
824k
                                   const std::string& prefix) const {
489
824k
  std::string result = SerializeOptions(config_options, prefix);
490
824k
  if (result.empty() || result.find('=') == std::string::npos) {
491
721k
    return result;
492
721k
  } else {
493
103k
    return "{" + result + "}";
494
103k
  }
495
824k
}
496
497
std::string Configurable::SerializeOptions(const ConfigOptions& config_options,
498
824k
                                           const std::string& header) const {
499
824k
  std::string result;
500
824k
  Status s = ConfigurableHelper::SerializeOptions(config_options, *this, header,
501
824k
                                                  &result);
502
824k
  assert(s.ok());
503
824k
  return result;
504
824k
}
505
506
Status Configurable::GetOption(const ConfigOptions& config_options,
507
                               const std::string& name,
508
0
                               std::string* value) const {
509
0
  return ConfigurableHelper::GetOption(config_options, *this,
510
0
                                       GetOptionName(name), value);
511
0
}
512
513
Status ConfigurableHelper::GetOption(const ConfigOptions& config_options,
514
                                     const Configurable& configurable,
515
                                     const std::string& short_name,
516
0
                                     std::string* value) {
517
  // Look for option directly
518
0
  assert(value);
519
0
  value->clear();
520
521
0
  std::string opt_name;
522
0
  void* opt_ptr = nullptr;
523
0
  const auto opt_info =
524
0
      FindOption(configurable, short_name, &opt_name, &opt_ptr);
525
0
  if (opt_info != nullptr) {
526
0
    ConfigOptions embedded = config_options;
527
0
    embedded.delimiter = ";";
528
0
    if (short_name == opt_name) {
529
0
      return opt_info->Serialize(embedded, opt_name, opt_ptr, value);
530
0
    } else if (opt_info->IsStruct()) {
531
0
      return opt_info->Serialize(embedded, opt_name, opt_ptr, value);
532
0
    } else if (opt_info->IsConfigurable()) {
533
0
      auto const* config = opt_info->AsRawPointer<Configurable>(opt_ptr);
534
0
      if (config != nullptr) {
535
0
        return config->GetOption(embedded, opt_name, value);
536
0
      }
537
0
    }
538
0
  }
539
0
  return Status::NotFound("Cannot find option: ", short_name);
540
0
}
541
542
Status ConfigurableHelper::SerializeOptions(const ConfigOptions& config_options,
543
                                            const Configurable& configurable,
544
                                            const std::string& prefix,
545
1.58M
                                            std::string* result) {
546
1.58M
  assert(result);
547
1.58M
  for (auto const& opt_iter : configurable.options_) {
548
1.21M
    if (opt_iter.type_map != nullptr) {
549
56.0M
      for (const auto& map_iter : *(opt_iter.type_map)) {
550
56.0M
        const auto& opt_name = map_iter.first;
551
56.0M
        const auto& opt_info = map_iter.second;
552
56.0M
        if (opt_info.ShouldSerialize()) {
553
45.2M
          std::string value;
554
45.2M
          Status s;
555
45.2M
          void* opt_ptr = ApplyOffset(&configurable, opt_iter.opt_offset);
556
45.2M
          if (!config_options.mutable_options_only) {
557
45.2M
            s = opt_info.Serialize(config_options, prefix + opt_name, opt_ptr,
558
45.2M
                                   &value);
559
45.2M
          } else if (opt_info.IsMutable()) {
560
0
            ConfigOptions copy = config_options;
561
0
            copy.mutable_options_only = false;
562
0
            s = opt_info.Serialize(copy, prefix + opt_name, opt_ptr, &value);
563
0
          } else if (opt_info.IsConfigurable()) {
564
            // If it is a Configurable and we are either printing all of the
565
            // details or not printing only the name, this option should be
566
            // included in the list
567
0
            if (config_options.IsDetailed() ||
568
0
                !opt_info.IsEnabled(OptionTypeFlags::kStringNameOnly)) {
569
0
              s = opt_info.Serialize(config_options, prefix + opt_name, opt_ptr,
570
0
                                     &value);
571
0
            }
572
0
          }
573
45.2M
          if (!s.ok()) {
574
0
            return s;
575
45.2M
          } else if (!value.empty()) {
576
            // <prefix><opt_name>=<value><delimiter>
577
44.2M
            result->append(prefix + opt_name + "=" + value +
578
44.2M
                           config_options.delimiter);
579
44.2M
          }
580
45.2M
        }
581
56.0M
      }
582
1.21M
    }
583
1.21M
  }
584
1.58M
  return Status::OK();
585
1.58M
}
586
587
//********************************************************************************
588
//
589
// Methods for listing the options from Configurables
590
//
591
//********************************************************************************
592
Status Configurable::GetOptionNames(
593
    const ConfigOptions& config_options,
594
0
    std::unordered_set<std::string>* result) const {
595
0
  assert(result);
596
0
  return ConfigurableHelper::ListOptions(config_options, *this, "", result);
597
0
}
598
599
Status ConfigurableHelper::ListOptions(
600
    const ConfigOptions& config_options, const Configurable& configurable,
601
0
    const std::string& prefix, std::unordered_set<std::string>* result) {
602
0
  Status status;
603
0
  for (auto const& opt_iter : configurable.options_) {
604
0
    if (opt_iter.type_map != nullptr) {
605
0
      for (const auto& map_iter : *(opt_iter.type_map)) {
606
0
        const auto& opt_name = map_iter.first;
607
0
        const auto& opt_info = map_iter.second;
608
        // If the option is no longer used in rocksdb and marked as deprecated,
609
        // we skip it in the serialization.
610
0
        if (!opt_info.IsDeprecated() && !opt_info.IsAlias()) {
611
0
          if (!config_options.mutable_options_only) {
612
0
            result->emplace(prefix + opt_name);
613
0
          } else if (opt_info.IsMutable()) {
614
0
            result->emplace(prefix + opt_name);
615
0
          }
616
0
        }
617
0
      }
618
0
    }
619
0
  }
620
0
  return status;
621
0
}
622
623
//*******************************************************************************
624
//
625
//       Methods for Comparing Configurables
626
//
627
//*******************************************************************************
628
629
bool Configurable::AreEquivalent(const ConfigOptions& config_options,
630
                                 const Configurable* other,
631
381k
                                 std::string* name) const {
632
381k
  assert(name);
633
381k
  name->clear();
634
381k
  if (this == other || config_options.IsCheckDisabled()) {
635
0
    return true;
636
381k
  } else if (other != nullptr) {
637
381k
    return ConfigurableHelper::AreEquivalent(config_options, *this, *other,
638
381k
                                             name);
639
381k
  } else {
640
0
    return false;
641
0
  }
642
381k
}
643
644
bool Configurable::OptionsAreEqual(const ConfigOptions& config_options,
645
                                   const OptionTypeInfo& opt_info,
646
                                   const std::string& opt_name,
647
                                   const void* const this_ptr,
648
                                   const void* const that_ptr,
649
4.22M
                                   std::string* mismatch) const {
650
4.22M
  if (opt_info.AreEqual(config_options, opt_name, this_ptr, that_ptr,
651
4.22M
                        mismatch)) {
652
4.22M
    return true;
653
4.22M
  } else if (opt_info.AreEqualByName(config_options, opt_name, this_ptr,
654
0
                                     that_ptr)) {
655
0
    *mismatch = "";
656
0
    return true;
657
0
  } else {
658
0
    return false;
659
0
  }
660
4.22M
}
661
662
bool ConfigurableHelper::AreEquivalent(const ConfigOptions& config_options,
663
                                       const Configurable& this_one,
664
                                       const Configurable& that_one,
665
381k
                                       std::string* mismatch) {
666
381k
  assert(mismatch != nullptr);
667
557k
  for (auto const& o : this_one.options_) {
668
557k
    const auto this_offset = this_one.GetOptionsPtr(o.name);
669
557k
    const auto that_offset = that_one.GetOptionsPtr(o.name);
670
557k
    if (this_offset != that_offset) {
671
557k
      if (this_offset == nullptr || that_offset == nullptr) {
672
0
        return false;
673
557k
      } else if (o.type_map != nullptr) {
674
25.5M
        for (const auto& map_iter : *(o.type_map)) {
675
25.5M
          const auto& opt_info = map_iter.second;
676
25.5M
          if (config_options.IsCheckEnabled(opt_info.GetSanityLevel())) {
677
19.8M
            if (!config_options.mutable_options_only) {
678
19.8M
              if (!this_one.OptionsAreEqual(config_options, opt_info,
679
19.8M
                                            map_iter.first, this_offset,
680
19.8M
                                            that_offset, mismatch)) {
681
0
                return false;
682
0
              }
683
19.8M
            } else if (opt_info.IsMutable()) {
684
0
              ConfigOptions copy = config_options;
685
0
              copy.mutable_options_only = false;
686
0
              if (!this_one.OptionsAreEqual(copy, opt_info, map_iter.first,
687
0
                                            this_offset, that_offset,
688
0
                                            mismatch)) {
689
0
                return false;
690
0
              }
691
0
            }
692
19.8M
          }
693
25.5M
        }
694
557k
      }
695
557k
    }
696
557k
  }
697
381k
  return true;
698
381k
}
699
700
Status Configurable::GetOptionsMap(
701
    const std::string& value, const std::string& default_id, std::string* id,
702
515k
    std::unordered_map<std::string, std::string>* props) {
703
515k
  assert(id);
704
515k
  assert(props);
705
515k
  Status status;
706
515k
  if (value.empty() || value == kNullptrString) {
707
0
    *id = default_id;
708
515k
  } else if (value.find('=') == std::string::npos) {
709
515k
    *id = value;
710
515k
  } else {
711
0
    status = StringToMap(value, props);
712
0
    if (!status.ok()) {       // There was an error creating the map.
713
0
      *id = value;            // Treat the value as id
714
0
      props->clear();         // Clear the properties
715
0
      status = Status::OK();  // and ignore the error
716
0
    } else {
717
0
      auto iter = props->find(OptionTypeInfo::kIdPropName());
718
0
      if (iter != props->end()) {
719
0
        *id = iter->second;
720
0
        props->erase(iter);
721
0
        if (*id == kNullptrString) {
722
0
          id->clear();
723
0
        }
724
0
      } else if (!default_id.empty()) {
725
0
        *id = default_id;
726
0
      } else {           // No id property and no default
727
0
        *id = value;     // Treat the value as id
728
0
        props->clear();  // Clear the properties
729
0
      }
730
0
    }
731
0
  }
732
515k
  return status;
733
515k
}
734
}  // namespace ROCKSDB_NAMESPACE