]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crush/CrushTester: add check_name_maps() method
authorKefu Chai <kchai@redhat.com>
Tue, 26 May 2015 04:08:09 +0000 (12:08 +0800)
committerKefu Chai <kchai@redhat.com>
Fri, 10 Jul 2015 07:40:00 +0000 (15:40 +0800)
* 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 <kchai@redhat.com>
(cherry picked from commit b75384d73958faf81d45847a7dfa56f4fa347e6f)

src/crush/CrushTester.cc
src/crush/CrushTester.h

index 5ca4978c4c5c5a29026f6247450ba877a912a10d..85ba693aa4bf4249dd72af42d78bc1166230bcc0 100644 (file)
@@ -1,6 +1,7 @@
 
 #include "include/stringify.h"
 #include "CrushTester.h"
+#include "CrushTreeDumper.h"
 
 #include <algorithm>
 #include <stdlib.h>
@@ -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<void> {
+    typedef void DumbFormatter;
+    typedef CrushTreeDumper::Dumper<DumbFormatter> 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) {
index 09936ce459e397417515c683556cc40c9556126a..cc7c7825d14211b77b5bc578ebd7f4f32d4c97f3 100644 (file)
@@ -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);