]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
common/config: hook in new Option config descriptions
authorJohn Spray <john.spray@redhat.com>
Fri, 7 Jul 2017 14:12:18 +0000 (10:12 -0400)
committerJohn Spray <john.spray@redhat.com>
Fri, 21 Jul 2017 10:27:25 +0000 (06:27 -0400)
The C++ class member fields continue to exist for
settings defined in common/legacy_config_opts.h, but
all the schema information is coming from common/options.cc
now.

The values in md_config_t::values are automatically
copied into the C++ class member fields for legacy config
options as needed.

Signed-off-by: John Spray <john.spray@redhat.com>
src/common/config.cc
src/common/config.h
src/common/options.cc
src/common/options.h
src/convert.cc

index 3df1d71fafe5046279adb70035ad4d0ca4fbebe2..12a9c317e9fd1c299ba5d0ad7bdeec794efb50b4 100644 (file)
@@ -15,7 +15,6 @@
 #include "common/ceph_argparse.h"
 #include "common/common_init.h"
 #include "common/config.h"
-#include "common/config_validators.h"
 #include "include/str_list.h"
 #include "include/stringify.h"
 #include "osd/osd_types.h"
@@ -73,101 +72,84 @@ int ceph_resolve_file_search(const std::string& filename_list,
   return ret;
 }
 
-#define OPTION(name, type, def_val)
-#define OPTION_VALIDATOR(name)              \
-struct md_config_t::option_##name##_t {     \
-  typedef decltype(md_config_t::name) type; \
-};
-#define SAFE_OPTION(name, type, def_val)
-#define SUBSYS(name, log, gather)
-#define DEFAULT_SUBSYS(log, gather)
-#include "common/legacy_config_opts.h"
-#undef OPTION
-#undef OPTION_VALIDATOR
-#undef SAFE_OPTION
-#undef SUBSYS
-#undef DEFAULT_SUBSYS
-
-namespace {
-
-template <typename T>
-typename std::enable_if<!std::is_destructible<T>::value,
-                        md_config_t::validator_t>::type create_validator() {
-  return md_config_t::validator_t();
-}
-
-template <typename T>
-typename std::enable_if<std::is_destructible<T>::value,
-                        md_config_t::validator_t>::type create_validator() {
-  // if T is defined (and not just forward declared), it implies
-  // that a validator function exists. use a dummy typed pointer to
-  // pick the correct validator function
-  return [](std::string *value, std::string *error_message) {
-      return ::validate(reinterpret_cast<T*>(0), value, error_message);
-    };
-}
 
-} // anonymous namespace
 
 md_config_t::md_config_t()
   : cluster(""),
-
-#define OPTION_OPT_INT(name, def_val) name(def_val),
-#define OPTION_OPT_LONGLONG(name, def_val) name((1LL) * def_val),
-#define OPTION_OPT_STR(name, def_val) name(def_val),
-#define OPTION_OPT_DOUBLE(name, def_val) name(def_val),
-#define OPTION_OPT_FLOAT(name, def_val) name(def_val),
-#define OPTION_OPT_BOOL(name, def_val) name(def_val),
-#define OPTION_OPT_ADDR(name, def_val) name(def_val),
-#define OPTION_OPT_U32(name, def_val) name(def_val),
-#define OPTION_OPT_U64(name, def_val) name(((uint64_t)1) * def_val),
-#define OPTION_OPT_UUID(name, def_val) name(def_val),
-#define OPTION(name, type, def_val) OPTION_##type(name, def_val)
-#define OPTION_VALIDATOR(name)
-#define SAFE_OPTION(name, type, def_val) OPTION(name, type, def_val)
-#define SUBSYS(name, log, gather)
-#define DEFAULT_SUBSYS(log, gather)
-#include "common/legacy_config_opts.h"
-#undef OPTION_OPT_INT
-#undef OPTION_OPT_LONGLONG
-#undef OPTION_OPT_STR
-#undef OPTION_OPT_DOUBLE
-#undef OPTION_OPT_FLOAT
-#undef OPTION_OPT_BOOL
-#undef OPTION_OPT_ADDR
-#undef OPTION_OPT_U32
-#undef OPTION_OPT_U64
-#undef OPTION_OPT_UUID
-#undef OPTION
-#undef OPTION_VALIDATOR
-#undef SAFE_OPTION
-#undef SUBSYS
-#undef DEFAULT_SUBSYS
   lock("md_config_t", true, false)
 {
-  static const std::vector<md_config_t::config_option> s_config_options = {
+  init_subsys();
+
+  // Load the compile-time list of Option into
+  // a map so that we can resolve keys quickly.
+  for (const auto &i : ceph_options) {
+    if (schema.count(i.name)) {
+      // We may be instantiated pre-logging so send 
+      std::cerr << "Duplicate config key in schema: '" << i.name << "'"
+                << std::endl;
+      assert(false);
+    }
+    schema.insert({i.name, i});
+  }
+
+  // Populate list of legacy_values according to the OPTION() definitions
+  // Note that this is just setting up our map of name->member ptr.  The
+  // default values etc will get loaded in along with new-style data,
+  // as all loads write to both the values map, and the legacy
+  // members if present.
+  legacy_values = {
 #define OPTION4(name, type, def_val, safe) \
-        config_option{ STRINGIFY(name), type, &md_config_t::name, safe, \
-                       create_validator<option_##name##_t>() },
+    {std::string(STRINGIFY(name)), &md_config_t::name},
 #define OPTION(name, type, def_val) OPTION4(name, type, def_val, false)
-#define OPTION_VALIDATOR(name)
 #define SAFE_OPTION(name, type, def_val) OPTION4(name, type, def_val, true)
-#define SUBSYS(name, log, gather)
-#define DEFAULT_SUBSYS(log, gather)
 #include "common/legacy_config_opts.h"
 #undef OPTION4
 #undef OPTION
-#undef OPTION_VALIDATOR
 #undef SAFE_OPTION
-#undef SUBSYS
-#undef DEFAULT_SUBSYS
   };
-  static std::shared_ptr<decltype(s_config_options)>
-    s_tbl(new std::vector<md_config_t::config_option>(std::move(s_config_options)));
-  config_options = s_tbl;
 
-  validate_default_settings();
-  init_subsys();
+  validate_schema();
+
+  // Load default values from the schema
+  for (const auto &i : schema) {
+    // TODO: select daemon default if appropriate.
+    values[i.first] = i.second.value;
+  }
+
+  // Copy out values (defaults) into any legacy (C struct member) fields
+  for (const auto &i : legacy_values) {
+    const auto &name = i.first;
+    const auto &option = schema.at(name);
+    auto ptr = i.second;
+
+    update_legacy_val(option, ptr);
+  }
+}
+
+/**
+ * Sanity check schema.  Assert out on failures, to ensure any bad changes
+ * cannot possibly pass any testing and make it into a release.
+ */
+void md_config_t::validate_schema()
+{
+  for (const auto &i : schema) {
+    const auto &opt = i.second;
+    for (const auto &see_also_key : opt.see_also) {
+      if (schema.count(see_also_key) == 0) {
+        std::cerr << "Non-existent see-also key '" << see_also_key
+                  << "' on option '" << opt.name << "'" << std::endl;
+        assert(false);
+      }
+    }
+  }
+
+  for (const auto &i : legacy_values) {
+    if (schema.count(i.first) == 0) {
+      std::cerr << "Schema is missing legacy field '" << i.first << "'"
+                << std::endl;
+      assert(false);
+    }
+  }
 }
 
 void md_config_t::init_subsys()
@@ -176,13 +158,7 @@ void md_config_t::init_subsys()
   subsys.add(ceph_subsys_##name, STRINGIFY(name), log, gather);
 #define DEFAULT_SUBSYS(log, gather) \
   subsys.add(ceph_subsys_, "none", log, gather);
-#define OPTION(a, b, c)
-#define OPTION_VALIDATOR(a)
-#define SAFE_OPTION(a, b, c)
-#include "common/legacy_config_opts.h"
-#undef OPTION
-#undef OPTION_VALIDATOR
-#undef SAFE_OPTION
+#include "common/subsys.h"
 #undef SUBSYS
 #undef DEFAULT_SUBSYS
 }
@@ -255,7 +231,7 @@ int md_config_t::parse_config_files(const char *conf_files,
     string &s = *p;
     if (s.find("$data_dir") != string::npos) {
       if (data_dir_option.length()) {
-       list<config_option const *> stack;
+       list<const Option *> stack;
        expand_meta(s, NULL, stack, warnings);
        p++;
       } else {
@@ -310,12 +286,13 @@ int md_config_t::parse_config_files_impl(const std::list<std::string> &conf_file
 
   std::vector <std::string> my_sections;
   _get_my_sections(my_sections);
-  for (auto& opt: *config_options) {
+  for (const auto &i : schema) {
+    const auto &opt = i.second;
     std::string val;
     int ret = _get_val_from_conf_file(my_sections, opt.name, val, false);
     if (ret == 0) {
       std::string error_message;
-      int r = set_val_impl(val, &opt, &error_message);
+      int r = set_val_impl(val, opt, &error_message);
       if (warnings != nullptr && (r != 0 || !error_message.empty())) {
         *warnings << "parse error setting '" << opt.name << "' to '" << val
                   << "'";
@@ -328,7 +305,7 @@ int md_config_t::parse_config_files_impl(const std::list<std::string> &conf_file
   }
 
   // subsystems?
-  for (int o = 0; o < subsys.get_num(); o++) {
+  for (size_t o = 0; o < subsys.get_num(); o++) {
     std::string as_option("debug_");
     as_option += subsys.get_name(o);
     std::string val;
@@ -402,7 +379,7 @@ void md_config_t::_show_config(std::ostream *out, Formatter *f)
     f->dump_string("name", stringify(name));
     f->dump_string("cluster", cluster);
   }
-  for (int o = 0; o < subsys.get_num(); o++) {
+  for (size_t o = 0; o < subsys.get_num(); o++) {
     if (out)
       *out << "debug_" << subsys.get_name(o)
           << " = " << subsys.get_log_level(o)
@@ -416,13 +393,14 @@ void md_config_t::_show_config(std::ostream *out, Formatter *f)
       f->dump_string(debug_name.c_str(), ss.str());
     }
   }
-  for (auto& opt: *config_options) {
+  for (const auto& i: schema) {
+    const Option &opt = i.second;
     char *buf;
     _get_val(opt.name, &buf, -1);
     if (out)
       *out << opt.name << " = " << buf << std::endl;
     if (f)
-      f->dump_string(opt.name, buf);
+      f->dump_string(opt.name.c_str(), buf);
     free(buf);
   }
 }
@@ -528,7 +506,7 @@ int md_config_t::parse_option(std::vector<const char*>& args,
                               ostream *oss)
 {
   int ret = 0;
-  int o;
+  size_t o = 0;
   std::string val;
 
   // subsystems?
@@ -556,16 +534,16 @@ int md_config_t::parse_option(std::vector<const char*>& args,
     return ret;
   }
 
-  const char *option_name = nullptr;
+  std::string option_name;
   std::string error_message;
   o = 0;
-  for (auto& opt_ref: *config_options) {
+  for (const auto& opt_iter: schema) {
+    const Option &opt = opt_iter.second;
     ostringstream err;
-    config_option const *opt = &opt_ref;
     std::string as_option("--");
-    as_option += opt->name;
-    option_name = opt->name;
-    if (opt->type == OPT_BOOL) {
+    as_option += opt.name;
+    option_name = opt.name;
+    if (opt.type == Option::TYPE_BOOL) {
       int res;
       if (ceph_argparse_binary_flag(args, i, &res, oss, as_option.c_str(),
                                    (char*)NULL)) {
@@ -578,7 +556,7 @@ int md_config_t::parse_option(std::vector<const char*>& args,
        break;
       } else {
        std::string no("--no-");
-       no += opt->name;
+       no += opt.name;
        if (ceph_argparse_flag(args, i, no.c_str(), (char*)NULL)) {
          ret = set_val_impl("false", opt, &error_message);
          break;
@@ -591,9 +569,9 @@ int md_config_t::parse_option(std::vector<const char*>& args,
        ret = -EINVAL;
        break;
       }
-      if (oss && ((!opt->is_safe()) &&
-                 (observers.find(opt->name) == observers.end()))) {
-       *oss << "You cannot change " << opt->name << " using injectargs.\n";
+      if (oss && ((!opt.is_safe()) &&
+                 (observers.find(opt.name) == observers.end()))) {
+       *oss << "You cannot change " << opt.name << " using injectargs.\n";
         return -ENOSYS;
       }
       ret = set_val_impl(val, opt, &error_message);
@@ -603,7 +581,7 @@ int md_config_t::parse_option(std::vector<const char*>& args,
   }
 
   if (ret != 0 || !error_message.empty()) {
-    assert(option_name);
+    assert(!option_name.empty());
     if (oss) {
       *oss << "Parse error setting " << option_name << " to '"
            << val << "' using injectargs";
@@ -621,7 +599,7 @@ int md_config_t::parse_option(std::vector<const char*>& args,
     }
   }
 
-  if (o == (int)config_options->size()) {
+  if (o == schema.size()) {
     // ignore
     ++i;
   }
@@ -666,6 +644,15 @@ void md_config_t::_apply_changes(std::ostream *oss)
 
   expand_all_meta();
 
+  // expand_all_meta could have modified anything.  Copy it all out again.
+  for (const auto &i : legacy_values) {
+    const auto &name = i.first;
+    const auto &option = schema.at(name);
+    auto ptr = i.second;
+
+    update_legacy_val(option, ptr);
+  }
+
   // create the reverse observer mapping, mapping observers to the set of
   // changed keys that they'll get.
   rev_obs_map_t robs;
@@ -754,59 +741,16 @@ int md_config_t::injectargs(const std::string& s, std::ostream *oss)
   return ret;
 }
 
-void md_config_t::set_val_or_die(const char *key, const char *val)
+void md_config_t::set_val_or_die(const std::string &key, const char *val)
 {
   int ret = set_val(key, val);
   assert(ret == 0);
 }
 
-struct is_integer_member : public boost::static_visitor<bool> {
-  template<typename T,
-           typename boost::enable_if<boost::is_integral<T>, int>::type = 0>
-  bool operator()(const T md_config_t::* /* member_ptr */) const {
-    return true;
-  }
-  template<typename T,
-           typename boost::enable_if_c<!boost::is_integral<T>::value, int>::type = 0>
-  bool operator()(const T md_config_t::* /* member_ptr */) const {
-    return false;
-  }
-};
-
-struct is_float_member : public boost::static_visitor<bool> {
-  template<typename T,
-           typename boost::enable_if<boost::is_float<T>, int>::type = 0>
-  bool operator()(const T md_config_t::* /* member_ptr */) const {
-    return true;
-  }
-  template<typename T,
-           typename boost::enable_if_c<!boost::is_float<T>::value, int>::type = 0>
-  bool operator()(const T md_config_t::* /* member_ptr */) const {
-    return false;
-  }
-};
-
-bool md_config_t::config_option::is_safe() const {
-  // for now integer and floating point options considered thread safe
-  return safe ||
-    boost::apply_visitor(is_integer_member(), md_member_ptr) ||
-    boost::apply_visitor(is_float_member(), md_member_ptr);
-}
-
-md_config_t::config_option const *md_config_t::find_config_option(const std::string &normalized_key) const
-{
-  auto opt_it = std::find_if(config_options->begin(),
-                             config_options->end(),
-                            [normalized_key](const config_option &opt) -> bool {
-                              return strcmp(normalized_key.c_str(), opt.name) == 0;
-                            });
-  return config_options->end() == opt_it ? nullptr : &(*opt_it);
-}
-
-int md_config_t::set_val(const char *key, const char *val, bool meta)
+int md_config_t::set_val(const std::string &key, const char *val, bool meta)
 {
   Mutex::Locker l(lock);
-  if (!key)
+  if (key.empty())
     return -EINVAL;
   if (!val)
     return -EINVAL;
@@ -815,11 +759,13 @@ int md_config_t::set_val(const char *key, const char *val, bool meta)
   if (meta)
     expand_meta(v, &std::cerr);
 
+  std::cerr << "set_val: expanded '" << std::string(val) << "' to '" << v << "'" << std::endl;
+
   string k(ConfFile::normalize_key_name(key));
 
   // subsystems?
   if (strncmp(k.c_str(), "debug_", 6) == 0) {
-    for (int o = 0; o < subsys.get_num(); o++) {
+    for (size_t o = 0; o < subsys.get_num(); o++) {
       std::string as_option = "debug_" + subsys.get_name(o);
       if (k == as_option) {
        int log, gather;
@@ -837,11 +783,12 @@ int md_config_t::set_val(const char *key, const char *val, bool meta)
     }  
   }
 
-  config_option const *opt = find_config_option(k);
-  if (opt) {
-    if ((!opt->is_safe()) && internal_safe_to_start_threads) {
+  const auto &opt_iter = schema.find(k);
+  if (opt_iter != schema.end()) {
+    const Option &opt = opt_iter->second;
+    if ((!opt.is_safe()) && internal_safe_to_start_threads) {
       // If threads have been started and the option is not thread safe
-      if (observers.find(opt->name) == observers.end()) {
+      if (observers.find(opt.name) == observers.end()) {
         // And there is no observer to safely change it...
         // You lose.
         return -ENOSYS;
@@ -849,8 +796,7 @@ int md_config_t::set_val(const char *key, const char *val, bool meta)
     }
 
     std::string error_message;
-    int r = set_val_impl(v, opt, &error_message);
-    return r;
+    return set_val_impl(v, opt, &error_message);
   }
 
   // couldn't find a configuration option with key 'key'
@@ -858,56 +804,48 @@ int md_config_t::set_val(const char *key, const char *val, bool meta)
 }
 
 
-int md_config_t::get_val(const char *key, char **buf, int len) const
+int md_config_t::get_val(const std::string &key, char **buf, int len) const
 {
   Mutex::Locker l(lock);
   return _get_val(key, buf,len);
 }
 
-md_config_t::config_value_t md_config_t::get_val_generic(const char *key) const
+Option::value_t md_config_t::get_val_generic(const std::string &key) const
 {
   Mutex::Locker l(lock);
   return _get_val(key);
 }
 
-class get_value_generic_visitor : public boost::static_visitor<md_config_t::config_value_t> {
-  md_config_t const *conf;
-public:
-  explicit get_value_generic_visitor(md_config_t const *conf_) : conf(conf_) { }
-  template<typename T> md_config_t::config_value_t operator()(const T md_config_t::* member_ptr) {
-    return md_config_t::config_value_t(conf->*member_ptr);
-  }
-};
-
-md_config_t::config_value_t md_config_t::_get_val(const char *key) const
+Option::value_t md_config_t::_get_val(const std::string &key) const
 {
   assert(lock.is_locked());
 
-  if (!key)
-    return config_value_t(invalid_config_value_t());
+  if (key.empty()) {
+    return Option::value_t(boost::blank());
+  }
 
   // In key names, leading and trailing whitespace are not significant.
   string k(ConfFile::normalize_key_name(key));
 
-  config_option const *opt = find_config_option(k);
-  if (!opt) {
-      return config_value_t(invalid_config_value_t());
+  const auto &opt_iter = schema.find(k);
+  if (opt_iter != schema.end()) {
+    // Using .at() is safe because all keys in the schema always have
+    // entries in ::values
+    return values.at(k);
+  } else {
+    return Option::value_t(boost::blank());
   }
-  get_value_generic_visitor gvv(this);
-  return boost::apply_visitor(gvv, opt->md_member_ptr);
 }
 
-int md_config_t::_get_val(const char *key, std::string *value) const {
+int md_config_t::_get_val(const std::string &key, std::string *value) const {
   assert(lock.is_locked());
 
   std::string normalized_key(ConfFile::normalize_key_name(key));
-  config_value_t config_value = _get_val(normalized_key.c_str());
-  if (!boost::get<invalid_config_value_t>(&config_value)) {
+  Option::value_t config_value = _get_val(normalized_key.c_str());
+  if (!boost::get<boost::blank>(&config_value)) {
     ostringstream oss;
     if (bool *flag = boost::get<bool>(&config_value)) {
       oss << (*flag ? "true" : "false");
-    } else if (float *fp = boost::get<float>(&config_value)) {
-      oss << std::fixed << *fp ;
     } else if (double *dp = boost::get<double>(&config_value)) {
       oss << std::fixed << *dp ;
     } else {
@@ -919,15 +857,15 @@ int md_config_t::_get_val(const char *key, std::string *value) const {
   return -ENOENT;
 }
 
-int md_config_t::_get_val(const char *key, char **buf, int len) const
+int md_config_t::_get_val(const std::string &key, char **buf, int len) const
 {
   assert(lock.is_locked());
 
-  if (!key)
+  if (key.empty())
     return -EINVAL;
 
   string val ;
-  if (!_get_val(key, &val)) {
+  if (_get_val(key, &val) == 0) {
     int l = val.length() + 1;
     if (len == -1) {
       *buf = (char*)malloc(l);
@@ -942,7 +880,7 @@ int md_config_t::_get_val(const char *key, char **buf, int len) const
 
   string k(ConfFile::normalize_key_name(key));
   // subsys?
-  for (int o = 0; o < subsys.get_num(); o++) {
+  for (size_t o = 0; o < subsys.get_num(); o++) {
     std::string as_option = "debug_" + subsys.get_name(o);
     if (k == as_option) {
       if (len == -1) {
@@ -962,14 +900,15 @@ void md_config_t::get_all_keys(std::vector<std::string> *keys) const {
   const std::string negative_flag_prefix("no_");
 
   keys->clear();
-  keys->reserve(config_options->size());
-  for (auto& opt: *config_options) {
+  keys->reserve(schema.size());
+  for (const auto &i: schema) {
+    const Option &opt = i.second;
     keys->push_back(opt.name);
-    if (opt.type == OPT_BOOL) {
+    if (opt.type == Option::TYPE_BOOL) {
       keys->push_back(negative_flag_prefix + opt.name);
     }
   }
-  for (int i = 0; i < subsys.get_num(); ++i) {
+  for (size_t i = 0; i < subsys.get_num(); ++i) {
     keys->push_back("debug_" + subsys.get_name(i));
   }
 }
@@ -1007,14 +946,14 @@ int md_config_t::get_all_sections(std::vector <std::string> &sections) const
 }
 
 int md_config_t::get_val_from_conf_file(const std::vector <std::string> &sections,
-                   const char *key, std::string &out, bool emeta) const
+                   const std::string &key, std::string &out, bool emeta) const
 {
   Mutex::Locker l(lock);
   return _get_val_from_conf_file(sections, key, out, emeta);
 }
 
 int md_config_t::_get_val_from_conf_file(const std::vector <std::string> &sections,
-                                        const char *key, std::string &out, bool emeta) const
+                                        const std::string &key, std::string &out, bool emeta) const
 {
   assert(lock.is_locked());
   std::vector <std::string>::const_iterator s = sections.begin();
@@ -1032,117 +971,115 @@ int md_config_t::_get_val_from_conf_file(const std::vector <std::string> &sectio
   return -ENOENT;
 }
 
-int md_config_t::set_val_impl(const std::string &val, config_option const *opt,
+int md_config_t::set_val_impl(const std::string &val, const Option &opt,
                               std::string *error_message)
 {
   assert(lock.is_locked());
-  std::string value(val);
-  if (opt->validator) {
-    int r = opt->validator(&value, error_message);
+
+  // TODO: hook validators back in
+#if 0
+  if (opt.validator) {
+    int r = opt.validator(&value, error_message);
     if (r < 0) {
       return r;
     }
   }
+#endif
 
-  int ret = set_val_raw(value.c_str(), opt);
-  if (ret)
-    return ret;
-  changed.insert(opt->name);
-  return 0;
-}
-
-template<typename T> struct strtox_helper;
-
-template<> struct strtox_helper<float> {
-  static inline void apply(const char *val, float &x, std::string &err) {
-    x = strict_strtof(val, &err);
-  }
-};
-
-template<> struct strtox_helper<double> {
-  static inline void apply(const char *val, double &x, std::string &err) {
-    x = strict_strtod(val, &err);
-  }
-};
-
-template<typename T> static inline int strict_strtox(const char *val, T &x) {
-  std::string err;
-  strtox_helper<T>::apply(val, x, err);
-  return err.empty() ? 0 : -EINVAL;
-}
-
-class set_value_visitor : public boost::static_visitor<int> {
-  md_config_t const *conf;
-  const char *val;
-public:
-  explicit set_value_visitor(md_config_t const *conf_, const char *val_) :
-    conf(conf_), val(val_) { }
-
-  int operator()(const std::string md_config_t::* member_ptr) {
-    auto *ptr = const_cast<std::string *>(&(conf->*member_ptr));
-    *ptr = val ? val : "";
-    return 0;
-  }
-
-  int operator()(const bool md_config_t::* member_ptr) {
-    bool *ptr = const_cast<bool *>(&(conf->*member_ptr));
-    if (strcasecmp(val, "false") == 0) {
-      *ptr = false;
-    } else if (strcasecmp(val, "true") == 0) {
-      *ptr = true;
+  Option::value_t new_value;
+  if (opt.type == Option::TYPE_INT) {
+    std::string err;
+    int64_t f = strict_si_cast<int64_t>(val.c_str(), &err);
+    if (!err.empty()) {
+      return -EINVAL;
+    }
+    new_value = f;
+  } else if (opt.type == Option::TYPE_STR) {
+    new_value = val;
+  } else if (opt.type == Option::TYPE_FLOAT) {
+    std::string err;
+    double f = strict_strtod(val.c_str(), &err);
+    if (!err.empty()) {
+      return -EINVAL;
+    } else {
+      new_value = f;
+    }
+  } else if (opt.type == Option::TYPE_BOOL) {
+    if (strcasecmp(val.c_str(), "false") == 0) {
+      new_value = false;
+    } else if (strcasecmp(val.c_str(), "true") == 0) {
+      new_value = true;
     } else {
       std::string err;
-      int b = strict_strtol(val, 10, &err);
+      int b = strict_strtol(val.c_str(), 10, &err);
       if (!err.empty()) {
        return -EINVAL;
       }
-      *ptr = !!b;
+      new_value = !!b;
     }
-    return 0;
+  } else if (opt.type == Option::TYPE_ADDR) {
+    entity_addr_t addr;
+    if (!addr.parse(val.c_str())){
+      return -EINVAL;
+    }
+    new_value = addr;
+  } else if (opt.type == Option::TYPE_UUID) {
+    uuid_d uuid;
+    if (!uuid.parse(val.c_str())) {
+      return -EINVAL;
+    }
+    new_value = uuid;
+  } else {
+    ceph_abort();
   }
-    
-  // type has parse() member function
-  template<typename T,
-    typename boost::enable_if<boost::is_member_function_pointer<decltype(&T::parse)>, int>::type = 0>
-      int operator()(const T md_config_t::* member_ptr) {
-       T *obj = const_cast<T *>(&(conf->*member_ptr));
-       if (!obj->parse(val)) {
-         return -EINVAL;
-       }
-       return 0;
-      }
 
-  // float, double
-  template<typename T,
-    typename boost::enable_if<boost::is_floating_point<T>, int>::type = 0>
-      int operator()(const T md_config_t::* member_ptr) {
-       T* ptr = const_cast<T *>(&(conf->*member_ptr));
-       return strict_strtox(val, *ptr);
-      }
+  // Apply the value to its entry in the `values` map
+  values[opt.name] = new_value;
 
-  // integers
-  template<typename T,
-    typename boost::enable_if_c<boost::is_integral<T>::value &&
-      !boost::is_same<T, bool>::value, int>::type = 0>
-      int operator()(const T md_config_t::* member_ptr) {
-       std::string err;
-       T f = strict_si_cast<T>(val, &err);
-       if (!err.empty()) {
-         return -EINVAL;
-       }
-       T *ptr = const_cast<T *>(&(conf->*member_ptr));
-       *ptr = f;
-       return 0;
+  // Apply the value to its legacy field, if it has one
+  auto legacy_ptr_iter = legacy_values.find(std::string(opt.name));
+  if (legacy_ptr_iter != legacy_values.end()) {
+    update_legacy_val(opt, legacy_ptr_iter->second);
+  }
+
+  changed.insert(opt.name);
+  return 0;
+}
+
+/**
+ * Handles assigning from a variant-of-types to a variant-of-pointers-to-types
+ */
+class assign_visitor : public boost::static_visitor<>
+{
+  md_config_t *conf;
+  Option::value_t val;
+  public:
+
+  assign_visitor(md_config_t *conf_, Option::value_t val_)
+    : conf(conf_), val(val_)
+  {}
+
+  template <typename T>
+  void operator()( T md_config_t::* ptr) const
+  {
+    T *member = const_cast<T *>(&(conf->*(boost::get<const T md_config_t::*>(ptr))));
+    *member = boost::get<T>(val);
   }
 };
 
-int md_config_t::set_val_raw(const char *val, config_option const *opt)
+void md_config_t::update_legacy_val(const Option &opt,
+                                    md_config_t::member_ptr_t member_ptr)
 {
-  assert(lock.is_locked());
-  set_value_visitor svv(this, val);
-  return boost::apply_visitor(svv, opt->md_member_ptr);
+  if (boost::get<boost::blank>(&values.at(opt.name))) {
+    // This shouldn't happen, but if it does then just don't even
+    // try to assign to the legacy field.
+    return;
+  }
+
+  boost::apply_visitor(assign_visitor(this, values.at(opt.name)), member_ptr);
 }
 
+
 static const char *CONF_METAVARIABLES[] = {
   "data_dir", // put this first: it may contain some of the others
   "cluster", "type", "name", "host", "num", "id", "pid", "cctid"
@@ -1154,27 +1091,29 @@ void md_config_t::expand_all_meta()
 {
   // Expand all metavariables
   ostringstream oss;
-  for (auto& opt: *config_options) {
-    std::string *str;
-    opt.conf_ptr(str, this);
-    if (str) {
-      list<config_option const *> stack;
+  for (const auto &i : schema) {
+    const Option &opt = i.second;
+
+    if (opt.type == Option::TYPE_STR) {
+      list<const Option*> stack;
+      std::string *str = boost::get<std::string>(&(values.at(opt.name)));
+      assert(str != nullptr);  // Non-string values should never get in
       expand_meta(*str, &opt, stack, &oss);
     }
   }
   cerr << oss.str();
 }
 
-bool md_config_t::expand_meta(std::string &origval,
+bool md_config_t::expand_meta(std::string &val,
                              std::ostream *oss) const
 {
-  list<config_option const *> stack;
-  return expand_meta(origval, NULL, stack, oss);
+  list<const Option*> stack;
+  return expand_meta(val, NULL, stack, oss);
 }
 
 bool md_config_t::expand_meta(std::string &origval,
-                             config_option const *opt,
-                             std::list<config_option const *> stack,
+                             const Option *opt,
+                             std::list<const Option *> stack,
                              std::ostream *oss) const
 {
   assert(lock.is_locked());
@@ -1186,25 +1125,22 @@ bool md_config_t::expand_meta(std::string &origval,
   // ignore an expansion loop and create a human readable
   // message about it
   if (opt) {
-    for (list<config_option const *>::iterator i = stack.begin();
-        i != stack.end();
-        ++i) {
-      if (strcmp(opt->name, (*i)->name) == 0) {
+    for (const auto stack_ptr : stack) {
+      if (opt->name == stack_ptr->name) {
        *oss << "variable expansion loop at "
             << opt->name << "=" << origval << std::endl;
        *oss << "expansion stack: " << std::endl;
-       for (list<config_option const *>::iterator j = stack.begin();
-            j != stack.end();
-            ++j) {
-         *oss << (*j)->name << "=" << *((*j)->conf_ptr<std::string>(this)) << std::endl;
+       for (const auto j : stack) {
+          std::string val;
+          _get_val(j->name, &val);
+         *oss << j->name << "=" << val << std::endl;
        }
        return false;
       }
     }
-  }
 
-  if (opt)
     stack.push_front(opt);
+  }
 
   bool found_meta = false;
   string out;
@@ -1285,22 +1221,25 @@ bool md_config_t::expand_meta(std::string &origval,
 
       if (!expanded) {
        // config option?
-        for (auto& opt: *config_options) {
-         if (var == opt.name) {
-           string *origval;
-           opt.conf_ptr(origval, const_cast<md_config_t *>(this));
-           if (origval) {
-             expand_meta(*origval, &opt, stack, oss);
-             out += *origval;
-           } else {
-             char *vv = NULL;
-             _get_val(opt.name, &vv, -1);
-             out += vv;
-             free(vv);
-           }
-           expanded = true;
-           break;
-         }
+        const auto other_opt_iter = schema.find(var);
+        if (other_opt_iter != schema.end()) {
+          const Option &other_opt = other_opt_iter->second;
+          if (other_opt.type == Option::TYPE_STR) {
+            // The referenced option is a string, it may need substitution
+            // before inserting.
+            Option::value_t *other_val_ptr = const_cast<Option::value_t*>(&(values.at(other_opt.name)));
+            std::string *other_opt_val = boost::get<std::string>(other_val_ptr);
+            expand_meta(*other_opt_val, &other_opt, stack, oss);
+            out += *other_opt_val;
+          } else {
+            // The referenced option is not a string: retrieve and insert
+            // its stringized form.
+            char *vv = NULL;
+            _get_val(other_opt.name, &vv, -1);
+            out += vv;
+            free(vv);
+          }
+          expanded = true;
        }
       }
     }
@@ -1341,7 +1280,8 @@ void md_config_t::diff_helper(
 
   char local_buf[4096];
   char other_buf[4096];
-  for (auto& opt : *config_options) {
+  for (const auto &i : schema) {
+    const Option &opt = i.second;
     if (!setting.empty()) {
       if (setting != opt.name) {
         continue;
@@ -1378,18 +1318,3 @@ void md_config_t::complain_about_parse_errors(CephContext *cct)
   ::complain_about_parse_errors(cct, &parse_errors);
 }
 
-void md_config_t::validate_default_settings() {
-  Mutex::Locker l(lock);
-  for (auto &opt : *config_options) {
-    // normalize config defaults using their validator
-    if (opt.validator) {
-      std::string value;
-      int r = _get_val(opt.name, &value);
-      assert(r == 0);
-
-      std::string error_message;
-      r = set_val_impl(value.c_str(), &opt, &error_message);
-      assert(r == 0);
-    }
-  }
-}
index 7aa9917982ab7dfdfc5f93d8b65a2cb9f9a815d2..c63bc1a65276e325d8af3d421de7322e3da1a1ec 100644 (file)
 
 #include "common/ConfUtils.h"
 #include "common/entity_name.h"
+#include "common/code_environment.h"
 #include "common/Mutex.h"
 #include "log/SubsystemMap.h"
 #include "common/config_obs.h"
+#include "common/options.h"
 
 #define OSD_REP_PRIMARY 0
 #define OSD_REP_SPLAY   1
@@ -64,6 +66,13 @@ extern const char *CEPH_CONF_FILE_DEFAULT;
  */
 struct md_config_t {
 public:
+  typedef boost::variant<int64_t md_config_t::*,
+                         std::string md_config_t::*,
+                         double md_config_t::*,
+                         bool md_config_t::*,
+                         entity_addr_t md_config_t::*,
+                         uuid_d md_config_t::*> member_ptr_t;
+
   /* Maps configuration options to the observer listening for them. */
   typedef std::multimap <std::string, md_config_obs_t*> obs_map_t;
 
@@ -71,81 +80,27 @@ public:
    * apply_changes */
   typedef std::set < std::string > changed_set_t;
 
-  struct invalid_config_value_t { };
-  typedef boost::variant<invalid_config_value_t,
-                         int,
-                         long long,
-                         std::string,
-                         double,
-                         float,
-                         bool,
-                         entity_addr_t,
-                         uint32_t,
-                         uint64_t,
-                         uuid_d> config_value_t;
-  typedef boost::variant<const int md_config_t::*,
-                         const long long md_config_t::*,
-                         const std::string md_config_t::*,
-                         const double md_config_t::*,
-                         const float md_config_t::*,
-                         const bool md_config_t::*,
-                         const entity_addr_t md_config_t::*,
-                         const uint32_t md_config_t::*,
-                         const uint64_t md_config_t::*,
-                         const uuid_d md_config_t::*> member_ptr_t;
+  /*
+   * Mapping from legacy config option names to class members
+   */
+  std::map<std::string, md_config_t::member_ptr_t> legacy_values;
+
+  /**
+   * The configuration schema, in the form of Option objects describing
+   * possible settings.
+   */
+  std::map<std::string, const Option &> schema;
+
+  /**
+   * The current values of all settings described by the schema
+   */
+  std::map<std::string, Option::value_t> values;
 
    typedef enum {
        OPT_INT, OPT_LONGLONG, OPT_STR, OPT_DOUBLE, OPT_FLOAT, OPT_BOOL,
        OPT_ADDR, OPT_U32, OPT_U64, OPT_UUID
    } opt_type_t;
 
-  typedef std::function<int(std::string*, std::string*)> validator_t;
-
-  class config_option {
-  public:
-    const char *name;
-    opt_type_t type;
-    md_config_t::member_ptr_t md_member_ptr;
-    bool safe; // promise to access it only via md_config_t::get_val
-    validator_t validator;
-  private:
-    template<typename T> struct get_typed_pointer_visitor : public boost::static_visitor<T const *> {
-      md_config_t const *conf;
-      explicit get_typed_pointer_visitor(md_config_t const *conf_) : conf(conf_) { }
-      template<typename U,
-       typename boost::enable_if<boost::is_same<T, U>, int>::type = 0>
-         T const *operator()(const U md_config_t::* member_ptr) {
-           return &(conf->*member_ptr);
-         }
-      template<typename U,
-       typename boost::enable_if_c<!boost::is_same<T, U>::value, int>::type = 0>
-         T const *operator()(const U md_config_t::* member_ptr) {
-           return nullptr;
-         }
-    };
-  public:
-    // is it OK to alter the value when threads are running?
-    bool is_safe() const;
-    // Given a configuration, return a pointer to this option inside
-    // that configuration.
-    template<typename T> void conf_ptr(T const *&ptr, md_config_t const *conf) const {
-      get_typed_pointer_visitor<T> gtpv(conf);
-      ptr = boost::apply_visitor(gtpv, md_member_ptr);
-    }
-    template<typename T> void conf_ptr(T *&ptr, md_config_t *conf) const {
-      get_typed_pointer_visitor<T> gtpv(conf);
-      ptr = const_cast<T *>(boost::apply_visitor(gtpv, md_member_ptr));
-    }
-    template<typename T> T const *conf_ptr(md_config_t const *conf) const {
-      get_typed_pointer_visitor<T> gtpv(conf);
-      return boost::apply_visitor(gtpv, md_member_ptr);
-    }
-    template<typename T> T *conf_ptr(md_config_t *conf) const {
-      get_typed_pointer_visitor<T> gtpv(conf);
-      return const_cast<T *>(boost::apply_visitor(gtpv, md_member_ptr));
-    }
-  };
-
   // Create a new md_config_t structure.
   md_config_t();
   ~md_config_t();
@@ -188,21 +143,21 @@ public:
 
   // Set a configuration value, or crash
   // Metavariables will be expanded.
-  void set_val_or_die(const char *key, const char *val);
+  void set_val_or_die(const std::string &key, const char *val);
 
   // Set a configuration value.
   // Metavariables will be expanded.
-  int set_val(const char *key, const char *val, bool meta=true);
-  int set_val(const char *key, const string& s, bool meta=true) {
+  int set_val(const std::string &key, const char *val, bool meta=true);
+  int set_val(const std::string &key, const string& s, bool meta=true) {
     return set_val(key, s.c_str(), meta);
   }
 
   // Get a configuration value.
   // No metavariables will be returned (they will have already been expanded)
-  int get_val(const char *key, char **buf, int len) const;
-  int _get_val(const char *key, char **buf, int len) const;
-  config_value_t get_val_generic(const char *key) const;
-  template<typename T> T get_val(const char *key) const;
+  int get_val(const std::string &key, char **buf, int len) const;
+  int _get_val(const std::string &key, char **buf, int len) const;
+  Option::value_t get_val_generic(const std::string &key) const;
+  template<typename T> T get_val(const std::string &key) const;
 
   void get_all_keys(std::vector<std::string> *keys) const;
 
@@ -215,7 +170,7 @@ public:
   // Get a value from the configuration file that we read earlier.
   // Metavariables will be expanded if emeta is true.
   int get_val_from_conf_file(const std::vector <std::string> &sections,
-                  const char *key, std::string &out, bool emeta) const;
+                  std::string const &key, std::string &out, bool emeta) const;
 
   /// dump all config values to a stream
   void show_config(std::ostream& out);
@@ -236,16 +191,17 @@ public:
   void complain_about_parse_errors(CephContext *cct);
 
 private:
+  void validate_schema();
   void validate_default_settings();
 
-  int _get_val(const char *key, std::string *value) const;
-  config_value_t _get_val(const char *key) const;
+  int _get_val(const std::string &key, std::string *value) const;
+  Option::value_t _get_val(const std::string &key) const;
   void _show_config(std::ostream *out, Formatter *f);
 
   void _get_my_sections(std::vector <std::string> &sections) const;
 
   int _get_val_from_conf_file(const std::vector <std::string> &sections,
-                             const char *key, std::string &out, bool emeta) const;
+                             const std::string &key, std::string &out, bool emeta) const;
 
   int parse_option(std::vector<const char*>& args,
                   std::vector<const char*>::iterator& i,
@@ -255,9 +211,15 @@ private:
   int parse_config_files_impl(const std::list<std::string> &conf_files,
                              std::ostream *warnings);
 
-  int set_val_impl(const std::string &val, config_option const *opt,
+  int set_val_impl(const std::string &val, const Option &opt,
                    std::string *error_message);
-  int set_val_raw(const char *val, config_option const *opt);
+
+  template <typename T>
+  void assign_member(member_ptr_t ptr, const Option::value_t &val);
+
+
+  void update_legacy_val(const Option &opt,
+      md_config_t::member_ptr_t member);
 
   void init_subsys();
 
@@ -276,8 +238,8 @@ public:  // for global_init
   }
 private:
   bool expand_meta(std::string &val,
-                  config_option const *opt,
-                  std::list<config_option const *> stack,
+                  const Option *opt,
+                  std::list<const Option*> stack,
                   std::ostream *oss) const;
 
   /// expand all metavariables in config structure.
@@ -306,28 +268,22 @@ public:
 // These C members are consumed by code that was written before
 // the new options.cc infrastructure: all newer code should
 // be consume options via explicit get() rather than C members.
-#define OPTION_OPT_INT(name) const int name;
-#define OPTION_OPT_LONGLONG(name) const long long name;
-#define OPTION_OPT_STR(name) const std::string name;
-#define OPTION_OPT_DOUBLE(name) const double name;
-#define OPTION_OPT_FLOAT(name) const float name;
-#define OPTION_OPT_BOOL(name) const bool name;
-#define OPTION_OPT_ADDR(name) const entity_addr_t name;
-#define OPTION_OPT_U32(name) const uint32_t name;
-#define OPTION_OPT_U64(name) const uint64_t name;
-#define OPTION_OPT_UUID(name) const uuid_d name;
+#define OPTION_OPT_INT(name) int64_t name;
+#define OPTION_OPT_LONGLONG(name) int64_t name;
+#define OPTION_OPT_STR(name) std::string name;
+#define OPTION_OPT_DOUBLE(name) double name;
+#define OPTION_OPT_FLOAT(name) double name;
+#define OPTION_OPT_BOOL(name) bool name;
+#define OPTION_OPT_ADDR(name) entity_addr_t name;
+#define OPTION_OPT_U32(name) int64_t name;
+#define OPTION_OPT_U64(name) int64_t name;
+#define OPTION_OPT_UUID(name) uuid_d name;
 #define OPTION(name, ty, init) \
   public:                      \
-    OPTION_##ty(name)          \
-    struct option_##name##_t;
-#define OPTION_VALIDATOR(name)
+    OPTION_##ty(name)          
 #define SAFE_OPTION(name, ty, init) \
   protected:                        \
-    OPTION_##ty(name)               \
-  public:                           \
-    struct option_##name##_t;
-#define SUBSYS(name, log, gather)
-#define DEFAULT_SUBSYS(log, gather)
+    OPTION_##ty(name)               
 #include "common/legacy_config_opts.h"
 #undef OPTION_OPT_INT
 #undef OPTION_OPT_LONGLONG
@@ -340,11 +296,9 @@ public:
 #undef OPTION_OPT_U64
 #undef OPTION_OPT_UUID
 #undef OPTION
-#undef OPTION_VALIDATOR
 #undef SAFE_OPTION
-#undef SUBSYS
-#undef DEFAULT_SUBSYS
 
+public:
   unsigned get_osd_pool_default_min_size() const {
     return osd_pool_default_min_size ?
       MIN(osd_pool_default_min_size, osd_pool_default_size) :
@@ -358,11 +312,6 @@ public:
   mutable Mutex lock;
 
   friend class test_md_config_t;
-protected:
-  // Tests and possibly users expect options to appear in the output
-  // of ceph-conf in the same order as declared in config_opts.h
-  std::shared_ptr<const std::vector<config_option>> config_options;
-  config_option const *find_config_option(const std::string& normalized_key) const;
 };
 
 template<typename T>
@@ -379,35 +328,26 @@ struct get_typed_value_visitor : public boost::static_visitor<T> {
       }
 };
 
-template<typename T> T md_config_t::get_val(const char *key) const {
-  config_value_t generic_val = this->get_val_generic(key);
+template<typename T> T md_config_t::get_val(const std::string &key) const {
+  Option::value_t generic_val = this->get_val_generic(key);
   get_typed_value_visitor<T> gtv;
   return boost::apply_visitor(gtv, generic_val);
 }
 
-inline std::ostream& operator<<(std::ostream& o, const md_config_t::invalid_config_value_t& ) {
+inline std::ostream& operator<<(std::ostream& o, const boost::blank& ) {
       return o << "INVALID_CONFIG_VALUE";
 }
 
 int ceph_resolve_file_search(const std::string& filename_list,
                             std::string& result);
 
-typedef md_config_t::config_option config_option;
-
-
 enum config_subsys_id {
   ceph_subsys_,   // default
-#define OPTION(a,b,c)
-#define OPTION_VALIDATOR(name)
-#define SAFE_OPTION(a,b,c)
 #define SUBSYS(name, log, gather) \
   ceph_subsys_##name,
 #define DEFAULT_SUBSYS(log, gather)
-#include "common/legacy_config_opts.h"
+#include "common/subsys.h"
 #undef SUBSYS
-#undef OPTION
-#undef OPTION_VALIDATOR
-#undef SAFE_OPTION
 #undef DEFAULT_SUBSYS
   ceph_subsys_max
 };
index 6618779a74174c70dfee44c091d72958546ea633..316fca1b57f1c2ac30d135c7dcc4f3244497e0e0 100644 (file)
@@ -22,11 +22,11 @@ const std::vector<Option> ceph_options = {
   .set_description("public-facing address to bind to")
   .add_tag("mon mds osd mgr"),
 
-  Option("cluster_addr", Option::TYPE_STR, Option::LEVEL_BASIC)
+  Option("cluster_addr", Option::TYPE_ADDR, Option::LEVEL_BASIC)
   .set_description("cluster-facing address to bind to")
   .add_tag("osd"),
 
-  Option("public_network", Option::TYPE_STR, Option::LEVEL_ADVANCED)
+  Option("public_network", Option::TYPE_ADDR, Option::LEVEL_ADVANCED)
   .set_default("")
   .set_description(""),
 
@@ -282,7 +282,8 @@ const std::vector<Option> ceph_options = {
 
   Option("plugin_dir", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default(CEPH_PKGLIBDIR)
-  .set_description(""),
+  .set_description("")
+  .set_safe(),
 
   Option("xio_trace_mempool", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
   .set_default(false)
@@ -406,7 +407,8 @@ const std::vector<Option> ceph_options = {
 
   Option("ms_type", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default("async+posix")
-  .set_description(""),
+  .set_description("")
+  .set_safe(),
 
   Option("ms_public_type", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default("")
@@ -510,7 +512,8 @@ const std::vector<Option> ceph_options = {
 
   Option("ms_inject_delay_type", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default("")
-  .set_description(""),
+  .set_description("")
+  .set_safe(),
 
   Option("ms_inject_delay_msg_type", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default("")
@@ -602,7 +605,8 @@ const std::vector<Option> ceph_options = {
 
   Option("ms_dpdk_coremask", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default("1")
-  .set_description(""),
+  .set_description("")
+  .set_safe(),
 
   Option("ms_dpdk_memory_channel", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default("4")
@@ -618,15 +622,18 @@ const std::vector<Option> ceph_options = {
 
   Option("ms_dpdk_host_ipv4_addr", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default("")
-  .set_description(""),
+  .set_description("")
+  .set_safe(),
 
   Option("ms_dpdk_gateway_ipv4_addr", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default("")
-  .set_description(""),
+  .set_description("")
+  .set_safe(),
 
   Option("ms_dpdk_netmask_ipv4_addr", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default("")
-  .set_description(""),
+  .set_description("")
+  .set_safe(),
 
   Option("ms_dpdk_lro", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
   .set_default(true)
@@ -660,10 +667,6 @@ const std::vector<Option> ceph_options = {
   .set_default("")
   .set_description(""),
 
-  Option("mon_sync_fs_threshold", Option::TYPE_INT, Option::LEVEL_ADVANCED)
-  .set_default(5)
-  .set_description(""),
-
   Option("mon_compact_on_start", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
   .set_default(false)
   .set_description(""),
@@ -756,10 +759,14 @@ const std::vector<Option> ceph_options = {
   .set_default(.75)
   .set_description(""),
 
-  Option("mon_osd_max_op_age", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  Option("mon_osd_warn_op_age", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
   .set_default(32)
   .set_description(""),
 
+  Option("mon_osd_err_op_age_ratio", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(128)
+  .set_description(""),
+
   Option("mon_osd_max_split_count", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(32)
   .set_description(""),
@@ -960,6 +967,10 @@ const std::vector<Option> ceph_options = {
   .set_default(.3)
   .set_description(""),
 
+  Option("mon_log_max_summary", Option::TYPE_INT, Option::LEVEL_ADVANCED)
+  .set_default(50)
+  .set_description(""),
+
   Option("mon_daemon_bytes", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(400ul << 20)
   .set_description(""),
@@ -1009,7 +1020,7 @@ const std::vector<Option> ceph_options = {
   .set_description(""),
 
   Option("mon_data_size_warn", Option::TYPE_INT, Option::LEVEL_ADVANCED)
-  .set_default(15*1024*1024*1024ull)
+  .set_default(15*1024*1024*1024)
   .set_description(""),
 
   Option("mon_warn_not_scrubbed", Option::TYPE_INT, Option::LEVEL_ADVANCED)
@@ -1136,6 +1147,10 @@ const std::vector<Option> ceph_options = {
   .set_default(false)
   .set_description(""),
 
+  Option("mon_osd_blacklist_default_expire", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(60*60)
+  .set_description(""),
+
   Option("paxos_stash_full_interval", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(25)
   .set_description(""),
@@ -1645,8 +1660,8 @@ const std::vector<Option> ceph_options = {
   .set_description(""),
 
   Option("mds_default_dir_hash", Option::TYPE_INT, Option::LEVEL_ADVANCED)
-  .set_default(2)
-  .set_description("2 == rjenkins"),
+  .set_default(CEPH_STR_HASH_RJENKINS)
+  .set_description(""),
 
   Option("mds_log_pause", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
   .set_default(false)
@@ -2037,7 +2052,7 @@ const std::vector<Option> ceph_options = {
   .set_description(""),
 
   Option("osd_uuid", Option::TYPE_UUID, Option::LEVEL_ADVANCED)
-//  .set_default(uuid_d())
+  .set_default(uuid_d())
   .set_description(""),
 
   Option("osd_data", Option::TYPE_STR, Option::LEVEL_ADVANCED)
@@ -2108,10 +2123,6 @@ const std::vector<Option> ceph_options = {
   .set_default(-1)
   .set_description(""),
 
-  Option("osd_pool_default_crush_replicated_ruleset", Option::TYPE_INT, Option::LEVEL_ADVANCED)
-  .set_default(0)
-  .set_description(""),
-
   Option("osd_pool_erasure_code_stripe_unit", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(4096)
   .set_description(""),
@@ -2137,7 +2148,7 @@ const std::vector<Option> ceph_options = {
   .set_description(""),
 
   Option("osd_erasure_code_plugins", Option::TYPE_STR, Option::LEVEL_ADVANCED)
-  .set_default("jerasure" " lrc" " isa")
+  .set_default("jerasure" " lrc")
   .set_description(""),
 
   Option("osd_allow_recovery_below_min_size", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
@@ -2280,7 +2291,7 @@ const std::vector<Option> ceph_options = {
   .set_default(5)
   .set_description(""),
 
-  Option("osd_op_threads", Option::TYPE_INT, Option::LEVEL_ADVANCED)
+  Option("osd_peering_wq_threads", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(2)
   .set_description(""),
 
@@ -2313,13 +2324,29 @@ const std::vector<Option> ceph_options = {
   .set_description(""),
 
   Option("osd_op_num_threads_per_shard", Option::TYPE_INT, Option::LEVEL_ADVANCED)
+  .set_default(0)
+  .set_description(""),
+
+  Option("osd_op_num_threads_per_shard_hdd", Option::TYPE_INT, Option::LEVEL_ADVANCED)
+  .set_default(1)
+  .set_description(""),
+
+  Option("osd_op_num_threads_per_shard_ssd", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(2)
   .set_description(""),
 
   Option("osd_op_num_shards", Option::TYPE_INT, Option::LEVEL_ADVANCED)
+  .set_default(0)
+  .set_description(""),
+
+  Option("osd_op_num_shards_hdd", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(5)
   .set_description(""),
 
+  Option("osd_op_num_shards_ssd", Option::TYPE_INT, Option::LEVEL_ADVANCED)
+  .set_default(8)
+  .set_description(""),
+
   Option("osd_op_queue", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default("wpq")
   .set_description(""),
@@ -2328,6 +2355,66 @@ const std::vector<Option> ceph_options = {
   .set_default("low")
   .set_description(""),
 
+  Option("osd_op_queue_mclock_client_op_res", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(1000.0)
+  .set_description(""),
+
+  Option("osd_op_queue_mclock_client_op_wgt", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(500.0)
+  .set_description(""),
+
+  Option("osd_op_queue_mclock_client_op_lim", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(0.0)
+  .set_description(""),
+
+  Option("osd_op_queue_mclock_osd_subop_res", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(1000.0)
+  .set_description(""),
+
+  Option("osd_op_queue_mclock_osd_subop_wgt", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(500.0)
+  .set_description(""),
+
+  Option("osd_op_queue_mclock_osd_subop_lim", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(0.0)
+  .set_description(""),
+
+  Option("osd_op_queue_mclock_snap_res", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(0.0)
+  .set_description(""),
+
+  Option("osd_op_queue_mclock_snap_wgt", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(1.0)
+  .set_description(""),
+
+  Option("osd_op_queue_mclock_snap_lim", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(0.001)
+  .set_description(""),
+
+  Option("osd_op_queue_mclock_recov_res", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(0.0)
+  .set_description(""),
+
+  Option("osd_op_queue_mclock_recov_wgt", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(1.0)
+  .set_description(""),
+
+  Option("osd_op_queue_mclock_recov_lim", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(0.001)
+  .set_description(""),
+
+  Option("osd_op_queue_mclock_scrub_res", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(0.0)
+  .set_description(""),
+
+  Option("osd_op_queue_mclock_scrub_wgt", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(1.0)
+  .set_description(""),
+
+  Option("osd_op_queue_mclock_scrub_lim", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(0.001)
+  .set_description(""),
+
   Option("osd_ignore_stale_divergent_priors", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
   .set_default(false)
   .set_description(""),
@@ -2393,7 +2480,7 @@ const std::vector<Option> ceph_options = {
   .set_description(""),
 
   Option("osd_heartbeat_addr", Option::TYPE_ADDR, Option::LEVEL_ADVANCED)
-  //.set_default(entity_addr_t())
+  .set_default(entity_addr_t())
   .set_description(""),
 
   Option("osd_heartbeat_interval", Option::TYPE_INT, Option::LEVEL_ADVANCED)
@@ -2412,6 +2499,10 @@ const std::vector<Option> ceph_options = {
   .set_default(false)
   .set_description(""),
 
+  Option("osd_heartbeat_min_size", Option::TYPE_INT, Option::LEVEL_ADVANCED)
+  .set_default(2000)
+  .set_description(""),
+
   Option("osd_pg_max_concurrent_snap_trims", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(2)
   .set_description(""),
@@ -2464,10 +2555,6 @@ const std::vector<Option> ceph_options = {
   .set_default(45)
   .set_description(""),
 
-  Option("osd_preserve_trimmed_log", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
-  .set_default(false)
-  .set_description(""),
-
   Option("osd_auto_mark_unfound_lost", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
   .set_default(false)
   .set_description(""),
@@ -2584,10 +2671,6 @@ const std::vector<Option> ceph_options = {
   .set_default(2*60*60)
   .set_description(""),
 
-  Option("osd_scan_list_ping_tp_interval", Option::TYPE_INT, Option::LEVEL_ADVANCED)
-  .set_default(100)
-  .set_description(""),
-
   Option("osd_class_dir", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default(CEPH_LIBDIR "/rados-classes")
   .set_description(""),
@@ -2740,6 +2823,10 @@ const std::vector<Option> ceph_options = {
   .set_default(false)
   .set_description(""),
 
+  Option("osd_debug_random_push_read_error", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(0)
+  .set_description(""),
+
   Option("osd_debug_verify_cached_snaps", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
   .set_default(false)
   .set_description(""),
@@ -2878,7 +2965,8 @@ const std::vector<Option> ceph_options = {
 
   Option("rocksdb_db_paths", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default("")
-  .set_description(""),
+  .set_description("")
+  .set_safe(),
 
   Option("rocksdb_log_to_ceph_log", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
   .set_default(true)
@@ -2888,10 +2976,18 @@ const std::vector<Option> ceph_options = {
   .set_default(128*1024*1024)
   .set_description(""),
 
+  Option("rocksdb_cache_row_ratio", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(.2)
+  .set_description(""),
+
   Option("rocksdb_cache_shard_bits", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(4)
   .set_description(""),
 
+  Option("rocksdb_cache_type", Option::TYPE_STR, Option::LEVEL_ADVANCED)
+  .set_default("lru")
+  .set_description(""),
+
   Option("rocksdb_block_size", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(4*1024)
   .set_description(""),
@@ -2973,7 +3069,7 @@ const std::vector<Option> ceph_options = {
   .set_description(""),
 
   Option("osd_max_object_size", Option::TYPE_INT, Option::LEVEL_ADVANCED)
-  .set_default(100*1024L*1024L*1024L)
+  .set_default(128*1024L*1024L)
   .set_description(""),
 
   Option("osd_max_object_name_len", Option::TYPE_INT, Option::LEVEL_ADVANCED)
@@ -3197,7 +3293,7 @@ const std::vector<Option> ceph_options = {
   .set_description(""),
 
   Option("bluestore_block_size", Option::TYPE_INT, Option::LEVEL_ADVANCED)
-  .set_default(10 * 1024*1024*1024ull)
+  .set_default(10 * 1024*1024*1024)
   .set_description(""),
 
   Option("bluestore_block_create", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
@@ -3369,11 +3465,15 @@ const std::vector<Option> ceph_options = {
   .set_description(""),
 
   Option("bluestore_cache_size", Option::TYPE_INT, Option::LEVEL_ADVANCED)
-  .set_default(1024*1024*1024)
+  .set_default(3*1024*1024*1024)
   .set_description(""),
 
   Option("bluestore_cache_meta_ratio", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
-  .set_default(.9)
+  .set_default(.7)
+  .set_description(""),
+
+  Option("bluestore_cache_kv_ratio", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(.2)
   .set_description(""),
 
   Option("bluestore_kvbackend", Option::TYPE_STR, Option::LEVEL_ADVANCED)
@@ -3441,7 +3541,7 @@ const std::vector<Option> ceph_options = {
   .set_description(""),
 
   Option("bluestore_throttle_cost_per_io_hdd", Option::TYPE_INT, Option::LEVEL_ADVANCED)
-  .set_default(1500000)
+  .set_default(670000)
   .set_description(""),
 
   Option("bluestore_throttle_cost_per_io_ssd", Option::TYPE_INT, Option::LEVEL_ADVANCED)
@@ -3524,10 +3624,22 @@ const std::vector<Option> ceph_options = {
   .set_default(false)
   .set_description(""),
 
+  Option("bluestore_debug_omit_kv_commit", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
+  .set_default(false)
+  .set_description(""),
+
+  Option("bluestore_debug_permit_any_bdev_label", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
+  .set_default(false)
+  .set_description(""),
+
   Option("bluestore_shard_finishers", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
   .set_default(false)
   .set_description(""),
 
+  Option("bluestore_debug_random_read_err", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
+  .set_default(0)
+  .set_description(""),
+
   Option("kstore_max_ops", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(512)
   .set_description(""),
@@ -3572,10 +3684,6 @@ const std::vector<Option> ceph_options = {
   .set_default(1024)
   .set_description(""),
 
-  Option("kstore_cache_tails", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
-  .set_default(true)
-  .set_description(""),
-
   Option("kstore_default_stripe_size", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(65536)
   .set_description(""),
@@ -3652,10 +3760,14 @@ const std::vector<Option> ceph_options = {
   .set_default(false)
   .set_description(""),
 
-  Option("filestore_debug_omap_check", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
+  Option("filestore_debug_random_read_err", Option::TYPE_FLOAT, Option::LEVEL_ADVANCED)
   .set_default(0)
   .set_description(""),
 
+  Option("filestore_debug_omap_check", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
+  .set_default(false)
+  .set_description(""),
+
   Option("filestore_omap_header_cache_size", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(1024)
   .set_description(""),
@@ -4108,6 +4220,10 @@ const std::vector<Option> ceph_options = {
   .set_default(0)
   .set_description(""),
 
+  Option("rbd_default_pool", Option::TYPE_STR, Option::LEVEL_ADVANCED)
+  .set_default("rbd")
+  .set_description(""),
+
   Option("rbd_default_format", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(2)
   .set_description(""),
@@ -4130,7 +4246,8 @@ const std::vector<Option> ceph_options = {
 
   Option("rbd_default_features", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default("layering,exclusive-lock,object-map,fast-diff,deep-flatten")
-  .set_description(""),
+  .set_description("")
+  .set_safe(),
 
   Option("rbd_default_map_options", Option::TYPE_STR, Option::LEVEL_ADVANCED)
   .set_default("")
@@ -4524,6 +4641,10 @@ const std::vector<Option> ceph_options = {
   .set_default(1)
   .set_description(""),
 
+  Option("rgw_verify_ssl", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
+  .set_default(true)
+  .set_description(""),
+
   Option("rgw_nfs_lru_lanes", Option::TYPE_INT, Option::LEVEL_ADVANCED)
   .set_default(5)
   .set_description(""),
@@ -4928,8 +5049,8 @@ const std::vector<Option> ceph_options = {
   .set_default(CEPH_PKGLIBDIR "/mgr")
   .set_description(""),
 
-  Option("mgr_modules", Option::TYPE_STR, Option::LEVEL_ADVANCED)
-  .set_default("restful")
+  Option("mgr_initial_modules", Option::TYPE_STR, Option::LEVEL_ADVANCED)
+  .set_default("restful status")
   .set_description(""),
 
   Option("mgr_data", Option::TYPE_STR, Option::LEVEL_ADVANCED)
@@ -5089,3 +5210,4 @@ const std::vector<Option> ceph_options = {
   .set_description(""),
 };
 
+
index ad1b29c113778880aaa94802e6a0300a62231a1b..53ef1d308e955631d692c5e8f04c282010fea231 100644 (file)
@@ -6,6 +6,8 @@
 #include <string>
 #include <list>
 #include <boost/variant.hpp>
+#include "msg/msg_types.h"
+#include "include/uuid.h"
 
 //#include "include/uuid.h"
 //#include "msg/msg_types.h"
@@ -39,12 +41,13 @@ struct Option {
   };
 
   using value_t = boost::variant<
+    boost::blank,
     std::string,
     int64_t,
     double,
-    bool/*,
+    bool,
     entity_addr_t,
-    uuid_d*/>;
+    uuid_d>;
   const std::string name;
   const type_t type;
   const level_t level;
@@ -64,9 +67,34 @@ struct Option {
 
   bool safe;
 
-  Option(const char* name, type_t t, level_t l)
+  Option(std::string const &name, type_t t, level_t l)
     : name(name), type(t), level(l), safe(false)
-  {}
+  {
+    // While value_t is nullable (via boost::blank), we don't ever
+    // want it set that way in an Option instance: within an instance,
+    // the type of ::value should always match the declared type.
+    if (type == TYPE_INT) {
+      value = int64_t(0);
+    } else if (type == TYPE_STR) {
+      value = std::string("");
+    } else if (type == TYPE_FLOAT) {
+      value = 0.0;
+    } else if (type == TYPE_BOOL) {
+      value = false;
+    } else if (type == TYPE_ADDR) {
+      value = entity_addr_t();
+    } else if (type == TYPE_UUID) {
+      value = uuid_d();
+    } else {
+      ceph_abort();
+    }
+  }
+
+  // const char * must be explicit to avoid it being treated as an int
+  Option& set_value(value_t& v, const char *new_value) {
+    v = std::string(new_value);
+    return *this;
+  }
 
   // bool is an integer, but we don't think so. teach it the hard way.
   template<typename T>
@@ -82,13 +110,25 @@ struct Option {
   }
   template<typename T, typename is_integer<T>::type = 0>
   Option& set_value(value_t& v, T new_value) {
-    v = int64_t(new_value);
+    if (type == TYPE_INT) {
+      v = int64_t(new_value);
+    } else if (type == TYPE_FLOAT) {
+      v = double(new_value);
+    } else if (type == TYPE_BOOL) {
+      v = bool(new_value);
+    } else {
+      std::cerr << "Bad type in set_value: " << name << ": "
+                << typeid(T).name() << std::endl;
+      ceph_abort();
+    }
     return *this;
   }
+
   template<typename T>
   Option& set_default(const T& v) {
     return set_value(value, v);
   }
+
   template<typename T>
   Option& set_daemon_default(const T& v) {
     return set_value(daemon_value, v);
index 48f149190c138079a5ebc702a212bcdea65667ab..e0e0ee5bf228a34234881dd48cac10052b0b8f60 100644 (file)
@@ -1,6 +1,6 @@
 
 #include <iostream>
-#include "include/acconfig.h"
+//#include "include/acconfig.h"
 using namespace std;
 #define _STR(x) #x
 #define STRINGIFY(x) _STR(x)
@@ -45,12 +45,9 @@ string convert_type(string t) {
   cout << "  Option(\"" << STRINGIFY(name) << "\", Option::" << convert_type(STRINGIFY(type)) \
   << ", Option::LEVEL_ADVANCED)\n"                                     \
   << "  .set_default(" << STRINGIFY(def_val) << ")\n"                  \
-  << "  .set_description(\"\")\n";                  \
+  << "  .set_description(\"\")\n"                  \
   << "  .set_safe(),\n\n";
   
-#define SUBSYS(name, log, gather)
-#define DEFAULT_SUBSYS(log, gather)
-
 int main(int argc, char **argv)
 {
   #include "common/legacy_config_opts.h"