]> git-server-git.apps.pok.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>
Sun, 31 May 2015 17:24:54 +0000 (01:24 +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>
src/crush/CrushTester.cc
src/crush/CrushTester.h

index 036c07b3f6c9b7e7e58df30dd14667334addcd27..9a37ca51c1e725d5a07c6f68d53aa8ed8d559def 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "include/stringify.h"
 #include "CrushTester.h"
+#include "CrushTreeDumper.h"
 
 #include <algorithm>
 #include <stdlib.h>
@@ -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<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 2cca2ad956e302e94ebbd55ac0326e5506f26d67..271ff2a2f3292843807ae1afd9558b4cf930ce3d 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 char *crushtool_cmd = "crushtool",
                          int timeout = 0);