crush: parse "class XXX" after device

Refs: http://tracker.ceph.com/issues/18943

Signed-off-by: Loic Dachary <ldachary@redhat.com>
This commit is contained in:
Loic Dachary 2017-02-15 15:21:15 +01:00
parent 3955caca28
commit eb5a7c3805
6 changed files with 142 additions and 2 deletions

View File

@ -45,6 +45,13 @@ static void print_item_name(ostream& out, int t, CrushWrapper &crush)
out << "bucket" << (-1-t);
}
static void print_item_class(ostream& out, int t, CrushWrapper &crush)
{
const char *c = crush.get_item_class(t);
if (c)
out << " class " << c;
}
static void print_rule_name(ostream& out, int t, CrushWrapper &crush)
{
const char *name = crush.get_rule_name(t);
@ -208,6 +215,7 @@ int CrushCompiler::decompile(ostream &out)
for (int i=0; i<crush.get_max_devices(); i++) {
out << "device " << i << " ";
print_item_name(out, i, crush);
print_item_class(out, i, crush);
out << "\n";
}
@ -361,7 +369,15 @@ int CrushCompiler::parse_device(iter_t const& i)
item_id[name] = id;
id_item[id] = name;
if (verbose) err << "device " << id << " '" << name << "'" << std::endl;
if (verbose) err << "device " << id << " '" << name << "'";
if (i->children.size() > 3) {
string c = string_node(i->children[4]);
crush.set_item_class(id, c);
if (verbose) err << " class" << " '" << c << "'" << std::endl;
} else {
if (verbose) err << std::endl;
}
return 0;
}

View File

@ -1219,6 +1219,10 @@ void CrushWrapper::encode(bufferlist& bl, uint64_t features) const
if (features & CEPH_FEATURE_CRUSH_TUNABLES5) {
::encode(crush->chooseleaf_stable, bl);
}
// device classes
::encode(class_map, bl);
::encode(class_name, bl);
}
static void decode_32_or_64_string_map(map<int32_t,string>& m, bufferlist::iterator& blp)
@ -1311,6 +1315,12 @@ void CrushWrapper::decode(bufferlist::iterator& blp)
if (!blp.end()) {
::decode(crush->chooseleaf_stable, blp);
}
if (!blp.end()) {
::decode(class_map, blp);
::decode(class_name, blp);
for (auto &c : class_name)
class_rname[c.second] = c.first;
}
finalize();
}
catch (...) {
@ -1436,6 +1446,9 @@ void CrushWrapper::dump(Formatter *f) const
sprintf(name, "device%d", i);
f->dump_string("name", name);
}
const char *device_class = get_item_class(i);
if (device_class != NULL)
f->dump_string("class", device_class);
f->close_section();
}
f->close_section();

View File

@ -54,6 +54,9 @@ public:
std::map<int32_t, string> type_map; /* bucket/device type names */
std::map<int32_t, string> name_map; /* bucket/device names */
std::map<int32_t, string> rule_name_map;
std::map<int32_t, int32_t> class_map; /* item id -> class id */
std::map<int32_t, string> class_name; /* class id -> class name */
std::map<string, int32_t> class_rname; /* class name -> class id */
private:
struct crush_map *crush;
@ -394,6 +397,44 @@ public:
return 0;
}
const char *get_class_name(int i) const {
std::map<int,string>::const_iterator p = class_name.find(i);
if (p != class_name.end())
return p->second.c_str();
return 0;
}
int get_class_id(const string& name) const {
std::map<string,int>::const_iterator p = class_rname.find(name);
if (p != class_rname.end())
return p->second;
else
return -EINVAL;
}
int get_or_create_class_id(const string& name) {
int c = get_class_id(name);
if (c < 0) {
int i = class_name.size();
class_name[i] = name;
class_rname[name] = i;
return i;
} else {
return c;
}
}
const char *get_item_class(int t) const {
std::map<int,int>::const_iterator p = class_map.find(t);
if (p == class_map.end())
return 0;
return get_class_name(p->second);
}
int set_item_class(int i, const string& name) {
if (!is_valid_crush_name(name))
return -EINVAL;
class_map[i] = get_or_create_class_id(name);
return 0;
}
int can_rename_item(const string& srcname,
const string& dstname,
ostream *ss) const;

View File

@ -108,7 +108,7 @@ struct crush_grammar : public grammar<crush_grammar>
tunable = str_p("tunable") >> name >> posint;
// devices
device = str_p("device") >> posint >> name;
device = str_p("device") >> posint >> name >> !( str_p("class") >> name );
// bucket types
bucket_type = str_p("type") >> posint >> name;

View File

@ -0,0 +1,64 @@
# begin crush map
# devices
device 0 device0 class ssd
device 1 device1 class ssd
device 2 device2 class hdd
# types
type 0 device
type 1 host
type 2 rack
type 3 root
# buckets
host host0 {
id -1 # do not change unnecessarily
# weight 1.000
alg straw
hash 0 # rjenkins1
item device0 weight 1.000
}
host host1 {
id -2 # do not change unnecessarily
# weight 1.000
alg straw
hash 0 # rjenkins1
item device1 weight 1.000
}
host host2 {
id -5 # do not change unnecessarily
# weight 1.000
alg straw
hash 0 # rjenkins1
item device2 weight 1.000
}
rack rack0 {
id -3 # do not change unnecessarily
# weight 3.000
alg straw
hash 0 # rjenkins1
item host0 weight 1.000
item host1 weight 1.000
item host2 weight 1.000
}
root root {
id -4 # do not change unnecessarily
# weight 4.000
alg straw
hash 0 # rjenkins1
item rack0 weight 4.000
}
# rules
rule data {
ruleset 1
type replicated
min_size 2
max_size 2
step take root
step chooseleaf firstn 0 type rack
step emit
}
# end crush map

View File

@ -0,0 +1,6 @@
$ cp "$TESTDIR/device-class.crush" .
$ crushtool -c device-class.crush -o device-class.compiled
$ crushtool -d device-class.compiled -o device-class.conf
$ crushtool -c device-class.conf -o device-class.recompiled
$ cmp device-class.crush device-class.conf
$ cmp device-class.compiled device-class.recompiled