From: Sage Weil Date: Fri, 12 May 2017 21:39:14 +0000 (-0400) Subject: crush: implement swap_bucket X-Git-Tag: v12.1.0~10^2~103^2~3 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=5f795631973407fc9ee39f3c52e7f905e4711ff8;p=ceph.git crush: implement swap_bucket Swap contents between buckets. Signed-off-by: Sage Weil --- diff --git a/src/crush/CrushWrapper.cc b/src/crush/CrushWrapper.cc index ee6db9bc629..b4319ce33e4 100644 --- a/src/crush/CrushWrapper.cc +++ b/src/crush/CrushWrapper.cc @@ -790,6 +790,52 @@ int CrushWrapper::move_bucket(CephContext *cct, int id, const map return insert_item(cct, id, bucket_weight / (float)0x10000, id_name, loc); } +int CrushWrapper::swap_bucket(CephContext *cct, int src, int dst) +{ + if (src >= 0 || dst >= 0) + return -EINVAL; + if (!item_exists(src) || !item_exists(dst)) + return -EINVAL; + crush_bucket *a = get_bucket(src); + crush_bucket *b = get_bucket(dst); + unsigned aw = a->weight; + unsigned bw = b->weight; + + // swap weights + adjust_item_weight(cct, a->id, bw); + adjust_item_weight(cct, b->id, aw); + + // swap items + map tmp; + unsigned as = a->size; + unsigned bs = b->size; + for (unsigned i = 0; i < as; ++i) { + int item = a->items[0]; + int itemw = crush_get_bucket_item_weight(a, 0); + tmp[item] = itemw; + crush_bucket_remove_item(crush, a, item); + } + assert(a->size == 0); + assert(b->size == bs); + for (unsigned i = 0; i < bs; ++i) { + int item = b->items[0]; + int itemw = crush_get_bucket_item_weight(b, 0); + crush_bucket_remove_item(crush, b, item); + crush_bucket_add_item(crush, a, item, itemw); + } + assert(a->size == bs); + assert(b->size == 0); + for (auto t : tmp) { + crush_bucket_add_item(crush, b, t.first, t.second); + } + assert(a->size == bs); + assert(b->size == as); + + // swap names + swap_names(src, dst); + return 0; +} + int CrushWrapper::link_bucket(CephContext *cct, int id, const map& loc) { if (choose_args.size() > 0) { diff --git a/src/crush/CrushWrapper.h b/src/crush/CrushWrapper.h index c47a5badc41..dde6d4c63c0 100644 --- a/src/crush/CrushWrapper.h +++ b/src/crush/CrushWrapper.h @@ -402,6 +402,16 @@ public: 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; @@ -651,6 +661,16 @@ public: */ int move_bucket(CephContext *cct, int id, const map& 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 * diff --git a/src/test/crush/CrushWrapper.cc b/src/test/crush/CrushWrapper.cc index 6e6fb05e5e7..d5a90b056b1 100644 --- a/src/test/crush/CrushWrapper.cc +++ b/src/test/crush/CrushWrapper.cc @@ -128,6 +128,69 @@ TEST(CrushWrapper, move_bucket) { delete c; } +TEST(CrushWrapper, swap_bucket) { + CrushWrapper *c = new CrushWrapper; + + const int ROOT_TYPE = 2; + c->set_type_name(ROOT_TYPE, "root"); + const int HOST_TYPE = 1; + c->set_type_name(HOST_TYPE, "host"); + const int OSD_TYPE = 0; + c->set_type_name(OSD_TYPE, "osd"); + + int root; + EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW2, CRUSH_HASH_RJENKINS1, + ROOT_TYPE, 0, NULL, NULL, &root)); + EXPECT_EQ(0, c->set_item_name(root, "root")); + + int a, b; + EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW2, CRUSH_HASH_RJENKINS1, + HOST_TYPE, 0, NULL, NULL, &a)); + EXPECT_EQ(0, c->set_item_name(a, "a")); + EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW2, CRUSH_HASH_RJENKINS1, + HOST_TYPE, 0, NULL, NULL, &b)); + EXPECT_EQ(0, c->set_item_name(b, "b")); + + { + map loc; + loc["root"] = "root"; + EXPECT_EQ(0, c->move_bucket(g_ceph_context, a, loc)); + } + { + map loc; + loc["root"] = "root"; + loc["host"] = "a"; + EXPECT_EQ(0, c->insert_item(g_ceph_context, 0, 1.0, "osd.0", loc)); + EXPECT_EQ(0, c->insert_item(g_ceph_context, 1, 1.0, "osd.1", loc)); + EXPECT_EQ(0, c->insert_item(g_ceph_context, 2, 1.0, "osd.2", loc)); + } + { + map loc; + loc["host"] = "b"; + EXPECT_EQ(0, c->insert_item(g_ceph_context, 3, 1.0, "osd.3", loc)); + } + ASSERT_EQ(0x30000, c->get_item_weight(a)); + ASSERT_EQ(string("a"), c->get_item_name(a)); + ASSERT_EQ(0x10000, c->get_item_weight(b)); + ASSERT_EQ(string("b"), c->get_item_name(b)); + ASSERT_EQ(a, c->get_bucket_item(root, 0)); + ASSERT_EQ(0, c->get_bucket_item(a, 0)); + ASSERT_EQ(1, c->get_bucket_item(a, 1)); + ASSERT_EQ(2, c->get_bucket_item(a, 2)); + ASSERT_EQ(3, c->get_bucket_item(b, 0)); + + c->swap_bucket(g_ceph_context, a, b); + ASSERT_EQ(0x30000, c->get_item_weight(b)); + ASSERT_EQ(string("a"), c->get_item_name(b)); + ASSERT_EQ(0x10000, c->get_item_weight(a)); + ASSERT_EQ(string("b"), c->get_item_name(a)); + ASSERT_EQ(a, c->get_bucket_item(root, 0)); + ASSERT_EQ(0, c->get_bucket_item(b, 0)); + ASSERT_EQ(1, c->get_bucket_item(b, 1)); + ASSERT_EQ(2, c->get_bucket_item(b, 2)); + ASSERT_EQ(3, c->get_bucket_item(a, 0)); +} + TEST(CrushWrapper, rename_bucket_or_item) { CrushWrapper *c = new CrushWrapper;