used_ids.insert(q.second);
}
}
+ // 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
set<int> roots;
find_nonshadow_roots(roots);
for (auto &r : roots) {
for (auto &c : class_name) {
int clone;
int res = device_class_clone(r, c.first, old_class_bucket, used_ids,
- &clone);
+ &clone, &cmap_item_weight);
if (res < 0)
return res;
}
int original_id, 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)
+ int *clone,
+ map<int,map<int,vector<int>>> *cmap_item_weight)
{
const char *item_name = get_item_name(original_id);
if (item_name == NULL)
*clone = get_item_id(copy_name);
return 0;
}
+
crush_bucket *original = get_bucket(original_id);
assert(!IS_ERR(original));
crush_bucket *copy = crush_make_bucket(crush,
original->type,
0, NULL, NULL);
assert(copy);
+
+ vector<unsigned> item_orig_pos; // new item pos -> orig item pos
for (unsigned i = 0; i < original->size; i++) {
int item = original->items[i];
int weight = crush_get_bucket_item_weight(original, i);
if (item >= 0) {
if (class_map.count(item) != 0 && class_map[item] == device_class) {
- int res = bucket_add_item(copy, item, weight);
+ int res = crush_bucket_add_item(crush, copy, item, weight);
if (res)
return res;
+ } else {
+ continue;
}
} else {
int child_copy_id;
int res = device_class_clone(item, device_class, old_class_bucket,
- used_ids, &child_copy_id);
+ used_ids, &child_copy_id,
+ cmap_item_weight);
if (res < 0)
return res;
crush_bucket *child_copy = get_bucket(child_copy_id);
assert(!IS_ERR(child_copy));
- res = bucket_add_item(copy, child_copy_id, child_copy->weight);
+ res = crush_bucket_add_item(crush, copy, child_copy_id,
+ child_copy->weight);
if (res)
return res;
}
+ item_orig_pos.push_back(i);
}
+ assert(item_orig_pos.size() == copy->size);
+
int bno = 0;
if (old_class_bucket.count(original_id) &&
old_class_bucket.at(original_id).count(device_class)) {
if (res)
return res;
assert(!bno || bno == *clone);
+
res = set_item_class(*clone, device_class);
if (res < 0)
return res;
+
// we do not use set_item_name because the name is intentionally invalid
name_map[*clone] = copy_name;
if (have_rmaps)
name_rmap[copy_name] = *clone;
class_bucket[original_id][device_class] = *clone;
+
+ // set up choose_args for the new bucket.
+ for (auto& w : choose_args) {
+ crush_choose_arg_map& cmap = w.second;
+ if (-1-bno >= (int)cmap.size) {
+ unsigned new_size = -1-bno + 1;
+ cmap.args = (crush_choose_arg*)realloc(cmap.args,
+ new_size * sizeof(cmap.args[0]));
+ memset(cmap.args + cmap.size, 0,
+ (new_size - cmap.size) * sizeof(cmap.args[0]));
+ }
+ 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 = (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[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 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 {
+ n.weight_set[s].weights[i] = (*cmap_item_weight)[w.first][item][s];
+ }
+ bucket_weights[s] += n.weight_set[s].weights[i];
+ }
+ (*cmap_item_weight)[w.first][bno] = bucket_weights;
+ }
+ }
return 0;
}
int root_id = c.get_item_id("default");
int clone_id;
map<int32_t, map<int32_t, int32_t>> old_class_bucket;
+ map<int,map<int,vector<int>>> cmap_item_weight; // cargs -> bno -> weights
set<int32_t> used_ids;
ASSERT_EQ(c.device_class_clone(root_id, cl, old_class_bucket, used_ids,
- &clone_id), 0);
+ &clone_id, &cmap_item_weight), 0);
ASSERT_TRUE(c.name_exists("default"));
ASSERT_TRUE(c.name_exists("default~ssd"));
c.reweight(g_ceph_context);
map<int32_t, map<int32_t, int32_t>> old_class_bucket;
+ map<int,map<int,vector<int>>> cmap_item_weight; // cargs -> bno -> weights
set<int32_t> used_ids;
int root_id = c.get_item_id("default");
int clone_id;
ASSERT_EQ(c.device_class_clone(root_id, cl, old_class_bucket, used_ids,
- &clone_id), 0);
+ &clone_id, &cmap_item_weight), 0);
ASSERT_TRUE(c.name_exists("default~ssd"));
ASSERT_EQ(clone_id, c.get_item_id("default~ssd"));
ASSERT_TRUE(c.subtree_contains(clone_id, item));
// cloning again does nothing and returns the existing one
int other_clone_id;
ASSERT_EQ(c.device_class_clone(root_id, cl, old_class_bucket, used_ids,
- &other_clone_id), 0);
+ &other_clone_id, &cmap_item_weight), 0);
ASSERT_EQ(clone_id, other_clone_id);
// invalid arguments
ASSERT_EQ(c.device_class_clone(12345, cl, old_class_bucket, used_ids,
- &other_clone_id), -ECHILD);
+ &other_clone_id, &cmap_item_weight), -ECHILD);
ASSERT_EQ(c.device_class_clone(root_id, 12345, old_class_bucket, used_ids,
- &other_clone_id), -EBADF);
+ &other_clone_id, &cmap_item_weight), -EBADF);
}
TEST(CrushWrapper, split_id_class) {
c.class_map[item] = class_id;
map<int32_t, map<int32_t, int32_t>> old_class_bucket;
+ map<int,map<int,vector<int>>> cmap_item_weight; // cargs -> bno -> weights
set<int32_t> used_ids;
int item_id = c.get_item_id("default");
int clone_id;
ASSERT_EQ(c.device_class_clone(item_id, class_id, old_class_bucket, used_ids,
- &clone_id), 0);
+ &clone_id, &cmap_item_weight), 0);
int retrieved_item_id;
int retrieved_class_id;
ASSERT_EQ(c.split_id_class(clone_id, &retrieved_item_id, &retrieved_class_id), 0);