]> git.proxmox.com Git - ceph.git/blob - ceph/src/crush/CrushWrapper.h
94730d53d19637d7f3b81740ec92fc47131a585d
[ceph.git] / ceph / src / crush / CrushWrapper.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #ifndef CEPH_CRUSH_WRAPPER_H
5 #define CEPH_CRUSH_WRAPPER_H
6
7 #include <stdlib.h>
8 #include <map>
9 #include <set>
10 #include <string>
11
12 #include <iosfwd>
13
14 #include "include/types.h"
15
16 extern "C" {
17 #include "crush.h"
18 #include "hash.h"
19 #include "mapper.h"
20 #include "builder.h"
21 }
22
23 #include "include/assert.h"
24 #include "include/err.h"
25 #include "include/encoding.h"
26 #include "include/mempool.h"
27
28 #include "common/Mutex.h"
29
30 #define BUG_ON(x) assert(!(x))
31
32 namespace ceph {
33 class Formatter;
34 }
35
36 namespace CrushTreeDumper {
37 typedef mempool::osdmap::map<int64_t,string> name_map_t;
38 }
39
40 WRITE_RAW_ENCODER(crush_rule_mask) // it's all u8's
41
42 inline static void encode(const crush_rule_step &s, bufferlist &bl)
43 {
44 ::encode(s.op, bl);
45 ::encode(s.arg1, bl);
46 ::encode(s.arg2, bl);
47 }
48 inline static void decode(crush_rule_step &s, bufferlist::iterator &p)
49 {
50 ::decode(s.op, p);
51 ::decode(s.arg1, p);
52 ::decode(s.arg2, p);
53 }
54
55 using namespace std;
56 class CrushWrapper {
57 public:
58 // magic value used by OSDMap for a "default" fallback choose_args, used if
59 // the choose_arg_map passed to do_rule does not exist. if this also
60 // doesn't exist, fall back to canonical weights.
61 enum {
62 DEFAULT_CHOOSE_ARGS = -1
63 };
64
65 std::map<int32_t, string> type_map; /* bucket/device type names */
66 std::map<int32_t, string> name_map; /* bucket/device names */
67 std::map<int32_t, string> rule_name_map;
68 std::map<int32_t, int32_t> class_map; /* item id -> class id */
69 std::map<int32_t, string> class_name; /* class id -> class name */
70 std::map<string, int32_t> class_rname; /* class name -> class id */
71 std::map<int32_t, map<int32_t, int32_t> > class_bucket; /* bucket[id][class] == id */
72 std::map<int64_t, crush_choose_arg_map> choose_args;
73
74 private:
75 struct crush_map *crush;
76
77 bool have_uniform_rules = false;
78
79 /* reverse maps */
80 mutable bool have_rmaps;
81 mutable std::map<string, int> type_rmap, name_rmap, rule_name_rmap;
82 void build_rmaps() const {
83 if (have_rmaps) return;
84 build_rmap(type_map, type_rmap);
85 build_rmap(name_map, name_rmap);
86 build_rmap(rule_name_map, rule_name_rmap);
87 have_rmaps = true;
88 }
89 void build_rmap(const map<int, string> &f, std::map<string, int> &r) const {
90 r.clear();
91 for (std::map<int, string>::const_iterator p = f.begin(); p != f.end(); ++p)
92 r[p->second] = p->first;
93 }
94
95 public:
96 CrushWrapper(const CrushWrapper& other);
97 const CrushWrapper& operator=(const CrushWrapper& other);
98
99 CrushWrapper() : crush(0), have_rmaps(false) {
100 create();
101 }
102 ~CrushWrapper() {
103 if (crush)
104 crush_destroy(crush);
105 choose_args_clear();
106 }
107
108 crush_map *get_crush_map() { return crush; }
109
110 /* building */
111 void create() {
112 if (crush)
113 crush_destroy(crush);
114 crush = crush_create();
115 choose_args_clear();
116 assert(crush);
117 have_rmaps = false;
118
119 set_tunables_default();
120 }
121
122 /// true if any rule has a ruleset != the rule id
123 bool has_legacy_rulesets() const;
124
125 /// fix rules whose ruleid != ruleset
126 int renumber_rules_by_ruleset();
127
128 /// true if any ruleset has more than 1 rule
129 bool has_multirule_rulesets() const;
130
131 /// true if any buckets that aren't straw2
132 bool has_non_straw2_buckets() const;
133
134 // tunables
135 void set_tunables_argonaut() {
136 crush->choose_local_tries = 2;
137 crush->choose_local_fallback_tries = 5;
138 crush->choose_total_tries = 19;
139 crush->chooseleaf_descend_once = 0;
140 crush->chooseleaf_vary_r = 0;
141 crush->chooseleaf_stable = 0;
142 crush->allowed_bucket_algs = CRUSH_LEGACY_ALLOWED_BUCKET_ALGS;
143 }
144 void set_tunables_bobtail() {
145 crush->choose_local_tries = 0;
146 crush->choose_local_fallback_tries = 0;
147 crush->choose_total_tries = 50;
148 crush->chooseleaf_descend_once = 1;
149 crush->chooseleaf_vary_r = 0;
150 crush->chooseleaf_stable = 0;
151 crush->allowed_bucket_algs = CRUSH_LEGACY_ALLOWED_BUCKET_ALGS;
152 }
153 void set_tunables_firefly() {
154 crush->choose_local_tries = 0;
155 crush->choose_local_fallback_tries = 0;
156 crush->choose_total_tries = 50;
157 crush->chooseleaf_descend_once = 1;
158 crush->chooseleaf_vary_r = 1;
159 crush->chooseleaf_stable = 0;
160 crush->allowed_bucket_algs = CRUSH_LEGACY_ALLOWED_BUCKET_ALGS;
161 }
162 void set_tunables_hammer() {
163 crush->choose_local_tries = 0;
164 crush->choose_local_fallback_tries = 0;
165 crush->choose_total_tries = 50;
166 crush->chooseleaf_descend_once = 1;
167 crush->chooseleaf_vary_r = 1;
168 crush->chooseleaf_stable = 0;
169 crush->allowed_bucket_algs =
170 (1 << CRUSH_BUCKET_UNIFORM) |
171 (1 << CRUSH_BUCKET_LIST) |
172 (1 << CRUSH_BUCKET_STRAW) |
173 (1 << CRUSH_BUCKET_STRAW2);
174 }
175 void set_tunables_jewel() {
176 crush->choose_local_tries = 0;
177 crush->choose_local_fallback_tries = 0;
178 crush->choose_total_tries = 50;
179 crush->chooseleaf_descend_once = 1;
180 crush->chooseleaf_vary_r = 1;
181 crush->chooseleaf_stable = 1;
182 crush->allowed_bucket_algs =
183 (1 << CRUSH_BUCKET_UNIFORM) |
184 (1 << CRUSH_BUCKET_LIST) |
185 (1 << CRUSH_BUCKET_STRAW) |
186 (1 << CRUSH_BUCKET_STRAW2);
187 }
188
189 void set_tunables_legacy() {
190 set_tunables_argonaut();
191 crush->straw_calc_version = 0;
192 }
193 void set_tunables_optimal() {
194 set_tunables_jewel();
195 crush->straw_calc_version = 1;
196 }
197 void set_tunables_default() {
198 set_tunables_jewel();
199 crush->straw_calc_version = 1;
200 }
201
202 int get_choose_local_tries() const {
203 return crush->choose_local_tries;
204 }
205 void set_choose_local_tries(int n) {
206 crush->choose_local_tries = n;
207 }
208
209 int get_choose_local_fallback_tries() const {
210 return crush->choose_local_fallback_tries;
211 }
212 void set_choose_local_fallback_tries(int n) {
213 crush->choose_local_fallback_tries = n;
214 }
215
216 int get_choose_total_tries() const {
217 return crush->choose_total_tries;
218 }
219 void set_choose_total_tries(int n) {
220 crush->choose_total_tries = n;
221 }
222
223 int get_chooseleaf_descend_once() const {
224 return crush->chooseleaf_descend_once;
225 }
226 void set_chooseleaf_descend_once(int n) {
227 crush->chooseleaf_descend_once = !!n;
228 }
229
230 int get_chooseleaf_vary_r() const {
231 return crush->chooseleaf_vary_r;
232 }
233 void set_chooseleaf_vary_r(int n) {
234 crush->chooseleaf_vary_r = n;
235 }
236
237 int get_chooseleaf_stable() const {
238 return crush->chooseleaf_stable;
239 }
240 void set_chooseleaf_stable(int n) {
241 crush->chooseleaf_stable = n;
242 }
243
244 int get_straw_calc_version() const {
245 return crush->straw_calc_version;
246 }
247 void set_straw_calc_version(int n) {
248 crush->straw_calc_version = n;
249 }
250
251 unsigned get_allowed_bucket_algs() const {
252 return crush->allowed_bucket_algs;
253 }
254 void set_allowed_bucket_algs(unsigned n) {
255 crush->allowed_bucket_algs = n;
256 }
257
258 bool has_argonaut_tunables() const {
259 return
260 crush->choose_local_tries == 2 &&
261 crush->choose_local_fallback_tries == 5 &&
262 crush->choose_total_tries == 19 &&
263 crush->chooseleaf_descend_once == 0 &&
264 crush->chooseleaf_vary_r == 0 &&
265 crush->chooseleaf_stable == 0 &&
266 crush->allowed_bucket_algs == CRUSH_LEGACY_ALLOWED_BUCKET_ALGS;
267 }
268 bool has_bobtail_tunables() const {
269 return
270 crush->choose_local_tries == 0 &&
271 crush->choose_local_fallback_tries == 0 &&
272 crush->choose_total_tries == 50 &&
273 crush->chooseleaf_descend_once == 1 &&
274 crush->chooseleaf_vary_r == 0 &&
275 crush->chooseleaf_stable == 0 &&
276 crush->allowed_bucket_algs == CRUSH_LEGACY_ALLOWED_BUCKET_ALGS;
277 }
278 bool has_firefly_tunables() const {
279 return
280 crush->choose_local_tries == 0 &&
281 crush->choose_local_fallback_tries == 0 &&
282 crush->choose_total_tries == 50 &&
283 crush->chooseleaf_descend_once == 1 &&
284 crush->chooseleaf_vary_r == 1 &&
285 crush->chooseleaf_stable == 0 &&
286 crush->allowed_bucket_algs == CRUSH_LEGACY_ALLOWED_BUCKET_ALGS;
287 }
288 bool has_hammer_tunables() const {
289 return
290 crush->choose_local_tries == 0 &&
291 crush->choose_local_fallback_tries == 0 &&
292 crush->choose_total_tries == 50 &&
293 crush->chooseleaf_descend_once == 1 &&
294 crush->chooseleaf_vary_r == 1 &&
295 crush->chooseleaf_stable == 0 &&
296 crush->allowed_bucket_algs == ((1 << CRUSH_BUCKET_UNIFORM) |
297 (1 << CRUSH_BUCKET_LIST) |
298 (1 << CRUSH_BUCKET_STRAW) |
299 (1 << CRUSH_BUCKET_STRAW2));
300 }
301 bool has_jewel_tunables() const {
302 return
303 crush->choose_local_tries == 0 &&
304 crush->choose_local_fallback_tries == 0 &&
305 crush->choose_total_tries == 50 &&
306 crush->chooseleaf_descend_once == 1 &&
307 crush->chooseleaf_vary_r == 1 &&
308 crush->chooseleaf_stable == 1 &&
309 crush->allowed_bucket_algs == ((1 << CRUSH_BUCKET_UNIFORM) |
310 (1 << CRUSH_BUCKET_LIST) |
311 (1 << CRUSH_BUCKET_STRAW) |
312 (1 << CRUSH_BUCKET_STRAW2));
313 }
314
315 bool has_optimal_tunables() const {
316 return has_jewel_tunables();
317 }
318 bool has_legacy_tunables() const {
319 return has_argonaut_tunables();
320 }
321
322 bool has_nondefault_tunables() const {
323 return
324 (crush->choose_local_tries != 2 ||
325 crush->choose_local_fallback_tries != 5 ||
326 crush->choose_total_tries != 19);
327 }
328 bool has_nondefault_tunables2() const {
329 return
330 crush->chooseleaf_descend_once != 0;
331 }
332 bool has_nondefault_tunables3() const {
333 return
334 crush->chooseleaf_vary_r != 0;
335 }
336 bool has_nondefault_tunables5() const {
337 return
338 crush->chooseleaf_stable != 0;
339 }
340
341 bool has_v2_rules() const;
342 bool has_v3_rules() const;
343 bool has_v4_buckets() const;
344 bool has_v5_rules() const;
345 bool has_choose_args() const; // any choose_args
346 bool has_incompat_choose_args() const; // choose_args that can't be made compat
347
348 bool is_v2_rule(unsigned ruleid) const;
349 bool is_v3_rule(unsigned ruleid) const;
350 bool is_v5_rule(unsigned ruleid) const;
351
352 string get_min_required_version() const {
353 if (has_v5_rules() || has_nondefault_tunables5())
354 return "jewel";
355 else if (has_v4_buckets())
356 return "hammer";
357 else if (has_nondefault_tunables3())
358 return "firefly";
359 else if (has_nondefault_tunables2() || has_nondefault_tunables())
360 return "bobtail";
361 else
362 return "argonaut";
363 }
364
365 // default bucket types
366 unsigned get_default_bucket_alg() const {
367 // in order of preference
368 if (crush->allowed_bucket_algs & (1 << CRUSH_BUCKET_STRAW2))
369 return CRUSH_BUCKET_STRAW2;
370 if (crush->allowed_bucket_algs & (1 << CRUSH_BUCKET_STRAW))
371 return CRUSH_BUCKET_STRAW;
372 if (crush->allowed_bucket_algs & (1 << CRUSH_BUCKET_TREE))
373 return CRUSH_BUCKET_TREE;
374 if (crush->allowed_bucket_algs & (1 << CRUSH_BUCKET_LIST))
375 return CRUSH_BUCKET_LIST;
376 if (crush->allowed_bucket_algs & (1 << CRUSH_BUCKET_UNIFORM))
377 return CRUSH_BUCKET_UNIFORM;
378 return 0;
379 }
380
381 // bucket types
382 int get_num_type_names() const {
383 return type_map.size();
384 }
385 int get_max_type_id() const {
386 if (type_map.empty())
387 return 0;
388 return type_map.rbegin()->first;
389 }
390 int get_type_id(const string& name) const {
391 build_rmaps();
392 if (type_rmap.count(name))
393 return type_rmap[name];
394 return -1;
395 }
396 const char *get_type_name(int t) const {
397 std::map<int,string>::const_iterator p = type_map.find(t);
398 if (p != type_map.end())
399 return p->second.c_str();
400 return 0;
401 }
402 void set_type_name(int i, const string& name) {
403 type_map[i] = name;
404 if (have_rmaps)
405 type_rmap[name] = i;
406 }
407
408 // item/bucket names
409 bool name_exists(const string& name) const {
410 build_rmaps();
411 return name_rmap.count(name);
412 }
413 bool item_exists(int i) const {
414 return name_map.count(i);
415 }
416 int get_item_id(const string& name) const {
417 build_rmaps();
418 if (name_rmap.count(name))
419 return name_rmap[name];
420 return 0; /* hrm */
421 }
422 const char *get_item_name(int t) const {
423 std::map<int,string>::const_iterator p = name_map.find(t);
424 if (p != name_map.end())
425 return p->second.c_str();
426 return 0;
427 }
428 int set_item_name(int i, const string& name) {
429 if (!is_valid_crush_name(name))
430 return -EINVAL;
431 name_map[i] = name;
432 if (have_rmaps)
433 name_rmap[name] = i;
434 return 0;
435 }
436 void swap_names(int a, int b) {
437 string an = name_map[a];
438 string bn = name_map[b];
439 name_map[a] = bn;
440 name_map[b] = an;
441 if (have_rmaps) {
442 name_rmap[an] = b;
443 name_rmap[bn] = a;
444 }
445 }
446 int split_id_class(int i, int *idout, int *classout) const;
447
448 bool class_exists(const string& name) const {
449 return class_rname.count(name);
450 }
451 const char *get_class_name(int i) const {
452 auto p = class_name.find(i);
453 if (p != class_name.end())
454 return p->second.c_str();
455 return 0;
456 }
457 int get_class_id(const string& name) const {
458 auto p = class_rname.find(name);
459 if (p != class_rname.end())
460 return p->second;
461 else
462 return -EINVAL;
463 }
464 int remove_class_name(const string& name) {
465 auto p = class_rname.find(name);
466 if (p == class_rname.end())
467 return -ENOENT;
468 int class_id = p->second;
469 auto q = class_name.find(class_id);
470 if (q == class_name.end())
471 return -ENOENT;
472 class_rname.erase(name);
473 class_name.erase(class_id);
474 return 0;
475 }
476
477 int32_t _alloc_class_id() const;
478
479 int get_or_create_class_id(const string& name) {
480 int c = get_class_id(name);
481 if (c < 0) {
482 int i = _alloc_class_id();
483 class_name[i] = name;
484 class_rname[name] = i;
485 return i;
486 } else {
487 return c;
488 }
489 }
490
491 const char *get_item_class(int t) const {
492 std::map<int,int>::const_iterator p = class_map.find(t);
493 if (p == class_map.end())
494 return 0;
495 return get_class_name(p->second);
496 }
497 int set_item_class(int i, const string& name) {
498 if (!is_valid_crush_name(name))
499 return -EINVAL;
500 class_map[i] = get_or_create_class_id(name);
501 return 0;
502 }
503 int set_item_class(int i, int c) {
504 class_map[i] = c;
505 return c;
506 }
507 void get_devices_by_class(const string &name, set<int> *devices) const {
508 assert(devices);
509 devices->clear();
510 if (!class_exists(name)) {
511 return;
512 }
513 auto cid = get_class_id(name);
514 for (auto& p : class_map) {
515 if (p.first >= 0 && p.second == cid) {
516 devices->insert(p.first);
517 }
518 }
519 }
520 void class_remove_item(int i) {
521 auto it = class_map.find(i);
522 if (it == class_map.end()) {
523 return;
524 }
525 class_map.erase(it);
526 }
527 int can_rename_item(const string& srcname,
528 const string& dstname,
529 ostream *ss) const;
530 int rename_item(const string& srcname,
531 const string& dstname,
532 ostream *ss);
533 int can_rename_bucket(const string& srcname,
534 const string& dstname,
535 ostream *ss) const;
536 int rename_bucket(const string& srcname,
537 const string& dstname,
538 ostream *ss);
539
540 // rule names
541 bool rule_exists(string name) const {
542 build_rmaps();
543 return rule_name_rmap.count(name);
544 }
545 int get_rule_id(string name) const {
546 build_rmaps();
547 if (rule_name_rmap.count(name))
548 return rule_name_rmap[name];
549 return -ENOENT;
550 }
551 const char *get_rule_name(int t) const {
552 std::map<int,string>::const_iterator p = rule_name_map.find(t);
553 if (p != rule_name_map.end())
554 return p->second.c_str();
555 return 0;
556 }
557 void set_rule_name(int i, const string& name) {
558 rule_name_map[i] = name;
559 if (have_rmaps)
560 rule_name_rmap[name] = i;
561 }
562 bool is_shadow_item(int id) const {
563 const char *name = get_item_name(id);
564 return name && !is_valid_crush_name(name);
565 }
566
567
568 /**
569 * find tree nodes referenced by rules by a 'take' command
570 *
571 * Note that these may not be parentless roots.
572 */
573 void find_takes(set<int>& roots) const;
574
575 /**
576 * find tree roots
577 *
578 * These are parentless nodes in the map.
579 */
580 void find_roots(set<int>& roots) const;
581
582
583 /**
584 * find tree roots that contain shadow (device class) items only
585 */
586 void find_shadow_roots(set<int>& roots) const {
587 set<int> all;
588 find_roots(all);
589 for (auto& p: all) {
590 if (is_shadow_item(p)) {
591 roots.insert(p);
592 }
593 }
594 }
595
596 /**
597 * find tree roots that are not shadow (device class) items
598 *
599 * These are parentless nodes in the map that are not shadow
600 * items for device classes.
601 */
602 void find_nonshadow_roots(set<int>& roots) const {
603 set<int> all;
604 find_roots(all);
605 for (auto& p: all) {
606 if (!is_shadow_item(p)) {
607 roots.insert(p);
608 }
609 }
610 }
611
612 /**
613 * see if an item is contained within a subtree
614 *
615 * @param root haystack
616 * @param item needle
617 * @return true if the item is located beneath the given node
618 */
619 bool subtree_contains(int root, int item) const;
620
621 private:
622 /**
623 * search for an item in any bucket
624 *
625 * @param i item
626 * @return true if present
627 */
628 bool _search_item_exists(int i) const;
629 public:
630
631 /**
632 * see if item is located where we think it is
633 *
634 * This verifies that the given item is located at a particular
635 * location in the hierarchy. However, that check is imprecise; we
636 * are actually verifying that the most specific location key/value
637 * is correct. For example, if loc specifies that rack=foo and
638 * host=bar, it will verify that host=bar is correct; any placement
639 * above that level in the hierarchy is ignored. This matches the
640 * semantics for insert_item().
641 *
642 * @param cct cct
643 * @param item item id
644 * @param loc location to check (map of type to bucket names)
645 * @param weight optional pointer to weight of item at that location
646 * @return true if item is at specified location
647 */
648 bool check_item_loc(CephContext *cct, int item, const map<string,string>& loc, int *iweight);
649 bool check_item_loc(CephContext *cct, int item, const map<string,string>& loc, float *weight) {
650 int iweight;
651 bool ret = check_item_loc(cct, item, loc, &iweight);
652 if (weight)
653 *weight = (float)iweight / (float)0x10000;
654 return ret;
655 }
656
657
658 /**
659 * returns the (type, name) of the parent bucket of id
660 *
661 * FIXME: ambiguous for items that occur multiple times in the map
662 */
663 pair<string,string> get_immediate_parent(int id, int *ret = NULL);
664
665 int get_immediate_parent_id(int id, int *parent) const;
666
667 /**
668 * return ancestor of the given type, or 0 if none
669 * (parent is always a bucket and thus <0)
670 */
671 int get_parent_of_type(int id, int type) const;
672
673 /**
674 * get the fully qualified location of a device by successively finding
675 * parents beginning at ID and ending at highest type number specified in
676 * the CRUSH map which assumes that if device foo is under device bar, the
677 * type_id of foo < bar where type_id is the integer specified in the CRUSH map
678 *
679 * returns the location in the form of (type=foo) where type is a type of bucket
680 * specified in the CRUSH map and foo is a name specified in the CRUSH map
681 */
682 map<string, string> get_full_location(int id);
683
684 /*
685 * identical to get_full_location(int id) although it returns the type/name
686 * pairs in the order they occur in the hierarchy.
687 *
688 * returns -ENOENT if id is not found.
689 */
690 int get_full_location_ordered(int id, vector<pair<string, string> >& path);
691
692 /*
693 * identical to get_full_location_ordered(int id, vector<pair<string, string> >& path),
694 * although it returns a concatenated string with the type/name pairs in descending
695 * hierarchical order with format key1=val1,key2=val2.
696 *
697 * returns the location in descending hierarchy as a string.
698 */
699 string get_full_location_ordered_string(int id);
700
701 /**
702 * returns (type_id, type) of all parent buckets between id and
703 * default, can be used to check for anomolous CRUSH maps
704 */
705 map<int, string> get_parent_hierarchy(int id);
706
707 /**
708 * enumerate immediate children of given node
709 *
710 * @param id parent bucket or device id
711 * @return number of items, or error
712 */
713 int get_children(int id, list<int> *children);
714
715 /**
716 * enumerate leaves(devices) of given node
717 *
718 * @param name parent bucket name
719 * @return 0 on success or a negative errno on error.
720 */
721 int get_leaves(const string &name, set<int> *leaves);
722 int _get_leaves(int id, list<int> *leaves); // worker
723
724 /**
725 * insert an item into the map at a specific position
726 *
727 * Add an item as a specific location of the hierarchy.
728 * Specifically, we look for the most specific location constraint
729 * for which a bucket already exists, and then create intervening
730 * buckets beneath that in order to place the item.
731 *
732 * Note that any location specifiers *above* the most specific match
733 * are ignored. For example, if we specify that osd.12 goes in
734 * host=foo, rack=bar, and row=baz, and rack=bar is the most
735 * specific match, we will create host=foo beneath that point and
736 * put osd.12 inside it. However, we will not verify that rack=bar
737 * is beneath row=baz or move it.
738 *
739 * In short, we will build out a hierarchy, and move leaves around,
740 * but not adjust the hierarchy's internal structure. Yet.
741 *
742 * If the item is already present in the map, we will return EEXIST.
743 * If the location key/value pairs are nonsensical
744 * (rack=nameofdevice), or location specifies that do not attach us
745 * to any existing part of the hierarchy, we will return EINVAL.
746 *
747 * @param cct cct
748 * @param id item id
749 * @param weight item weight
750 * @param name item name
751 * @param loc location (map of type to bucket names)
752 * @return 0 for success, negative on error
753 */
754 int insert_item(CephContext *cct, int id, float weight, string name, const map<string,string>& loc);
755
756 /**
757 * move a bucket in the hierarchy to the given location
758 *
759 * This has the same location and ancestor creation behavior as
760 * insert_item(), but will relocate the specified existing bucket.
761 *
762 * @param cct cct
763 * @param id bucket id
764 * @param loc location (map of type to bucket names)
765 * @return 0 for success, negative on error
766 */
767 int move_bucket(CephContext *cct, int id, const map<string,string>& loc);
768
769 /**
770 * swap bucket contents of two buckets without touching bucket ids
771 *
772 * @param cct cct
773 * @param src bucket a
774 * @param dst bucket b
775 * @return 0 for success, negative on error
776 */
777 int swap_bucket(CephContext *cct, int src, int dst);
778
779 /**
780 * add a link to an existing bucket in the hierarchy to the new location
781 *
782 * This has the same location and ancestor creation behavior as
783 * insert_item(), but will add a new link to the specified existing
784 * bucket.
785 *
786 * @param cct cct
787 * @param id bucket id
788 * @param loc location (map of type to bucket names)
789 * @return 0 for success, negative on error
790 */
791 int link_bucket(CephContext *cct, int id, const map<string,string>& loc);
792
793 /**
794 * add or update an item's position in the map
795 *
796 * This is analogous to insert_item, except we will move an item if
797 * it is already present.
798 *
799 * @param cct cct
800 * @param id item id
801 * @param weight item weight
802 * @param name item name
803 * @param loc location (map of type to bucket names)
804 * @return 0 for no change, 1 for successful change, negative on error
805 */
806 int update_item(CephContext *cct, int id, float weight, string name, const map<string,string>& loc);
807
808 /**
809 * create or move an item, but do not adjust its weight if it already exists
810 *
811 * @param cct cct
812 * @param item item id
813 * @param weight initial item weight (if we need to create it)
814 * @param name item name
815 * @param loc location (map of type to bucket names)
816 * @return 0 for no change, 1 for successful change, negative on error
817 */
818 int create_or_move_item(CephContext *cct, int item, float weight, string name,
819 const map<string,string>& loc);
820
821 /**
822 * remove all instances of an item from the map
823 *
824 * @param cct cct
825 * @param id item id to remove
826 * @param unlink_only unlink but do not remove bucket (useful if multiple links or not empty)
827 * @return 0 on success, negative on error
828 */
829 int remove_item(CephContext *cct, int id, bool unlink_only);
830
831 /**
832 * recursively remove buckets starting at item and stop removing
833 * when a bucket is in use.
834 *
835 * @param item id to remove
836 * @param unused true if only unused items should be removed
837 * @return 0 on success, negative on error
838 */
839 int remove_root(int item, bool unused);
840
841 /**
842 * remove all instances of an item nested beneath a certain point from the map
843 *
844 * @param cct cct
845 * @param id item id to remove
846 * @param ancestor ancestor item id under which to search for id
847 * @param unlink_only unlink but do not remove bucket (useful if bucket has multiple links or is not empty)
848 * @return 0 on success, negative on error
849 */
850 private:
851 bool _maybe_remove_last_instance(CephContext *cct, int id, bool unlink_only);
852 int _remove_item_under(CephContext *cct, int id, int ancestor, bool unlink_only);
853 bool _bucket_is_in_use(int id);
854 public:
855 int remove_item_under(CephContext *cct, int id, int ancestor, bool unlink_only);
856
857 /**
858 * calculate the locality/distance from a given id to a crush location map
859 *
860 * Specifically, we look for the lowest-valued type for which the
861 * location of id matches that described in loc.
862 *
863 * @param cct cct
864 * @param id the existing id in the map
865 * @param loc a set of key=value pairs describing a location in the hierarchy
866 */
867 int get_common_ancestor_distance(CephContext *cct, int id,
868 const std::multimap<string,string>& loc);
869
870 /**
871 * parse a set of key/value pairs out of a string vector
872 *
873 * These are used to describe a location in the CRUSH hierarchy.
874 *
875 * @param args list of strings (each key= or key=value)
876 * @param ploc pointer to a resulting location map or multimap
877 */
878 static int parse_loc_map(const std::vector<string>& args,
879 std::map<string,string> *ploc);
880 static int parse_loc_multimap(const std::vector<string>& args,
881 std::multimap<string,string> *ploc);
882
883 /**
884 * get an item's weight
885 *
886 * Will return the weight for the first instance it finds.
887 *
888 * @param id item id to check
889 * @return weight of item
890 */
891 int get_item_weight(int id) const;
892 float get_item_weightf(int id) const {
893 return (float)get_item_weight(id) / (float)0x10000;
894 }
895 int get_item_weight_in_loc(int id, const map<string,string> &loc);
896 float get_item_weightf_in_loc(int id, const map<string,string> &loc) {
897 return (float)get_item_weight_in_loc(id, loc) / (float)0x10000;
898 }
899
900 int validate_weightf(float weight) {
901 uint64_t iweight = weight * 0x10000;
902 if (iweight > std::numeric_limits<int>::max()) {
903 return -EOVERFLOW;
904 }
905 return 0;
906 }
907 int adjust_item_weight(CephContext *cct, int id, int weight);
908 int adjust_item_weightf(CephContext *cct, int id, float weight) {
909 int r = validate_weightf(weight);
910 if (r < 0) {
911 return r;
912 }
913 return adjust_item_weight(cct, id, (int)(weight * (float)0x10000));
914 }
915 int adjust_item_weight_in_loc(CephContext *cct, int id, int weight, const map<string,string>& loc);
916 int adjust_item_weightf_in_loc(CephContext *cct, int id, float weight, const map<string,string>& loc) {
917 int r = validate_weightf(weight);
918 if (r < 0) {
919 return r;
920 }
921 return adjust_item_weight_in_loc(cct, id, (int)(weight * (float)0x10000), loc);
922 }
923 void reweight(CephContext *cct);
924
925 int adjust_subtree_weight(CephContext *cct, int id, int weight);
926 int adjust_subtree_weightf(CephContext *cct, int id, float weight) {
927 int r = validate_weightf(weight);
928 if (r < 0) {
929 return r;
930 }
931 return adjust_subtree_weight(cct, id, (int)(weight * (float)0x10000));
932 }
933
934 /// check if item id is present in the map hierarchy
935 bool check_item_present(int id) const;
936
937
938 /*** devices ***/
939 int get_max_devices() const {
940 if (!crush) return 0;
941 return crush->max_devices;
942 }
943
944
945 /*** rules ***/
946 private:
947 crush_rule *get_rule(unsigned ruleno) const {
948 if (!crush) return (crush_rule *)(-ENOENT);
949 if (ruleno >= crush->max_rules)
950 return 0;
951 return crush->rules[ruleno];
952 }
953 crush_rule_step *get_rule_step(unsigned ruleno, unsigned step) const {
954 crush_rule *n = get_rule(ruleno);
955 if (IS_ERR(n)) return (crush_rule_step *)(-EINVAL);
956 if (step >= n->len) return (crush_rule_step *)(-EINVAL);
957 return &n->steps[step];
958 }
959
960 public:
961 /* accessors */
962 int get_max_rules() const {
963 if (!crush) return 0;
964 return crush->max_rules;
965 }
966 bool rule_exists(unsigned ruleno) const {
967 if (!crush) return false;
968 if (ruleno < crush->max_rules &&
969 crush->rules[ruleno] != NULL)
970 return true;
971 return false;
972 }
973 int get_rule_len(unsigned ruleno) const {
974 crush_rule *r = get_rule(ruleno);
975 if (IS_ERR(r)) return PTR_ERR(r);
976 return r->len;
977 }
978 int get_rule_mask_ruleset(unsigned ruleno) const {
979 crush_rule *r = get_rule(ruleno);
980 if (IS_ERR(r)) return -1;
981 return r->mask.ruleset;
982 }
983 int get_rule_mask_type(unsigned ruleno) const {
984 crush_rule *r = get_rule(ruleno);
985 if (IS_ERR(r)) return -1;
986 return r->mask.type;
987 }
988 int get_rule_mask_min_size(unsigned ruleno) const {
989 crush_rule *r = get_rule(ruleno);
990 if (IS_ERR(r)) return -1;
991 return r->mask.min_size;
992 }
993 int get_rule_mask_max_size(unsigned ruleno) const {
994 crush_rule *r = get_rule(ruleno);
995 if (IS_ERR(r)) return -1;
996 return r->mask.max_size;
997 }
998 int get_rule_op(unsigned ruleno, unsigned step) const {
999 crush_rule_step *s = get_rule_step(ruleno, step);
1000 if (IS_ERR(s)) return PTR_ERR(s);
1001 return s->op;
1002 }
1003 int get_rule_arg1(unsigned ruleno, unsigned step) const {
1004 crush_rule_step *s = get_rule_step(ruleno, step);
1005 if (IS_ERR(s)) return PTR_ERR(s);
1006 return s->arg1;
1007 }
1008 int get_rule_arg2(unsigned ruleno, unsigned step) const {
1009 crush_rule_step *s = get_rule_step(ruleno, step);
1010 if (IS_ERR(s)) return PTR_ERR(s);
1011 return s->arg2;
1012 }
1013
1014 /**
1015 * calculate a map of osds to weights for a given rule
1016 *
1017 * Generate a map of which OSDs get how much relative weight for a
1018 * given rule.
1019 *
1020 * @param ruleno [in] rule id
1021 * @param pmap [out] map of osd to weight
1022 * @return 0 for success, or negative error code
1023 */
1024 int get_rule_weight_osd_map(unsigned ruleno, map<int,float> *pmap);
1025
1026 /* modifiers */
1027
1028 int add_rule(int ruleno, int len, int type, int minsize, int maxsize) {
1029 if (!crush) return -ENOENT;
1030 crush_rule *n = crush_make_rule(len, ruleno, type, minsize, maxsize);
1031 assert(n);
1032 ruleno = crush_add_rule(crush, n, ruleno);
1033 return ruleno;
1034 }
1035 int set_rule_mask_max_size(unsigned ruleno, int max_size) {
1036 crush_rule *r = get_rule(ruleno);
1037 if (IS_ERR(r)) return -1;
1038 return r->mask.max_size = max_size;
1039 }
1040 int set_rule_step(unsigned ruleno, unsigned step, int op, int arg1, int arg2) {
1041 if (!crush) return -ENOENT;
1042 crush_rule *n = get_rule(ruleno);
1043 if (!n) return -1;
1044 crush_rule_set_step(n, step, op, arg1, arg2);
1045 return 0;
1046 }
1047 int set_rule_step_take(unsigned ruleno, unsigned step, int val) {
1048 return set_rule_step(ruleno, step, CRUSH_RULE_TAKE, val, 0);
1049 }
1050 int set_rule_step_set_choose_tries(unsigned ruleno, unsigned step, int val) {
1051 return set_rule_step(ruleno, step, CRUSH_RULE_SET_CHOOSE_TRIES, val, 0);
1052 }
1053 int set_rule_step_set_choose_local_tries(unsigned ruleno, unsigned step, int val) {
1054 return set_rule_step(ruleno, step, CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES, val, 0);
1055 }
1056 int set_rule_step_set_choose_local_fallback_tries(unsigned ruleno, unsigned step, int val) {
1057 return set_rule_step(ruleno, step, CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES, val, 0);
1058 }
1059 int set_rule_step_set_chooseleaf_tries(unsigned ruleno, unsigned step, int val) {
1060 return set_rule_step(ruleno, step, CRUSH_RULE_SET_CHOOSELEAF_TRIES, val, 0);
1061 }
1062 int set_rule_step_set_chooseleaf_vary_r(unsigned ruleno, unsigned step, int val) {
1063 return set_rule_step(ruleno, step, CRUSH_RULE_SET_CHOOSELEAF_VARY_R, val, 0);
1064 }
1065 int set_rule_step_set_chooseleaf_stable(unsigned ruleno, unsigned step, int val) {
1066 return set_rule_step(ruleno, step, CRUSH_RULE_SET_CHOOSELEAF_STABLE, val, 0);
1067 }
1068 int set_rule_step_choose_firstn(unsigned ruleno, unsigned step, int val, int type) {
1069 return set_rule_step(ruleno, step, CRUSH_RULE_CHOOSE_FIRSTN, val, type);
1070 }
1071 int set_rule_step_choose_indep(unsigned ruleno, unsigned step, int val, int type) {
1072 return set_rule_step(ruleno, step, CRUSH_RULE_CHOOSE_INDEP, val, type);
1073 }
1074 int set_rule_step_choose_leaf_firstn(unsigned ruleno, unsigned step, int val, int type) {
1075 return set_rule_step(ruleno, step, CRUSH_RULE_CHOOSELEAF_FIRSTN, val, type);
1076 }
1077 int set_rule_step_choose_leaf_indep(unsigned ruleno, unsigned step, int val, int type) {
1078 return set_rule_step(ruleno, step, CRUSH_RULE_CHOOSELEAF_INDEP, val, type);
1079 }
1080 int set_rule_step_emit(unsigned ruleno, unsigned step) {
1081 return set_rule_step(ruleno, step, CRUSH_RULE_EMIT, 0, 0);
1082 }
1083
1084 int add_simple_rule(
1085 string name, string root_name, string failure_domain_type,
1086 string device_class,
1087 string mode, int rule_type, ostream *err = 0);
1088
1089 /**
1090 * @param rno rule[set] id to use, -1 to pick the lowest available
1091 */
1092 int add_simple_rule_at(
1093 string name, string root_name,
1094 string failure_domain_type, string device_class, string mode,
1095 int rule_type, int rno, ostream *err = 0);
1096
1097 int remove_rule(int ruleno);
1098
1099
1100 /** buckets **/
1101 const crush_bucket *get_bucket(int id) const {
1102 if (!crush)
1103 return (crush_bucket *)(-EINVAL);
1104 unsigned int pos = (unsigned int)(-1 - id);
1105 unsigned int max_buckets = crush->max_buckets;
1106 if (pos >= max_buckets)
1107 return (crush_bucket *)(-ENOENT);
1108 crush_bucket *ret = crush->buckets[pos];
1109 if (ret == NULL)
1110 return (crush_bucket *)(-ENOENT);
1111 return ret;
1112 }
1113 private:
1114 crush_bucket *get_bucket(int id) {
1115 if (!crush)
1116 return (crush_bucket *)(-EINVAL);
1117 unsigned int pos = (unsigned int)(-1 - id);
1118 unsigned int max_buckets = crush->max_buckets;
1119 if (pos >= max_buckets)
1120 return (crush_bucket *)(-ENOENT);
1121 crush_bucket *ret = crush->buckets[pos];
1122 if (ret == NULL)
1123 return (crush_bucket *)(-ENOENT);
1124 return ret;
1125 }
1126 /**
1127 * detach a bucket from its parent and adjust the parent weight
1128 *
1129 * returns the weight of the detached bucket
1130 **/
1131 int detach_bucket(CephContext *cct, int item);
1132
1133 public:
1134 int get_max_buckets() const {
1135 if (!crush) return -EINVAL;
1136 return crush->max_buckets;
1137 }
1138 int get_next_bucket_id() const {
1139 if (!crush) return -EINVAL;
1140 return crush_get_next_bucket_id(crush);
1141 }
1142 bool bucket_exists(int id) const {
1143 const crush_bucket *b = get_bucket(id);
1144 if (IS_ERR(b))
1145 return false;
1146 return true;
1147 }
1148 int get_bucket_weight(int id) const {
1149 const crush_bucket *b = get_bucket(id);
1150 if (IS_ERR(b)) return PTR_ERR(b);
1151 return b->weight;
1152 }
1153 float get_bucket_weightf(int id) const {
1154 const crush_bucket *b = get_bucket(id);
1155 if (IS_ERR(b)) return 0;
1156 return b->weight / (float)0x10000;
1157 }
1158 int get_bucket_type(int id) const {
1159 const crush_bucket *b = get_bucket(id);
1160 if (IS_ERR(b)) return PTR_ERR(b);
1161 return b->type;
1162 }
1163 int get_bucket_alg(int id) const {
1164 const crush_bucket *b = get_bucket(id);
1165 if (IS_ERR(b)) return PTR_ERR(b);
1166 return b->alg;
1167 }
1168 int get_bucket_hash(int id) const {
1169 const crush_bucket *b = get_bucket(id);
1170 if (IS_ERR(b)) return PTR_ERR(b);
1171 return b->hash;
1172 }
1173 int get_bucket_size(int id) const {
1174 const crush_bucket *b = get_bucket(id);
1175 if (IS_ERR(b)) return PTR_ERR(b);
1176 return b->size;
1177 }
1178 int get_bucket_item(int id, int pos) const {
1179 const crush_bucket *b = get_bucket(id);
1180 if (IS_ERR(b)) return PTR_ERR(b);
1181 if ((__u32)pos >= b->size)
1182 return PTR_ERR(b);
1183 return b->items[pos];
1184 }
1185 int get_bucket_item_weight(int id, int pos) const {
1186 const crush_bucket *b = get_bucket(id);
1187 if (IS_ERR(b)) return PTR_ERR(b);
1188 return crush_get_bucket_item_weight(b, pos);
1189 }
1190 float get_bucket_item_weightf(int id, int pos) const {
1191 const crush_bucket *b = get_bucket(id);
1192 if (IS_ERR(b)) return 0;
1193 return (float)crush_get_bucket_item_weight(b, pos) / (float)0x10000;
1194 }
1195
1196 /* modifiers */
1197 int add_bucket(int bucketno, int alg, int hash, int type, int size,
1198 int *items, int *weights, int *idout);
1199 int bucket_add_item(crush_bucket *bucket, int item, int weight);
1200 int bucket_remove_item(struct crush_bucket *bucket, int item);
1201 int bucket_adjust_item_weight(CephContext *cct, struct crush_bucket *bucket, int item, int weight);
1202
1203 void finalize() {
1204 assert(crush);
1205 crush_finalize(crush);
1206 have_uniform_rules = !has_legacy_rulesets();
1207 }
1208
1209 int update_device_class(int id, const string& class_name, const string& name, ostream *ss);
1210 int remove_device_class(CephContext *cct, int id, ostream *ss);
1211 int device_class_clone(int original, int device_class, int *clone);
1212 bool class_is_in_use(int class_id, ostream *ss = nullptr);
1213 int populate_classes();
1214 int rebuild_roots_with_classes();
1215 /* remove unused roots generated for class devices */
1216 int trim_roots_with_class(bool unused);
1217 int cleanup_classes();
1218
1219 void start_choose_profile() {
1220 free(crush->choose_tries);
1221 /*
1222 * the original choose_total_tries value was off by one (it
1223 * counted "retries" and not "tries"). add one to alloc.
1224 */
1225 crush->choose_tries = (__u32 *)calloc(sizeof(*crush->choose_tries),
1226 (crush->choose_total_tries + 1));
1227 memset(crush->choose_tries, 0,
1228 sizeof(*crush->choose_tries) * (crush->choose_total_tries + 1));
1229 }
1230 void stop_choose_profile() {
1231 free(crush->choose_tries);
1232 crush->choose_tries = 0;
1233 }
1234
1235 int get_choose_profile(__u32 **vec) {
1236 if (crush->choose_tries) {
1237 *vec = crush->choose_tries;
1238 return crush->choose_total_tries;
1239 }
1240 return 0;
1241 }
1242
1243
1244 void set_max_devices(int m) {
1245 crush->max_devices = m;
1246 }
1247
1248 int find_rule(int ruleset, int type, int size) const {
1249 if (!crush) return -1;
1250 if (!have_uniform_rules) {
1251 return crush_find_rule(crush, ruleset, type, size);
1252 } else {
1253 if (ruleset < (int)crush->max_rules &&
1254 crush->rules[ruleset])
1255 return ruleset;
1256 return -1;
1257 }
1258 }
1259
1260 bool ruleset_exists(int const ruleset) const {
1261 for (size_t i = 0; i < crush->max_rules; ++i) {
1262 if (rule_exists(i) && crush->rules[i]->mask.ruleset == ruleset) {
1263 return true;
1264 }
1265 }
1266
1267 return false;
1268 }
1269
1270 /**
1271 * Return the lowest numbered ruleset of type `type`
1272 *
1273 * @returns a ruleset ID, or -1 if no matching rulesets found.
1274 */
1275 int find_first_ruleset(int type) const {
1276 int result = -1;
1277
1278 for (size_t i = 0; i < crush->max_rules; ++i) {
1279 if (crush->rules[i]
1280 && crush->rules[i]->mask.type == type
1281 && (crush->rules[i]->mask.ruleset < result || result == -1)) {
1282 result = crush->rules[i]->mask.ruleset;
1283 }
1284 }
1285
1286 return result;
1287 }
1288
1289 bool have_choose_args(int64_t choose_args_index) const {
1290 return choose_args.count(choose_args_index);
1291 }
1292
1293 crush_choose_arg_map choose_args_get_with_fallback(
1294 int64_t choose_args_index) const {
1295 auto i = choose_args.find(choose_args_index);
1296 if (i == choose_args.end()) {
1297 i = choose_args.find(DEFAULT_CHOOSE_ARGS);
1298 }
1299 if (i == choose_args.end()) {
1300 crush_choose_arg_map arg_map;
1301 arg_map.args = NULL;
1302 arg_map.size = 0;
1303 return arg_map;
1304 } else {
1305 return i->second;
1306 }
1307 }
1308 crush_choose_arg_map choose_args_get(int64_t choose_args_index) const {
1309 auto i = choose_args.find(choose_args_index);
1310 if (i == choose_args.end()) {
1311 crush_choose_arg_map arg_map;
1312 arg_map.args = NULL;
1313 arg_map.size = 0;
1314 return arg_map;
1315 } else {
1316 return i->second;
1317 }
1318 }
1319
1320 void destroy_choose_args(crush_choose_arg_map arg_map) {
1321 for (__u32 i = 0; i < arg_map.size; i++) {
1322 crush_choose_arg *arg = &arg_map.args[i];
1323 for (__u32 j = 0; j < arg->weight_set_size; j++) {
1324 crush_weight_set *weight_set = &arg->weight_set[j];
1325 free(weight_set->weights);
1326 }
1327 if (arg->weight_set)
1328 free(arg->weight_set);
1329 if (arg->ids)
1330 free(arg->ids);
1331 }
1332 free(arg_map.args);
1333 }
1334
1335 void create_choose_args(int64_t id, int positions) {
1336 if (choose_args.count(id))
1337 return;
1338 assert(positions);
1339 auto &cmap = choose_args[id];
1340 cmap.args = (crush_choose_arg*)calloc(sizeof(crush_choose_arg),
1341 crush->max_buckets);
1342 cmap.size = crush->max_buckets;
1343 for (int bidx=0; bidx < crush->max_buckets; ++bidx) {
1344 crush_bucket *b = crush->buckets[bidx];
1345 auto &carg = cmap.args[bidx];
1346 carg.ids = NULL;
1347 carg.ids_size = 0;
1348 if (b && b->alg == CRUSH_BUCKET_STRAW2) {
1349 crush_bucket_straw2 *sb = (crush_bucket_straw2*)b;
1350 carg.weight_set_size = positions;
1351 carg.weight_set = (crush_weight_set*)calloc(sizeof(crush_weight_set),
1352 carg.weight_set_size);
1353 // initialize with canonical weights
1354 for (int pos = 0; pos < positions; ++pos) {
1355 carg.weight_set[pos].size = b->size;
1356 carg.weight_set[pos].weights = (__u32*)calloc(4, b->size);
1357 for (unsigned i = 0; i < b->size; ++i) {
1358 carg.weight_set[pos].weights[i] = sb->item_weights[i];
1359 }
1360 }
1361 } else {
1362 carg.weight_set = NULL;
1363 carg.weight_set_size = 0;
1364 }
1365 }
1366 }
1367
1368 void rm_choose_args(int64_t id) {
1369 auto p = choose_args.find(id);
1370 if (p != choose_args.end()) {
1371 destroy_choose_args(p->second);
1372 choose_args.erase(p);
1373 }
1374 }
1375
1376 void choose_args_clear() {
1377 for (auto w : choose_args)
1378 destroy_choose_args(w.second);
1379 choose_args.clear();
1380 }
1381
1382 // adjust choose_args_map weight, preserving the hierarchical summation
1383 // property. used by callers optimizing layouts by tweaking weights.
1384 int _choose_args_adjust_item_weight_in_bucket(
1385 CephContext *cct,
1386 crush_choose_arg_map cmap,
1387 int bucketid,
1388 int id,
1389 const vector<int>& weight,
1390 ostream *ss);
1391 int choose_args_adjust_item_weight(
1392 CephContext *cct,
1393 crush_choose_arg_map cmap,
1394 int id, const vector<int>& weight,
1395 ostream *ss);
1396 int choose_args_adjust_item_weightf(
1397 CephContext *cct,
1398 crush_choose_arg_map cmap,
1399 int id, const vector<double>& weightf,
1400 ostream *ss) {
1401 vector<int> weight(weightf.size());
1402 for (unsigned i = 0; i < weightf.size(); ++i) {
1403 weight[i] = (int)(weightf[i] * (float)0x10000);
1404 }
1405 return choose_args_adjust_item_weight(cct, cmap, id, weight, ss);
1406 }
1407
1408 int get_choose_args_positions(crush_choose_arg_map cmap) {
1409 // infer positions from other buckets
1410 for (unsigned j = 0; j < cmap.size; ++j) {
1411 if (cmap.args[j].weight_set_size) {
1412 return cmap.args[j].weight_set_size;
1413 }
1414 }
1415 return 1;
1416 }
1417
1418 template<typename WeightVector>
1419 void do_rule(int rule, int x, vector<int>& out, int maxout,
1420 const WeightVector& weight,
1421 uint64_t choose_args_index) const {
1422 int rawout[maxout];
1423 char work[crush_work_size(crush, maxout)];
1424 crush_init_workspace(crush, work);
1425 crush_choose_arg_map arg_map = choose_args_get_with_fallback(
1426 choose_args_index);
1427 int numrep = crush_do_rule(crush, rule, x, rawout, maxout, &weight[0],
1428 weight.size(), work, arg_map.args);
1429 if (numrep < 0)
1430 numrep = 0;
1431 out.resize(numrep);
1432 for (int i=0; i<numrep; i++)
1433 out[i] = rawout[i];
1434 }
1435
1436 int _choose_type_stack(
1437 CephContext *cct,
1438 const vector<pair<int,int>>& stack,
1439 const set<int>& overfull,
1440 const vector<int>& underfull,
1441 const vector<int>& orig,
1442 vector<int>::const_iterator& i,
1443 set<int>& used,
1444 vector<int> *pw) const;
1445
1446 int try_remap_rule(
1447 CephContext *cct,
1448 int rule,
1449 int maxout,
1450 const set<int>& overfull,
1451 const vector<int>& underfull,
1452 const vector<int>& orig,
1453 vector<int> *out) const;
1454
1455 bool check_crush_rule(int ruleset, int type, int size, ostream& ss) {
1456 assert(crush);
1457
1458 __u32 i;
1459 for (i = 0; i < crush->max_rules; i++) {
1460 if (crush->rules[i] &&
1461 crush->rules[i]->mask.ruleset == ruleset &&
1462 crush->rules[i]->mask.type == type) {
1463
1464 if (crush->rules[i]->mask.min_size <= size &&
1465 crush->rules[i]->mask.max_size >= size) {
1466 return true;
1467 } else if (size < crush->rules[i]->mask.min_size) {
1468 ss << "pool size is smaller than the crush rule min size";
1469 return false;
1470 } else {
1471 ss << "pool size is bigger than the crush rule max size";
1472 return false;
1473 }
1474 }
1475 }
1476
1477 return false;
1478 }
1479
1480 void encode(bufferlist &bl, uint64_t features) const;
1481 void decode(bufferlist::iterator &blp);
1482 void decode_crush_bucket(crush_bucket** bptr, bufferlist::iterator &blp);
1483 void dump(Formatter *f) const;
1484 void dump_rules(Formatter *f) const;
1485 void dump_rule(int ruleset, Formatter *f) const;
1486 void dump_tunables(Formatter *f) const;
1487 void dump_choose_args(Formatter *f) const;
1488 void list_rules(Formatter *f) const;
1489 void list_rules(ostream *ss) const;
1490 void dump_tree(ostream *out,
1491 Formatter *f,
1492 const CrushTreeDumper::name_map_t& ws,
1493 bool show_shadow = false) const;
1494 void dump_tree(ostream *out, Formatter *f) {
1495 dump_tree(out, f, CrushTreeDumper::name_map_t());
1496 }
1497 void dump_tree(Formatter *f,
1498 const CrushTreeDumper::name_map_t& ws) const;
1499 static void generate_test_instances(list<CrushWrapper*>& o);
1500
1501 int get_osd_pool_default_crush_replicated_ruleset(CephContext *cct);
1502
1503 static bool is_valid_crush_name(const string& s);
1504 static bool is_valid_crush_loc(CephContext *cct,
1505 const map<string,string>& loc);
1506 };
1507 WRITE_CLASS_ENCODER_FEATURES(CrushWrapper)
1508
1509 #endif