// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
+#include <boost/algorithm/string/split.hpp>
+
#include "ConfigMap.h"
#include "crush/CrushWrapper.h"
+#include "common/entity_name.h"
int MaskedOption::get_precision(const CrushWrapper *crush)
{
// 0 = most precise
- if (location_type.size()) {
- int r = crush->get_type_id(location_type);
+ if (mask.location_type.size()) {
+ int r = crush->get_type_id(mask.location_type);
if (r >= 0) {
return r;
}
// bad type name, ignore it
}
int num_types = crush->get_num_type_names();
- if (device_class.size()) {
+ if (mask.device_class.size()) {
return num_types;
}
return num_types + 1;
{
f->dump_string("name", opt.name);
f->dump_string("value", raw_value);
- if (location_type.size()) {
- f->dump_string("location_type", location_type);
- f->dump_string("location_value", location_value);
+ if (mask.location_type.size()) {
+ f->dump_string("location_type", mask.location_type);
+ f->dump_string("location_value", mask.location_value);
}
- if (device_class.size()) {
- f->dump_string("device_class", device_class);
+ if (mask.device_class.size()) {
+ f->dump_string("device_class", mask.device_class);
}
}
ostream& operator<<(ostream& out, const MaskedOption& o)
{
out << o.opt.name;
- if (o.location_type.size()) {
- out << "@" << o.location_type << '=' << o.location_value;
+ if (o.mask.location_type.size()) {
+ out << "@" << o.mask.location_type << '=' << o.mask.location_value;
}
- if (o.device_class.size()) {
- out << "@class=" << o.device_class;
+ if (o.mask.device_class.size()) {
+ out << "@class=" << o.mask.device_class;
}
return out;
}
for (auto& i : s->options) {
auto& o = i.second;
// match against crush location, class
- if (o.device_class.size() &&
- o.device_class != device_class) {
+ if (o.mask.device_class.size() &&
+ o.mask.device_class != device_class) {
continue;
}
- if (o.location_type.size()) {
- auto p = crush_location.find(o.location_type);
+ if (o.mask.location_type.size()) {
+ auto p = crush_location.find(o.mask.location_type);
if (p == crush_location.end() ||
- p->second != o.location_value) {
+ p->second != o.mask.location_value) {
continue;
}
}
}
}
}
+
+bool ConfigMap::parse_mask(
+ const std::string& who,
+ std::string *section,
+ OptionMask *mask)
+{
+ vector<std::string> split;
+ boost::split(split, who, [](char c){ return c == '/'; });
+ for (unsigned j = 0; j < split.size(); ++j) {
+ auto& i = split[j];
+ if (i == "global") {
+ continue;
+ }
+ size_t delim = i.find(':');
+ if (delim != std::string::npos) {
+ string k = i.substr(0, delim);
+ if (k == "class") {
+ mask->device_class = i.substr(delim + 1);
+ } else {
+ mask->location_type = k;
+ mask->location_value = i.substr(delim + 1);
+ }
+ continue;
+ }
+ string type, id;
+ auto dotpos = i.find('.');
+ if (dotpos != std::string::npos) {
+ type = i.substr(0, dotpos);
+ id = i.substr(dotpos + 1);
+ } else {
+ type = i;
+ }
+ if (str_to_ceph_entity_type(type.c_str()) == CEPH_ENTITY_TYPE_ANY) {
+ return false;
+ }
+ *section = i;
+ }
+ return true;
+}
// is less precise than host, because the crush limiters are only
// resolved within a section (global, per-daemon, per-instance).
+struct OptionMask {
+ std::string location_type, location_value; ///< matches crush_location
+ std::string device_class; ///< matches device class
+
+ std::string to_str() const {
+ std::string r;
+ if (location_type.size()) {
+ r += location_type + ":" + location_value;
+ }
+ if (device_class.size()) {
+ if (r.size()) {
+ r += "/";
+ }
+ r += "class:" + device_class;
+ }
+ return r;
+ }
+};
+
struct MaskedOption {
string raw_value; ///< raw, unparsed, unvalidated value
Option opt; ///< the option
- std::string location_type, location_value; ///< matches crush_location
- std::string device_class; ///< matches device class
+ OptionMask mask;
MaskedOption(const Option& o) : opt(o) {}
const CrushWrapper *crush,
const std::string& device_class,
std::map<std::string,std::string> *out);
+
+ static bool parse_mask(
+ const std::string& in,
+ std::string *section,
+ OptionMask *mask);
};
it->key().compare(0, KEY_PREFIX.size(), KEY_PREFIX) == 0) {
string key = it->key().substr(KEY_PREFIX.size());
string value = it->value().to_str();
- vector<string> split;
- boost::split(split, key, [](char c){return c == '/';});
- string name = split.back();
- split.pop_back();
- Section *section = &config_map.global;
+
+ auto last_slash = key.rfind('/');
+ string name;
+ string who;
+ if (last_slash == std::string::npos) {
+ name = key;
+ } else {
+ name = key.substr(last_slash + 1);
+ who = key.substr(0, last_slash);
+ }
+ string section_name;
Option fake_opt(name, Option::TYPE_STR, Option::LEVEL_DEV);
const Option *opt = g_conf->find_option(name);
int r = opt->pre_validate(&value, &err);
if (r < 0) {
dout(10) << __func__ << " pre-validate failed on '" << name << "' = '"
- << value << "' for " << split << dendl;
+ << value << "' for " << name << dendl;
}
MaskedOption mopt(*opt);
mopt.raw_value = value;
- string device_class;
- string loc_type, loc_value;
- for (unsigned j = 0; j < split.size(); ++j) {
- auto& i = split[j];
- size_t delim = i.find(':');
- if (delim != std::string::npos) {
- string k = i.substr(0, delim);
- if (k == "class") {
- mopt.device_class = i.substr(delim + 1);
+
+ if (ConfigMap::parse_mask(who, §ion_name, &mopt.mask)) {
+ Section *section = &config_map.global;;
+ if (section_name.size()) {
+ if (section_name.find('.') != std::string::npos) {
+ section = &config_map.by_id[section_name];
} else {
- mopt.location_type = k;
- mopt.location_value = i.substr(delim + 1);
+ section = &config_map.by_type[section_name];
}
- continue;
- }
- if (split.front().find('.') != std::string::npos) {
- section = &config_map.by_id[i];
- } else {
- section = &config_map.by_type[i];
}
+ section->options.insert(make_pair(name, mopt));
+ ++num;
+ } else {
+ derr << __func__ << " ignoring key " << key << dendl;
}
- section->options.insert(make_pair(name, mopt));
- ++num;
it->next();
}
dout(10) << __func__ << " got " << num << " keys" << dendl;