#define dout_subsys ceph_subsys_crush
-bool CrushWrapper::has_legacy_rulesets() const
+bool CrushWrapper::has_legacy_rule_ids() const
{
for (unsigned i=0; i<crush->max_rules; i++) {
crush_rule *r = crush->rules[i];
return false;
}
-int CrushWrapper::renumber_rules_by_ruleset()
+std::map<int, int> CrushWrapper::renumber_rules()
{
- int max_ruleset = 0;
+ std::map<int, int> result;
for (unsigned i=0; i<crush->max_rules; i++) {
crush_rule *r = crush->rules[i];
- if (r && r->mask.ruleset >= max_ruleset) {
- max_ruleset = r->mask.ruleset + 1;
+ if (r && r->mask.ruleset != i) {
+ result[r->mask.ruleset] = i;
+ r->mask.ruleset = i;
}
}
- struct crush_rule **newrules =
- (crush_rule**)calloc(1, max_ruleset * sizeof(crush_rule*));
- for (unsigned i=0; i<crush->max_rules; i++) {
- crush_rule *r = crush->rules[i];
- if (!r)
- continue;
- if (newrules[r->mask.ruleset]) {
- // collision, we can't do it.
- free(newrules);
- return -EINVAL;
- }
- newrules[r->mask.ruleset] = r;
- }
-
- // success, swap!
- free(crush->rules);
- crush->rules = newrules;
- crush->max_rules = max_ruleset;
- return 0;
-}
-
-bool CrushWrapper::has_multirule_rulesets() const
-{
- for (unsigned i=0; i<crush->max_rules; i++) {
- crush_rule *r = crush->rules[i];
- if (!r)
- continue;
- for (unsigned j=i+1; j<crush->max_rules; j++) {
- crush_rule *s = crush->rules[j];
- if (!s)
- continue;
- if (r->mask.ruleset == s->mask.ruleset)
- return true;
- }
- }
- return false;
+ return result;
}
bool CrushWrapper::has_non_straw2_buckets() const
crush_choose_arg_map arg_map = choose_args.begin()->second;
for (__u32 i = 0; i < arg_map.size; i++) {
crush_choose_arg *arg = &arg_map.args[i];
- if (arg->weight_set_size == 0 &&
+ if (arg->weight_set_positions == 0 &&
arg->ids_size == 0)
continue;
- if (arg->weight_set_size != 1)
+ if (arg->weight_set_positions != 1)
return true;
if (arg->ids_size != 0)
return true;
return set_item_name(oldid, dstname);
}
-void CrushWrapper::find_takes(set<int>& roots) const
+int CrushWrapper::rename_rule(const string& srcname,
+ const string& dstname,
+ ostream *ss)
+{
+ if (!rule_exists(srcname)) {
+ if (ss) {
+ *ss << "source rule name '" << srcname << "' does not exist";
+ }
+ return -ENOENT;
+ }
+ if (rule_exists(dstname)) {
+ if (ss) {
+ *ss << "destination rule name '" << dstname << "' already exists";
+ }
+ return -EEXIST;
+ }
+ int rule_id = get_rule_id(srcname);
+ auto it = rule_name_map.find(rule_id);
+ assert(it != rule_name_map.end());
+ it->second = dstname;
+ if (have_rmaps) {
+ rule_name_rmap.erase(srcname);
+ rule_name_rmap[dstname] = rule_id;
+ }
+ return 0;
+}
+
+void CrushWrapper::find_takes(set<int> *roots) const
{
for (unsigned i=0; i<crush->max_rules; i++) {
crush_rule *r = crush->rules[i];
continue;
for (unsigned j=0; j<r->len; j++) {
if (r->steps[j].op == CRUSH_RULE_TAKE)
- roots.insert(r->steps[j].arg1);
+ roots->insert(r->steps[j].arg1);
}
}
}
-void CrushWrapper::find_roots(set<int>& roots) const
+void CrushWrapper::find_takes_by_rule(int rule, set<int> *roots) const
+{
+ if (rule < 0 || rule >= (int)crush->max_rules)
+ return;
+ crush_rule *r = crush->rules[rule];
+ if (!r)
+ return;
+ for (unsigned i = 0; i < r->len; i++) {
+ if (r->steps[i].op == CRUSH_RULE_TAKE)
+ roots->insert(r->steps[i].arg1);
+ }
+}
+
+void CrushWrapper::find_roots(set<int> *roots) const
{
for (int i = 0; i < crush->max_buckets; i++) {
if (!crush->buckets[i])
continue;
crush_bucket *b = crush->buckets[i];
if (!_search_item_exists(b->id))
- roots.insert(b->id);
+ roots->insert(b->id);
}
}
if (class_bucket.count(item) != 0)
class_bucket.erase(item);
class_remove_item(item);
+ update_choose_args(cct);
}
if ((item >= 0 || !unlink_only) && name_map.count(item)) {
ldout(cct, 5) << "_maybe_remove_last_instance removing name for item " << item << dendl;
if (class_bucket.count(item) != 0)
class_bucket.erase(item);
class_remove_item(item);
+ update_choose_args(nullptr);
return 0;
}
+void CrushWrapper::update_choose_args(CephContext *cct)
+{
+ for (auto& i : choose_args) {
+ crush_choose_arg_map &arg_map = i.second;
+ unsigned positions = get_choose_args_positions(arg_map);
+ for (int j = 0; j < crush->max_buckets; ++j) {
+ crush_bucket *b = crush->buckets[j];
+ auto& carg = arg_map.args[j];
+ // strip out choose_args for any buckets that no longer exist
+ if (!b || b->alg != CRUSH_BUCKET_STRAW2) {
+ if (carg.ids) {
+ if (cct)
+ ldout(cct,0) << __func__ << " removing " << i.first << " bucket "
+ << (-1-j) << " ids" << dendl;
+ free(carg.ids);
+ carg.ids = 0;
+ carg.ids_size = 0;
+ }
+ if (carg.weight_set) {
+ if (cct)
+ ldout(cct,0) << __func__ << " removing " << i.first << " bucket "
+ << (-1-j) << " weight_sets" << dendl;
+ for (unsigned p = 0; p < carg.weight_set_positions; ++p) {
+ free(carg.weight_set[p].weights);
+ }
+ free(carg.weight_set);
+ carg.weight_set = 0;
+ carg.weight_set_positions = 0;
+ }
+ continue;
+ }
+ if (carg.weight_set_positions == 0) {
+ continue; // skip it
+ }
+ if (carg.weight_set_positions != positions) {
+ if (cct)
+ lderr(cct) << __func__ << " " << i.first << " bucket "
+ << (-1-j) << " positions " << carg.weight_set_positions
+ << " -> " << positions << dendl;
+ continue; // wth... skip!
+ }
+ // mis-sized weight_sets? this shouldn't ever happen.
+ for (unsigned p = 0; p < positions; ++p) {
+ if (carg.weight_set[p].size != b->size) {
+ if (cct)
+ lderr(cct) << __func__ << " fixing " << i.first << " bucket "
+ << (-1-j) << " position " << p
+ << " size " << carg.weight_set[p].size << " -> "
+ << b->size << dendl;
+ auto old_ws = carg.weight_set[p];
+ carg.weight_set[p].size = b->size;
+ carg.weight_set[p].weights = (__u32*)calloc(b->size, sizeof(__u32));
+ auto max = std::min<unsigned>(old_ws.size, b->size);
+ for (unsigned k = 0; k < max; ++k) {
+ carg.weight_set[p].weights[k] = old_ws.weights[k];
+ }
+ free(old_ws.weights);
+ }
+ }
+ }
+ }
+}
+
int CrushWrapper::remove_item(CephContext *cct, int item, bool unlink_only)
{
ldout(cct, 5) << "remove_item " << item
return false;
}
- ldout(cct, 1) << "check_item_loc item " << item << " loc " << loc << dendl;
+ ldout(cct, 2) << __func__ << " item " << item << " loc " << loc << dendl;
return false;
}
return b->size;
}
+void CrushWrapper::get_children_of_type(int id,
+ int type,
+ set<int> *children,
+ bool exclude_shadow) const
+{
+ if (id >= 0) {
+ if (type == 0) {
+ // want leaf?
+ children->insert(id);
+ }
+ return;
+ }
+ auto b = get_bucket(id);
+ if (IS_ERR(b)) {
+ return;
+ }
+ if (b->type < type) {
+ // give up
+ return;
+ } else if (b->type == type) {
+ if (!is_shadow_item(b->id) || !exclude_shadow) {
+ children->insert(b->id);
+ }
+ return;
+ }
+ for (unsigned n = 0; n < b->size; n++) {
+ get_children_of_type(b->items[n], type, children, exclude_shadow);
+ }
+}
+
+int CrushWrapper::get_rule_failure_domain(int rule_id)
+{
+ crush_rule *rule = get_rule(rule_id);
+ if (IS_ERR(rule)) {
+ return -ENOENT;
+ }
+ int type = 0; // default to osd-level
+ for (unsigned s = 0; s < rule->len; ++s) {
+ if ((rule->steps[s].op == CRUSH_RULE_CHOOSE_FIRSTN ||
+ rule->steps[s].op == CRUSH_RULE_CHOOSE_INDEP ||
+ rule->steps[s].op == CRUSH_RULE_CHOOSELEAF_FIRSTN ||
+ rule->steps[s].op == CRUSH_RULE_CHOOSELEAF_INDEP) &&
+ rule->steps[s].arg2 > type) {
+ type = rule->steps[s].arg2;
+ }
+ }
+ return type;
+}
+
int CrushWrapper::_get_leaves(int id, list<int> *leaves)
{
assert(leaves);
// swap names
swap_names(src, dst);
- return 0;
+ return rebuild_roots_with_classes();
}
int CrushWrapper::link_bucket(
return -ENOENT;
}
-int CrushWrapper::get_parent_of_type(int item, int type) const
+int CrushWrapper::get_parent_of_type(int item, int type, int rule) const
{
- do {
- int r = get_immediate_parent_id(item, &item);
- if (r < 0) {
- return 0;
+ if (rule < 0) {
+ // no rule specified
+ do {
+ int r = get_immediate_parent_id(item, &item);
+ if (r < 0) {
+ return 0;
+ }
+ } while (get_bucket_type(item) != type);
+ return item;
+ }
+ set<int> roots;
+ find_takes_by_rule(rule, &roots);
+ for (auto root : roots) {
+ set<int> candidates;
+ get_children_of_type(root, type, &candidates, false);
+ for (auto candidate : candidates) {
+ if (subtree_contains(candidate, item)) {
+ // note that here we assure that no two different buckets
+ // from a single crush rule will share a same device,
+ // which should generally be true.
+ return candidate;
+ }
}
- } while (get_bucket_type(item) != type);
- return item;
+ }
+ return 0; // not found
}
int CrushWrapper::rename_class(const string& srcname, const string& dstname)
// accumulate weight values for each carg and bucket as we go. because it is
// depth first, we will have the nested bucket weights we need when we
// finish constructing the containing buckets.
- map<int,map<int,vector<int>>> cmap_item_weight; // cargs -> bno -> weights
+ map<int,map<int,vector<int>>> cmap_item_weight; // cargs -> bno -> [bucket weight for each position]
set<int> roots;
- find_nonshadow_roots(roots);
+ find_nonshadow_roots(&roots);
for (auto &r : roots) {
if (r >= 0)
continue;
int CrushWrapper::trim_roots_with_class()
{
set<int> roots;
- find_shadow_roots(roots);
+ find_shadow_roots(&roots);
for (auto &r : roots) {
if (r >= 0)
continue;
void CrushWrapper::reweight(CephContext *cct)
{
set<int> roots;
- find_roots(roots);
+ find_roots(&roots);
for (set<int>::iterator p = roots.begin(); p != roots.end(); ++p) {
if (*p >= 0)
continue;
rule_type, -1, err);
}
-int CrushWrapper::get_rule_weight_osd_map(unsigned ruleno, map<int,float> *pmap)
+float CrushWrapper::_get_take_weight_osd_map(int root,
+ map<int,float> *pmap) const
+{
+ float sum = 0.0;
+ list<int> q;
+ q.push_back(root);
+ //breadth first iterate the OSD tree
+ while (!q.empty()) {
+ int bno = q.front();
+ q.pop_front();
+ crush_bucket *b = crush->buckets[-1-bno];
+ assert(b);
+ for (unsigned j=0; j<b->size; ++j) {
+ int item_id = b->items[j];
+ if (item_id >= 0) { //it's an OSD
+ float w = crush_get_bucket_item_weight(b, j);
+ (*pmap)[item_id] = w;
+ sum += w;
+ } else { //not an OSD, expand the child later
+ q.push_back(item_id);
+ }
+ }
+ }
+ return sum;
+}
+
+void CrushWrapper::_normalize_weight_map(float sum,
+ const map<int,float>& m,
+ map<int,float> *pmap) const
+{
+ for (auto& p : m) {
+ map<int,float>::iterator q = pmap->find(p.first);
+ if (q == pmap->end()) {
+ (*pmap)[p.first] = p.second / sum;
+ } else {
+ q->second += p.second / sum;
+ }
+ }
+}
+
+int CrushWrapper::get_take_weight_osd_map(int root, map<int,float> *pmap) const
+{
+ map<int,float> m;
+ float sum = _get_take_weight_osd_map(root, &m);
+ _normalize_weight_map(sum, m, pmap);
+ return 0;
+}
+
+int CrushWrapper::get_rule_weight_osd_map(unsigned ruleno,
+ map<int,float> *pmap) const
{
if (ruleno >= crush->max_rules)
return -ENOENT;
m[n] = 1.0;
sum = 1.0;
} else {
- list<int> q;
- q.push_back(n);
- //breadth first iterate the OSD tree
- while (!q.empty()) {
- int bno = q.front();
- q.pop_front();
- crush_bucket *b = crush->buckets[-1-bno];
- assert(b);
- for (unsigned j=0; j<b->size; ++j) {
- int item_id = b->items[j];
- if (item_id >= 0) { //it's an OSD
- float w = crush_get_bucket_item_weight(b, j);
- m[item_id] = w;
- sum += w;
- } else { //not an OSD, expand the child later
- q.push_back(item_id);
- }
- }
- }
- }
- }
- for (map<int,float>::iterator p = m.begin(); p != m.end(); ++p) {
- map<int,float>::iterator q = pmap->find(p->first);
- if (q == pmap->end()) {
- (*pmap)[p->first] = p->second / sum;
- } else {
- q->second += p->second / sum;
+ sum += _get_take_weight_osd_map(n, &m);
}
}
+ _normalize_weight_map(sum, m, pmap);
}
return 0;
crush->rules[ruleno] = NULL;
rule_name_map.erase(ruleno);
have_rmaps = false;
- return 0;
+ return rebuild_roots_with_classes();
}
int CrushWrapper::bucket_adjust_item_weight(CephContext *cct, crush_bucket *bucket, int item, int weight)
if (bucket->items[position] == item)
break;
assert(position != bucket->size);
- for (auto w : choose_args) {
- crush_choose_arg_map arg_map = w.second;
+ for (auto &w : choose_args) {
+ crush_choose_arg_map &arg_map = w.second;
crush_choose_arg *arg = &arg_map.args[-1-bucket->id];
- 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];
weight_set->weights[position] = weight;
}
crush_bucket *b = crush_make_bucket(crush, alg, hash, type, size, items,
weights);
assert(b);
+ assert(idout);
int r = crush_add_bucket(crush, bucketno, b, idout);
+ int pos = -1 - *idout;
for (auto& p : choose_args) {
crush_choose_arg_map& cmap = p.second;
if (cmap.args) {
- if ((int)cmap.size <= *idout) {
+ if ((int)cmap.size <= pos) {
cmap.args = (crush_choose_arg*)realloc(
cmap.args,
- sizeof(crush_choose_arg) * (*idout + 1));
+ sizeof(crush_choose_arg) * (pos + 1));
+ assert(cmap.args);
memset(&cmap.args[cmap.size], 0,
- sizeof(crush_choose_arg) * (*idout + 1 - cmap.size));
- cmap.size = *idout + 1;
+ sizeof(crush_choose_arg) * (pos + 1 - cmap.size));
+ cmap.size = pos + 1;
}
} else {
cmap.args = (crush_choose_arg*)calloc(sizeof(crush_choose_arg),
- *idout + 1);
- cmap.size = *idout + 1;
+ pos + 1);
+ assert(cmap.args);
+ cmap.size = pos + 1;
}
if (size > 0) {
int positions = get_choose_args_positions(cmap);
- crush_choose_arg& carg = cmap.args[*idout];
+ crush_choose_arg& carg = cmap.args[pos];
carg.weight_set = (crush_weight_set*)calloc(sizeof(crush_weight_set),
size);
- carg.weight_set_size = positions;
+ carg.weight_set_positions = positions;
for (int ppos = 0; ppos < positions; ++ppos) {
carg.weight_set[ppos].weights = (__u32*)calloc(sizeof(__u32), size);
carg.weight_set[ppos].size = size;
if (r < 0) {
return r;
}
- for (auto w : choose_args) {
- crush_choose_arg_map arg_map = w.second;
+ for (auto &w : choose_args) {
+ crush_choose_arg_map &arg_map = w.second;
crush_choose_arg *arg = &arg_map.args[-1-bucket->id];
- 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];
weight_set->weights = (__u32*)realloc(weight_set->weights,
new_size * sizeof(__u32));
if (r < 0) {
return r;
}
- for (auto w : choose_args) {
- crush_choose_arg_map arg_map = w.second;
+ for (auto &w : choose_args) {
+ crush_choose_arg_map &arg_map = w.second;
crush_choose_arg *arg = &arg_map.args[-1-bucket->id];
- 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];
assert(weight_set->size - 1 == new_size);
for (__u32 k = position; k < new_size; k++)
return 0;
}
+int CrushWrapper::bucket_set_alg(int bid, int alg)
+{
+ crush_bucket *b = get_bucket(bid);
+ if (!b) {
+ return -ENOENT;
+ }
+ b->alg = alg;
+ return 0;
+}
+
int CrushWrapper::update_device_class(int id,
const string& class_name,
const string& name,
unsigned new_size = -1-bno + 1;
cmap.args = (crush_choose_arg*)realloc(cmap.args,
new_size * sizeof(cmap.args[0]));
+ assert(cmap.args);
memset(cmap.args + cmap.size, 0,
(new_size - cmap.size) * sizeof(cmap.args[0]));
+ cmap.size = new_size;
}
auto& o = cmap.args[-1-original_id];
auto& n = cmap.args[-1-bno];
n.ids_size = 0; // FIXME: implement me someday
- n.weight_set_size = o.weight_set_size;
+ n.weight_set_positions = o.weight_set_positions;
n.weight_set = (crush_weight_set*)calloc(
- n.weight_set_size, sizeof(crush_weight_set));
- for (size_t s = 0; s < n.weight_set_size; ++s) {
+ n.weight_set_positions, sizeof(crush_weight_set));
+ for (size_t s = 0; s < n.weight_set_positions; ++s) {
n.weight_set[s].size = copy->size;
n.weight_set[s].weights = (__u32*)calloc(copy->size, sizeof(__u32));
}
- for (size_t s = 0; s < n.weight_set_size; ++s) {
- vector<int> bucket_weights(n.weight_set_size);
+ for (size_t s = 0; s < n.weight_set_positions; ++s) {
+ vector<int> bucket_weights(n.weight_set_positions);
for (size_t i = 0; i < copy->size; ++i) {
int item = copy->items[i];
if (item >= 0) {
n.weight_set[s].weights[i] = o.weight_set[s].weights[item_orig_pos[i]];
- } else {
+ } else if ((*cmap_item_weight)[w.first].count(item)) {
n.weight_set[s].weights[i] = (*cmap_item_weight)[w.first][item][s];
+ } else {
+ n.weight_set[s].weights[i] = 0;
}
bucket_weights[s] += n.weight_set[s].weights[i];
}
return 0;
}
+int CrushWrapper::get_rules_by_class(const string &class_name, set<int> *rules)
+{
+ assert(rules);
+ rules->clear();
+ if (!class_exists(class_name)) {
+ return -ENOENT;
+ }
+ int class_id = get_class_id(class_name);
+ for (unsigned i = 0; i < crush->max_rules; ++i) {
+ crush_rule *r = crush->rules[i];
+ if (!r)
+ continue;
+ for (unsigned j = 0; j < r->len; ++j) {
+ if (r->steps[j].op == CRUSH_RULE_TAKE) {
+ int step_item = r->steps[j].arg1;
+ int original_item;
+ int c;
+ int res = split_id_class(step_item, &original_item, &c);
+ if (res < 0) {
+ return res;
+ }
+ if (c != -1 && c == class_id) {
+ rules->insert(i);
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+// return rules that might reference the given osd
+int CrushWrapper::get_rules_by_osd(int osd, set<int> *rules)
+{
+ assert(rules);
+ rules->clear();
+ if (osd < 0) {
+ return -EINVAL;
+ }
+ for (unsigned i = 0; i < crush->max_rules; ++i) {
+ crush_rule *r = crush->rules[i];
+ if (!r)
+ continue;
+ for (unsigned j = 0; j < r->len; ++j) {
+ if (r->steps[j].op == CRUSH_RULE_TAKE) {
+ int step_item = r->steps[j].arg1;
+ list<int> unordered;
+ int rc = _get_leaves(step_item, &unordered);
+ if (rc < 0) {
+ return rc; // propagate fatal errors!
+ }
+ bool match = false;
+ for (auto &o: unordered) {
+ assert(o >= 0);
+ if (o == osd) {
+ match = true;
+ break;
+ }
+ }
+ if (match) {
+ rules->insert(i);
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
bool CrushWrapper::_class_is_dead(int class_id)
{
for (auto &p: class_map) {
{
__u32 *weights;
if (encode_compat_choose_args &&
- arg_map.args[i].weight_set_size > 0) {
+ arg_map.args[i].weight_set_positions > 0) {
weights = arg_map.args[i].weight_set[0].weights;
} else {
weights = (reinterpret_cast<crush_bucket_straw2*>(crush->buckets[i]))->item_weights;
size = 0;
for (__u32 i = 0; i < arg_map.size; i++) {
crush_choose_arg *arg = &arg_map.args[i];
- if (arg->weight_set_size == 0 &&
+ if (arg->weight_set_positions == 0 &&
arg->ids_size == 0)
continue;
size++;
::encode(size, bl);
for (__u32 i = 0; i < arg_map.size; i++) {
crush_choose_arg *arg = &arg_map.args[i];
- if (arg->weight_set_size == 0 &&
+ if (arg->weight_set_positions == 0 &&
arg->ids_size == 0)
continue;
::encode(i, bl);
- ::encode(arg->weight_set_size, bl);
- for (__u32 j = 0; j < arg->weight_set_size; j++) {
+ ::encode(arg->weight_set_positions, bl);
+ for (__u32 j = 0; j < arg->weight_set_positions; j++) {
crush_weight_set *weight_set = &arg->weight_set[j];
::encode(weight_set->size, bl);
for (__u32 k = 0; k < weight_set->size; k++)
__u32 choose_args_size;
::decode(choose_args_size, blp);
for (__u32 i = 0; i < choose_args_size; i++) {
- uint64_t choose_args_index;
+ typename decltype(choose_args)::key_type choose_args_index;
::decode(choose_args_index, blp);
crush_choose_arg_map arg_map;
arg_map.size = crush->max_buckets;
::decode(bucket_index, blp);
assert(bucket_index < arg_map.size);
crush_choose_arg *arg = &arg_map.args[bucket_index];
- ::decode(arg->weight_set_size, blp);
- if (arg->weight_set_size) {
+ ::decode(arg->weight_set_positions, blp);
+ if (arg->weight_set_positions) {
arg->weight_set = (crush_weight_set*)calloc(
- arg->weight_set_size, sizeof(crush_weight_set));
- for (__u32 k = 0; k < arg->weight_set_size; k++) {
+ arg->weight_set_positions, sizeof(crush_weight_set));
+ for (__u32 k = 0; k < arg->weight_set_positions; k++) {
crush_weight_set *weight_set = &arg->weight_set[k];
::decode(weight_set->size, blp);
weight_set->weights = (__u32*)calloc(
choose_args[choose_args_index] = arg_map;
}
}
+ update_choose_args(nullptr); // in case we decode a legacy "corrupted" map
finalize();
}
catch (...) {
void dump(Formatter *f) {
set<int> roots;
- crush->find_roots(roots);
+ crush->find_roots(&roots);
for (set<int>::iterator root = roots.begin(); root != roots.end(); ++root) {
dump_item(Item(*root, 0, 0, crush->get_bucket_weightf(*root)), f);
}
f->open_array_section(stringify(c.first).c_str());
for (__u32 i = 0; i < arg_map.size; i++) {
crush_choose_arg *arg = &arg_map.args[i];
- if (arg->weight_set_size == 0 &&
+ if (arg->weight_set_positions == 0 &&
arg->ids_size == 0)
continue;
f->open_object_section("choose_args");
int bucket_index = i;
f->dump_int("bucket_id", -1-bucket_index);
- if (arg->weight_set_size > 0) {
+ if (arg->weight_set_positions > 0) {
f->open_array_section("weight_set");
- for (__u32 j = 0; j < arg->weight_set_size; j++) {
+ for (__u32 j = 0; j < arg->weight_set_positions; j++) {
f->open_array_section("weights");
__u32 *weights = arg->weight_set[j].weights;
__u32 size = arg->weight_set[j].size;
if (b &&
bidx < (int)cmap.size &&
cmap.args[bidx].weight_set &&
- cmap.args[bidx].weight_set_size >= 1) {
+ cmap.args[bidx].weight_set_positions >= 1) {
int pos;
for (pos = 0;
pos < (int)cmap.args[bidx].weight_set[0].size &&
<< " w " << w << dendl;
vector<int> o;
auto tmpi = i;
+ if (i == orig.end()) {
+ ldout(cct, 10) << __func__ << " end of orig, break 0" << dendl;
+ break;
+ }
for (auto from : w) {
ldout(cct, 10) << " from " << from << dendl;
// identify leaves under each choice. we use this to check whether any of these
ldout(cct, 10) << __func__ << " pos " << pos << " replace "
<< *i << " -> " << item << dendl;
replaced = true;
+ assert(i != orig.end());
++i;
break;
}
if (!replaced) {
ldout(cct, 10) << __func__ << " pos " << pos << " keep " << *i
<< dendl;
+ assert(i != orig.end());
o.push_back(*i);
++i;
}
if (numrep <= 0)
numrep += maxout;
type_stack.push_back(make_pair(type, numrep));
- type_stack.push_back(make_pair(0, 1));
+ if (type > 0)
+ type_stack.push_back(make_pair(0, 1));
int r = _choose_type_stack(cct, type_stack, overfull, underfull, orig,
i, used, &w);
if (r < 0)
}
crush_choose_arg *carg = &cmap.args[bidx];
if (carg->weight_set == NULL) {
- if (ss)
- *ss << "no weight-set for bucket " << b->id;
- ldout(cct, 10) << __func__ << " no weight_set for bucket " << b->id
- << dendl;
- return 0;
+ // create a weight-set for this bucket and populate it with the
+ // bucket weights
+ unsigned positions = get_choose_args_positions(cmap);
+ carg->weight_set_positions = positions;
+ carg->weight_set = static_cast<crush_weight_set*>(
+ calloc(sizeof(crush_weight_set), positions));
+ for (unsigned p = 0; p < positions; ++p) {
+ carg->weight_set[p].size = b->size;
+ carg->weight_set[p].weights = (__u32*)calloc(b->size, sizeof(__u32));
+ for (unsigned i = 0; i < b->size; ++i) {
+ carg->weight_set[p].weights[i] = crush_get_bucket_item_weight(b, i);
+ }
+ }
+ changed++;
}
- if (carg->weight_set_size != weight.size()) {
+ if (carg->weight_set_positions != weight.size()) {
if (ss)
- *ss << "weight_set_size != " << weight.size() << " for bucket " << b->id;
- ldout(cct, 10) << __func__ << " weight_set_size != " << weight.size()
+ *ss << "weight_set_positions != " << weight.size() << " for bucket " << b->id;
+ ldout(cct, 10) << __func__ << " weight_set_positions != " << weight.size()
<< " for bucket " << b->id << dendl;
return 0;
}