]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/rocksdb/options/configurable.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rocksdb / options / configurable.cc
index 3167c5d060b08b2610f6c13b970b7688ef3a759a..08aff10fd2c314e76173c352f0dbdbdbf495eee5 100644 (file)
 
 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;
@@ -28,7 +28,7 @@ void ConfigurableHelper::RegisterOptions(
   (void)type_map;
 #endif  // ROCKSDB_LITE
   opts.opt_ptr = opt_ptr;
-  configurable.options_.emplace_back(opts);
+  options_.emplace_back(opts);
 }
 
 //*************************************************************************
@@ -38,21 +38,18 @@ void ConfigurableHelper::RegisterOptions(
 //*************************************************************************
 
 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;
           }
         }
       }
@@ -61,9 +58,6 @@ Status Configurable::PrepareOptions(const ConfigOptions& opts) {
 #else
   (void)opts;
 #endif  // ROCKSDB_LITE
-  if (status.ok()) {
-    prepared_ = true;
-  }
   return status;
 }
 
@@ -72,18 +66,12 @@ Status Configurable::ValidateOptions(const DBOptions& db_opts,
   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;
           }
@@ -122,11 +110,13 @@ const OptionTypeInfo* ConfigurableHelper::FindOption(
     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;
@@ -158,14 +148,26 @@ Status Configurable::ConfigureOptions(
     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);
   }
@@ -174,6 +176,7 @@ Status Configurable::ConfigureOptions(
     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();
   }
@@ -223,9 +226,8 @@ Status Configurable::ConfigureFromString(const ConfigOptions& config_options,
 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);
 }
 
 /**
@@ -239,9 +241,16 @@ Status Configurable::ParseOption(const ConfigOptions& config_options,
                                  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);
@@ -259,12 +268,14 @@ Status ConfigurableHelper::ConfigureOptions(
   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
@@ -364,42 +375,104 @@ Status ConfigurableHelper::ConfigureSomeOptions(
 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);
@@ -409,32 +482,6 @@ Status ConfigurableHelper::ConfigureOption(
 }
 #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
@@ -516,19 +563,38 @@ Status ConfigurableHelper::SerializeOptions(const ConfigOptions& config_options,
                                             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);
+          }
         }
       }
     }
@@ -551,17 +617,23 @@ Status Configurable::GetOptionNames(
 }
 
 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);
+          }
+        }
       }
     }
   }
@@ -624,13 +696,25 @@ bool ConfigurableHelper::AreEquivalent(const ConfigOptions& config_options,
     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;
+              }
+            }
           }
         }
       }
@@ -640,13 +724,7 @@ bool ConfigurableHelper::AreEquivalent(const ConfigOptions& config_options,
 }
 #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);
@@ -659,15 +737,23 @@ Status ConfigurableHelper::GetOptionsMap(
 #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