From: Sage Weil Date: Wed, 30 Oct 2013 15:59:00 +0000 (-0700) Subject: crush/CrushWrapper: add get_common_ancestor_distance() X-Git-Tag: v0.75~37^2~7 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=dcc5e3559f625689b11a39ca5c587c00eb5f88b7;p=ceph.git crush/CrushWrapper: add get_common_ancestor_distance() Calculate closest common ancestor (type) in the hierarchy. Signed-off-by: Sage Weil --- diff --git a/src/crush/CrushWrapper.cc b/src/crush/CrushWrapper.cc index 95ec2e6977a..9a7abd2cd13 100644 --- a/src/crush/CrushWrapper.cc +++ b/src/crush/CrushWrapper.cc @@ -193,6 +193,33 @@ int CrushWrapper::remove_item_under(CephContext *cct, int item, int ancestor, bo return ret; } +int CrushWrapper::get_common_ancestor_distance(CephContext *cct, int id, + const std::multimap& loc) +{ + ldout(cct, 5) << __func__ << " " << id << " " << loc << dendl; + if (!item_exists(id)) + return -ENOENT; + map id_loc = get_full_location(id); + ldout(cct, 20) << " id is at " << id_loc << dendl; + + for (map::const_iterator p = type_map.begin(); + p != type_map.end(); + ++p) { + map::iterator ip = id_loc.find(p->second); + if (ip == id_loc.end()) + continue; + for (std::multimap::const_iterator q = loc.find(p->second); + q != loc.end(); + ++q) { + if (q->first != p->second) + break; + if (q->second == ip->second) + return p->first; + } + } + return -ERANGE; +} + int CrushWrapper::parse_loc_map(const std::vector& args, std::map *ploc) { diff --git a/src/crush/CrushWrapper.h b/src/crush/CrushWrapper.h index a4c9dd00227..9ff1b02c878 100644 --- a/src/crush/CrushWrapper.h +++ b/src/crush/CrushWrapper.h @@ -472,6 +472,19 @@ private: public: int remove_item_under(CephContext *cct, int id, int ancestor, bool unlink_only); + /** + * calculate the locality/distance from a given id to a crush location map + * + * Specifically, we look for the lowest-valued type for which the + * location of id matches that described in loc. + * + * @param cct cct + * @param id the existing id in the map + * @param loc a set of key=value pairs describing a location in the hierarchy + */ + int get_common_ancestor_distance(CephContext *cct, int id, + const std::multimap& loc); + /** * parse a set of key/value pairs out of a string vector * diff --git a/src/test/Makefile.am b/src/test/Makefile.am index f3a433ab4e9..a6ec1004e45 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -274,6 +274,11 @@ unittest_str_map_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_str_map_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_str_map +unittest_crushwrapper_SOURCES = test/test_crushwrapper.cc +unittest_crushwrapper_CXXFLAGS = $(UNITTEST_CXXFLAGS) +unittest_crushwrapper_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(LIBCRUSH) +check_PROGRAMS += unittest_crushwrapper + unittest_sharedptr_registry_SOURCES = test/common/test_sharedptr_registry.cc unittest_sharedptr_registry_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_sharedptr_registry_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) diff --git a/src/test/test_crushwrapper.cc b/src/test/test_crushwrapper.cc new file mode 100644 index 00000000000..eeec8f757a9 --- /dev/null +++ b/src/test/test_crushwrapper.cc @@ -0,0 +1,107 @@ +// -*- 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 + * + * 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 "crush/CrushWrapper.h" +#include "gtest/gtest.h" +#include "global/global_init.h" +#include "global/global_context.h" +#include "common/ceph_argparse.h" +#include "common/Formatter.h" + +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); + env_to_vec(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(); +}