From: Kefu Chai Date: Tue, 26 May 2015 04:08:09 +0000 (+0800) Subject: crush/CrushTester: add check_name_maps() method X-Git-Tag: v9.0.3~196^2~7 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=b75384d73958faf81d45847a7dfa56f4fa347e6f;p=ceph.git 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 --- diff --git a/src/crush/CrushTester.cc b/src/crush/CrushTester.cc index 036c07b3f6c9..9a37ca51c1e7 100644 --- a/src/crush/CrushTester.cc +++ b/src/crush/CrushTester.cc @@ -3,6 +3,7 @@ #include "include/stringify.h" #include "CrushTester.h" +#include "CrushTreeDumper.h" #include #include @@ -383,6 +384,54 @@ int CrushTester::test_with_crushtool(const char *crushtool_cmd, int timeout) return 0; } +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 2cca2ad956e3..271ff2a2f329 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 char *crushtool_cmd = "crushtool", int timeout = 0);