#include "builder.h"
}
+#include "include/assert.h"
#include "include/err.h"
#include "include/encoding.h"
#include "common/Mutex.h"
-#include "include/assert.h"
#define BUG_ON(x) assert(!(x))
namespace ceph {
private:
struct crush_map *crush;
+
+ bool have_uniform_rules = false;
+
/* reverse maps */
mutable bool have_rmaps;
mutable std::map<string, int> type_rmap, name_rmap, rule_name_rmap;
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 ruleset has more than 1 rule
+ bool has_multirule_rulesets() const;
+
// tunables
void set_tunables_argonaut() {
crush->choose_local_tries = 2;
crush->straw_calc_version = 1;
}
void set_tunables_default() {
- set_tunables_hammer();
+ set_tunables_jewel();
crush->straw_calc_version = 1;
}
bool has_v3_rules() const;
bool has_v4_buckets() const;
bool has_v5_rules() const;
- bool has_chooseargs() const; // any chooseargs
- bool has_incompat_chooseargs() const; // chooseargs that can't be made compat
+ bool has_choose_args() const; // any choose_args
+ bool has_incompat_choose_args() const; // choose_args that can't be made compat
bool is_v2_rule(unsigned ruleid) const;
bool is_v3_rule(unsigned ruleid) const;
int get_num_type_names() const {
return type_map.size();
}
+ int get_max_type_id() const {
+ if (type_map.empty())
+ return 0;
+ return type_map.rbegin()->first;
+ }
int get_type_id(const string& name) const {
build_rmaps();
if (type_rmap.count(name))
name_rmap[name] = i;
return 0;
}
+ void swap_names(int a, int b) {
+ string an = name_map[a];
+ string bn = name_map[b];
+ name_map[a] = bn;
+ name_map[b] = an;
+ if (have_rmaps) {
+ name_rmap[an] = b;
+ name_rmap[bn] = a;
+ }
+ }
bool id_has_class(int i) {
int idout;
int classout;
return class_rname.count(name);
}
const char *get_class_name(int i) const {
- std::map<int,string>::const_iterator p = class_name.find(i);
+ auto p = class_name.find(i);
if (p != class_name.end())
return p->second.c_str();
return 0;
}
int get_class_id(const string& name) const {
- std::map<string,int>::const_iterator p = class_rname.find(name);
+ auto p = class_rname.find(name);
if (p != class_rname.end())
return p->second;
else
return -EINVAL;
}
int remove_class_name(const string& name) {
- std::map<string,int>::const_iterator p = class_rname.find(name);
+ auto p = class_rname.find(name);
if (p == class_rname.end())
return -ENOENT;
int class_id = p->second;
- std::map<int,string>::const_iterator q = class_name.find(class_id);
+ auto q = class_name.find(class_id);
if (q == class_name.end())
return -ENOENT;
class_rname.erase(name);
class_name.erase(class_id);
return 0;
}
+
+ int rename_class(const string& srcname, const string& dstname) {
+ auto p = class_rname.find(srcname);
+ if (p == class_rname.end())
+ return -ENOENT;
+ int class_id = p->second;
+ auto q = class_name.find(class_id);
+ if (q == class_name.end())
+ return -ENOENT;
+ class_rname.erase(srcname);
+ class_name.erase(class_id);
+ class_rname[dstname] = class_id;
+ class_name[class_id] = dstname;
+ return 0;
+ }
+
+ int32_t _alloc_class_id() const;
+
int get_or_create_class_id(const string& name) {
int c = get_class_id(name);
if (c < 0) {
- int i = class_name.size();
+ int i = _alloc_class_id();
class_name[i] = name;
class_rname[name] = i;
return i;
class_map[i] = c;
return c;
}
-
+ void get_devices_by_class(const string &name, set<int> *devices) const {
+ assert(devices);
+ devices->clear();
+ if (!class_exists(name)) {
+ return;
+ }
+ auto cid = get_class_id(name);
+ for (auto& p : class_map) {
+ if (p.first >= 0 && p.second == cid) {
+ devices->insert(p.first);
+ }
+ }
+ }
+ void class_remove_item(int i) {
+ auto it = class_map.find(i);
+ if (it == class_map.end()) {
+ return;
+ }
+ class_map.erase(it);
+ }
int can_rename_item(const string& srcname,
const string& dstname,
ostream *ss) const;
*/
void find_roots(set<int>& roots) const;
+ /**
+ * find tree roots that are not shadow (device class) items
+ *
+ * These are parentless nodes in the map that are not shadow
+ * items for device classes.
+ */
+ void find_nonshadow_roots(set<int>& roots) const;
+
/**
* see if an item is contained within a subtree
*
pair<string,string> get_immediate_parent(int id, int *ret = NULL);
int get_immediate_parent_id(int id, int *parent) const;
+ /**
+ * return ancestor of the given type, or 0 if none
+ * (parent is always a bucket and thus <0)
+ */
+ int get_parent_of_type(int id, int type) const;
+
/**
* get the fully qualified location of a device by successively finding
* parents beginning at ID and ending at highest type number specified in
*/
int get_full_location_ordered(int id, vector<pair<string, string> >& path);
+ /*
+ * identical to get_full_location_ordered(int id, vector<pair<string, string> >& path),
+ * although it returns a concatenated string with the type/name pairs in descending
+ * hierarchical order with format key1=val1,key2=val2.
+ *
+ * returns the location in descending hierarchy as a string.
+ */
+ string get_full_location_ordered_string(int id);
+
/**
* returns (type_id, type) of all parent buckets between id and
* default, can be used to check for anomolous CRUSH maps
*/
int get_children(int id, list<int> *children);
+ /**
+ * enumerate leaves(devices) of given node
+ *
+ * @param name parent bucket name
+ * @return 0 on success or a negative errno on error.
+ */
+ int get_leaves(const string &name, set<int> *leaves);
+ int _get_leaves(int id, list<int> *leaves); // worker
+
/**
* insert an item into the map at a specific position
*
*/
int move_bucket(CephContext *cct, int id, const map<string,string>& loc);
+ /**
+ * swap bucket contents of two buckets without touching bucket ids
+ *
+ * @param cct cct
+ * @param src bucket a
+ * @param dst bucket b
+ * @return 0 for success, negative on error
+ */
+ int swap_bucket(CephContext *cct, int src, int dst);
+
/**
* add a link to an existing bucket in the hierarchy to the new location
*
return (float)get_item_weight_in_loc(id, loc) / (float)0x10000;
}
+ int validate_weightf(float weight) {
+ uint64_t iweight = weight * 0x10000;
+ if (iweight > std::numeric_limits<int>::max()) {
+ return -EOVERFLOW;
+ }
+ return 0;
+ }
int adjust_item_weight(CephContext *cct, int id, int weight);
int adjust_item_weightf(CephContext *cct, int id, float weight) {
+ int r = validate_weightf(weight);
+ if (r < 0) {
+ return r;
+ }
return adjust_item_weight(cct, id, (int)(weight * (float)0x10000));
}
int adjust_item_weight_in_loc(CephContext *cct, int id, int weight, const map<string,string>& loc);
int adjust_item_weightf_in_loc(CephContext *cct, int id, float weight, const map<string,string>& loc) {
+ int r = validate_weightf(weight);
+ if (r < 0) {
+ return r;
+ }
return adjust_item_weight_in_loc(cct, id, (int)(weight * (float)0x10000), loc);
}
void reweight(CephContext *cct);
int adjust_subtree_weight(CephContext *cct, int id, int weight);
int adjust_subtree_weightf(CephContext *cct, int id, float weight) {
+ int r = validate_weightf(weight);
+ if (r < 0) {
+ return r;
+ }
return adjust_subtree_weight(cct, id, (int)(weight * (float)0x10000));
}
return set_rule_step(ruleno, step, CRUSH_RULE_EMIT, 0, 0);
}
- int add_simple_ruleset(string name, string root_name, string failure_domain_type,
- string mode, int rule_type, ostream *err = 0);
+ int add_simple_rule(
+ string name, string root_name, string failure_domain_type,
+ string device_class,
+ string mode, int rule_type, ostream *err = 0);
+
/**
- * @param rno ruleset id to use, -1 to pick the lowest available
+ * @param rno rule[set] id to use, -1 to pick the lowest available
*/
- int add_simple_ruleset_at(string name, string root_name,
- string failure_domain_type, string mode,
- int rule_type, int rno, ostream *err = 0);
+ int add_simple_rule_at(
+ string name, string root_name,
+ string failure_domain_type, string device_class, string mode,
+ int rule_type, int rno, ostream *err = 0);
int remove_rule(int ruleno);
if (!IS_ERR(parent_bucket)) {
// zero out the bucket weight
- crush_bucket_adjust_item_weight(crush, parent_bucket, item, 0);
+ bucket_adjust_item_weight(cct, parent_bucket, item, 0);
adjust_item_weight(cct, parent_bucket->id, parent_bucket->weight);
// remove the bucket from the parent
- crush_bucket_remove_item(crush, parent_bucket, item);
+ bucket_remove_item(parent_bucket, item);
} else if (PTR_ERR(parent_bucket) != -ENOENT) {
return PTR_ERR(parent_bucket);
}
assert(b);
return crush_add_bucket(crush, bucketno, b, idout);
}
-
+
+ int bucket_add_item(crush_bucket *bucket, int item, int weight);
+ int bucket_remove_item(struct crush_bucket *bucket, int item);
+ int bucket_adjust_item_weight(CephContext *cct, struct crush_bucket *bucket, int item, int weight);
+
void finalize() {
assert(crush);
crush_finalize(crush);
+ have_uniform_rules = !has_legacy_rulesets();
}
- int update_device_class(CephContext *cct, int id, const string& class_name, const string& name);
+ int update_device_class(int id, const string& class_name, const string& name, ostream *ss);
int device_class_clone(int original, int device_class, int *clone);
bool class_is_in_use(int class_id);
int populate_classes();
int find_rule(int ruleset, int type, int size) const {
if (!crush) return -1;
- return crush_find_rule(crush, ruleset, type, size);
+ 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;
+ }
}
bool ruleset_exists(int const ruleset) const {
void dump_tree(Formatter *f) const;
static void generate_test_instances(list<CrushWrapper*>& o);
- int _get_osd_pool_default_crush_replicated_ruleset(CephContext *cct,
- bool quiet);
int get_osd_pool_default_crush_replicated_ruleset(CephContext *cct);
static bool is_valid_crush_name(const string& s);