]>
git.proxmox.com Git - ceph.git/blob - ceph/src/crush/CrushTreeDumper.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph distributed storage system
6 * Copyright (C) 2015 Mirantis Inc
8 * Author: Mykola Golub <mgolub@mirantis.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
17 #ifndef CRUSH_TREE_DUMPER_H
18 #define CRUSH_TREE_DUMPER_H
20 #include "CrushWrapper.h"
21 #include "include/stringify.h"
25 * A helper class and functions to dump a crush tree.
29 * class SimpleDumper : public CrushTreeDumper::Dumper<ostream> {
31 * SimpleDumper(const CrushWrapper *crush) :
32 * CrushTreeDumper::Dumper<ostream>(crush) {}
34 * virtual void dump_item(const CrushTreeDumper::Item &qi, ostream *out) {
36 * for (int k = 0; k < qi.depth; k++)
39 * *out << crush->get_item_name(qi.id)
41 * *out << "osd." << qi.id;
46 * SimpleDumper(crush).dump(out);
50 namespace CrushTreeDumper
{
59 Item() : id(0), parent(0), depth(0), weight(0) {}
60 Item(int i
, int p
, int d
, float w
) : id(i
), parent(p
), depth(d
), weight(w
) {}
62 bool is_bucket() const { return id
< 0; }
66 class Dumper
: public list
<Item
> {
68 explicit Dumper(const CrushWrapper
*crush_
,
69 const name_map_t
& weight_set_names_
)
70 : crush(crush_
), weight_set_names(weight_set_names_
) {
71 crush
->find_nonshadow_roots(roots
);
74 explicit Dumper(const CrushWrapper
*crush_
,
75 const name_map_t
& weight_set_names_
,
77 : crush(crush_
), weight_set_names(weight_set_names_
) {
79 crush
->find_roots(roots
);
81 crush
->find_nonshadow_roots(roots
);
88 virtual void reset() {
94 virtual bool should_dump_leaf(int i
) const {
97 virtual bool should_dump_empty_bucket() const {
101 bool should_dump(int id
) {
103 return should_dump_leaf(id
);
104 if (should_dump_empty_bucket())
106 int s
= crush
->get_bucket_size(id
);
107 for (int k
= s
- 1; k
>= 0; k
--) {
108 int c
= crush
->get_bucket_item(id
, k
);
115 bool next(Item
&qi
) {
117 while (root
!= roots
.end() && !should_dump(*root
))
119 if (root
== roots
.end())
121 push_back(Item(*root
, 0, 0, crush
->get_bucket_weightf(*root
)));
127 touched
.insert(qi
.id
);
129 if (qi
.is_bucket()) {
130 // queue bucket contents...
131 int s
= crush
->get_bucket_size(qi
.id
);
132 for (int k
= s
- 1; k
>= 0; k
--) {
133 int id
= crush
->get_bucket_item(qi
.id
, k
);
134 if (should_dump(id
)) {
135 qi
.children
.push_back(id
);
136 push_front(Item(id
, qi
.id
, qi
.depth
+ 1,
137 crush
->get_bucket_item_weightf(qi
.id
, k
)));
151 bool is_touched(int id
) const { return touched
.count(id
) > 0; }
154 virtual void dump_item(const Item
&qi
, F
*f
) = 0;
157 const CrushWrapper
*crush
;
158 const name_map_t
&weight_set_names
;
163 set
<int>::iterator root
;
166 inline void dump_item_fields(const CrushWrapper
*crush
,
167 const name_map_t
& weight_set_names
,
168 const Item
&qi
, Formatter
*f
) {
169 f
->dump_int("id", qi
.id
);
170 const char *c
= crush
->get_item_class(qi
.id
);
172 f
->dump_string("device_class", c
);
173 if (qi
.is_bucket()) {
174 int type
= crush
->get_bucket_type(qi
.id
);
175 f
->dump_string("name", crush
->get_item_name(qi
.id
));
176 f
->dump_string("type", crush
->get_type_name(type
));
177 f
->dump_int("type_id", type
);
179 f
->dump_stream("name") << "osd." << qi
.id
;
180 f
->dump_string("type", crush
->get_type_name(0));
181 f
->dump_int("type_id", 0);
182 f
->dump_float("crush_weight", qi
.weight
);
183 f
->dump_unsigned("depth", qi
.depth
);
186 f
->open_object_section("pool_weights");
187 for (auto& p
: crush
->choose_args
) {
188 const crush_choose_arg_map
& cmap
= p
.second
;
189 int bidx
= -1 - qi
.parent
;
190 const crush_bucket
*b
= crush
->get_bucket(qi
.parent
);
192 bidx
< (int)cmap
.size
&&
193 cmap
.args
[bidx
].weight_set
&&
194 cmap
.args
[bidx
].weight_set_size
>= 1) {
197 bpos
< (int)cmap
.args
[bidx
].weight_set
[0].size
&&
198 b
->items
[bpos
] != qi
.id
;
201 if (p
.first
== CrushWrapper::DEFAULT_CHOOSE_ARGS
) {
204 auto q
= weight_set_names
.find(p
.first
);
205 name
= q
!= weight_set_names
.end() ? q
->second
:
208 f
->open_array_section(name
.c_str());
209 for (unsigned opos
= 0;
210 opos
< cmap
.args
[bidx
].weight_set_size
;
212 float w
= (float)cmap
.args
[bidx
].weight_set
[opos
].weights
[bpos
] /
214 f
->dump_float("weight", w
);
223 inline void dump_bucket_children(const CrushWrapper
*crush
,
224 const Item
&qi
, Formatter
*f
) {
228 f
->open_array_section("children");
229 for (list
<int>::const_iterator i
= qi
.children
.begin();
230 i
!= qi
.children
.end();
232 f
->dump_int("child", *i
);
237 class FormattingDumper
: public Dumper
<Formatter
> {
239 explicit FormattingDumper(const CrushWrapper
*crush
,
240 const name_map_t
& weight_set_names
)
241 : Dumper
<Formatter
>(crush
, weight_set_names
) {}
242 explicit FormattingDumper(const CrushWrapper
*crush
,
243 const name_map_t
& weight_set_names
,
245 : Dumper
<Formatter
>(crush
, weight_set_names
, show_shadow
) {}
248 void dump_item(const Item
&qi
, Formatter
*f
) override
{
249 f
->open_object_section("item");
250 dump_item_fields(qi
, f
);
251 dump_bucket_children(qi
, f
);
255 virtual void dump_item_fields(const Item
&qi
, Formatter
*f
) {
256 CrushTreeDumper::dump_item_fields(crush
, weight_set_names
, qi
, f
);
259 virtual void dump_bucket_children(const Item
&qi
, Formatter
*f
) {
260 CrushTreeDumper::dump_bucket_children(crush
, qi
, f
);