]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
crush: dump weight-set values with 'osd crush tree'
authorSage Weil <sage@redhat.com>
Thu, 13 Jul 2017 21:45:43 +0000 (17:45 -0400)
committerSage Weil <sage@redhat.com>
Fri, 21 Jul 2017 17:50:50 +0000 (13:50 -0400)
For plain, include a column for each pool.  Show only the first weight if
it is positional.

For formatted, include the full set of weights.

As far of this we switch 'ceph osd crush tree' to have a plaintext mode.

Signed-off-by: Sage Weil <sage@redhat.com>
doc/release-notes.rst
src/crush/CrushTester.cc
src/crush/CrushTreeDumper.h
src/crush/CrushWrapper.cc
src/crush/CrushWrapper.h
src/mon/OSDMonitor.cc
src/osd/OSDMap.cc
src/osd/OSDMap.h

index e92449ae176729882321ae279b4e9e0ea7ff0f5f..4f3f4ce9280c6a83ad69cbd6a81cb3b44ec81530 100644 (file)
@@ -426,6 +426,9 @@ Upgrade compatibility notes, Kraken to Luminous
   (when the ``ceph osd require-osd-release luminous`` command is run)
   but any provisioning tools that create erasure coded pools may need
   to be updated.
+* The structure of the XML output for ``osd crush tree`` has changed
+  slightly to better match the ``osd tree`` output.  The top level
+  structure is now ``nodes`` instead of ``crush_map_roots``.
 * When assigning a network to the public network and not to
   the cluster network the network specification of the public
   network will be used for the cluster network as well.
index da0d2a51c8961d72f2df0249b2ecd6e60dc886ab..b6b4b2f20c3b17d784c8dbf7204106d85ccde405 100644 (file)
@@ -386,7 +386,7 @@ namespace {
     int max_id;
   public:
     CrushWalker(const CrushWrapper *crush, unsigned max_id)
-      : Parent(crush), max_id(max_id) {}
+      : Parent(crush, CrushTreeDumper::name_map_t()), max_id(max_id) {}
     void dump_item(const CrushTreeDumper::Item &qi, DumbFormatter *) override {
       int type = -1;
       if (qi.is_bucket()) {
index 2c927998f527b17fda373825e12171a0913d10a1..199b3c39be3ec61f334b56efeb5c4a1ed6089e49 100644 (file)
@@ -18,6 +18,7 @@
 #define CRUSH_TREE_DUMPER_H
 
 #include "CrushWrapper.h"
+#include "include/stringify.h"
 
 /**
  * CrushTreeDumper:
@@ -64,7 +65,9 @@ namespace CrushTreeDumper {
   template <typename F>
   class Dumper : public list<Item> {
   public:
-    explicit Dumper(const CrushWrapper *crush_) : crush(crush_) {
+    explicit Dumper(const CrushWrapper *crush_,
+                   const name_map_t& weight_set_names_)
+      : crush(crush_), weight_set_names(weight_set_names_) {
       crush->find_nonshadow_roots(roots);
       root = roots.begin();
     }
@@ -141,6 +144,7 @@ namespace CrushTreeDumper {
 
   protected:
     const CrushWrapper *crush;
+    const name_map_t &weight_set_names;
 
   private:
     set<int> touched;
@@ -149,12 +153,12 @@ namespace CrushTreeDumper {
   };
 
   inline void dump_item_fields(const CrushWrapper *crush,
+                              const name_map_t& weight_set_names,
                               const Item &qi, Formatter *f) {
     f->dump_int("id", qi.id);
     const char *c = crush->get_item_class(qi.id);
-    if (!c)
-      c = "";
-    f->dump_string("device_class", c);
+    if (c)
+      f->dump_string("device_class", c);
     if (qi.is_bucket()) {
       int type = crush->get_bucket_type(qi.id);
       f->dump_string("name", crush->get_item_name(qi.id));
@@ -167,6 +171,42 @@ namespace CrushTreeDumper {
       f->dump_float("crush_weight", qi.weight);
       f->dump_unsigned("depth", qi.depth);
     }
+    if (qi.parent < 0) {
+      f->open_object_section("pool_weights");
+      for (auto& p : crush->choose_args) {
+       const crush_choose_arg_map& cmap = p.second;
+       int bidx = -1 - qi.parent;
+       const crush_bucket *b = crush->get_bucket(qi.parent);
+       if (b &&
+           bidx < (int)cmap.size &&
+           cmap.args[bidx].weight_set &&
+           cmap.args[bidx].weight_set_size >= 1) {
+         int bpos;
+         for (bpos = 0;
+              bpos < (int)cmap.args[bidx].weight_set[0].size &&
+                b->items[bpos] != qi.id;
+              ++bpos) ;
+         string name;
+         if (p.first == CrushWrapper::DEFAULT_CHOOSE_ARGS) {
+           name = "(compat)";
+         } else {
+           auto q = weight_set_names.find(p.first);
+           name = q != weight_set_names.end() ? q->second :
+             stringify(p.first);
+         }
+         f->open_array_section(name.c_str());
+         for (unsigned opos = 0;
+              opos < cmap.args[bidx].weight_set_size;
+              ++opos) {
+           float w = (float)cmap.args[bidx].weight_set[opos].weights[bpos] /
+             (float)0x10000;
+           f->dump_float("weight", w);
+         }
+         f->close_section();
+       }
+      }
+      f->close_section();
+    }
   }
 
   inline void dump_bucket_children(const CrushWrapper *crush,
@@ -185,7 +225,9 @@ namespace CrushTreeDumper {
 
   class FormattingDumper : public Dumper<Formatter> {
   public:
-    explicit FormattingDumper(const CrushWrapper *crush) : Dumper<Formatter>(crush) {}
+    explicit FormattingDumper(const CrushWrapper *crush,
+                             const name_map_t& weight_set_names)
+      : Dumper<Formatter>(crush, weight_set_names) {}
 
   protected:
     void dump_item(const Item &qi, Formatter *f) override {
@@ -196,7 +238,7 @@ namespace CrushTreeDumper {
     }
 
     virtual void dump_item_fields(const Item &qi, Formatter *f) {
-      CrushTreeDumper::dump_item_fields(crush, qi, f);
+      CrushTreeDumper::dump_item_fields(crush, weight_set_names, qi, f);
     }
 
     virtual void dump_bucket_children(const Item &qi, Formatter *f) {
index 79afc4299db635647f8843c4e11f9b14561f7535..be533172c91707778c851e77d85cf410c3afbe78 100644 (file)
@@ -5,6 +5,7 @@
 #include "common/debug.h"
 #include "common/Formatter.h"
 #include "common/errno.h"
+#include "common/TextTable.h"
 #include "include/stringify.h"
 
 #include "CrushWrapper.h"
@@ -2214,9 +2215,11 @@ namespace {
   class TreeDumper {
     typedef CrushTreeDumper::Item Item;
     const CrushWrapper *crush;
+    const CrushTreeDumper::name_map_t& weight_set_names;
   public:
-    explicit TreeDumper(const CrushWrapper *crush)
-      : crush(crush) {}
+    explicit TreeDumper(const CrushWrapper *crush,
+                       const CrushTreeDumper::name_map_t& wsnames)
+      : crush(crush), weight_set_names(wsnames) {}
 
     void dump(Formatter *f) {
       set<int> roots;
@@ -2230,12 +2233,12 @@ namespace {
     void dump_item(const Item& qi, Formatter* f) {
       if (qi.is_bucket()) {
        f->open_object_section("bucket");
-       CrushTreeDumper::dump_item_fields(crush, qi, f);
+       CrushTreeDumper::dump_item_fields(crush, weight_set_names, qi, f);
        dump_bucket_children(qi, f);
        f->close_section();
       } else {
        f->open_object_section("device");
-       CrushTreeDumper::dump_item_fields(crush, qi, f);
+       CrushTreeDumper::dump_item_fields(crush, weight_set_names, qi, f);
        f->close_section();
       }
     }
@@ -2253,10 +2256,12 @@ namespace {
   };
 }
 
-void CrushWrapper::dump_tree(Formatter *f) const
+void CrushWrapper::dump_tree(
+  Formatter *f,
+  const CrushTreeDumper::name_map_t& weight_set_names) const
 {
   assert(f);
-  TreeDumper(this).dump(f);
+  TreeDumper(this, weight_set_names).dump(f);
 }
 
 void CrushWrapper::dump_tunables(Formatter *f) const
@@ -2426,36 +2431,69 @@ void CrushWrapper::list_rules(Formatter *f) const
   }
 }
 
-class CrushTreePlainDumper : public CrushTreeDumper::Dumper<ostream> {
+class CrushTreePlainDumper : public CrushTreeDumper::Dumper<TextTable> {
 public:
-  typedef CrushTreeDumper::Dumper<ostream> Parent;
-
-  explicit CrushTreePlainDumper(const CrushWrapper *crush)
-    : Parent(crush) {}
-
-  void dump(ostream *out) {
-    *out << "ID\tWEIGHT\tTYPE NAME\n";
-    Parent::dump(out);
+  typedef CrushTreeDumper::Dumper<TextTable> Parent;
+
+  explicit CrushTreePlainDumper(const CrushWrapper *crush,
+                               const CrushTreeDumper::name_map_t& wsnames)
+    : Parent(crush, wsnames) {}
+
+  void dump(TextTable *tbl) {
+    tbl->define_column("ID", TextTable::LEFT, TextTable::RIGHT);
+    tbl->define_column("WEIGHT", TextTable::LEFT, TextTable::RIGHT);
+    for (auto& p : crush->choose_args) {
+      if (p.first == CrushWrapper::DEFAULT_CHOOSE_ARGS) {
+       tbl->define_column("(compat)", TextTable::LEFT, TextTable::RIGHT);
+      } else {
+       string name;
+       auto q = weight_set_names.find(p.first);
+       name = q != weight_set_names.end() ? q->second :
+         stringify(p.first);
+       tbl->define_column(name.c_str(), TextTable::LEFT, TextTable::RIGHT);
+      }
+    }
+    tbl->define_column("TYPE NAME", TextTable::LEFT, TextTable::LEFT);
+    Parent::dump(tbl);
   }
 
 protected:
-  void dump_item(const CrushTreeDumper::Item &qi, ostream *out) override {
-    *out << qi.id << "\t"
-        << weightf_t(qi.weight) << "\t";
-
-    for (int k=0; k < qi.depth; k++)
-      *out << "\t";
-
-    if (qi.is_bucket())
-    {
-      *out << crush->get_type_name(crush->get_bucket_type(qi.id)) << " "
-          << crush->get_item_name(qi.id);
+  void dump_item(const CrushTreeDumper::Item &qi, TextTable *tbl) override {
+    *tbl << qi.id
+        << weightf_t(qi.weight);
+    for (auto& p : crush->choose_args) {
+      if (qi.parent < 0) {
+       const crush_choose_arg_map cmap = crush->choose_args_get(p.first);
+       int bidx = -1 - qi.parent;
+       const crush_bucket *b = crush->get_bucket(qi.parent);
+       if (b &&
+           bidx < (int)cmap.size &&
+           cmap.args[bidx].weight_set &&
+           cmap.args[bidx].weight_set_size >= 1) {
+         int pos;
+         for (pos = 0;
+              pos < (int)cmap.args[bidx].weight_set[0].size &&
+                b->items[pos] != qi.id;
+              ++pos) ;
+         *tbl << weightf_t((float)cmap.args[bidx].weight_set[0].weights[pos] /
+                           (float)0x10000);
+         continue;
+       }
+      }
+      *tbl << "";
     }
-    else
-    {
-      *out << "osd." << qi.id;
+    ostringstream ss;
+    for (int k=0; k < qi.depth; k++) {
+      ss << "    ";
     }
-    *out << "\n";
+    if (qi.is_bucket()) {
+      ss << crush->get_type_name(crush->get_bucket_type(qi.id)) << " "
+        << crush->get_item_name(qi.id);
+    } else {
+      ss << "osd." << qi.id;
+    }
+    *tbl << ss.str();
+    *tbl << TextTable::endrow;
   }
 };
 
@@ -2464,8 +2502,10 @@ class CrushTreeFormattingDumper : public CrushTreeDumper::FormattingDumper {
 public:
   typedef CrushTreeDumper::FormattingDumper Parent;
 
-  explicit CrushTreeFormattingDumper(const CrushWrapper *crush)
-    : Parent(crush) {}
+  explicit CrushTreeFormattingDumper(
+    const CrushWrapper *crush,
+    const CrushTreeDumper::name_map_t& wsnames)
+    : Parent(crush, wsnames) {}
 
   void dump(Formatter *f) {
     f->open_array_section("nodes");
@@ -2477,12 +2517,18 @@ public:
 };
 
 
-void CrushWrapper::dump_tree(ostream *out, Formatter *f) const
+void CrushWrapper::dump_tree(
+  ostream *out, Formatter *f,
+  const CrushTreeDumper::name_map_t& weight_set_names) const
 {
-  if (out)
-    CrushTreePlainDumper(this).dump(out);
-  if (f)
-    CrushTreeFormattingDumper(this).dump(f);
+  if (out) {
+    TextTable tbl;
+    CrushTreePlainDumper(this, weight_set_names).dump(&tbl);
+    *out << tbl;
+  }
+  if (f) {
+    CrushTreeFormattingDumper(this, weight_set_names).dump(f);
+  }
 }
 
 void CrushWrapper::generate_test_instances(list<CrushWrapper*>& o)
index 1bcbb474d48f95b23fdc2a2382cc50fb3a081fcf..eb3b0e2fb856b156994ae7f47735a23a306d9bf6 100644 (file)
@@ -23,7 +23,7 @@ extern "C" {
 #include "include/assert.h"
 #include "include/err.h"
 #include "include/encoding.h"
-
+#include "include/mempool.h"
 
 #include "common/Mutex.h"
 
@@ -33,6 +33,10 @@ namespace ceph {
   class Formatter;
 }
 
+namespace CrushTreeDumper {
+  typedef mempool::osdmap::map<int64_t,string> name_map_t;
+}
+
 WRITE_RAW_ENCODER(crush_rule_mask)   // it's all u8's
 
 inline static void encode(const crush_rule_step &s, bufferlist &bl)
@@ -1089,7 +1093,6 @@ public:
 
 
   /** buckets **/
-private:
   const crush_bucket *get_bucket(int id) const {
     if (!crush)
       return (crush_bucket *)(-EINVAL);
@@ -1102,6 +1105,7 @@ private:
       return (crush_bucket *)(-ENOENT);
     return ret;
   }
+private:
   crush_bucket *get_bucket(int id) {
     if (!crush)
       return (crush_bucket *)(-EINVAL);
@@ -1452,8 +1456,13 @@ public:
   void dump_tunables(Formatter *f) const;
   void dump_choose_args(Formatter *f) const;
   void list_rules(Formatter *f) const;
-  void dump_tree(ostream *out, Formatter *f) const;
-  void dump_tree(Formatter *f) const;
+  void dump_tree(ostream *out, Formatter *f,
+                const CrushTreeDumper::name_map_t& ws) const;
+  void dump_tree(ostream *out, Formatter *f) {
+    dump_tree(out, f, CrushTreeDumper::name_map_t());
+  }
+  void dump_tree(Formatter *f,
+                const CrushTreeDumper::name_map_t& ws) const;
   static void generate_test_instances(list<CrushWrapper*>& o);
 
   int get_osd_pool_default_crush_replicated_ruleset(CephContext *cct);
index 96eabc5794233a17125836a524422167ba9e4d3c..0fdfaa823b741360a03afd5ae7f3ac087c36a398 100644 (file)
@@ -5079,11 +5079,15 @@ bool OSDMonitor::preprocess_command(MonOpRequestRef op)
     rs << "\n";
     rdata.append(rs.str());
   } else if (prefix == "osd crush tree") {
-    boost::scoped_ptr<Formatter> f(Formatter::create(format, "json-pretty", "json-pretty"));
-    f->open_array_section("crush_map_roots");
-    osdmap.crush->dump_tree(f.get());
-    f->close_section();
-    f->flush(rdata);
+    boost::scoped_ptr<Formatter> f(Formatter::create(format));
+    if (f) {
+      osdmap.crush->dump_tree(nullptr, f.get(), osdmap.get_pool_names());
+      f->flush(rdata);
+    } else {
+      ostringstream ss;
+      osdmap.crush->dump_tree(&ss, nullptr, osdmap.get_pool_names());
+      rdata.append(ss.str());
+    }
   } else if (prefix == "osd crush class ls") {
     boost::scoped_ptr<Formatter> f(Formatter::create(format, "json-pretty", "json-pretty"));
     f->open_array_section("crush_classes");
index d404253ca706c0c5b97e9cdbc32635a26e08762e..ad5f6ee81c517bdee09547f226d4b45c152f4562 100644 (file)
@@ -3052,7 +3052,7 @@ public:
 
   OSDTreePlainDumper(const CrushWrapper *crush, const OSDMap *osdmap_,
                     unsigned f)
-    : Parent(crush), osdmap(osdmap_), filter(f) { }
+    : Parent(crush, osdmap_->get_pool_names()), osdmap(osdmap_), filter(f) { }
 
   bool should_dump_leaf(int i) const override {
     if (((filter & OSDMap::DUMP_UP) && !osdmap->is_up(i)) ||
@@ -3130,7 +3130,7 @@ public:
 
   OSDTreeFormattingDumper(const CrushWrapper *crush, const OSDMap *osdmap_,
                          unsigned f)
-    : Parent(crush), osdmap(osdmap_), filter(f) { }
+    : Parent(crush, osdmap_->get_pool_names()), osdmap(osdmap_), filter(f) { }
 
   bool should_dump_leaf(int i) const override {
     if (((filter & OSDMap::DUMP_UP) && !osdmap->is_up(i)) ||
@@ -3942,7 +3942,7 @@ public:
 
   OSDUtilizationDumper(const CrushWrapper *crush, const OSDMap *osdmap_,
                       const PGStatService *pgs_, bool tree_) :
-    Parent(crush),
+    Parent(crush, osdmap_->get_pool_names()),
     osdmap(osdmap_),
     pgs(pgs_),
     tree(tree_),
@@ -4214,7 +4214,7 @@ protected:
                         const size_t num_pgs,
                         Formatter *f) override {
     f->open_object_section("item");
-    CrushTreeDumper::dump_item_fields(crush, qi, f);
+    CrushTreeDumper::dump_item_fields(crush, weight_set_names, qi, f);
     f->dump_float("reweight", reweight);
     f->dump_int("kb", kb);
     f->dump_int("kb_used", kb_used);
index 6538c9e62964ddc8d6b64c2d13b0f6989c7c04fb..aeda1813fc8b5d4dc752511faf927be8d35209fd 100644 (file)
@@ -1176,6 +1176,9 @@ public:
     assert(i != pool_name.end());
     return i->second;
   }
+  const mempool::osdmap::map<int64_t,string>& get_pool_names() const {
+    return pool_name;
+  }
   bool have_pg_pool(int64_t p) const {
     return pools.count(p);
   }