]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
crush: parse "class XXX" after device
authorLoic Dachary <ldachary@redhat.com>
Wed, 15 Feb 2017 14:21:15 +0000 (15:21 +0100)
committerLoic Dachary <ldachary@redhat.com>
Wed, 1 Mar 2017 16:24:08 +0000 (17:24 +0100)
Refs: http://tracker.ceph.com/issues/18943

Signed-off-by: Loic Dachary <ldachary@redhat.com>
src/crush/CrushCompiler.cc
src/crush/CrushWrapper.cc
src/crush/CrushWrapper.h
src/crush/grammar.h
src/test/cli/crushtool/device-class.crush [new file with mode: 0644]
src/test/cli/crushtool/device-class.t [new file with mode: 0644]

index 13ffdc7be0b6628357bcc782c6c1fa2d036376f9..43d862db9e800a5beca9d822c39eb043fcbe8507 100644 (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;
 }
 
index 932c2c91a9c35593e7aed2cb2b0e3b0fa070cac7..34b41269624fc1cf064462ad80ab0caada2ba867 100644 (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();
index fa3c008e5536c71c5d3d39dcebc673e4bc3aa3bf..6dd35bfd9b6253b7b7cf677b62b573e37ada26d3 100644 (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;
index 351cf0cfa79ae96dc1000adcd9280f9e85b73dba..66c010bb45f48db02c82e6f2a6bd44a429051c0c 100644 (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;
diff --git a/src/test/cli/crushtool/device-class.crush b/src/test/cli/crushtool/device-class.crush
new file mode 100644 (file)
index 0000000..2d4a69a
--- /dev/null
@@ -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 (file)
index 0000000..9dcf95e
--- /dev/null
@@ -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