]>
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, sorted by (class, name)
131 int s
= crush
->get_bucket_size(qi
.id
);
132 map
<string
,pair
<int,float>> sorted
;
133 for (int k
= s
- 1; k
>= 0; k
--) {
134 int id
= crush
->get_bucket_item(qi
.id
, k
);
135 if (should_dump(id
)) {
138 const char *c
= crush
->get_item_class(id
);
139 sort_by
= c
? c
: "";
142 snprintf(nn
, sizeof(nn
), "osd.%08d", id
);
146 sort_by
+= crush
->get_item_name(id
);
148 sorted
[sort_by
] = make_pair(
149 id
, crush
->get_bucket_item_weightf(qi
.id
, k
));
152 for (auto p
= sorted
.rbegin(); p
!= sorted
.rend(); ++p
) {
153 qi
.children
.push_back(p
->second
.first
);
154 push_front(Item(p
->second
.first
, qi
.id
, qi
.depth
+ 1,
168 bool is_touched(int id
) const { return touched
.count(id
) > 0; }
171 virtual void dump_item(const Item
&qi
, F
*f
) = 0;
174 const CrushWrapper
*crush
;
175 const name_map_t
&weight_set_names
;
180 set
<int>::iterator root
;
183 inline void dump_item_fields(const CrushWrapper
*crush
,
184 const name_map_t
& weight_set_names
,
185 const Item
&qi
, Formatter
*f
) {
186 f
->dump_int("id", qi
.id
);
187 const char *c
= crush
->get_item_class(qi
.id
);
189 f
->dump_string("device_class", c
);
190 if (qi
.is_bucket()) {
191 int type
= crush
->get_bucket_type(qi
.id
);
192 f
->dump_string("name", crush
->get_item_name(qi
.id
));
193 f
->dump_string("type", crush
->get_type_name(type
));
194 f
->dump_int("type_id", type
);
196 f
->dump_stream("name") << "osd." << qi
.id
;
197 f
->dump_string("type", crush
->get_type_name(0));
198 f
->dump_int("type_id", 0);
199 f
->dump_float("crush_weight", qi
.weight
);
200 f
->dump_unsigned("depth", qi
.depth
);
203 f
->open_object_section("pool_weights");
204 for (auto& p
: crush
->choose_args
) {
205 const crush_choose_arg_map
& cmap
= p
.second
;
206 int bidx
= -1 - qi
.parent
;
207 const crush_bucket
*b
= crush
->get_bucket(qi
.parent
);
209 bidx
< (int)cmap
.size
&&
210 cmap
.args
[bidx
].weight_set
&&
211 cmap
.args
[bidx
].weight_set_positions
>= 1) {
214 bpos
< (int)cmap
.args
[bidx
].weight_set
[0].size
&&
215 b
->items
[bpos
] != qi
.id
;
218 if (p
.first
== CrushWrapper::DEFAULT_CHOOSE_ARGS
) {
221 auto q
= weight_set_names
.find(p
.first
);
222 name
= q
!= weight_set_names
.end() ? q
->second
:
225 f
->open_array_section(name
.c_str());
226 for (unsigned opos
= 0;
227 opos
< cmap
.args
[bidx
].weight_set_positions
;
229 float w
= (float)cmap
.args
[bidx
].weight_set
[opos
].weights
[bpos
] /
231 f
->dump_float("weight", w
);
240 inline void dump_bucket_children(const CrushWrapper
*crush
,
241 const Item
&qi
, Formatter
*f
) {
245 f
->open_array_section("children");
246 for (list
<int>::const_iterator i
= qi
.children
.begin();
247 i
!= qi
.children
.end();
249 f
->dump_int("child", *i
);
254 class FormattingDumper
: public Dumper
<Formatter
> {
256 explicit FormattingDumper(const CrushWrapper
*crush
,
257 const name_map_t
& weight_set_names
)
258 : Dumper
<Formatter
>(crush
, weight_set_names
) {}
259 explicit FormattingDumper(const CrushWrapper
*crush
,
260 const name_map_t
& weight_set_names
,
262 : Dumper
<Formatter
>(crush
, weight_set_names
, show_shadow
) {}
265 void dump_item(const Item
&qi
, Formatter
*f
) override
{
266 f
->open_object_section("item");
267 dump_item_fields(qi
, f
);
268 dump_bucket_children(qi
, f
);
272 virtual void dump_item_fields(const Item
&qi
, Formatter
*f
) {
273 CrushTreeDumper::dump_item_fields(crush
, weight_set_names
, qi
, f
);
276 virtual void dump_bucket_children(const Item
&qi
, Formatter
*f
) {
277 CrushTreeDumper::dump_bucket_children(crush
, qi
, f
);