From: Samuel Just Date: Wed, 20 Dec 2023 01:00:44 +0000 (-0800) Subject: test/crush/crush.cc: add test variants for firstn rules X-Git-Tag: v19.3.0~57^2~9 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=0445c3347e4ad825ec05dd4623806f3a65fcbb89;p=ceph.git test/crush/crush.cc: add test variants for firstn rules Signed-off-by: Samuel Just --- diff --git a/src/test/crush/crush.cc b/src/test/crush/crush.cc index ce92afcfb42f..03bbca97e32f 100644 --- a/src/test/crush/crush.cc +++ b/src/test/crush/crush.cc @@ -388,6 +388,309 @@ INSTANTIATE_TEST_SUITE_P( ::testing::Values(RuleType(true), RuleType(false)), testing::PrintToStringParamName()); +class FirstnTest : public ::testing::TestWithParam +{ +public: + void SetUp() final + { + CephInitParameters params(CEPH_ENTITY_TYPE_CLIENT); + cct = common_preinit(params, CODE_ENVIRONMENT_UTILITY, + CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); + } + void TearDown() final + { + cct->put(); + cct = nullptr; + } + + std::unique_ptr build_firstn_map( + CephContext *cct, int num_rack, int num_host, int num_osd) + { + std::unique_ptr c(new CrushWrapper); + c->create(); + c->set_tunables_optimal(); + + 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, nullptr, nullptr, &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; + + if (GetParam().is_msr()) { + unsigned step_id = 0; + ret = c->add_rule(ruleno, 4, CRUSH_RULE_TYPE_MSR_FIRSTN); + ceph_assert(ret == ruleno); + ret = c->set_rule_step(ruleno, step_id++, CRUSH_RULE_TAKE, rootno, 0); + ceph_assert(ret == 0); + ret = c->set_rule_step( + ruleno, step_id++, CRUSH_RULE_CHOOSE_MSR, CRUSH_CHOOSE_N, 1); + ceph_assert(ret == 0); + ret = c->set_rule_step(ruleno, step_id++, CRUSH_RULE_CHOOSE_MSR, 1, 0); + ceph_assert(ret == 0); + ret = c->set_rule_step(ruleno, step_id++, CRUSH_RULE_EMIT, 0, 0); + ceph_assert(ret == 0); + } else { + unsigned step_id = 0; + ret = c->add_rule(ruleno, 4, CRUSH_RULE_TYPE_ERASURE); + ceph_assert(ret == ruleno); + ret = c->set_rule_step( + ruleno, step_id++, CRUSH_RULE_SET_CHOOSELEAF_TRIES, 0, 0); + ceph_assert(ret == 0); + ret = c->set_rule_step(ruleno, step_id++, CRUSH_RULE_TAKE, rootno, 0); + ceph_assert(ret == 0); + ret = c->set_rule_step( + ruleno, step_id++, CRUSH_RULE_CHOOSELEAF_FIRSTN, CRUSH_CHOOSE_N, 1); + ceph_assert(ret == 0); + ret = c->set_rule_step(ruleno, step_id++, CRUSH_RULE_EMIT, 0, 0); + ceph_assert(ret == 0); + } + + c->set_rule_name(ruleno, "data"); + c->finalize(); + + 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; + } + +protected: + CephContext *cct = nullptr; +}; + +TEST_P(FirstnTest, basic) { + std::unique_ptr c(build_firstn_map(cct, 3, 3, 3)); + vector<__u32> weight(c->get_max_devices(), 0x10000); + c->dump_tree(&cout, nullptr); + + for (int x = 0; x < 100; ++x) { + vector out; + c->do_rule(0, x, out, 3, weight, 0); + cout << x << " -> " << out << std::endl; + for (unsigned i=0; i c(build_firstn_map(cct, 1, 3, 1)); + vector<__u32> weight(c->get_max_devices(), 0x10000); + c->dump_tree(&cout, nullptr); + + for (int x = 0; x < 100; ++x) { + vector out; + c->do_rule(0, x, out, 5, weight, 0); + cout << x << " -> " << out << std::endl; + for (unsigned i=0; i c(build_firstn_map(cct, 3, 3, 3)); + c->dump_tree(&cout, nullptr); + + for (int x = 0; x < 1000; ++x) { + vector<__u32> weight(c->get_max_devices(), 0x10000); + vector out; + c->do_rule(0, x, out, 3, weight, 0); + + for (unsigned i=0; i out2; + c->do_rule(0, x, out2, 3, weight, 0); + + cout << "input " << x + << " marked out " << out[0] + << " out " << out + << " -> out2 " << out2 + << std::endl; + + ASSERT_EQ(3, out2.size()); + ASSERT_EQ(0, get_num_dups(out2)); + for (unsigned i=0; i c(build_firstn_map(cct, 3, 3, 3)); + c->dump_tree(&cout, nullptr); + + for (int x = 0; x < 1000; ++x) { + vector<__u32> weight(c->get_max_devices(), 0x10000); + vector out; + c->do_rule(0, x, out, 3, weight, 0); + + for (unsigned i=0; i out2; + c->do_rule(0, x, out2, 3, weight, 0); + + cout << "input " << x + << " marked out " << out[0] + << " out " << out + << " -> out2 " << out2 + << std::endl; + + ASSERT_EQ(3, out2.size()); + ASSERT_EQ(0, get_num_dups(out2)); + for (unsigned i=0; i c(build_firstn_map(cct, 3, 3, 3)); + vector<__u32> weight(c->get_max_devices(), 0x10000); + + // mark a bunch of osds out + int num = 3*3*3; + for (int i=0; idump_tree(&cout, nullptr); + + // need more retries to get 9/9 hosts for x in 0..99 + if (!GetParam().is_msr()) { + c->set_choose_total_tries(500); + } + for (int x = 0; x < 100; ++x) { + vector out; + c->do_rule(0, x, out, 9, weight, 0); + cout << x << " -> " << out << std::endl; + ASSERT_EQ(9, out.size()); + ASSERT_EQ(0, get_num_dups(out)); + } +} + +TEST_P(FirstnTest, out_contig) { + std::unique_ptr c(build_firstn_map(cct, 3, 3, 3)); + vector<__u32> weight(c->get_max_devices(), 0x10000); + + // mark a bunch of osds out + int num = 3*3*3; + for (int i=0; idump_tree(&cout, nullptr); + + // need more retries to get 7/7 hosts for x in 0..99 + if (!GetParam().is_msr()) { + c->set_choose_total_tries(500); + } + for (int x = 0; x < 100; ++x) { + vector out; + c->do_rule(0, x, out, 7, weight, 0); + cout << x << " -> " << out << std::endl; + ASSERT_EQ(6, out.size()); + ASSERT_EQ(0, get_num_dups(out)); + } +} + +TEST_P(FirstnTest, out_progressive) { + std::unique_ptr c(build_firstn_map(cct, 3, 3, 3)); + if (!GetParam().is_msr()) { + c->set_choose_total_tries(500); + } + vector<__u32> tweight(c->get_max_devices(), 0x10000); + c->dump_tree(&cout, nullptr); + + int tchanged = 0; + for (int x = 1; x < 5; ++x) { + vector<__u32> weight(c->get_max_devices(), 0x10000); + + std::set prev; + for (unsigned i=0; i out; + c->do_rule(0, x, out, 7, weight, 0); + cout << "(" << i << "/" << weight.size() << " out) "; + if (i > 0) cout << "marked out " << i - 1 << " "; + cout << x << " -> " << out << std::endl; + + ASSERT_EQ(0, get_num_dups(out)); + + int changed = 0; + for (unsigned j=0; j{out.begin(), out.end()}; + } + } + cout << tchanged << " total changed" << std::endl; +} + +INSTANTIATE_TEST_SUITE_P( + FirstnTest, + FirstnTest, + ::testing::Values(RuleType(true), RuleType(false)), + testing::PrintToStringParamName()); class CRUSHTest : public ::testing::Test {