From 960ea49699f421ceb89c9e0c9430378a35f09a9a Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Tue, 26 May 2015 12:08:09 +0800 Subject: [PATCH] crush/CrushTester: add check_name_maps() method * check for dangling bucket name or type names referenced by the buckets/items in the crush map. * also check for the references from Item(0, 0, 0) which does not necessarily exist in the crush map under testing. the rationale behind this is: the "ceph osd tree" will also print stray OSDs whose id is greater or equal to 0. so it would be useful to check if the crush map offers the type name indexed by "0" (the name of OSDs is always "OSD.{id}", so we don't need to look up the name of an OSD item in the crushmap). Signed-off-by: Kefu Chai (cherry picked from commit b75384d73958faf81d45847a7dfa56f4fa347e6f) --- src/crush/CrushTester.cc | 49 ++++++++++++++++++++++++++++++++++++++++ src/crush/CrushTester.h | 5 ++++ 2 files changed, 54 insertions(+) diff --git a/src/crush/CrushTester.cc b/src/crush/CrushTester.cc index 5ca4978c4c5c5..85ba693aa4bf4 100644 --- a/src/crush/CrushTester.cc +++ b/src/crush/CrushTester.cc @@ -1,6 +1,7 @@ #include "include/stringify.h" #include "CrushTester.h" +#include "CrushTreeDumper.h" #include #include @@ -433,6 +434,54 @@ int CrushTester::test_with_crushtool(const string& crushtool, return -r; } +namespace { + class BadCrushMap : public std::runtime_error { + public: + int item; + BadCrushMap(const char* msg, int id) + : std::runtime_error(msg), item(id) {} + }; + // throws if any node in the crush fail to print + class CrushWalker : public CrushTreeDumper::Dumper { + typedef void DumbFormatter; + typedef CrushTreeDumper::Dumper Parent; + public: + CrushWalker(const CrushWrapper *crush) + : Parent(crush) {} + void dump_item(const CrushTreeDumper::Item &qi, DumbFormatter *) { + int type = -1; + if (qi.is_bucket()) { + if (!crush->get_item_name(qi.id)) { + throw BadCrushMap("unknown item name", qi.id); + } + type = crush->get_bucket_type(qi.id); + } else { + type = 0; + } + if (!crush->get_type_name(type)) { + throw BadCrushMap("unknown type name", qi.id); + } + } + }; +} + +bool CrushTester::check_name_maps() const +{ + CrushWalker crush_walker(&crush); + try { + // walk through the crush, to see if its self-contained + crush_walker.dump(NULL); + // and see if the maps is also able to handle straying OSDs, whose id >= 0. + // "ceph osd tree" will try to print them, even they are not listed in the + // crush map. + crush_walker.dump_item(CrushTreeDumper::Item(0, 0, 0), NULL); + } catch (const BadCrushMap& e) { + err << e.what() << ": item#" << e.item << std::endl; + return false; + } + return true; +} + int CrushTester::test() { if (min_rule < 0 || max_rule < 0) { diff --git a/src/crush/CrushTester.h b/src/crush/CrushTester.h index 09936ce459e39..cc7c7825d1421 100644 --- a/src/crush/CrushTester.h +++ b/src/crush/CrushTester.h @@ -333,6 +333,11 @@ public: min_rule = max_rule = rule; } + /** + * check if any bucket/nodes is referencing an unknown name or type + * @return false if an dangling name/type is referenced, true otherwise + */ + bool check_name_maps() const; int test(); int test_with_crushtool(const string& crushtool, int timeout); -- 2.39.5