From 89aa8ff9855ae868d59bd10fe3a3aab8517e90fc Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Tue, 2 Jun 2015 23:52:22 +0800 Subject: [PATCH] mon: add an "osd crush tree" command * to print crush buckets/items in a tree Fixes: #11833 Signed-off-by: Kefu Chai (cherry picked from commit 5436c290f3622feb8d4b279ed6552b2510e0cee9) Conflicts: src/test/mon/osd-crush.sh: do not start mon as run() takes care of it already --- doc/man/8/ceph.rst | 6 ++++ src/crush/CrushWrapper.cc | 50 ++++++++++++++++++++++++++ src/crush/CrushWrapper.h | 1 + src/mon/MonCommands.h | 3 ++ src/mon/OSDMonitor.cc | 6 ++++ src/test/mon/osd-crush-tree.rng | 62 +++++++++++++++++++++++++++++++++ src/test/mon/osd-crush.sh | 7 +++- 7 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 src/test/mon/osd-crush-tree.rng diff --git a/doc/man/8/ceph.rst b/doc/man/8/ceph.rst index 08d06bae38782..97c98ada8214f 100644 --- a/doc/man/8/ceph.rst +++ b/doc/man/8/ceph.rst @@ -669,6 +669,12 @@ Usage:: ceph osd crush show-tunables +Subcommand ``tree`` shows the crush buckets and items in a tree view. + +Usage:: + + ceph osd crush tree + Subcommand ``tunables`` sets crush tunables values to . Usage:: diff --git a/src/crush/CrushWrapper.cc b/src/crush/CrushWrapper.cc index 497c2196958a2..48945b95fdd9b 100644 --- a/src/crush/CrushWrapper.cc +++ b/src/crush/CrushWrapper.cc @@ -1409,6 +1409,56 @@ void CrushWrapper::dump(Formatter *f) const f->close_section(); } +namespace { + // depth first walker + class TreeDumper { + typedef CrushTreeDumper::Item Item; + const CrushWrapper *crush; + public: + TreeDumper(const CrushWrapper *crush) + : crush(crush) {} + + void dump(Formatter *f) { + set roots; + crush->find_roots(roots); + for (set::iterator root = roots.begin(); root != roots.end(); ++root) { + dump_item(Item(*root, 0, crush->get_bucket_weightf(*root)), f); + } + } + + private: + void dump_item(const Item& qi, Formatter* f) { + if (qi.is_bucket()) { + f->open_object_section("bucket"); + CrushTreeDumper::dump_item_fields(crush, qi, f); + dump_bucket_children(qi, f); + f->close_section(); + } else { + f->open_object_section("device"); + CrushTreeDumper::dump_item_fields(crush, qi, f); + f->close_section(); + } + } + + void dump_bucket_children(const Item& parent, Formatter* f) { + f->open_array_section("items"); + const int max_pos = crush->get_bucket_size(parent.id); + for (int pos = 0; pos < max_pos; pos++) { + int id = crush->get_bucket_item(parent.id, pos); + float weight = crush->get_bucket_item_weightf(parent.id, pos); + dump_item(Item(id, parent.depth + 1, weight), f); + } + f->close_section(); + } + }; +} + +void CrushWrapper::dump_tree(Formatter *f) const +{ + assert(f); + TreeDumper(this).dump(f); +} + void CrushWrapper::dump_tunables(Formatter *f) const { f->dump_int("choose_local_tries", get_choose_local_tries()); diff --git a/src/crush/CrushWrapper.h b/src/crush/CrushWrapper.h index cfafab067dee2..ec4f57a7c9e35 100644 --- a/src/crush/CrushWrapper.h +++ b/src/crush/CrushWrapper.h @@ -1054,6 +1054,7 @@ public: void dump_tunables(Formatter *f) const; void list_rules(Formatter *f) const; void dump_tree(ostream *out, Formatter *f) const; + void dump_tree(Formatter *f) const; static void generate_test_instances(list& o); int get_osd_pool_default_crush_replicated_ruleset(CephContext *cct); diff --git a/src/mon/MonCommands.h b/src/mon/MonCommands.h index a72aa4b02d4a3..c6d0f85f4c24b 100644 --- a/src/mon/MonCommands.h +++ b/src/mon/MonCommands.h @@ -521,6 +521,9 @@ COMMAND("osd crush rule create-erasure " \ COMMAND("osd crush rule rm " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] ", \ "remove crush rule ", "osd", "rw", "cli,rest") +COMMAND("osd crush tree", + "dump crush buckets and items in a tree view", + "osd", "r", "cli,rest") COMMAND("osd setmaxosd " \ "name=newmax,type=CephInt,range=0", \ "set new maximum osd value", "osd", "rw", "cli,rest") diff --git a/src/mon/OSDMonitor.cc b/src/mon/OSDMonitor.cc index 2857e58599491..3fdcd17969cec 100644 --- a/src/mon/OSDMonitor.cc +++ b/src/mon/OSDMonitor.cc @@ -3367,6 +3367,12 @@ stats_out: f->flush(rs); 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); } else if (prefix == "osd erasure-code-profile ls") { const map > &profiles = osdmap.get_erasure_code_profiles(); diff --git a/src/test/mon/osd-crush-tree.rng b/src/test/mon/osd-crush-tree.rng new file mode 100644 index 0000000000000..d050ed20524fc --- /dev/null +++ b/src/test/mon/osd-crush-tree.rng @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/mon/osd-crush.sh b/src/test/mon/osd-crush.sh index 1c6347f48e4aa..2242e9c957ce3 100755 --- a/src/test/mon/osd-crush.sh +++ b/src/test/mon/osd-crush.sh @@ -200,7 +200,12 @@ function TEST_crush_reject_empty() { ./ceph osd setcrushmap -i $empty_map.map || return 1 } -main osd-crush +function TEST_crush_tree() { + ./ceph osd crush tree --format=xml | \ + $XMLSTARLET val -e -r test/mon/osd-crush-tree.rng - || return 1 +} + +main osd-crush # Local Variables: # compile-command: "cd ../.. ; make -j4 && test/mon/osd-crush.sh" -- 2.39.5