From f5b3ec97032e67d3aa04d7bcfa4d632ce4aa6a60 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 13 Jul 2017 17:45:43 -0400 Subject: [PATCH] crush: dump weight-set values with 'osd crush tree' 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 --- doc/release-notes.rst | 3 + src/crush/CrushTester.cc | 2 +- src/crush/CrushTreeDumper.h | 54 ++++++++++++++-- src/crush/CrushWrapper.cc | 120 +++++++++++++++++++++++++----------- src/crush/CrushWrapper.h | 17 +++-- src/mon/OSDMonitor.cc | 14 +++-- src/osd/OSDMap.cc | 8 +-- src/osd/OSDMap.h | 3 + 8 files changed, 164 insertions(+), 57 deletions(-) diff --git a/doc/release-notes.rst b/doc/release-notes.rst index e92449ae176..4f3f4ce9280 100644 --- a/doc/release-notes.rst +++ b/doc/release-notes.rst @@ -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. diff --git a/src/crush/CrushTester.cc b/src/crush/CrushTester.cc index da0d2a51c89..b6b4b2f20c3 100644 --- a/src/crush/CrushTester.cc +++ b/src/crush/CrushTester.cc @@ -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()) { diff --git a/src/crush/CrushTreeDumper.h b/src/crush/CrushTreeDumper.h index 2c927998f52..199b3c39be3 100644 --- a/src/crush/CrushTreeDumper.h +++ b/src/crush/CrushTreeDumper.h @@ -18,6 +18,7 @@ #define CRUSH_TREE_DUMPER_H #include "CrushWrapper.h" +#include "include/stringify.h" /** * CrushTreeDumper: @@ -64,7 +65,9 @@ namespace CrushTreeDumper { template class Dumper : public list { 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 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 { public: - explicit FormattingDumper(const CrushWrapper *crush) : Dumper(crush) {} + explicit FormattingDumper(const CrushWrapper *crush, + const name_map_t& weight_set_names) + : Dumper(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) { diff --git a/src/crush/CrushWrapper.cc b/src/crush/CrushWrapper.cc index 79afc4299db..be533172c91 100644 --- a/src/crush/CrushWrapper.cc +++ b/src/crush/CrushWrapper.cc @@ -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 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 { +class CrushTreePlainDumper : public CrushTreeDumper::Dumper { public: - typedef CrushTreeDumper::Dumper Parent; - - explicit CrushTreePlainDumper(const CrushWrapper *crush) - : Parent(crush) {} - - void dump(ostream *out) { - *out << "ID\tWEIGHT\tTYPE NAME\n"; - Parent::dump(out); + typedef CrushTreeDumper::Dumper 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& o) diff --git a/src/crush/CrushWrapper.h b/src/crush/CrushWrapper.h index 1bcbb474d48..eb3b0e2fb85 100644 --- a/src/crush/CrushWrapper.h +++ b/src/crush/CrushWrapper.h @@ -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 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& o); int get_osd_pool_default_crush_replicated_ruleset(CephContext *cct); diff --git a/src/mon/OSDMonitor.cc b/src/mon/OSDMonitor.cc index 96eabc57942..0fdfaa823b7 100644 --- a/src/mon/OSDMonitor.cc +++ b/src/mon/OSDMonitor.cc @@ -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 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 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 f(Formatter::create(format, "json-pretty", "json-pretty")); f->open_array_section("crush_classes"); diff --git a/src/osd/OSDMap.cc b/src/osd/OSDMap.cc index d404253ca70..ad5f6ee81c5 100644 --- a/src/osd/OSDMap.cc +++ b/src/osd/OSDMap.cc @@ -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); diff --git a/src/osd/OSDMap.h b/src/osd/OSDMap.h index 6538c9e6296..aeda1813fc8 100644 --- a/src/osd/OSDMap.h +++ b/src/osd/OSDMap.h @@ -1176,6 +1176,9 @@ public: assert(i != pool_name.end()); return i->second; } + const mempool::osdmap::map& get_pool_names() const { + return pool_name; + } bool have_pg_pool(int64_t p) const { return pools.count(p); } -- 2.39.5