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