#define CRUSH_TREE_DUMPER_H
#include "CrushWrapper.h"
+#include "include/stringify.h"
/**
* CrushTreeDumper:
struct Item {
int id;
+ int parent;
int depth;
float weight;
list<int> children;
- Item() : id(0), depth(0), weight(0) {}
- Item(int i, int d, float w) : id(i), depth(d), weight(w) {}
+ Item() : id(0), parent(0), depth(0), weight(0) {}
+ Item(int i, int p, int d, float w) : id(i), parent(p), depth(d), weight(w) {}
bool is_bucket() const { return id < 0; }
};
template <typename F>
class Dumper : public list<Item> {
public:
- explicit Dumper(const CrushWrapper *crush_) : crush(crush_) {
+ explicit Dumper(const CrushWrapper *crush_,
+ const name_map_t& weight_set_names_)
+ : crush(crush_), weight_set_names(weight_set_names_) {
crush->find_nonshadow_roots(roots);
root = roots.begin();
}
+ explicit Dumper(const CrushWrapper *crush_,
+ const name_map_t& weight_set_names_,
+ bool show_shadow)
+ : crush(crush_), weight_set_names(weight_set_names_) {
+ if (show_shadow) {
+ crush->find_roots(roots);
+ } else {
+ crush->find_nonshadow_roots(roots);
+ }
+ root = roots.begin();
+ }
virtual ~Dumper() {}
++root;
if (root == roots.end())
return false;
- push_back(Item(*root, 0, crush->get_bucket_weightf(*root)));
+ push_back(Item(*root, 0, 0, crush->get_bucket_weightf(*root)));
++root;
}
touched.insert(qi.id);
if (qi.is_bucket()) {
- // queue bucket contents...
+ // queue bucket contents, sorted by (class, name)
int s = crush->get_bucket_size(qi.id);
+ map<string,pair<int,float>> sorted;
for (int k = s - 1; k >= 0; k--) {
int id = crush->get_bucket_item(qi.id, k);
if (should_dump(id)) {
- qi.children.push_back(id);
- push_front(Item(id, qi.depth + 1,
- crush->get_bucket_item_weightf(qi.id, k)));
+ string sort_by;
+ if (id >= 0) {
+ const char *c = crush->get_item_class(id);
+ sort_by = c ? c : "";
+ sort_by += "_";
+ char nn[80];
+ snprintf(nn, sizeof(nn), "osd.%08d", id);
+ sort_by += nn;
+ } else {
+ sort_by = "_";
+ sort_by += crush->get_item_name(id);
+ }
+ sorted[sort_by] = make_pair(
+ id, crush->get_bucket_item_weightf(qi.id, k));
}
}
+ for (auto p = sorted.rbegin(); p != sorted.rend(); ++p) {
+ qi.children.push_back(p->second.first);
+ push_front(Item(p->second.first, qi.id, qi.depth + 1,
+ p->second.second));
+ }
}
return true;
}
protected:
const CrushWrapper *crush;
+ const name_map_t &weight_set_names;
private:
set<int> touched;
};
inline void dump_item_fields(const CrushWrapper *crush,
+ const name_map_t& weight_set_names,
const Item &qi, Formatter *f) {
f->dump_int("id", qi.id);
const char *c = crush->get_item_class(qi.id);
- if (!c)
- c = "";
- f->dump_string("device_class", c);
+ if (c)
+ f->dump_string("device_class", c);
if (qi.is_bucket()) {
int type = crush->get_bucket_type(qi.id);
f->dump_string("name", crush->get_item_name(qi.id));
f->dump_float("crush_weight", qi.weight);
f->dump_unsigned("depth", qi.depth);
}
+ if (qi.parent < 0) {
+ f->open_object_section("pool_weights");
+ for (auto& p : crush->choose_args) {
+ const crush_choose_arg_map& cmap = p.second;
+ int bidx = -1 - qi.parent;
+ const crush_bucket *b = crush->get_bucket(qi.parent);
+ if (b &&
+ bidx < (int)cmap.size &&
+ cmap.args[bidx].weight_set &&
+ cmap.args[bidx].weight_set_size >= 1) {
+ int bpos;
+ for (bpos = 0;
+ bpos < (int)cmap.args[bidx].weight_set[0].size &&
+ b->items[bpos] != qi.id;
+ ++bpos) ;
+ string name;
+ if (p.first == CrushWrapper::DEFAULT_CHOOSE_ARGS) {
+ name = "(compat)";
+ } else {
+ auto q = weight_set_names.find(p.first);
+ name = q != weight_set_names.end() ? q->second :
+ stringify(p.first);
+ }
+ f->open_array_section(name.c_str());
+ for (unsigned opos = 0;
+ opos < cmap.args[bidx].weight_set_size;
+ ++opos) {
+ float w = (float)cmap.args[bidx].weight_set[opos].weights[bpos] /
+ (float)0x10000;
+ f->dump_float("weight", w);
+ }
+ f->close_section();
+ }
+ }
+ f->close_section();
+ }
}
inline void dump_bucket_children(const CrushWrapper *crush,
class FormattingDumper : public Dumper<Formatter> {
public:
- explicit FormattingDumper(const CrushWrapper *crush) : Dumper<Formatter>(crush) {}
+ explicit FormattingDumper(const CrushWrapper *crush,
+ const name_map_t& weight_set_names)
+ : Dumper<Formatter>(crush, weight_set_names) {}
+ explicit FormattingDumper(const CrushWrapper *crush,
+ const name_map_t& weight_set_names,
+ bool show_shadow)
+ : Dumper<Formatter>(crush, weight_set_names, show_shadow) {}
protected:
void dump_item(const Item &qi, Formatter *f) override {
}
virtual void dump_item_fields(const Item &qi, Formatter *f) {
- CrushTreeDumper::dump_item_fields(crush, qi, f);
+ CrushTreeDumper::dump_item_fields(crush, weight_set_names, qi, f);
}
virtual void dump_bucket_children(const Item &qi, Formatter *f) {