From: Sage Weil Date: Fri, 16 Jan 2015 05:06:57 +0000 (-0800) Subject: crush: rename unit tests X-Git-Tag: v0.93~272^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=ddb91b2f8f4e330a543b99174eeaae12caff9ba1;p=ceph.git crush: rename unit tests Signed-off-by: Sage Weil --- diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 03ba231b6648..2279f24ff5f8 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -338,10 +338,15 @@ unittest_util_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_util_LDADD = $(LIBCOMMON) -lm $(UNITTEST_LDADD) $(CRYPTO_LIBS) $(EXTRALIBS) check_PROGRAMS += unittest_util -unittest_crush_indep_SOURCES = test/crush/indep.cc -unittest_crush_indep_CXXFLAGS = $(UNITTEST_CXXFLAGS) -unittest_crush_indep_LDADD = $(LIBCOMMON) -lm $(UNITTEST_LDADD) $(CEPH_CRUSH) $(EXTRALIBS) $(CEPH_GLOBAL) -check_PROGRAMS += unittest_crush_indep +unittest_crush_wrapper_SOURCES = test/crush/CrushWrapper.cc +unittest_crush_wrapper_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(LIBCRUSH) +unittest_crush_wrapper_CXXFLAGS = $(UNITTEST_CXXFLAGS) -O2 +check_PROGRAMS += unittest_crush_wrapper + +unittest_crush_SOURCES = test/crush/crush.cc +unittest_crush_CXXFLAGS = $(UNITTEST_CXXFLAGS) +unittest_crush_LDADD = $(LIBCOMMON) -lm $(UNITTEST_LDADD) $(CEPH_CRUSH) $(EXTRALIBS) $(CEPH_GLOBAL) +check_PROGRAMS += unittest_crush unittest_osdmap_SOURCES = test/osd/TestOSDMap.cc unittest_osdmap_CXXFLAGS = $(UNITTEST_CXXFLAGS) @@ -378,11 +383,6 @@ unittest_throttle_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_throttle_CXXFLAGS = $(UNITTEST_CXXFLAGS) -O2 check_PROGRAMS += unittest_throttle -unittest_crush_wrapper_SOURCES = test/crush/TestCrushWrapper.cc -unittest_crush_wrapper_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(LIBCRUSH) -unittest_crush_wrapper_CXXFLAGS = $(UNITTEST_CXXFLAGS) -O2 -check_PROGRAMS += unittest_crush_wrapper - unittest_base64_SOURCES = test/base64.cc unittest_base64_LDADD = $(LIBCEPHFS) -lm $(UNITTEST_LDADD) unittest_base64_CXXFLAGS = $(UNITTEST_CXXFLAGS) diff --git a/src/test/crush/CrushWrapper.cc b/src/test/crush/CrushWrapper.cc new file mode 100644 index 000000000000..b735b8469dd6 --- /dev/null +++ b/src/test/crush/CrushWrapper.cc @@ -0,0 +1,978 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2013 Cloudwatt + * Copyright (C) 2014 Red Hat + * + * Author: Loic Dachary + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details. + * + */ + +#include +#include + +#include "include/stringify.h" +#include "common/ceph_argparse.h" +#include "global/global_init.h" +#include "global/global_context.h" +#include "include/Context.h" +#include "osd/osd_types.h" + +#include "crush/CrushWrapper.h" + +TEST(CrushWrapper, get_immediate_parent) { + CrushWrapper *c = new CrushWrapper; + + const int ROOT_TYPE = 1; + c->set_type_name(ROOT_TYPE, "root"); + const int OSD_TYPE = 0; + c->set_type_name(OSD_TYPE, "osd"); + + int rootno; + c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + ROOT_TYPE, 0, NULL, NULL, &rootno); + c->set_item_name(rootno, "default"); + + int item = 0; + + pair loc; + int ret; + loc = c->get_immediate_parent(item, &ret); + EXPECT_EQ(-ENOENT, ret); + + { + map loc; + loc["root"] = "default"; + + EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, + "osd.0", loc)); + } + + loc = c->get_immediate_parent(item, &ret); + EXPECT_EQ(0, ret); + EXPECT_EQ("root", loc.first); + EXPECT_EQ("default", loc.second); + + delete c; +} + +TEST(CrushWrapper, straw_zero) { + // zero weight items should have no effect on placement. + + CrushWrapper *c = new CrushWrapper; + const int ROOT_TYPE = 1; + c->set_type_name(ROOT_TYPE, "root"); + const int OSD_TYPE = 0; + c->set_type_name(OSD_TYPE, "osd"); + + int n = 5; + int items[n], weights[n]; + for (int i=0; i set_max_devices(n); + + string root_name0("root0"); + int root0; + EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + ROOT_TYPE, n, items, weights, &root0)); + EXPECT_EQ(0, c->set_item_name(root0, root_name0)); + + string name0("rule0"); + int ruleset0 = c->add_simple_ruleset(name0, root_name0, "osd", + "firstn", pg_pool_t::TYPE_REPLICATED); + EXPECT_EQ(0, ruleset0); + + string root_name1("root1"); + int root1; + EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + ROOT_TYPE, n-1, items, weights, &root1)); + EXPECT_EQ(0, c->set_item_name(root1, root_name1)); + + string name1("rule1"); + int ruleset1 = c->add_simple_ruleset(name1, root_name1, "osd", + "firstn", pg_pool_t::TYPE_REPLICATED); + EXPECT_EQ(1, ruleset1); + + vector reweight(n, 0x10000); + for (int i=0; i<10000; ++i) { + vector out0, out1; + c->do_rule(ruleset0, i, out0, 1, reweight); + ASSERT_EQ(1u, out0.size()); + c->do_rule(ruleset1, i, out1, 1, reweight); + ASSERT_EQ(1u, out1.size()); + ASSERT_EQ(out0[0], out1[0]); + //cout << i << "\t" << out0 << "\t" << out1 << std::endl; + } +} + +TEST(CrushWrapper, straw_same) { + // items with the same weight should map about the same as items + // with very similar weights. + // + // give the 0 vector a paired stair pattern, with dup weights. note + // that the original straw flaw does not appear when there are 2 of + // the initial weight, but it does when there is just 1. + // + // give the 1 vector a similar stair pattern, but make the same + // steps weights slightly different (no dups). this works. + // + // compare the result and verify that the resulting mapping is + // almost identical. + + CrushWrapper *c = new CrushWrapper; + const int ROOT_TYPE = 1; + c->set_type_name(ROOT_TYPE, "root"); + const int OSD_TYPE = 0; + c->set_type_name(OSD_TYPE, "osd"); + + int n = 10; + int items[n], weights[n]; + for (int i=0; i set_max_devices(n); + + string root_name0("root0"); + int root0; + EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + ROOT_TYPE, n, items, weights, &root0)); + EXPECT_EQ(0, c->set_item_name(root0, root_name0)); + + string name0("rule0"); + int ruleset0 = c->add_simple_ruleset(name0, root_name0, "osd", + "firstn", pg_pool_t::TYPE_REPLICATED); + EXPECT_EQ(0, ruleset0); + + for (int i=0; i add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + ROOT_TYPE, n, items, weights, &root1)); + EXPECT_EQ(0, c->set_item_name(root1, root_name1)); + + string name1("rule1"); + int ruleset1 = c->add_simple_ruleset(name1, root_name1, "osd", + "firstn", pg_pool_t::TYPE_REPLICATED); + EXPECT_EQ(1, ruleset1); + + if (0) { + crush_bucket_straw *sb0 = reinterpret_cast(c->get_crush_map()->buckets[-1-root0]); + crush_bucket_straw *sb1 = reinterpret_cast(c->get_crush_map()->buckets[-1-root1]); + + for (int i=0; iitem_weights[i] + << "\t" << sb1->item_weights[i] + << "\t" + << "\t" << sb0->straws[i] + << "\t" << sb1->straws[i] + << std::endl; + } + } + + if (0) { + JSONFormatter jf(true); + jf.open_object_section("crush"); + c->dump(&jf); + jf.close_section(); + jf.flush(cout); + } + + vector sum0(n, 0), sum1(n, 0); + vector reweight(n, 0x10000); + int different = 0; + int max = 100000; + for (int i=0; i out0, out1; + c->do_rule(ruleset0, i, out0, 1, reweight); + ASSERT_EQ(1u, out0.size()); + c->do_rule(ruleset1, i, out1, 1, reweight); + ASSERT_EQ(1u, out1.size()); + sum0[out0[0]]++; + sum1[out1[0]]++; + if (out0[0] != out1[0]) + different++; + } + for (int i=0; iset_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 root0; + EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + ROOT_TYPE, 0, NULL, NULL, &root0)); + EXPECT_EQ(0, c->set_item_name(root0, "root0")); + + { + map loc; + loc["root"] = "root0"; + loc["host"] = "host0"; + + int item = 0; + EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, + "osd.0", loc)); + } + int host0 = c->get_item_id("host0"); + + int root1; + EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + ROOT_TYPE, 0, NULL, NULL, &root1)); + EXPECT_EQ(0, c->set_item_name(root1, "root1")); + + map loc; + loc["root"] = "root1"; + + // 0 is not a valid bucket number, must be negative + EXPECT_EQ(-EINVAL, c->move_bucket(g_ceph_context, 0, loc)); + // -100 is not an existing bucket + EXPECT_EQ(-ENOENT, c->move_bucket(g_ceph_context, -100, loc)); + // move host0 from root0 to root1 + { + pair loc; + int ret; + loc = c->get_immediate_parent(host0, &ret); + EXPECT_EQ(0, ret); + EXPECT_EQ("root", loc.first); + EXPECT_EQ("root0", loc.second); + } + EXPECT_EQ(0, c->move_bucket(g_ceph_context, host0, loc)); + { + pair loc; + int ret; + loc = c->get_immediate_parent(host0, &ret); + EXPECT_EQ(0, ret); + EXPECT_EQ("root", loc.first); + EXPECT_EQ("root1", loc.second); + } + + delete c; +} + +TEST(CrushWrapper, rename_bucket_or_item) { + 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 root0; + EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + ROOT_TYPE, 0, NULL, NULL, &root0)); + EXPECT_EQ(0, c->set_item_name(root0, "root0")); + + int item = 0; + { + map loc; + loc["root"] = "root0"; + loc["host"] = "host0"; + + EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, + "osd.0", loc)); + } + item++; + { + map loc; + loc["root"] = "root0"; + loc["host"] = "host1"; + + EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, + "osd.1", loc)); + } + + stringstream ss; + EXPECT_EQ(-EINVAL, c->can_rename_item("host0", "????", &ss)); + EXPECT_EQ(-EINVAL, c->rename_item("host0", "????", &ss)); + EXPECT_EQ(-EINVAL, c->can_rename_bucket("host0", "????", &ss)); + EXPECT_EQ(-EINVAL, c->rename_bucket("host0", "????", &ss)); + + EXPECT_EQ(-EEXIST, c->can_rename_item("host0", "host1", &ss)); + EXPECT_EQ(-EEXIST, c->rename_item("host0", "host1", &ss)); + EXPECT_EQ(-EEXIST, c->can_rename_bucket("host0", "host1", &ss)); + EXPECT_EQ(-EEXIST, c->rename_bucket("host0", "host1", &ss)); + + EXPECT_EQ(-EALREADY, c->can_rename_item("gone", "host1", &ss)); + EXPECT_EQ(-EALREADY, c->rename_item("gone", "host1", &ss)); + EXPECT_EQ(-EALREADY, c->can_rename_bucket("gone", "host1", &ss)); + EXPECT_EQ(-EALREADY, c->rename_bucket("gone", "host1", &ss)); + + EXPECT_EQ(-ENOENT, c->can_rename_item("doesnotexist", "somethingelse", &ss)); + EXPECT_EQ(-ENOENT, c->rename_item("doesnotexist", "somethingelse", &ss)); + EXPECT_EQ(-ENOENT, c->can_rename_bucket("doesnotexist", "somethingelse", &ss)); + EXPECT_EQ(-ENOENT, c->rename_bucket("doesnotexist", "somethingelse", &ss)); + + EXPECT_EQ(-ENOTDIR, c->can_rename_bucket("osd.1", "somethingelse", &ss)); + EXPECT_EQ(-ENOTDIR, c->rename_bucket("osd.1", "somethingelse", &ss)); + + int host0id = c->get_item_id("host0"); + EXPECT_EQ(0, c->rename_bucket("host0", "host0renamed", &ss)); + EXPECT_EQ(host0id, c->get_item_id("host0renamed")); + + int osd0id = c->get_item_id("osd0"); + EXPECT_EQ(0, c->rename_item("osd.0", "osd0renamed", &ss)); + EXPECT_EQ(osd0id, c->get_item_id("osd0renamed")); + + delete c; +} + +TEST(CrushWrapper, check_item_loc) { + CrushWrapper *c = new CrushWrapper; + int item = 0; + float expected_weight = 1.0; + + // fail if loc is empty + { + float weight; + map loc; + EXPECT_FALSE(c->check_item_loc(g_ceph_context, item, loc, &weight)); + } + + 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 rootno; + c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + ROOT_TYPE, 0, NULL, NULL, &rootno); + c->set_item_name(rootno, "default"); + + // fail because the item is not found at the specified location + { + float weight; + map loc; + loc["root"] = "default"; + EXPECT_FALSE(c->check_item_loc(g_ceph_context, item, loc, &weight)); + } + // fail because the bucket name does not match an existing bucket + { + float weight; + map loc; + loc["root"] = "default"; + const string HOST("host0"); + loc["host"] = HOST; + EXPECT_FALSE(c->check_item_loc(g_ceph_context, item, loc, &weight)); + } + const string OSD("osd.0"); + { + map loc; + loc["root"] = "default"; + EXPECT_EQ(0, c->insert_item(g_ceph_context, item, expected_weight, + OSD, loc)); + } + // fail because osd.0 is not a bucket and must not be in loc, in + // addition to being of the wrong type + { + float weight; + map loc; + loc["root"] = "osd.0"; + EXPECT_FALSE(c->check_item_loc(g_ceph_context, item, loc, &weight)); + } + // succeed and retrieves the expected weight + { + float weight; + map loc; + loc["root"] = "default"; + EXPECT_TRUE(c->check_item_loc(g_ceph_context, item, loc, &weight)); + EXPECT_EQ(expected_weight, weight); + } + + delete c; +} + +TEST(CrushWrapper, update_item) { + 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 rootno; + c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + ROOT_TYPE, 0, NULL, NULL, &rootno); + c->set_item_name(rootno, "default"); + + const string HOST0("host0"); + int host0; + c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + HOST_TYPE, 0, NULL, NULL, &host0); + c->set_item_name(host0, HOST0); + + const string HOST1("host1"); + int host1; + c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + HOST_TYPE, 0, NULL, NULL, &host1); + c->set_item_name(host1, HOST1); + + int item = 0; + + // fail if invalid names anywhere in loc + { + map loc; + loc["rack"] = "\001"; + EXPECT_EQ(-EINVAL, c->update_item(g_ceph_context, item, 1.0, + "osd." + stringify(item), loc)); + } + // fail if invalid item name + { + map loc; + EXPECT_EQ(-EINVAL, c->update_item(g_ceph_context, item, 1.0, + "\005", loc)); + } + const string OSD0("osd.0"); + const string OSD1("osd.1"); + float original_weight = 1.0; + float modified_weight = 2.0; + float weight; + + map loc; + loc["root"] = "default"; + loc["host"] = HOST0; + EXPECT_GE(0.0, c->get_item_weightf(host0)); + EXPECT_EQ(0, c->insert_item(g_ceph_context, item, original_weight, + OSD0, loc)); + + // updating nothing changes nothing + EXPECT_EQ(OSD0, c->get_item_name(item)); + EXPECT_EQ(original_weight, c->get_item_weightf(item)); + EXPECT_TRUE(c->check_item_loc(g_ceph_context, item, loc, &weight)); + EXPECT_EQ(0, c->update_item(g_ceph_context, item, original_weight, + OSD0, loc)); + EXPECT_EQ(OSD0, c->get_item_name(item)); + EXPECT_EQ(original_weight, c->get_item_weightf(item)); + EXPECT_TRUE(c->check_item_loc(g_ceph_context, item, loc, &weight)); + + // update the name and weight of the item but not the location + EXPECT_EQ(OSD0, c->get_item_name(item)); + EXPECT_EQ(original_weight, c->get_item_weightf(item)); + EXPECT_TRUE(c->check_item_loc(g_ceph_context, item, loc, &weight)); + EXPECT_EQ(1, c->update_item(g_ceph_context, item, modified_weight, + OSD1, loc)); + EXPECT_EQ(OSD1, c->get_item_name(item)); + EXPECT_EQ(modified_weight, c->get_item_weightf(item)); + EXPECT_TRUE(c->check_item_loc(g_ceph_context, item, loc, &weight)); + c->set_item_name(item, OSD0); + c->adjust_item_weightf(g_ceph_context, item, original_weight); + + // update the name and weight of the item and change its location + map other_loc; + other_loc["root"] = "default"; + other_loc["host"] = HOST1; + + EXPECT_EQ(OSD0, c->get_item_name(item)); + EXPECT_EQ(original_weight, c->get_item_weightf(item)); + EXPECT_TRUE(c->check_item_loc(g_ceph_context, item, loc, &weight)); + EXPECT_FALSE(c->check_item_loc(g_ceph_context, item, other_loc, &weight)); + EXPECT_EQ(1, c->update_item(g_ceph_context, item, modified_weight, + OSD1, other_loc)); + EXPECT_EQ(OSD1, c->get_item_name(item)); + EXPECT_EQ(modified_weight, c->get_item_weightf(item)); + EXPECT_FALSE(c->check_item_loc(g_ceph_context, item, loc, &weight)); + EXPECT_TRUE(c->check_item_loc(g_ceph_context, item, other_loc, &weight)); + + delete c; +} + +TEST(CrushWrapper, adjust_item_weight) { + 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 rootno; + c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + ROOT_TYPE, 0, NULL, NULL, &rootno); + c->set_item_name(rootno, "default"); + + const string HOST0("host0"); + int host0; + c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + HOST_TYPE, 0, NULL, NULL, &host0); + c->set_item_name(host0, HOST0); + + const string FAKE("fake"); + int hostfake; + c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + HOST_TYPE, 0, NULL, NULL, &hostfake); + c->set_item_name(hostfake, FAKE); + + int item = 0; + + // construct crush map + + { + map loc; + loc["host"] = "host0"; + float host_weight = 2.0; + int bucket_id = 0; + + item = 0; + EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, + "osd." + stringify(item), loc)); + item = 1; + EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, + "osd." + stringify(item), loc)); + + bucket_id = c->get_item_id("host0"); + EXPECT_EQ(true, c->bucket_exists(bucket_id)); + EXPECT_EQ(host_weight, c->get_bucket_weightf(bucket_id)); + + } + + { + map loc; + loc["host"] = "fake"; + float host_weight = 2.0; + int bucket_id = 0; + + item = 0; + EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, + "osd." + stringify(item), loc)); + item = 1; + EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, + "osd." + stringify(item), loc)); + + bucket_id = c->get_item_id("fake"); + EXPECT_EQ(true, c->bucket_exists(bucket_id)); + EXPECT_EQ(host_weight, c->get_bucket_weightf(bucket_id)); + } + + // + // When there is: + // + // default --> host0 --> osd.0 1.0 + // | | + // | +-> osd.1 1.0 + // | + // +-> fake --> osd.0 1.0 + // | + // +-> osd.1 1.0 + // + // Trying to adjust osd.0 weight to 2.0 in all buckets + // Trying to adjust osd.1 weight to 2.0 in host=fake + // + // So the crush map will be: + // + // default --> host0 --> osd.0 2.0 + // | | + // | +-> osd.1 1.0 + // | + // +-> fake --> osd.0 2.0 + // | + // +-> osd.1 2.0 + // + + float original_weight = 1.0; + float modified_weight = 2.0; + map loc_one, loc_two; + loc_one["host"] = "host0"; + loc_two["host"] = "fake"; + + item = 0; + EXPECT_EQ(2, c->adjust_item_weightf(g_ceph_context, item, modified_weight)); + EXPECT_EQ(modified_weight, c->get_item_weightf_in_loc(item, loc_one)); + EXPECT_EQ(modified_weight, c->get_item_weightf_in_loc(item, loc_two)); + + item = 1; + EXPECT_EQ(1, c->adjust_item_weightf_in_loc(g_ceph_context, item, modified_weight, loc_two)); + EXPECT_EQ(original_weight, c->get_item_weightf_in_loc(item, loc_one)); + EXPECT_EQ(modified_weight, c->get_item_weightf_in_loc(item, loc_two)); +} + +TEST(CrushWrapper, insert_item) { + 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 rootno; + c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + ROOT_TYPE, 0, NULL, NULL, &rootno); + c->set_item_name(rootno, "default"); + + int item = 0; + + // invalid names anywhere in loc trigger an error + { + map loc; + loc["host"] = "\001"; + EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, + "osd." + stringify(item), loc)); + } + + // insert an item in an existing bucket + { + map loc; + loc["root"] = "default"; + + item++; + EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, + "osd." + stringify(item), loc)); + int another_item = item + 1; + EXPECT_EQ(-EEXIST, c->insert_item(g_ceph_context, another_item, 1.0, + "osd." + stringify(item), loc)); + } + // implicit creation of a bucket + { + string name = "NAME"; + map loc; + loc["root"] = "default"; + loc["host"] = name; + + item++; + EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, + "osd." + stringify(item), loc)); + } + // adding to an existing item name that is not associated with a bucket + { + string name = "ITEM_WITHOUT_BUCKET"; + map loc; + loc["root"] = "default"; + loc["host"] = name; + item++; + c->set_item_name(item, name); + + item++; + EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, + "osd." + stringify(item), loc)); + } + // + // When there is: + // + // default --> host0 --> item + // + // Trying to insert the same item higher in the hirarchy will fail + // because it would create a loop. + // + // default --> host0 --> item + // | + // +-> item + // + { + item++; + { + map loc; + loc["root"] = "default"; + loc["host"] = "host0"; + + EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, + "osd." + stringify(item), loc)); + } + { + map loc; + loc["root"] = "default"; + + EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, + "osd." + stringify(item), loc)); + } + } + // + // When there is: + // + // default --> host0 + // + // Trying to insert default under host0 must fail + // because it would create a loop. + // + // default --> host0 --> default + // + { + map loc; + loc["host"] = "host0"; + + EXPECT_EQ(-ELOOP, c->insert_item(g_ceph_context, rootno, 1.0, + "default", loc)); + } + // fail when mapping a bucket to the wrong type + { + // create an OSD bucket + int osdno; + int r = c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + 10, 0, NULL, NULL, &osdno); + ASSERT_EQ(0, r); + c->set_item_name(osdno, "myosd"); + map loc; + loc["root"] = "default"; + // wrongfully pretend the osd is of type host + loc["host"] = "myosd"; + + item++; + EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, + "osd." + stringify(item), loc)); + } + // fail when no location + { + map loc; + item++; + EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, + "osd." + stringify(item), loc)); + } + + delete c; +} + +TEST(CrushWrapper, item_bucket_names) { + CrushWrapper *c = new CrushWrapper; + int index = 123; + string name = "NAME"; + EXPECT_EQ(-EINVAL, c->set_item_name(index, "\001")); + EXPECT_EQ(0, c->set_item_name(index, name)); + EXPECT_TRUE(c->name_exists(name)); + EXPECT_TRUE(c->item_exists(index)); + EXPECT_EQ(index, c->get_item_id(name)); + EXPECT_EQ(name, c->get_item_name(index)); + delete c; +} + +TEST(CrushWrapper, bucket_types) { + CrushWrapper *c = new CrushWrapper; + int index = 123; + string name = "NAME"; + c->set_type_name(index, name); + EXPECT_EQ(1, c->get_num_type_names()); + EXPECT_EQ(index, c->get_type_id(name)); + EXPECT_EQ(name, c->get_type_name(index)); + delete c; +} + +TEST(CrushWrapper, is_valid_crush_name) { + EXPECT_TRUE(CrushWrapper::is_valid_crush_name("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012456789-_")); + EXPECT_FALSE(CrushWrapper::is_valid_crush_name("")); + EXPECT_FALSE(CrushWrapper::is_valid_crush_name("\001")); +} + +TEST(CrushWrapper, is_valid_crush_loc) { + map loc; + EXPECT_TRUE(CrushWrapper::is_valid_crush_loc(g_ceph_context, loc)); + loc["good"] = "better"; + EXPECT_TRUE(CrushWrapper::is_valid_crush_loc(g_ceph_context, loc)); + { + map loc; + loc["\005"] = "default"; + EXPECT_FALSE(CrushWrapper::is_valid_crush_loc(g_ceph_context, loc)); + } + { + map loc; + loc["host"] = "\003"; + EXPECT_FALSE(CrushWrapper::is_valid_crush_loc(g_ceph_context, loc)); + } +} + +TEST(CrushWrapper, dump_rules) { + CrushWrapper *c = new CrushWrapper; + + const int ROOT_TYPE = 1; + c->set_type_name(ROOT_TYPE, "root"); + const int OSD_TYPE = 0; + c->set_type_name(OSD_TYPE, "osd"); + + string failure_domain_type("osd"); + string root_name("default"); + int rootno; + c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + ROOT_TYPE, 0, NULL, NULL, &rootno); + c->set_item_name(rootno, root_name); + + int item = 0; + + pair loc; + int ret; + loc = c->get_immediate_parent(item, &ret); + EXPECT_EQ(-ENOENT, ret); + + { + map loc; + loc["root"] = root_name; + + EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, + "osd.0", loc)); + } + + // no ruleset by default + { + Formatter *f = Formatter::create("json-pretty"); + c->dump_rules(f); + stringstream ss; + f->flush(ss); + delete f; + EXPECT_EQ("\n", ss.str()); + } + + string name("NAME"); + int ruleset = c->add_simple_ruleset(name, root_name, failure_domain_type, + "firstn", pg_pool_t::TYPE_ERASURE); + EXPECT_EQ(0, ruleset); + + { + Formatter *f = Formatter::create("xml"); + c->dump_rules(f); + stringstream ss; + f->flush(ss); + delete f; + EXPECT_EQ((unsigned)0, ss.str().find("0NAME")); + } + + { + Formatter *f = Formatter::create("xml"); + c->dump_rule(ruleset, f); + stringstream ss; + f->flush(ss); + delete f; + EXPECT_EQ((unsigned)0, ss.str().find("0NAME")); + EXPECT_NE(string::npos, + ss.str().find("default")); + } + + map wm; + c->get_rule_weight_osd_map(0, &wm); + ASSERT_TRUE(wm.size() == 1); + ASSERT_TRUE(wm[0] == 1.0); + + delete c; +} + +TEST(CrushWrapper, distance) { + CrushWrapper c; + c.create(); + c.set_type_name(1, "host"); + c.set_type_name(2, "rack"); + c.set_type_name(3, "root"); + int bno; + int r = c.add_bucket(0, CRUSH_BUCKET_STRAW, + CRUSH_HASH_DEFAULT, 3, 0, NULL, + NULL, &bno); + ASSERT_EQ(0, r); + ASSERT_EQ(-1, bno); + c.set_item_name(bno, "default"); + + c.set_max_devices(10); + + //JSONFormatter jf(true); + + map loc; + loc["host"] = "a1"; + loc["rack"] = "a"; + loc["root"] = "default"; + c.insert_item(g_ceph_context, 0, 1, "osd.0", loc); + + loc.clear(); + loc["host"] = "a2"; + loc["rack"] = "a"; + loc["root"] = "default"; + c.insert_item(g_ceph_context, 1, 1, "osd.1", loc); + + loc.clear(); + loc["host"] = "b1"; + loc["rack"] = "b"; + loc["root"] = "default"; + c.insert_item(g_ceph_context, 2, 1, "osd.2", loc); + + loc.clear(); + loc["host"] = "b2"; + loc["rack"] = "b"; + loc["root"] = "default"; + c.insert_item(g_ceph_context, 3, 1, "osd.3", loc); + + vector > ol; + c.get_full_location_ordered(3, ol); + ASSERT_EQ(3u, ol.size()); + ASSERT_EQ(make_pair(string("host"),string("b2")), ol[0]); + ASSERT_EQ(make_pair(string("rack"),string("b")), ol[1]); + ASSERT_EQ(make_pair(string("root"),string("default")), ol[2]); + + //c.dump(&jf); + //jf.flush(cout); + + multimap p; + p.insert(make_pair("host","b2")); + p.insert(make_pair("rack","b")); + p.insert(make_pair("root","default")); + ASSERT_EQ(3, c.get_common_ancestor_distance(g_ceph_context, 0, p)); + ASSERT_EQ(3, c.get_common_ancestor_distance(g_ceph_context, 1, p)); + ASSERT_EQ(2, c.get_common_ancestor_distance(g_ceph_context, 2, p)); + ASSERT_EQ(1, c.get_common_ancestor_distance(g_ceph_context, 3, p)); + ASSERT_EQ(-ENOENT, c.get_common_ancestor_distance(g_ceph_context, 123, p)); + + // make sure a "multipath" location will reflect a minimal + // distance for both paths + p.insert(make_pair("host","b1")); + ASSERT_EQ(1, c.get_common_ancestor_distance(g_ceph_context, 2, p)); + ASSERT_EQ(1, c.get_common_ancestor_distance(g_ceph_context, 3, p)); +} + +int main(int argc, char **argv) { + vector args; + argv_to_vec(argc, (const char **)argv, args); + + vector def_args; + def_args.push_back("--debug-crush=0"); + global_init(&def_args, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); + common_init_finish(g_ceph_context); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +/* + * Local Variables: + * compile-command: "cd ../.. ; make -j4 unittest_crush_wrapper && + * valgrind \ + * --max-stackframe=20000000 --tool=memcheck \ + * ./unittest_crush_wrapper --log-to-stderr=true --debug-crush=20 \ + * # --gtest_filter=CrushWrapper.insert_item" + * End: + */ diff --git a/src/test/crush/TestCrushWrapper.cc b/src/test/crush/TestCrushWrapper.cc deleted file mode 100644 index b735b8469dd6..000000000000 --- a/src/test/crush/TestCrushWrapper.cc +++ /dev/null @@ -1,978 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2013 Cloudwatt - * Copyright (C) 2014 Red Hat - * - * Author: Loic Dachary - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library Public License for more details. - * - */ - -#include -#include - -#include "include/stringify.h" -#include "common/ceph_argparse.h" -#include "global/global_init.h" -#include "global/global_context.h" -#include "include/Context.h" -#include "osd/osd_types.h" - -#include "crush/CrushWrapper.h" - -TEST(CrushWrapper, get_immediate_parent) { - CrushWrapper *c = new CrushWrapper; - - const int ROOT_TYPE = 1; - c->set_type_name(ROOT_TYPE, "root"); - const int OSD_TYPE = 0; - c->set_type_name(OSD_TYPE, "osd"); - - int rootno; - c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - ROOT_TYPE, 0, NULL, NULL, &rootno); - c->set_item_name(rootno, "default"); - - int item = 0; - - pair loc; - int ret; - loc = c->get_immediate_parent(item, &ret); - EXPECT_EQ(-ENOENT, ret); - - { - map loc; - loc["root"] = "default"; - - EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, - "osd.0", loc)); - } - - loc = c->get_immediate_parent(item, &ret); - EXPECT_EQ(0, ret); - EXPECT_EQ("root", loc.first); - EXPECT_EQ("default", loc.second); - - delete c; -} - -TEST(CrushWrapper, straw_zero) { - // zero weight items should have no effect on placement. - - CrushWrapper *c = new CrushWrapper; - const int ROOT_TYPE = 1; - c->set_type_name(ROOT_TYPE, "root"); - const int OSD_TYPE = 0; - c->set_type_name(OSD_TYPE, "osd"); - - int n = 5; - int items[n], weights[n]; - for (int i=0; i set_max_devices(n); - - string root_name0("root0"); - int root0; - EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - ROOT_TYPE, n, items, weights, &root0)); - EXPECT_EQ(0, c->set_item_name(root0, root_name0)); - - string name0("rule0"); - int ruleset0 = c->add_simple_ruleset(name0, root_name0, "osd", - "firstn", pg_pool_t::TYPE_REPLICATED); - EXPECT_EQ(0, ruleset0); - - string root_name1("root1"); - int root1; - EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - ROOT_TYPE, n-1, items, weights, &root1)); - EXPECT_EQ(0, c->set_item_name(root1, root_name1)); - - string name1("rule1"); - int ruleset1 = c->add_simple_ruleset(name1, root_name1, "osd", - "firstn", pg_pool_t::TYPE_REPLICATED); - EXPECT_EQ(1, ruleset1); - - vector reweight(n, 0x10000); - for (int i=0; i<10000; ++i) { - vector out0, out1; - c->do_rule(ruleset0, i, out0, 1, reweight); - ASSERT_EQ(1u, out0.size()); - c->do_rule(ruleset1, i, out1, 1, reweight); - ASSERT_EQ(1u, out1.size()); - ASSERT_EQ(out0[0], out1[0]); - //cout << i << "\t" << out0 << "\t" << out1 << std::endl; - } -} - -TEST(CrushWrapper, straw_same) { - // items with the same weight should map about the same as items - // with very similar weights. - // - // give the 0 vector a paired stair pattern, with dup weights. note - // that the original straw flaw does not appear when there are 2 of - // the initial weight, but it does when there is just 1. - // - // give the 1 vector a similar stair pattern, but make the same - // steps weights slightly different (no dups). this works. - // - // compare the result and verify that the resulting mapping is - // almost identical. - - CrushWrapper *c = new CrushWrapper; - const int ROOT_TYPE = 1; - c->set_type_name(ROOT_TYPE, "root"); - const int OSD_TYPE = 0; - c->set_type_name(OSD_TYPE, "osd"); - - int n = 10; - int items[n], weights[n]; - for (int i=0; i set_max_devices(n); - - string root_name0("root0"); - int root0; - EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - ROOT_TYPE, n, items, weights, &root0)); - EXPECT_EQ(0, c->set_item_name(root0, root_name0)); - - string name0("rule0"); - int ruleset0 = c->add_simple_ruleset(name0, root_name0, "osd", - "firstn", pg_pool_t::TYPE_REPLICATED); - EXPECT_EQ(0, ruleset0); - - for (int i=0; i add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - ROOT_TYPE, n, items, weights, &root1)); - EXPECT_EQ(0, c->set_item_name(root1, root_name1)); - - string name1("rule1"); - int ruleset1 = c->add_simple_ruleset(name1, root_name1, "osd", - "firstn", pg_pool_t::TYPE_REPLICATED); - EXPECT_EQ(1, ruleset1); - - if (0) { - crush_bucket_straw *sb0 = reinterpret_cast(c->get_crush_map()->buckets[-1-root0]); - crush_bucket_straw *sb1 = reinterpret_cast(c->get_crush_map()->buckets[-1-root1]); - - for (int i=0; iitem_weights[i] - << "\t" << sb1->item_weights[i] - << "\t" - << "\t" << sb0->straws[i] - << "\t" << sb1->straws[i] - << std::endl; - } - } - - if (0) { - JSONFormatter jf(true); - jf.open_object_section("crush"); - c->dump(&jf); - jf.close_section(); - jf.flush(cout); - } - - vector sum0(n, 0), sum1(n, 0); - vector reweight(n, 0x10000); - int different = 0; - int max = 100000; - for (int i=0; i out0, out1; - c->do_rule(ruleset0, i, out0, 1, reweight); - ASSERT_EQ(1u, out0.size()); - c->do_rule(ruleset1, i, out1, 1, reweight); - ASSERT_EQ(1u, out1.size()); - sum0[out0[0]]++; - sum1[out1[0]]++; - if (out0[0] != out1[0]) - different++; - } - for (int i=0; iset_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 root0; - EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - ROOT_TYPE, 0, NULL, NULL, &root0)); - EXPECT_EQ(0, c->set_item_name(root0, "root0")); - - { - map loc; - loc["root"] = "root0"; - loc["host"] = "host0"; - - int item = 0; - EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, - "osd.0", loc)); - } - int host0 = c->get_item_id("host0"); - - int root1; - EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - ROOT_TYPE, 0, NULL, NULL, &root1)); - EXPECT_EQ(0, c->set_item_name(root1, "root1")); - - map loc; - loc["root"] = "root1"; - - // 0 is not a valid bucket number, must be negative - EXPECT_EQ(-EINVAL, c->move_bucket(g_ceph_context, 0, loc)); - // -100 is not an existing bucket - EXPECT_EQ(-ENOENT, c->move_bucket(g_ceph_context, -100, loc)); - // move host0 from root0 to root1 - { - pair loc; - int ret; - loc = c->get_immediate_parent(host0, &ret); - EXPECT_EQ(0, ret); - EXPECT_EQ("root", loc.first); - EXPECT_EQ("root0", loc.second); - } - EXPECT_EQ(0, c->move_bucket(g_ceph_context, host0, loc)); - { - pair loc; - int ret; - loc = c->get_immediate_parent(host0, &ret); - EXPECT_EQ(0, ret); - EXPECT_EQ("root", loc.first); - EXPECT_EQ("root1", loc.second); - } - - delete c; -} - -TEST(CrushWrapper, rename_bucket_or_item) { - 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 root0; - EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - ROOT_TYPE, 0, NULL, NULL, &root0)); - EXPECT_EQ(0, c->set_item_name(root0, "root0")); - - int item = 0; - { - map loc; - loc["root"] = "root0"; - loc["host"] = "host0"; - - EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, - "osd.0", loc)); - } - item++; - { - map loc; - loc["root"] = "root0"; - loc["host"] = "host1"; - - EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, - "osd.1", loc)); - } - - stringstream ss; - EXPECT_EQ(-EINVAL, c->can_rename_item("host0", "????", &ss)); - EXPECT_EQ(-EINVAL, c->rename_item("host0", "????", &ss)); - EXPECT_EQ(-EINVAL, c->can_rename_bucket("host0", "????", &ss)); - EXPECT_EQ(-EINVAL, c->rename_bucket("host0", "????", &ss)); - - EXPECT_EQ(-EEXIST, c->can_rename_item("host0", "host1", &ss)); - EXPECT_EQ(-EEXIST, c->rename_item("host0", "host1", &ss)); - EXPECT_EQ(-EEXIST, c->can_rename_bucket("host0", "host1", &ss)); - EXPECT_EQ(-EEXIST, c->rename_bucket("host0", "host1", &ss)); - - EXPECT_EQ(-EALREADY, c->can_rename_item("gone", "host1", &ss)); - EXPECT_EQ(-EALREADY, c->rename_item("gone", "host1", &ss)); - EXPECT_EQ(-EALREADY, c->can_rename_bucket("gone", "host1", &ss)); - EXPECT_EQ(-EALREADY, c->rename_bucket("gone", "host1", &ss)); - - EXPECT_EQ(-ENOENT, c->can_rename_item("doesnotexist", "somethingelse", &ss)); - EXPECT_EQ(-ENOENT, c->rename_item("doesnotexist", "somethingelse", &ss)); - EXPECT_EQ(-ENOENT, c->can_rename_bucket("doesnotexist", "somethingelse", &ss)); - EXPECT_EQ(-ENOENT, c->rename_bucket("doesnotexist", "somethingelse", &ss)); - - EXPECT_EQ(-ENOTDIR, c->can_rename_bucket("osd.1", "somethingelse", &ss)); - EXPECT_EQ(-ENOTDIR, c->rename_bucket("osd.1", "somethingelse", &ss)); - - int host0id = c->get_item_id("host0"); - EXPECT_EQ(0, c->rename_bucket("host0", "host0renamed", &ss)); - EXPECT_EQ(host0id, c->get_item_id("host0renamed")); - - int osd0id = c->get_item_id("osd0"); - EXPECT_EQ(0, c->rename_item("osd.0", "osd0renamed", &ss)); - EXPECT_EQ(osd0id, c->get_item_id("osd0renamed")); - - delete c; -} - -TEST(CrushWrapper, check_item_loc) { - CrushWrapper *c = new CrushWrapper; - int item = 0; - float expected_weight = 1.0; - - // fail if loc is empty - { - float weight; - map loc; - EXPECT_FALSE(c->check_item_loc(g_ceph_context, item, loc, &weight)); - } - - 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 rootno; - c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - ROOT_TYPE, 0, NULL, NULL, &rootno); - c->set_item_name(rootno, "default"); - - // fail because the item is not found at the specified location - { - float weight; - map loc; - loc["root"] = "default"; - EXPECT_FALSE(c->check_item_loc(g_ceph_context, item, loc, &weight)); - } - // fail because the bucket name does not match an existing bucket - { - float weight; - map loc; - loc["root"] = "default"; - const string HOST("host0"); - loc["host"] = HOST; - EXPECT_FALSE(c->check_item_loc(g_ceph_context, item, loc, &weight)); - } - const string OSD("osd.0"); - { - map loc; - loc["root"] = "default"; - EXPECT_EQ(0, c->insert_item(g_ceph_context, item, expected_weight, - OSD, loc)); - } - // fail because osd.0 is not a bucket and must not be in loc, in - // addition to being of the wrong type - { - float weight; - map loc; - loc["root"] = "osd.0"; - EXPECT_FALSE(c->check_item_loc(g_ceph_context, item, loc, &weight)); - } - // succeed and retrieves the expected weight - { - float weight; - map loc; - loc["root"] = "default"; - EXPECT_TRUE(c->check_item_loc(g_ceph_context, item, loc, &weight)); - EXPECT_EQ(expected_weight, weight); - } - - delete c; -} - -TEST(CrushWrapper, update_item) { - 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 rootno; - c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - ROOT_TYPE, 0, NULL, NULL, &rootno); - c->set_item_name(rootno, "default"); - - const string HOST0("host0"); - int host0; - c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - HOST_TYPE, 0, NULL, NULL, &host0); - c->set_item_name(host0, HOST0); - - const string HOST1("host1"); - int host1; - c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - HOST_TYPE, 0, NULL, NULL, &host1); - c->set_item_name(host1, HOST1); - - int item = 0; - - // fail if invalid names anywhere in loc - { - map loc; - loc["rack"] = "\001"; - EXPECT_EQ(-EINVAL, c->update_item(g_ceph_context, item, 1.0, - "osd." + stringify(item), loc)); - } - // fail if invalid item name - { - map loc; - EXPECT_EQ(-EINVAL, c->update_item(g_ceph_context, item, 1.0, - "\005", loc)); - } - const string OSD0("osd.0"); - const string OSD1("osd.1"); - float original_weight = 1.0; - float modified_weight = 2.0; - float weight; - - map loc; - loc["root"] = "default"; - loc["host"] = HOST0; - EXPECT_GE(0.0, c->get_item_weightf(host0)); - EXPECT_EQ(0, c->insert_item(g_ceph_context, item, original_weight, - OSD0, loc)); - - // updating nothing changes nothing - EXPECT_EQ(OSD0, c->get_item_name(item)); - EXPECT_EQ(original_weight, c->get_item_weightf(item)); - EXPECT_TRUE(c->check_item_loc(g_ceph_context, item, loc, &weight)); - EXPECT_EQ(0, c->update_item(g_ceph_context, item, original_weight, - OSD0, loc)); - EXPECT_EQ(OSD0, c->get_item_name(item)); - EXPECT_EQ(original_weight, c->get_item_weightf(item)); - EXPECT_TRUE(c->check_item_loc(g_ceph_context, item, loc, &weight)); - - // update the name and weight of the item but not the location - EXPECT_EQ(OSD0, c->get_item_name(item)); - EXPECT_EQ(original_weight, c->get_item_weightf(item)); - EXPECT_TRUE(c->check_item_loc(g_ceph_context, item, loc, &weight)); - EXPECT_EQ(1, c->update_item(g_ceph_context, item, modified_weight, - OSD1, loc)); - EXPECT_EQ(OSD1, c->get_item_name(item)); - EXPECT_EQ(modified_weight, c->get_item_weightf(item)); - EXPECT_TRUE(c->check_item_loc(g_ceph_context, item, loc, &weight)); - c->set_item_name(item, OSD0); - c->adjust_item_weightf(g_ceph_context, item, original_weight); - - // update the name and weight of the item and change its location - map other_loc; - other_loc["root"] = "default"; - other_loc["host"] = HOST1; - - EXPECT_EQ(OSD0, c->get_item_name(item)); - EXPECT_EQ(original_weight, c->get_item_weightf(item)); - EXPECT_TRUE(c->check_item_loc(g_ceph_context, item, loc, &weight)); - EXPECT_FALSE(c->check_item_loc(g_ceph_context, item, other_loc, &weight)); - EXPECT_EQ(1, c->update_item(g_ceph_context, item, modified_weight, - OSD1, other_loc)); - EXPECT_EQ(OSD1, c->get_item_name(item)); - EXPECT_EQ(modified_weight, c->get_item_weightf(item)); - EXPECT_FALSE(c->check_item_loc(g_ceph_context, item, loc, &weight)); - EXPECT_TRUE(c->check_item_loc(g_ceph_context, item, other_loc, &weight)); - - delete c; -} - -TEST(CrushWrapper, adjust_item_weight) { - 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 rootno; - c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - ROOT_TYPE, 0, NULL, NULL, &rootno); - c->set_item_name(rootno, "default"); - - const string HOST0("host0"); - int host0; - c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - HOST_TYPE, 0, NULL, NULL, &host0); - c->set_item_name(host0, HOST0); - - const string FAKE("fake"); - int hostfake; - c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - HOST_TYPE, 0, NULL, NULL, &hostfake); - c->set_item_name(hostfake, FAKE); - - int item = 0; - - // construct crush map - - { - map loc; - loc["host"] = "host0"; - float host_weight = 2.0; - int bucket_id = 0; - - item = 0; - EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, - "osd." + stringify(item), loc)); - item = 1; - EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, - "osd." + stringify(item), loc)); - - bucket_id = c->get_item_id("host0"); - EXPECT_EQ(true, c->bucket_exists(bucket_id)); - EXPECT_EQ(host_weight, c->get_bucket_weightf(bucket_id)); - - } - - { - map loc; - loc["host"] = "fake"; - float host_weight = 2.0; - int bucket_id = 0; - - item = 0; - EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, - "osd." + stringify(item), loc)); - item = 1; - EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, - "osd." + stringify(item), loc)); - - bucket_id = c->get_item_id("fake"); - EXPECT_EQ(true, c->bucket_exists(bucket_id)); - EXPECT_EQ(host_weight, c->get_bucket_weightf(bucket_id)); - } - - // - // When there is: - // - // default --> host0 --> osd.0 1.0 - // | | - // | +-> osd.1 1.0 - // | - // +-> fake --> osd.0 1.0 - // | - // +-> osd.1 1.0 - // - // Trying to adjust osd.0 weight to 2.0 in all buckets - // Trying to adjust osd.1 weight to 2.0 in host=fake - // - // So the crush map will be: - // - // default --> host0 --> osd.0 2.0 - // | | - // | +-> osd.1 1.0 - // | - // +-> fake --> osd.0 2.0 - // | - // +-> osd.1 2.0 - // - - float original_weight = 1.0; - float modified_weight = 2.0; - map loc_one, loc_two; - loc_one["host"] = "host0"; - loc_two["host"] = "fake"; - - item = 0; - EXPECT_EQ(2, c->adjust_item_weightf(g_ceph_context, item, modified_weight)); - EXPECT_EQ(modified_weight, c->get_item_weightf_in_loc(item, loc_one)); - EXPECT_EQ(modified_weight, c->get_item_weightf_in_loc(item, loc_two)); - - item = 1; - EXPECT_EQ(1, c->adjust_item_weightf_in_loc(g_ceph_context, item, modified_weight, loc_two)); - EXPECT_EQ(original_weight, c->get_item_weightf_in_loc(item, loc_one)); - EXPECT_EQ(modified_weight, c->get_item_weightf_in_loc(item, loc_two)); -} - -TEST(CrushWrapper, insert_item) { - 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 rootno; - c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - ROOT_TYPE, 0, NULL, NULL, &rootno); - c->set_item_name(rootno, "default"); - - int item = 0; - - // invalid names anywhere in loc trigger an error - { - map loc; - loc["host"] = "\001"; - EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, - "osd." + stringify(item), loc)); - } - - // insert an item in an existing bucket - { - map loc; - loc["root"] = "default"; - - item++; - EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, - "osd." + stringify(item), loc)); - int another_item = item + 1; - EXPECT_EQ(-EEXIST, c->insert_item(g_ceph_context, another_item, 1.0, - "osd." + stringify(item), loc)); - } - // implicit creation of a bucket - { - string name = "NAME"; - map loc; - loc["root"] = "default"; - loc["host"] = name; - - item++; - EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, - "osd." + stringify(item), loc)); - } - // adding to an existing item name that is not associated with a bucket - { - string name = "ITEM_WITHOUT_BUCKET"; - map loc; - loc["root"] = "default"; - loc["host"] = name; - item++; - c->set_item_name(item, name); - - item++; - EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, - "osd." + stringify(item), loc)); - } - // - // When there is: - // - // default --> host0 --> item - // - // Trying to insert the same item higher in the hirarchy will fail - // because it would create a loop. - // - // default --> host0 --> item - // | - // +-> item - // - { - item++; - { - map loc; - loc["root"] = "default"; - loc["host"] = "host0"; - - EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, - "osd." + stringify(item), loc)); - } - { - map loc; - loc["root"] = "default"; - - EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, - "osd." + stringify(item), loc)); - } - } - // - // When there is: - // - // default --> host0 - // - // Trying to insert default under host0 must fail - // because it would create a loop. - // - // default --> host0 --> default - // - { - map loc; - loc["host"] = "host0"; - - EXPECT_EQ(-ELOOP, c->insert_item(g_ceph_context, rootno, 1.0, - "default", loc)); - } - // fail when mapping a bucket to the wrong type - { - // create an OSD bucket - int osdno; - int r = c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - 10, 0, NULL, NULL, &osdno); - ASSERT_EQ(0, r); - c->set_item_name(osdno, "myosd"); - map loc; - loc["root"] = "default"; - // wrongfully pretend the osd is of type host - loc["host"] = "myosd"; - - item++; - EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, - "osd." + stringify(item), loc)); - } - // fail when no location - { - map loc; - item++; - EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, - "osd." + stringify(item), loc)); - } - - delete c; -} - -TEST(CrushWrapper, item_bucket_names) { - CrushWrapper *c = new CrushWrapper; - int index = 123; - string name = "NAME"; - EXPECT_EQ(-EINVAL, c->set_item_name(index, "\001")); - EXPECT_EQ(0, c->set_item_name(index, name)); - EXPECT_TRUE(c->name_exists(name)); - EXPECT_TRUE(c->item_exists(index)); - EXPECT_EQ(index, c->get_item_id(name)); - EXPECT_EQ(name, c->get_item_name(index)); - delete c; -} - -TEST(CrushWrapper, bucket_types) { - CrushWrapper *c = new CrushWrapper; - int index = 123; - string name = "NAME"; - c->set_type_name(index, name); - EXPECT_EQ(1, c->get_num_type_names()); - EXPECT_EQ(index, c->get_type_id(name)); - EXPECT_EQ(name, c->get_type_name(index)); - delete c; -} - -TEST(CrushWrapper, is_valid_crush_name) { - EXPECT_TRUE(CrushWrapper::is_valid_crush_name("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012456789-_")); - EXPECT_FALSE(CrushWrapper::is_valid_crush_name("")); - EXPECT_FALSE(CrushWrapper::is_valid_crush_name("\001")); -} - -TEST(CrushWrapper, is_valid_crush_loc) { - map loc; - EXPECT_TRUE(CrushWrapper::is_valid_crush_loc(g_ceph_context, loc)); - loc["good"] = "better"; - EXPECT_TRUE(CrushWrapper::is_valid_crush_loc(g_ceph_context, loc)); - { - map loc; - loc["\005"] = "default"; - EXPECT_FALSE(CrushWrapper::is_valid_crush_loc(g_ceph_context, loc)); - } - { - map loc; - loc["host"] = "\003"; - EXPECT_FALSE(CrushWrapper::is_valid_crush_loc(g_ceph_context, loc)); - } -} - -TEST(CrushWrapper, dump_rules) { - CrushWrapper *c = new CrushWrapper; - - const int ROOT_TYPE = 1; - c->set_type_name(ROOT_TYPE, "root"); - const int OSD_TYPE = 0; - c->set_type_name(OSD_TYPE, "osd"); - - string failure_domain_type("osd"); - string root_name("default"); - int rootno; - c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - ROOT_TYPE, 0, NULL, NULL, &rootno); - c->set_item_name(rootno, root_name); - - int item = 0; - - pair loc; - int ret; - loc = c->get_immediate_parent(item, &ret); - EXPECT_EQ(-ENOENT, ret); - - { - map loc; - loc["root"] = root_name; - - EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, - "osd.0", loc)); - } - - // no ruleset by default - { - Formatter *f = Formatter::create("json-pretty"); - c->dump_rules(f); - stringstream ss; - f->flush(ss); - delete f; - EXPECT_EQ("\n", ss.str()); - } - - string name("NAME"); - int ruleset = c->add_simple_ruleset(name, root_name, failure_domain_type, - "firstn", pg_pool_t::TYPE_ERASURE); - EXPECT_EQ(0, ruleset); - - { - Formatter *f = Formatter::create("xml"); - c->dump_rules(f); - stringstream ss; - f->flush(ss); - delete f; - EXPECT_EQ((unsigned)0, ss.str().find("0NAME")); - } - - { - Formatter *f = Formatter::create("xml"); - c->dump_rule(ruleset, f); - stringstream ss; - f->flush(ss); - delete f; - EXPECT_EQ((unsigned)0, ss.str().find("0NAME")); - EXPECT_NE(string::npos, - ss.str().find("default")); - } - - map wm; - c->get_rule_weight_osd_map(0, &wm); - ASSERT_TRUE(wm.size() == 1); - ASSERT_TRUE(wm[0] == 1.0); - - delete c; -} - -TEST(CrushWrapper, distance) { - CrushWrapper c; - c.create(); - c.set_type_name(1, "host"); - c.set_type_name(2, "rack"); - c.set_type_name(3, "root"); - int bno; - int r = c.add_bucket(0, CRUSH_BUCKET_STRAW, - CRUSH_HASH_DEFAULT, 3, 0, NULL, - NULL, &bno); - ASSERT_EQ(0, r); - ASSERT_EQ(-1, bno); - c.set_item_name(bno, "default"); - - c.set_max_devices(10); - - //JSONFormatter jf(true); - - map loc; - loc["host"] = "a1"; - loc["rack"] = "a"; - loc["root"] = "default"; - c.insert_item(g_ceph_context, 0, 1, "osd.0", loc); - - loc.clear(); - loc["host"] = "a2"; - loc["rack"] = "a"; - loc["root"] = "default"; - c.insert_item(g_ceph_context, 1, 1, "osd.1", loc); - - loc.clear(); - loc["host"] = "b1"; - loc["rack"] = "b"; - loc["root"] = "default"; - c.insert_item(g_ceph_context, 2, 1, "osd.2", loc); - - loc.clear(); - loc["host"] = "b2"; - loc["rack"] = "b"; - loc["root"] = "default"; - c.insert_item(g_ceph_context, 3, 1, "osd.3", loc); - - vector > ol; - c.get_full_location_ordered(3, ol); - ASSERT_EQ(3u, ol.size()); - ASSERT_EQ(make_pair(string("host"),string("b2")), ol[0]); - ASSERT_EQ(make_pair(string("rack"),string("b")), ol[1]); - ASSERT_EQ(make_pair(string("root"),string("default")), ol[2]); - - //c.dump(&jf); - //jf.flush(cout); - - multimap p; - p.insert(make_pair("host","b2")); - p.insert(make_pair("rack","b")); - p.insert(make_pair("root","default")); - ASSERT_EQ(3, c.get_common_ancestor_distance(g_ceph_context, 0, p)); - ASSERT_EQ(3, c.get_common_ancestor_distance(g_ceph_context, 1, p)); - ASSERT_EQ(2, c.get_common_ancestor_distance(g_ceph_context, 2, p)); - ASSERT_EQ(1, c.get_common_ancestor_distance(g_ceph_context, 3, p)); - ASSERT_EQ(-ENOENT, c.get_common_ancestor_distance(g_ceph_context, 123, p)); - - // make sure a "multipath" location will reflect a minimal - // distance for both paths - p.insert(make_pair("host","b1")); - ASSERT_EQ(1, c.get_common_ancestor_distance(g_ceph_context, 2, p)); - ASSERT_EQ(1, c.get_common_ancestor_distance(g_ceph_context, 3, p)); -} - -int main(int argc, char **argv) { - vector args; - argv_to_vec(argc, (const char **)argv, args); - - vector def_args; - def_args.push_back("--debug-crush=0"); - global_init(&def_args, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); - common_init_finish(g_ceph_context); - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - -/* - * Local Variables: - * compile-command: "cd ../.. ; make -j4 unittest_crush_wrapper && - * valgrind \ - * --max-stackframe=20000000 --tool=memcheck \ - * ./unittest_crush_wrapper --log-to-stderr=true --debug-crush=20 \ - * # --gtest_filter=CrushWrapper.insert_item" - * End: - */ diff --git a/src/test/crush/crush.cc b/src/test/crush/crush.cc new file mode 100644 index 000000000000..887791472588 --- /dev/null +++ b/src/test/crush/crush.cc @@ -0,0 +1,265 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2013 Inktank + * + * LGPL2.1 (see COPYING-LGPL2.1) or later + */ + +#include +#include + +#include "include/stringify.h" +#include "common/ceph_argparse.h" +#include "global/global_init.h" +#include "global/global_context.h" + +#include "crush/CrushWrapper.h" + +#include + +CrushWrapper *build_indep_map(CephContext *cct, int num_rack, int num_host, + int num_osd) +{ + CrushWrapper *c = new CrushWrapper; + c->create(); + + c->set_type_name(5, "root"); + c->set_type_name(4, "row"); + c->set_type_name(3, "rack"); + c->set_type_name(2, "chasis"); + c->set_type_name(1, "host"); + c->set_type_name(0, "osd"); + + int rootno; + c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, + 5, 0, NULL, NULL, &rootno); + c->set_item_name(rootno, "default"); + + map loc; + loc["root"] = "default"; + + int osd = 0; + for (int r=0; rinsert_item(cct, osd, 1.0, string("osd.") + stringify(osd), loc); + } + } + } + int ret; + int ruleno = 0; + int ruleset = 0; + ruleno = ruleset; + ret = c->add_rule(4, ruleset, 123, 1, 20, ruleno); + assert(ret == ruleno); + ret = c->set_rule_step(ruleno, 0, CRUSH_RULE_SET_CHOOSELEAF_TRIES, 10, 0); + assert(ret == 0); + ret = c->set_rule_step(ruleno, 1, CRUSH_RULE_TAKE, rootno, 0); + assert(ret == 0); + ret = c->set_rule_step(ruleno, 2, CRUSH_RULE_CHOOSELEAF_INDEP, CRUSH_CHOOSE_N, 1); + assert(ret == 0); + ret = c->set_rule_step(ruleno, 3, CRUSH_RULE_EMIT, 0, 0); + assert(ret == 0); + c->set_rule_name(ruleno, "data"); + + if (false) { + Formatter *f = Formatter::create("json-pretty"); + f->open_object_section("crush_map"); + c->dump(f); + f->close_section(); + f->flush(cout); + delete f; + } + + return c; +} + +int get_num_dups(const vector& v) +{ + std::set s; + int dups = 0; + for (unsigned i=0; i weight(c->get_max_devices(), 0x10000); + c->dump_tree(weight, &cout, NULL); + + for (int x = 0; x < 100; ++x) { + vector out; + c->do_rule(0, x, out, 5, weight); + cout << x << " -> " << out << std::endl; + int num_none = 0; + for (unsigned i=0; i weight(c->get_max_devices(), 0x10000); + c->dump_tree(weight, &cout, NULL); + + for (int x = 0; x < 100; ++x) { + vector out; + c->do_rule(0, x, out, 5, weight); + cout << x << " -> " << out << std::endl; + int num_none = 0; + for (unsigned i=0; i weight(c->get_max_devices(), 0x10000); + + // mark a bunch of osds out + int num = 3*3*3; + for (int i=0; idump_tree(weight, &cout, NULL); + + // need more retries to get 9/9 hosts for x in 0..99 + c->set_choose_total_tries(100); + for (int x = 0; x < 100; ++x) { + vector out; + c->do_rule(0, x, out, 9, weight); + cout << x << " -> " << out << std::endl; + int num_none = 0; + for (unsigned i=0; i weight(c->get_max_devices(), 0x10000); + + // mark a bunch of osds out + int num = 3*3*3; + for (int i=0; idump_tree(weight, &cout, NULL); + + c->set_choose_total_tries(100); + for (int x = 0; x < 100; ++x) { + vector out; + c->do_rule(0, x, out, 7, weight); + cout << x << " -> " << out << std::endl; + int num_none = 0; + for (unsigned i=0; iset_choose_total_tries(100); + vector<__u32> tweight(c->get_max_devices(), 0x10000); + c->dump_tree(tweight, &cout, NULL); + + int tchanged = 0; + for (int x = 1; x < 5; ++x) { + vector<__u32> weight(c->get_max_devices(), 0x10000); + + std::map pos; + vector prev; + for (unsigned i=0; i out; + c->do_rule(0, x, out, 7, weight); + cout << "(" << i << "/" << weight.size() << " out) " + << x << " -> " << out << std::endl; + int num_none = 0; + for (unsigned k=0; k args; + argv_to_vec(argc, (const char **)argv, args); + + global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); + common_init_finish(g_ceph_context); + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/test/crush/indep.cc b/src/test/crush/indep.cc deleted file mode 100644 index 887791472588..000000000000 --- a/src/test/crush/indep.cc +++ /dev/null @@ -1,265 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2013 Inktank - * - * LGPL2.1 (see COPYING-LGPL2.1) or later - */ - -#include -#include - -#include "include/stringify.h" -#include "common/ceph_argparse.h" -#include "global/global_init.h" -#include "global/global_context.h" - -#include "crush/CrushWrapper.h" - -#include - -CrushWrapper *build_indep_map(CephContext *cct, int num_rack, int num_host, - int num_osd) -{ - CrushWrapper *c = new CrushWrapper; - c->create(); - - c->set_type_name(5, "root"); - c->set_type_name(4, "row"); - c->set_type_name(3, "rack"); - c->set_type_name(2, "chasis"); - c->set_type_name(1, "host"); - c->set_type_name(0, "osd"); - - int rootno; - c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, - 5, 0, NULL, NULL, &rootno); - c->set_item_name(rootno, "default"); - - map loc; - loc["root"] = "default"; - - int osd = 0; - for (int r=0; rinsert_item(cct, osd, 1.0, string("osd.") + stringify(osd), loc); - } - } - } - int ret; - int ruleno = 0; - int ruleset = 0; - ruleno = ruleset; - ret = c->add_rule(4, ruleset, 123, 1, 20, ruleno); - assert(ret == ruleno); - ret = c->set_rule_step(ruleno, 0, CRUSH_RULE_SET_CHOOSELEAF_TRIES, 10, 0); - assert(ret == 0); - ret = c->set_rule_step(ruleno, 1, CRUSH_RULE_TAKE, rootno, 0); - assert(ret == 0); - ret = c->set_rule_step(ruleno, 2, CRUSH_RULE_CHOOSELEAF_INDEP, CRUSH_CHOOSE_N, 1); - assert(ret == 0); - ret = c->set_rule_step(ruleno, 3, CRUSH_RULE_EMIT, 0, 0); - assert(ret == 0); - c->set_rule_name(ruleno, "data"); - - if (false) { - Formatter *f = Formatter::create("json-pretty"); - f->open_object_section("crush_map"); - c->dump(f); - f->close_section(); - f->flush(cout); - delete f; - } - - return c; -} - -int get_num_dups(const vector& v) -{ - std::set s; - int dups = 0; - for (unsigned i=0; i weight(c->get_max_devices(), 0x10000); - c->dump_tree(weight, &cout, NULL); - - for (int x = 0; x < 100; ++x) { - vector out; - c->do_rule(0, x, out, 5, weight); - cout << x << " -> " << out << std::endl; - int num_none = 0; - for (unsigned i=0; i weight(c->get_max_devices(), 0x10000); - c->dump_tree(weight, &cout, NULL); - - for (int x = 0; x < 100; ++x) { - vector out; - c->do_rule(0, x, out, 5, weight); - cout << x << " -> " << out << std::endl; - int num_none = 0; - for (unsigned i=0; i weight(c->get_max_devices(), 0x10000); - - // mark a bunch of osds out - int num = 3*3*3; - for (int i=0; idump_tree(weight, &cout, NULL); - - // need more retries to get 9/9 hosts for x in 0..99 - c->set_choose_total_tries(100); - for (int x = 0; x < 100; ++x) { - vector out; - c->do_rule(0, x, out, 9, weight); - cout << x << " -> " << out << std::endl; - int num_none = 0; - for (unsigned i=0; i weight(c->get_max_devices(), 0x10000); - - // mark a bunch of osds out - int num = 3*3*3; - for (int i=0; idump_tree(weight, &cout, NULL); - - c->set_choose_total_tries(100); - for (int x = 0; x < 100; ++x) { - vector out; - c->do_rule(0, x, out, 7, weight); - cout << x << " -> " << out << std::endl; - int num_none = 0; - for (unsigned i=0; iset_choose_total_tries(100); - vector<__u32> tweight(c->get_max_devices(), 0x10000); - c->dump_tree(tweight, &cout, NULL); - - int tchanged = 0; - for (int x = 1; x < 5; ++x) { - vector<__u32> weight(c->get_max_devices(), 0x10000); - - std::map pos; - vector prev; - for (unsigned i=0; i out; - c->do_rule(0, x, out, 7, weight); - cout << "(" << i << "/" << weight.size() << " out) " - << x << " -> " << out << std::endl; - int num_none = 0; - for (unsigned k=0; k args; - argv_to_vec(argc, (const char **)argv, args); - - global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); - common_init_finish(g_ceph_context); - - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -}