From eb5a7c380553a6d6bac28a26728a9ea2c91cff19 Mon Sep 17 00:00:00 2001 From: Loic Dachary Date: Wed, 15 Feb 2017 15:21:15 +0100 Subject: [PATCH] crush: parse "class XXX" after device Refs: http://tracker.ceph.com/issues/18943 Signed-off-by: Loic Dachary --- src/crush/CrushCompiler.cc | 18 ++++++- src/crush/CrushWrapper.cc | 13 +++++ src/crush/CrushWrapper.h | 41 +++++++++++++++ src/crush/grammar.h | 2 +- src/test/cli/crushtool/device-class.crush | 64 +++++++++++++++++++++++ src/test/cli/crushtool/device-class.t | 6 +++ 6 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 src/test/cli/crushtool/device-class.crush create mode 100644 src/test/cli/crushtool/device-class.t diff --git a/src/crush/CrushCompiler.cc b/src/crush/CrushCompiler.cc index 13ffdc7be0b..43d862db9e8 100644 --- a/src/crush/CrushCompiler.cc +++ b/src/crush/CrushCompiler.cc @@ -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; ichildren.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; } diff --git a/src/crush/CrushWrapper.cc b/src/crush/CrushWrapper.cc index 932c2c91a9c..34b41269624 100644 --- a/src/crush/CrushWrapper.cc +++ b/src/crush/CrushWrapper.cc @@ -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& 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(); diff --git a/src/crush/CrushWrapper.h b/src/crush/CrushWrapper.h index fa3c008e553..6dd35bfd9b6 100644 --- a/src/crush/CrushWrapper.h +++ b/src/crush/CrushWrapper.h @@ -54,6 +54,9 @@ public: std::map type_map; /* bucket/device type names */ std::map name_map; /* bucket/device names */ std::map rule_name_map; + std::map class_map; /* item id -> class id */ + std::map class_name; /* class id -> class name */ + std::map 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::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::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::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; diff --git a/src/crush/grammar.h b/src/crush/grammar.h index 351cf0cfa79..66c010bb45f 100644 --- a/src/crush/grammar.h +++ b/src/crush/grammar.h @@ -108,7 +108,7 @@ struct crush_grammar : public 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; diff --git a/src/test/cli/crushtool/device-class.crush b/src/test/cli/crushtool/device-class.crush new file mode 100644 index 00000000000..2d4a69a9eca --- /dev/null +++ b/src/test/cli/crushtool/device-class.crush @@ -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 diff --git a/src/test/cli/crushtool/device-class.t b/src/test/cli/crushtool/device-class.t new file mode 100644 index 00000000000..9dcf95e1c05 --- /dev/null +++ b/src/test/cli/crushtool/device-class.t @@ -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 -- 2.47.3