namespace ROCKSDB_NAMESPACE {
-void ConfigurableHelper::RegisterOptions(
- Configurable& configurable, const std::string& name, void* opt_ptr,
+void Configurable::RegisterOptions(
+ const std::string& name, void* opt_ptr,
const std::unordered_map<std::string, OptionTypeInfo>* type_map) {
- Configurable::RegisteredOptions opts;
+ RegisteredOptions opts;
opts.name = name;
#ifndef ROCKSDB_LITE
opts.type_map = type_map;
(void)type_map;
#endif // ROCKSDB_LITE
opts.opt_ptr = opt_ptr;
- configurable.options_.emplace_back(opts);
+ options_.emplace_back(opts);
}
//*************************************************************************
//*************************************************************************
Status Configurable::PrepareOptions(const ConfigOptions& opts) {
+ // We ignore the invoke_prepare_options here intentionally,
+ // as if you are here, you must have called PrepareOptions explicitly.
Status status = Status::OK();
#ifndef ROCKSDB_LITE
for (auto opt_iter : options_) {
- for (auto map_iter : *(opt_iter.type_map)) {
- auto& opt_info = map_iter.second;
- if (!opt_info.IsDeprecated() && !opt_info.IsAlias() &&
- opt_info.IsConfigurable()) {
- if (!opt_info.IsEnabled(OptionTypeFlags::kDontPrepare)) {
- Configurable* config =
- opt_info.AsRawPointer<Configurable>(opt_iter.opt_ptr);
- if (config != nullptr) {
- status = config->PrepareOptions(opts);
- if (!status.ok()) {
- return status;
- }
+ if (opt_iter.type_map != nullptr) {
+ for (auto map_iter : *(opt_iter.type_map)) {
+ auto& opt_info = map_iter.second;
+ if (opt_info.ShouldPrepare()) {
+ status = opt_info.Prepare(opts, map_iter.first, opt_iter.opt_ptr);
+ if (!status.ok()) {
+ return status;
}
}
}
#else
(void)opts;
#endif // ROCKSDB_LITE
- if (status.ok()) {
- prepared_ = true;
- }
return status;
}
Status status;
#ifndef ROCKSDB_LITE
for (auto opt_iter : options_) {
- for (auto map_iter : *(opt_iter.type_map)) {
- auto& opt_info = map_iter.second;
- if (!opt_info.IsDeprecated() && !opt_info.IsAlias()) {
- if (opt_info.IsConfigurable()) {
- const Configurable* config =
- opt_info.AsRawPointer<Configurable>(opt_iter.opt_ptr);
- if (config != nullptr) {
- status = config->ValidateOptions(db_opts, cf_opts);
- } else if (!opt_info.CanBeNull()) {
- status =
- Status::NotFound("Missing configurable object", map_iter.first);
- }
+ if (opt_iter.type_map != nullptr) {
+ for (auto map_iter : *(opt_iter.type_map)) {
+ auto& opt_info = map_iter.second;
+ if (opt_info.ShouldValidate()) {
+ status = opt_info.Validate(db_opts, cf_opts, map_iter.first,
+ opt_iter.opt_ptr);
if (!status.ok()) {
return status;
}
const std::vector<Configurable::RegisteredOptions>& options,
const std::string& short_name, std::string* opt_name, void** opt_ptr) {
for (auto iter : options) {
- const auto opt_info =
- OptionTypeInfo::Find(short_name, *(iter.type_map), opt_name);
- if (opt_info != nullptr) {
- *opt_ptr = iter.opt_ptr;
- return opt_info;
+ if (iter.type_map != nullptr) {
+ const auto opt_info =
+ OptionTypeInfo::Find(short_name, *(iter.type_map), opt_name);
+ if (opt_info != nullptr) {
+ *opt_ptr = iter.opt_ptr;
+ return opt_info;
+ }
}
}
return nullptr;
const std::unordered_map<std::string, std::string>& opts_map,
std::unordered_map<std::string, std::string>* unused) {
std::string curr_opts;
+ Status s;
+ if (!opts_map.empty()) {
+ // There are options in the map.
+ // Save the current configuration in curr_opts and then configure the
+ // options, but do not prepare them now. We will do all the prepare when
+ // the configuration is complete.
+ ConfigOptions copy = config_options;
+ copy.invoke_prepare_options = false;
#ifndef ROCKSDB_LITE
- if (!config_options.ignore_unknown_options) {
- // If we are not ignoring unused, get the defaults in case we need to reset
- GetOptionString(config_options, &curr_opts).PermitUncheckedError();
- }
+ if (!config_options.ignore_unknown_options) {
+ // If we are not ignoring unused, get the defaults in case we need to
+ // reset
+ copy.depth = ConfigOptions::kDepthDetailed;
+ copy.delimiter = "; ";
+ GetOptionString(copy, &curr_opts).PermitUncheckedError();
+ }
#endif // ROCKSDB_LITE
- Status s = ConfigurableHelper::ConfigureOptions(config_options, *this,
- opts_map, unused);
+
+ s = ConfigurableHelper::ConfigureOptions(copy, *this, opts_map, unused);
+ }
if (config_options.invoke_prepare_options && s.ok()) {
s = PrepareOptions(config_options);
}
ConfigOptions reset = config_options;
reset.ignore_unknown_options = true;
reset.invoke_prepare_options = true;
+ reset.ignore_unsupported_options = true;
// There are some options to reset from this current error
ConfigureFromString(reset, curr_opts).PermitUncheckedError();
}
Status Configurable::ConfigureOption(const ConfigOptions& config_options,
const std::string& name,
const std::string& value) {
- const std::string& opt_name = GetOptionName(name);
- return ConfigurableHelper::ConfigureSingleOption(config_options, *this,
- opt_name, value);
+ return ConfigurableHelper::ConfigureSingleOption(config_options, *this, name,
+ value);
}
/**
const OptionTypeInfo& opt_info,
const std::string& opt_name,
const std::string& opt_value, void* opt_ptr) {
- if (opt_info.IsMutable() || opt_info.IsConfigurable()) {
- return opt_info.Parse(config_options, opt_name, opt_value, opt_ptr);
- } else if (prepared_) {
+ if (opt_info.IsMutable()) {
+ if (config_options.mutable_options_only) {
+ // This option is mutable. Treat all of its children as mutable as well
+ ConfigOptions copy = config_options;
+ copy.mutable_options_only = false;
+ return opt_info.Parse(copy, opt_name, opt_value, opt_ptr);
+ } else {
+ return opt_info.Parse(config_options, opt_name, opt_value, opt_ptr);
+ }
+ } else if (config_options.mutable_options_only) {
return Status::InvalidArgument("Option not changeable: " + opt_name);
} else {
return opt_info.Parse(config_options, opt_name, opt_value, opt_ptr);
if (!opts_map.empty()) {
#ifndef ROCKSDB_LITE
for (const auto& iter : configurable.options_) {
- s = ConfigureSomeOptions(config_options, configurable, *(iter.type_map),
- &remaining, iter.opt_ptr);
- if (remaining.empty()) { // Are there more options left?
- break;
- } else if (!s.ok()) {
- break;
+ if (iter.type_map != nullptr) {
+ s = ConfigureSomeOptions(config_options, configurable, *(iter.type_map),
+ &remaining, iter.opt_ptr);
+ if (remaining.empty()) { // Are there more options left?
+ break;
+ } else if (!s.ok()) {
+ break;
+ }
}
}
#else
Status ConfigurableHelper::ConfigureSingleOption(
const ConfigOptions& config_options, Configurable& configurable,
const std::string& name, const std::string& value) {
- std::string opt_name;
+ const std::string& opt_name = configurable.GetOptionName(name);
+ std::string elem_name;
void* opt_ptr = nullptr;
const auto opt_info =
- FindOption(configurable.options_, name, &opt_name, &opt_ptr);
+ FindOption(configurable.options_, opt_name, &elem_name, &opt_ptr);
if (opt_info == nullptr) {
return Status::NotFound("Could not find option: ", name);
} else {
- return ConfigureOption(config_options, configurable, *opt_info, name,
- opt_name, value, opt_ptr);
+ return ConfigureOption(config_options, configurable, *opt_info, opt_name,
+ elem_name, value, opt_ptr);
}
}
-
-Status ConfigurableHelper::ConfigureOption(
+Status ConfigurableHelper::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) {
- if (opt_name == name) {
- return configurable.ParseOption(config_options, opt_info, opt_name, value,
- opt_ptr);
- } else if (opt_info.IsCustomizable() &&
- EndsWith(opt_name, ConfigurableHelper::kIdPropSuffix)) {
- return configurable.ParseOption(config_options, opt_info, name, value,
- opt_ptr);
+ Customizable* custom = opt_info.AsRawPointer<Customizable>(opt_ptr);
+ ConfigOptions copy = config_options;
+ if (opt_info.IsMutable()) {
+ // This option is mutable. Pass that property on to any subsequent calls
+ copy.mutable_options_only = false;
+ }
- } else if (opt_info.IsCustomizable()) {
- Customizable* custom = opt_info.AsRawPointer<Customizable>(opt_ptr);
- if (value.empty()) {
+ if (opt_info.IsMutable() || !config_options.mutable_options_only) {
+ // Either the option is mutable, or we are processing all of the options
+ if (opt_name == name || name == OptionTypeInfo::kIdPropName() ||
+ EndsWith(opt_name, OptionTypeInfo::kIdPropSuffix())) {
+ return configurable.ParseOption(copy, opt_info, name, value, opt_ptr);
+ } else if (value.empty()) {
return Status::OK();
} else if (custom == nullptr || !StartsWith(name, custom->GetId() + ".")) {
- return configurable.ParseOption(config_options, opt_info, name, value,
- opt_ptr);
+ return configurable.ParseOption(copy, opt_info, name, value, opt_ptr);
} else if (value.find("=") != std::string::npos) {
- return custom->ConfigureFromString(config_options, value);
+ return custom->ConfigureFromString(copy, value);
+ } else {
+ return custom->ConfigureOption(copy, name, value);
+ }
+ } else {
+ // We are processing immutable options, which means that we cannot change
+ // the Customizable object itself, but could change its mutable properties.
+ // Check to make sure that nothing is trying to change the Customizable
+ if (custom == nullptr) {
+ // We do not have a Customizable to configure. This is OK if the
+ // value is empty (nothing being configured) but an error otherwise
+ if (value.empty()) {
+ return Status::OK();
+ } else {
+ return Status::InvalidArgument("Option not changeable: " + opt_name);
+ }
+ } else if (EndsWith(opt_name, OptionTypeInfo::kIdPropSuffix()) ||
+ name == OptionTypeInfo::kIdPropName()) {
+ // We have a property of the form "id=value" or "table.id=value"
+ // This is OK if we ID/value matches the current customizable object
+ if (custom->GetId() == value) {
+ return Status::OK();
+ } else {
+ return Status::InvalidArgument("Option not changeable: " + opt_name);
+ }
+ } else if (opt_name == name) {
+ // The properties are of one of forms:
+ // name = { id = id; prop1 = value1; ... }
+ // name = { prop1=value1; prop2=value2; ... }
+ // name = ID
+ // Convert the value to a map and extract the ID
+ // If the ID does not match that of the current customizable, return an
+ // error. Otherwise, update the current customizable via the properties
+ // map
+ std::unordered_map<std::string, std::string> props;
+ std::string id;
+ Status s =
+ Configurable::GetOptionsMap(value, custom->GetId(), &id, &props);
+ if (!s.ok()) {
+ return s;
+ } else if (custom->GetId() != id) {
+ return Status::InvalidArgument("Option not changeable: " + opt_name);
+ } else if (props.empty()) {
+ return Status::OK();
+ } else {
+ return custom->ConfigureFromMap(copy, props);
+ }
} else {
- return custom->ConfigureOption(config_options, name, value);
+ // Attempting to configure one of the properties of the customizable
+ // Let it through
+ return custom->ConfigureOption(copy, name, value);
}
+ }
+}
+
+Status ConfigurableHelper::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) {
+ if (opt_info.IsCustomizable()) {
+ return ConfigureCustomizableOption(config_options, configurable, opt_info,
+ opt_name, name, value, opt_ptr);
+ } else if (opt_name == name) {
+ return configurable.ParseOption(config_options, opt_info, opt_name, value,
+ opt_ptr);
} else if (opt_info.IsStruct() || opt_info.IsConfigurable()) {
return configurable.ParseOption(config_options, opt_info, name, value,
opt_ptr);
}
#endif // ROCKSDB_LITE
-Status ConfigurableHelper::ConfigureNewObject(
- const ConfigOptions& config_options_in, Configurable* object,
- const std::string& id, const std::string& base_opts,
- const std::unordered_map<std::string, std::string>& opts) {
- if (object != nullptr) {
- ConfigOptions config_options = config_options_in;
- config_options.invoke_prepare_options = false;
- if (!base_opts.empty()) {
-#ifndef ROCKSDB_LITE
- // Don't run prepare options on the base, as we would do that on the
- // overlay opts instead
- Status status = object->ConfigureFromString(config_options, base_opts);
- if (!status.ok()) {
- return status;
- }
-#endif // ROCKSDB_LITE
- }
- if (!opts.empty()) {
- return object->ConfigureFromMap(config_options, opts);
- }
- } else if (!opts.empty()) { // No object but no map. This is OK
- return Status::InvalidArgument("Cannot configure null object ", id);
- }
- return Status::OK();
-}
-
//*******************************************************************************
//
// Methods for Converting Options into strings
std::string* result) {
assert(result);
for (auto const& opt_iter : configurable.options_) {
- for (const auto& map_iter : *(opt_iter.type_map)) {
- const auto& opt_name = map_iter.first;
- const auto& opt_info = map_iter.second;
- if (opt_info.ShouldSerialize()) {
- std::string value;
- Status s = opt_info.Serialize(config_options, prefix + opt_name,
- opt_iter.opt_ptr, &value);
- if (!s.ok()) {
- return s;
- } else if (!value.empty()) {
- // <prefix><opt_name>=<value><delimiter>
- result->append(prefix + opt_name + "=" + value +
- config_options.delimiter);
+ if (opt_iter.type_map != nullptr) {
+ for (const auto& map_iter : *(opt_iter.type_map)) {
+ const auto& opt_name = map_iter.first;
+ const auto& opt_info = map_iter.second;
+ if (opt_info.ShouldSerialize()) {
+ std::string value;
+ Status s;
+ if (!config_options.mutable_options_only) {
+ s = opt_info.Serialize(config_options, prefix + opt_name,
+ opt_iter.opt_ptr, &value);
+ } else if (opt_info.IsMutable()) {
+ ConfigOptions copy = config_options;
+ copy.mutable_options_only = false;
+ s = opt_info.Serialize(copy, prefix + opt_name, opt_iter.opt_ptr,
+ &value);
+ } else if (opt_info.IsConfigurable()) {
+ // If it is a Configurable and we are either printing all of the
+ // details or not printing only the name, this option should be
+ // included in the list
+ if (config_options.IsDetailed() ||
+ !opt_info.IsEnabled(OptionTypeFlags::kStringNameOnly)) {
+ s = opt_info.Serialize(config_options, prefix + opt_name,
+ opt_iter.opt_ptr, &value);
+ }
+ }
+ if (!s.ok()) {
+ return s;
+ } else if (!value.empty()) {
+ // <prefix><opt_name>=<value><delimiter>
+ result->append(prefix + opt_name + "=" + value +
+ config_options.delimiter);
+ }
}
}
}
}
Status ConfigurableHelper::ListOptions(
- const ConfigOptions& /*config_options*/, const Configurable& configurable,
+ const ConfigOptions& config_options, const Configurable& configurable,
const std::string& prefix, std::unordered_set<std::string>* result) {
Status status;
for (auto const& opt_iter : configurable.options_) {
- for (const auto& map_iter : *(opt_iter.type_map)) {
- const auto& opt_name = map_iter.first;
- const auto& opt_info = map_iter.second;
- // If the option is no longer used in rocksdb and marked as deprecated,
- // we skip it in the serialization.
- if (!opt_info.IsDeprecated() && !opt_info.IsAlias()) {
- result->emplace(prefix + opt_name);
+ if (opt_iter.type_map != nullptr) {
+ for (const auto& map_iter : *(opt_iter.type_map)) {
+ const auto& opt_name = map_iter.first;
+ const auto& opt_info = map_iter.second;
+ // If the option is no longer used in rocksdb and marked as deprecated,
+ // we skip it in the serialization.
+ if (!opt_info.IsDeprecated() && !opt_info.IsAlias()) {
+ if (!config_options.mutable_options_only) {
+ result->emplace(prefix + opt_name);
+ } else if (opt_info.IsMutable()) {
+ result->emplace(prefix + opt_name);
+ }
+ }
}
}
}
if (this_offset != that_offset) {
if (this_offset == nullptr || that_offset == nullptr) {
return false;
- } else {
+ } else if (o.type_map != nullptr) {
for (const auto& map_iter : *(o.type_map)) {
- if (config_options.IsCheckEnabled(map_iter.second.GetSanityLevel()) &&
- !this_one.OptionsAreEqual(config_options, map_iter.second,
- map_iter.first, this_offset,
- that_offset, mismatch)) {
- return false;
+ const auto& opt_info = map_iter.second;
+ if (config_options.IsCheckEnabled(opt_info.GetSanityLevel())) {
+ if (!config_options.mutable_options_only) {
+ if (!this_one.OptionsAreEqual(config_options, opt_info,
+ map_iter.first, this_offset,
+ that_offset, mismatch)) {
+ return false;
+ }
+ } else if (opt_info.IsMutable()) {
+ ConfigOptions copy = config_options;
+ copy.mutable_options_only = false;
+ if (!this_one.OptionsAreEqual(copy, opt_info, map_iter.first,
+ this_offset, that_offset,
+ mismatch)) {
+ return false;
+ }
+ }
}
}
}
}
#endif // ROCKSDB_LITE
-Status ConfigurableHelper::GetOptionsMap(
- const std::string& value, std::string* id,
- std::unordered_map<std::string, std::string>* props) {
- return GetOptionsMap(value, "", id, props);
-}
-
-Status ConfigurableHelper::GetOptionsMap(
+Status Configurable::GetOptionsMap(
const std::string& value, const std::string& default_id, std::string* id,
std::unordered_map<std::string, std::string>* props) {
assert(id);
#ifndef ROCKSDB_LITE
} else {
status = StringToMap(value, props);
- if (status.ok()) {
- auto iter = props->find(ConfigurableHelper::kIdPropName);
+ if (!status.ok()) { // There was an error creating the map.
+ *id = value; // Treat the value as id
+ props->clear(); // Clear the properties
+ status = Status::OK(); // and ignore the error
+ } else {
+ auto iter = props->find(OptionTypeInfo::kIdPropName());
if (iter != props->end()) {
*id = iter->second;
props->erase(iter);
- } else if (default_id.empty()) { // Should this be an error??
- status = Status::InvalidArgument("Name property is missing");
- } else {
+ if (*id == kNullptrString) {
+ id->clear();
+ }
+ } else if (!default_id.empty()) {
*id = default_id;
+ } else { // No id property and no default
+ *id = value; // Treat the value as id
+ props->clear(); // Clear the properties
}
}
#else