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);
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";
}
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;
}
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)
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 (...) {
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();
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;
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;
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;
--- /dev/null
+# 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
--- /dev/null
+ $ 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