std::map<int32_t, string> type_map; /* bucket/device type names */
std::map<int32_t, string> name_map; /* bucket/device names */
std::map<int32_t, string> rule_name_map;
+
std::map<int32_t, int32_t> class_map; /* item id -> class id */
std::map<int32_t, string> class_name; /* class id -> class name */
std::map<string, int32_t> class_rname; /* class name -> class id */
std::map<int64_t, crush_choose_arg_map> choose_args;
private:
- struct crush_map *crush;
+ struct crush_map *crush = nullptr;
bool have_uniform_rules = false;
/* reverse maps */
- mutable bool have_rmaps;
+ mutable bool have_rmaps = false;
mutable std::map<string, int> type_rmap, name_rmap, rule_name_rmap;
void build_rmaps() const {
if (have_rmaps) return;
CrushWrapper(const CrushWrapper& other);
const CrushWrapper& operator=(const CrushWrapper& other);
- CrushWrapper() : crush(0), have_rmaps(false) {
+ CrushWrapper() {
create();
}
~CrushWrapper() {
set_tunables_default();
}
- /// true if any rule has a ruleset != the rule id
- bool has_legacy_rulesets() const;
-
- /// fix rules whose ruleid != ruleset
- int renumber_rules_by_ruleset();
+ /**
+ * true if any rule has a rule id != its position in the array
+ *
+ * These indicate "ruleset" IDs that were created by older versions
+ * of Ceph. They are cleaned up in renumber_rules so that eventually
+ * we can remove the code for handling them.
+ */
+ bool has_legacy_rule_ids() const;
- /// true if any ruleset has more than 1 rule
- bool has_multirule_rulesets() const;
+ /**
+ * fix rules whose ruleid != ruleset
+ *
+ * These rules were created in older versions of Ceph. The concept
+ * of a ruleset no longer exists.
+ *
+ * Return a map of old ID -> new ID. Caller must update OSDMap
+ * to use new IDs.
+ */
+ std::map<int, int> renumber_rules();
/// true if any buckets that aren't straw2
bool has_non_straw2_buckets() const;
ostream *ss);
// rule names
+ int rename_rule(const string& srcname,
+ const string& dstname,
+ ostream *ss);
bool rule_exists(string name) const {
build_rmaps();
return rule_name_rmap.count(name);
*
* Note that these may not be parentless roots.
*/
- void find_takes(set<int>& roots) const;
+ void find_takes(set<int> *roots) const;
+ void find_takes_by_rule(int rule, set<int> *roots) const;
/**
* find tree roots
*
* These are parentless nodes in the map.
*/
- void find_roots(set<int>& roots) const;
+ void find_roots(set<int> *roots) const;
/**
* find tree roots that contain shadow (device class) items only
*/
- void find_shadow_roots(set<int>& roots) const {
+ void find_shadow_roots(set<int> *roots) const {
set<int> all;
- find_roots(all);
+ find_roots(&all);
for (auto& p: all) {
if (is_shadow_item(p)) {
- roots.insert(p);
+ roots->insert(p);
}
}
}
* These are parentless nodes in the map that are not shadow
* items for device classes.
*/
- void find_nonshadow_roots(set<int>& roots) const {
+ void find_nonshadow_roots(set<int> *roots) const {
set<int> all;
- find_roots(all);
+ find_roots(&all);
for (auto& p: all) {
if (!is_shadow_item(p)) {
- roots.insert(p);
+ roots->insert(p);
}
}
}
/**
* return ancestor of the given type, or 0 if none
+ * can pass in a specific crush **rule** to return ancestor from that rule only
* (parent is always a bucket and thus <0)
*/
- int get_parent_of_type(int id, int type) const;
+ int get_parent_of_type(int id, int type, int rule = -1) const;
/**
* get the fully qualified location of a device by successively finding
* @return number of items, or error
*/
int get_children(int id, list<int> *children);
+ void get_children_of_type(int id,
+ int type,
+ set<int> *children,
+ bool exclude_shadow = true) const;
+
+ /**
+ * get failure-domain type of a specific crush rule
+ * @param rule_id crush rule id
+ * @return type of failure-domain or a negative errno on error.
+ */
+ int get_rule_failure_domain(int rule_id);
/**
* enumerate leaves(devices) of given node
* when a bucket is in use.
*
* @param item id to remove
- * @param unused true if only unused items should be removed
* @return 0 on success, negative on error
*/
- int remove_root(int item, bool unused);
+ int remove_root(int item);
/**
* remove all instances of an item nested beneath a certain point from the map
return true;
return false;
}
+ bool rule_has_take(unsigned ruleno, int take) const {
+ if (!crush) return false;
+ crush_rule *rule = get_rule(ruleno);
+ for (unsigned i = 0; i < rule->len; ++i) {
+ if (rule->steps[i].op == CRUSH_RULE_TAKE &&
+ rule->steps[i].arg1 == take) {
+ return true;
+ }
+ }
+ return false;
+ }
int get_rule_len(unsigned ruleno) const {
crush_rule *r = get_rule(ruleno);
if (IS_ERR(r)) return PTR_ERR(r);
return s->arg2;
}
+private:
+ float _get_take_weight_osd_map(int root, map<int,float> *pmap) const;
+ void _normalize_weight_map(float sum, const map<int,float>& m,
+ map<int,float> *pmap) const;
+
+public:
/**
* calculate a map of osds to weights for a given rule
*
* @param pmap [out] map of osd to weight
* @return 0 for success, or negative error code
*/
- int get_rule_weight_osd_map(unsigned ruleno, map<int,float> *pmap);
+ int get_rule_weight_osd_map(unsigned ruleno, map<int,float> *pmap) const;
+
+ /**
+ * calculate a map of osds to weights for a given starting root
+ *
+ * Generate a map of which OSDs get how much relative weight for a
+ * given starting root
+ *
+ * @param root node
+ * @param pmap [out] map of osd to weight
+ * @return 0 for success, or negative error code
+ */
+ int get_take_weight_osd_map(int root, map<int,float> *pmap) const;
/* modifiers */
void finalize() {
assert(crush);
crush_finalize(crush);
- have_uniform_rules = !has_legacy_rulesets();
+ if (!name_map.empty() &&
+ name_map.rbegin()->first >= crush->max_devices) {
+ crush->max_devices = name_map.rbegin()->first + 1;
+ }
+ have_uniform_rules = !has_legacy_rule_ids();
}
+ int bucket_set_alg(int id, int alg);
int update_device_class(int id, const string& class_name, const string& name, ostream *ss);
int remove_device_class(CephContext *cct, int id, ostream *ss);
- int device_class_clone(int original, int device_class, int *clone);
- bool class_is_in_use(int class_id, ostream *ss = nullptr);
- int populate_classes();
+ int device_class_clone(
+ int original, int device_class,
+ const std::map<int32_t, map<int32_t, int32_t>>& old_class_bucket,
+ const std::set<int32_t>& used_ids,
+ int *clone,
+ map<int,map<int,vector<int>>> *cmap_item_weight);
+ int rename_class(const string& srcname, const string& dstname);
+ int populate_classes(
+ const std::map<int32_t, map<int32_t, int32_t>>& old_class_bucket);
+ int get_rules_by_class(const string &class_name, set<int> *rules);
+ int get_rules_by_osd(int osd, set<int> *rules);
+ bool _class_is_dead(int class_id);
+ void cleanup_dead_classes();
int rebuild_roots_with_classes();
/* remove unused roots generated for class devices */
- int trim_roots_with_class(bool unused);
- int cleanup_classes();
+ int trim_roots_with_class();
void start_choose_profile() {
free(crush->choose_tries);
int find_rule(int ruleset, int type, int size) const {
if (!crush) return -1;
- if (!have_uniform_rules) {
- return crush_find_rule(crush, ruleset, type, size);
- } else {
- if (ruleset < (int)crush->max_rules &&
- crush->rules[ruleset])
- return ruleset;
- return -1;
+ if (have_uniform_rules &&
+ ruleset < (int)crush->max_rules &&
+ crush->rules[ruleset] &&
+ crush->rules[ruleset]->mask.type == type &&
+ crush->rules[ruleset]->mask.min_size <= size &&
+ crush->rules[ruleset]->mask.max_size >= size) {
+ return ruleset;
}
+ return crush_find_rule(crush, ruleset, type, size);
}
- bool ruleset_exists(int const ruleset) const {
+ bool ruleset_exists(const int ruleset) const {
for (size_t i = 0; i < crush->max_rules; ++i) {
if (rule_exists(i) && crush->rules[i]->mask.ruleset == ruleset) {
return true;
/**
* Return the lowest numbered ruleset of type `type`
*
- * @returns a ruleset ID, or -1 if no matching rulesets found.
+ * @returns a ruleset ID, or -1 if no matching rules found.
*/
int find_first_ruleset(int type) const {
int result = -1;
void destroy_choose_args(crush_choose_arg_map arg_map) {
for (__u32 i = 0; i < arg_map.size; i++) {
crush_choose_arg *arg = &arg_map.args[i];
- for (__u32 j = 0; j < arg->weight_set_size; j++) {
+ for (__u32 j = 0; j < arg->weight_set_positions; j++) {
crush_weight_set *weight_set = &arg->weight_set[j];
free(weight_set->weights);
}
carg.ids_size = 0;
if (b && b->alg == CRUSH_BUCKET_STRAW2) {
crush_bucket_straw2 *sb = (crush_bucket_straw2*)b;
- carg.weight_set_size = positions;
+ carg.weight_set_positions = positions;
carg.weight_set = (crush_weight_set*)calloc(sizeof(crush_weight_set),
- carg.weight_set_size);
+ carg.weight_set_positions);
// initialize with canonical weights
for (int pos = 0; pos < positions; ++pos) {
carg.weight_set[pos].size = b->size;
}
} else {
carg.weight_set = NULL;
- carg.weight_set_size = 0;
+ carg.weight_set_positions = 0;
}
}
}
choose_args.clear();
}
+ // remove choose_args for buckets that no longer exist, create them for new buckets
+ void update_choose_args(CephContext *cct);
+
// adjust choose_args_map weight, preserving the hierarchical summation
// property. used by callers optimizing layouts by tweaking weights.
int _choose_args_adjust_item_weight_in_bucket(
int get_choose_args_positions(crush_choose_arg_map cmap) {
// infer positions from other buckets
for (unsigned j = 0; j < cmap.size; ++j) {
- if (cmap.args[j].weight_set_size) {
- return cmap.args[j].weight_set_size;
+ if (cmap.args[j].weight_set_positions) {
+ return cmap.args[j].weight_set_positions;
}
}
return 1;