mirror of
https://github.com/ceph/ceph
synced 2025-03-30 07:19:14 +00:00
crush/CrushWrapper: add get_common_ancestor_distance()
Calculate closest common ancestor (type) in the hierarchy. Signed-off-by: Sage Weil <sage@inktank.com>
This commit is contained in:
parent
0903f3fa46
commit
dcc5e3559f
@ -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<string,string>& loc)
|
||||
{
|
||||
ldout(cct, 5) << __func__ << " " << id << " " << loc << dendl;
|
||||
if (!item_exists(id))
|
||||
return -ENOENT;
|
||||
map<string,string> id_loc = get_full_location(id);
|
||||
ldout(cct, 20) << " id is at " << id_loc << dendl;
|
||||
|
||||
for (map<int,string>::const_iterator p = type_map.begin();
|
||||
p != type_map.end();
|
||||
++p) {
|
||||
map<string,string>::iterator ip = id_loc.find(p->second);
|
||||
if (ip == id_loc.end())
|
||||
continue;
|
||||
for (std::multimap<string,string>::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<string>& args,
|
||||
std::map<string,string> *ploc)
|
||||
{
|
||||
|
@ -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<string,string>& loc);
|
||||
|
||||
/**
|
||||
* parse a set of key/value pairs out of a string vector
|
||||
*
|
||||
|
@ -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)
|
||||
|
107
src/test/test_crushwrapper.cc
Normal file
107
src/test/test_crushwrapper.cc
Normal file
@ -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 <info@inktank.com>
|
||||
*
|
||||
* 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<string,string> 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<pair<string,string> > 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<string,string> 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<const char*> 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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user