#include "include/stringify.h"
#include "CrushTester.h"
+#include "CrushTreeDumper.h"
#include <algorithm>
#include <stdlib.h>
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) {
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);