return -ENOENT;
}
+int CrushWrapper::trim_roots_with_class()
+{
+ set<int> takes;
+ find_takes(takes);
+ set<int> roots;
+ find_roots(roots);
+ for (auto &r : roots) {
+ if (r >= 0)
+ continue;
+ if (!id_has_class(r))
+ continue;
+ int res = remove_unused_root(r);
+ if (res)
+ return res;
+ }
+ // there is no need to reweight because we only remove from the
+ // root and down
+ return 0;
+}
+
void CrushWrapper::reweight(CephContext *cct)
{
set<int> roots;
name_rmap[name] = i;
return 0;
}
+ bool id_has_class(int i) {
+ int idout;
+ int classout;
+ if (split_id_class(i, &idout, &classout) != 0)
+ return false;
+ return classout != -1;
+ }
int split_id_class(int i, int *idout, int *classout) const;
bool class_exists(const string& name) const {
}
int device_class_clone(int original, int device_class, int *clone);
+ /* remove unused roots generated for class devices */
+ int trim_roots_with_class();
void start_choose_profile() {
free(crush->choose_tries);
/*
ASSERT_FALSE(c.name_exists("r12"));
}
+TEST(CrushWrapper, trim_roots_with_class) {
+ CrushWrapper c;
+ c.create();
+ c.set_type_name(1, "root");
+
+ int weight = 1;
+ map<string,string> loc;
+ loc["root"] = "default";
+
+ int item = 1;
+ c.insert_item(g_ceph_context, item, weight, "osd.1", loc);
+ int cl = c.get_or_create_class_id("ssd");
+ c.class_map[item] = cl;
+
+
+ int root_id = c.get_item_id("default");
+ int clone_id;
+ ASSERT_EQ(c.device_class_clone(root_id, cl, &clone_id), 0);
+
+ ASSERT_TRUE(c.name_exists("default"));
+ ASSERT_TRUE(c.name_exists("default~ssd"));
+ c.trim_roots_with_class(); // do nothing because still in use
+ ASSERT_TRUE(c.name_exists("default"));
+ ASSERT_TRUE(c.name_exists("default~ssd"));
+ c.class_bucket.clear();
+ c.trim_roots_with_class(); // do nothing because still in use
+ ASSERT_TRUE(c.name_exists("default"));
+ ASSERT_FALSE(c.name_exists("default~ssd"));
+}
+
TEST(CrushWrapper, device_class_clone) {
CrushWrapper c;
c.create();