(when the ``ceph osd require-osd-release luminous`` command is run)
but any provisioning tools that create erasure coded pools may need
to be updated.
+* The structure of the XML output for ``osd crush tree`` has changed
+ slightly to better match the ``osd tree`` output. The top level
+ structure is now ``nodes`` instead of ``crush_map_roots``.
* When assigning a network to the public network and not to
the cluster network the network specification of the public
network will be used for the cluster network as well.
int max_id;
public:
CrushWalker(const CrushWrapper *crush, unsigned max_id)
- : Parent(crush), max_id(max_id) {}
+ : Parent(crush, CrushTreeDumper::name_map_t()), max_id(max_id) {}
void dump_item(const CrushTreeDumper::Item &qi, DumbFormatter *) override {
int type = -1;
if (qi.is_bucket()) {
#define CRUSH_TREE_DUMPER_H
#include "CrushWrapper.h"
+#include "include/stringify.h"
/**
* CrushTreeDumper:
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();
}
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) {}
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) {
#include "common/debug.h"
#include "common/Formatter.h"
#include "common/errno.h"
+#include "common/TextTable.h"
#include "include/stringify.h"
#include "CrushWrapper.h"
class TreeDumper {
typedef CrushTreeDumper::Item Item;
const CrushWrapper *crush;
+ const CrushTreeDumper::name_map_t& weight_set_names;
public:
- explicit TreeDumper(const CrushWrapper *crush)
- : crush(crush) {}
+ explicit TreeDumper(const CrushWrapper *crush,
+ const CrushTreeDumper::name_map_t& wsnames)
+ : crush(crush), weight_set_names(wsnames) {}
void dump(Formatter *f) {
set<int> roots;
void dump_item(const Item& qi, Formatter* f) {
if (qi.is_bucket()) {
f->open_object_section("bucket");
- CrushTreeDumper::dump_item_fields(crush, qi, f);
+ CrushTreeDumper::dump_item_fields(crush, weight_set_names, qi, f);
dump_bucket_children(qi, f);
f->close_section();
} else {
f->open_object_section("device");
- CrushTreeDumper::dump_item_fields(crush, qi, f);
+ CrushTreeDumper::dump_item_fields(crush, weight_set_names, qi, f);
f->close_section();
}
}
};
}
-void CrushWrapper::dump_tree(Formatter *f) const
+void CrushWrapper::dump_tree(
+ Formatter *f,
+ const CrushTreeDumper::name_map_t& weight_set_names) const
{
assert(f);
- TreeDumper(this).dump(f);
+ TreeDumper(this, weight_set_names).dump(f);
}
void CrushWrapper::dump_tunables(Formatter *f) const
}
}
-class CrushTreePlainDumper : public CrushTreeDumper::Dumper<ostream> {
+class CrushTreePlainDumper : public CrushTreeDumper::Dumper<TextTable> {
public:
- typedef CrushTreeDumper::Dumper<ostream> Parent;
-
- explicit CrushTreePlainDumper(const CrushWrapper *crush)
- : Parent(crush) {}
-
- void dump(ostream *out) {
- *out << "ID\tWEIGHT\tTYPE NAME\n";
- Parent::dump(out);
+ typedef CrushTreeDumper::Dumper<TextTable> Parent;
+
+ explicit CrushTreePlainDumper(const CrushWrapper *crush,
+ const CrushTreeDumper::name_map_t& wsnames)
+ : Parent(crush, wsnames) {}
+
+ void dump(TextTable *tbl) {
+ tbl->define_column("ID", TextTable::LEFT, TextTable::RIGHT);
+ tbl->define_column("WEIGHT", TextTable::LEFT, TextTable::RIGHT);
+ for (auto& p : crush->choose_args) {
+ if (p.first == CrushWrapper::DEFAULT_CHOOSE_ARGS) {
+ tbl->define_column("(compat)", TextTable::LEFT, TextTable::RIGHT);
+ } else {
+ string name;
+ auto q = weight_set_names.find(p.first);
+ name = q != weight_set_names.end() ? q->second :
+ stringify(p.first);
+ tbl->define_column(name.c_str(), TextTable::LEFT, TextTable::RIGHT);
+ }
+ }
+ tbl->define_column("TYPE NAME", TextTable::LEFT, TextTable::LEFT);
+ Parent::dump(tbl);
}
protected:
- void dump_item(const CrushTreeDumper::Item &qi, ostream *out) override {
- *out << qi.id << "\t"
- << weightf_t(qi.weight) << "\t";
-
- for (int k=0; k < qi.depth; k++)
- *out << "\t";
-
- if (qi.is_bucket())
- {
- *out << crush->get_type_name(crush->get_bucket_type(qi.id)) << " "
- << crush->get_item_name(qi.id);
+ void dump_item(const CrushTreeDumper::Item &qi, TextTable *tbl) override {
+ *tbl << qi.id
+ << weightf_t(qi.weight);
+ for (auto& p : crush->choose_args) {
+ if (qi.parent < 0) {
+ const crush_choose_arg_map cmap = crush->choose_args_get(p.first);
+ 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 pos;
+ for (pos = 0;
+ pos < (int)cmap.args[bidx].weight_set[0].size &&
+ b->items[pos] != qi.id;
+ ++pos) ;
+ *tbl << weightf_t((float)cmap.args[bidx].weight_set[0].weights[pos] /
+ (float)0x10000);
+ continue;
+ }
+ }
+ *tbl << "";
}
- else
- {
- *out << "osd." << qi.id;
+ ostringstream ss;
+ for (int k=0; k < qi.depth; k++) {
+ ss << " ";
}
- *out << "\n";
+ if (qi.is_bucket()) {
+ ss << crush->get_type_name(crush->get_bucket_type(qi.id)) << " "
+ << crush->get_item_name(qi.id);
+ } else {
+ ss << "osd." << qi.id;
+ }
+ *tbl << ss.str();
+ *tbl << TextTable::endrow;
}
};
public:
typedef CrushTreeDumper::FormattingDumper Parent;
- explicit CrushTreeFormattingDumper(const CrushWrapper *crush)
- : Parent(crush) {}
+ explicit CrushTreeFormattingDumper(
+ const CrushWrapper *crush,
+ const CrushTreeDumper::name_map_t& wsnames)
+ : Parent(crush, wsnames) {}
void dump(Formatter *f) {
f->open_array_section("nodes");
};
-void CrushWrapper::dump_tree(ostream *out, Formatter *f) const
+void CrushWrapper::dump_tree(
+ ostream *out, Formatter *f,
+ const CrushTreeDumper::name_map_t& weight_set_names) const
{
- if (out)
- CrushTreePlainDumper(this).dump(out);
- if (f)
- CrushTreeFormattingDumper(this).dump(f);
+ if (out) {
+ TextTable tbl;
+ CrushTreePlainDumper(this, weight_set_names).dump(&tbl);
+ *out << tbl;
+ }
+ if (f) {
+ CrushTreeFormattingDumper(this, weight_set_names).dump(f);
+ }
}
void CrushWrapper::generate_test_instances(list<CrushWrapper*>& o)
#include "include/assert.h"
#include "include/err.h"
#include "include/encoding.h"
-
+#include "include/mempool.h"
#include "common/Mutex.h"
class Formatter;
}
+namespace CrushTreeDumper {
+ typedef mempool::osdmap::map<int64_t,string> name_map_t;
+}
+
WRITE_RAW_ENCODER(crush_rule_mask) // it's all u8's
inline static void encode(const crush_rule_step &s, bufferlist &bl)
/** buckets **/
-private:
const crush_bucket *get_bucket(int id) const {
if (!crush)
return (crush_bucket *)(-EINVAL);
return (crush_bucket *)(-ENOENT);
return ret;
}
+private:
crush_bucket *get_bucket(int id) {
if (!crush)
return (crush_bucket *)(-EINVAL);
void dump_tunables(Formatter *f) const;
void dump_choose_args(Formatter *f) const;
void list_rules(Formatter *f) const;
- void dump_tree(ostream *out, Formatter *f) const;
- void dump_tree(Formatter *f) const;
+ void dump_tree(ostream *out, Formatter *f,
+ const CrushTreeDumper::name_map_t& ws) const;
+ void dump_tree(ostream *out, Formatter *f) {
+ dump_tree(out, f, CrushTreeDumper::name_map_t());
+ }
+ void dump_tree(Formatter *f,
+ const CrushTreeDumper::name_map_t& ws) const;
static void generate_test_instances(list<CrushWrapper*>& o);
int get_osd_pool_default_crush_replicated_ruleset(CephContext *cct);
rs << "\n";
rdata.append(rs.str());
} else if (prefix == "osd crush tree") {
- boost::scoped_ptr<Formatter> f(Formatter::create(format, "json-pretty", "json-pretty"));
- f->open_array_section("crush_map_roots");
- osdmap.crush->dump_tree(f.get());
- f->close_section();
- f->flush(rdata);
+ boost::scoped_ptr<Formatter> f(Formatter::create(format));
+ if (f) {
+ osdmap.crush->dump_tree(nullptr, f.get(), osdmap.get_pool_names());
+ f->flush(rdata);
+ } else {
+ ostringstream ss;
+ osdmap.crush->dump_tree(&ss, nullptr, osdmap.get_pool_names());
+ rdata.append(ss.str());
+ }
} else if (prefix == "osd crush class ls") {
boost::scoped_ptr<Formatter> f(Formatter::create(format, "json-pretty", "json-pretty"));
f->open_array_section("crush_classes");
OSDTreePlainDumper(const CrushWrapper *crush, const OSDMap *osdmap_,
unsigned f)
- : Parent(crush), osdmap(osdmap_), filter(f) { }
+ : Parent(crush, osdmap_->get_pool_names()), osdmap(osdmap_), filter(f) { }
bool should_dump_leaf(int i) const override {
if (((filter & OSDMap::DUMP_UP) && !osdmap->is_up(i)) ||
OSDTreeFormattingDumper(const CrushWrapper *crush, const OSDMap *osdmap_,
unsigned f)
- : Parent(crush), osdmap(osdmap_), filter(f) { }
+ : Parent(crush, osdmap_->get_pool_names()), osdmap(osdmap_), filter(f) { }
bool should_dump_leaf(int i) const override {
if (((filter & OSDMap::DUMP_UP) && !osdmap->is_up(i)) ||
OSDUtilizationDumper(const CrushWrapper *crush, const OSDMap *osdmap_,
const PGStatService *pgs_, bool tree_) :
- Parent(crush),
+ Parent(crush, osdmap_->get_pool_names()),
osdmap(osdmap_),
pgs(pgs_),
tree(tree_),
const size_t num_pgs,
Formatter *f) override {
f->open_object_section("item");
- CrushTreeDumper::dump_item_fields(crush, qi, f);
+ CrushTreeDumper::dump_item_fields(crush, weight_set_names, qi, f);
f->dump_float("reweight", reweight);
f->dump_int("kb", kb);
f->dump_int("kb_used", kb_used);
assert(i != pool_name.end());
return i->second;
}
+ const mempool::osdmap::map<int64_t,string>& get_pool_names() const {
+ return pool_name;
+ }
bool have_pg_pool(int64_t p) const {
return pools.count(p);
}