From d8ae14f48965e2aff191d67fda7b5ffd85840d47 Mon Sep 17 00:00:00 2001 From: Adam Crume Date: Mon, 22 Sep 2014 11:10:48 -0700 Subject: [PATCH] librados: Add rados_pool_get_base_tier call Fixes: #8188 Signed-off-by: Adam Crume --- src/include/rados/librados.h | 13 ++++++ src/include/rados/librados.hpp | 1 + src/librados/RadosClient.cc | 25 ++++++++++++ src/librados/RadosClient.h | 1 + src/librados/librados.cc | 17 ++++++++ src/pybind/rados.py | 72 +++++++++++++++++++++++++++++++++- src/test/librados/pool.cc | 48 +++++++++++++++++++++++ src/test/pybind/test_rados.py | 30 ++++++++++++++ src/tracing/librados.tp | 20 ++++++++++ 9 files changed, 226 insertions(+), 1 deletion(-) diff --git a/src/include/rados/librados.h b/src/include/rados/librados.h index 6ed12c2f9189f..c4d4d6b102465 100644 --- a/src/include/rados/librados.h +++ b/src/include/rados/librados.h @@ -709,6 +709,19 @@ int rados_pool_create_with_crush_rule(rados_t cluster, const char *pool_name, int rados_pool_create_with_all(rados_t cluster, const char *pool_name, uint64_t auid, uint8_t crush_rule_num); +/** + * Returns the pool that is the base tier for this pool. + * + * The return value is the ID of the pool that should be used to read from/write to. + * If tiering is not set up for the pool, returns \c pool. + * + * @param cluster the cluster the pool is in + * @param pool ID of the pool to query + * @param[out] base_tier base tier, or \c pool if tiering is not configured + * @returns 0 on success, negative error code on failure + */ +int rados_pool_get_base_tier(rados_t cluster, int64_t pool, int64_t* base_tier); + /** * Delete a pool and all data inside it * diff --git a/src/include/rados/librados.hpp b/src/include/rados/librados.hpp index e6e40b2cb63d2..bf00c3aa65cf2 100644 --- a/src/include/rados/librados.hpp +++ b/src/include/rados/librados.hpp @@ -909,6 +909,7 @@ namespace librados int pool_create_async(const char *name, PoolAsyncCompletion *c); int pool_create_async(const char *name, uint64_t auid, PoolAsyncCompletion *c); int pool_create_async(const char *name, uint64_t auid, uint8_t crush_rule, PoolAsyncCompletion *c); + int pool_get_base_tier(int64_t pool, int64_t* base_tier); int pool_delete(const char *name); int pool_delete_async(const char *name, PoolAsyncCompletion *c); int64_t pool_lookup(const char *name); diff --git a/src/librados/RadosClient.cc b/src/librados/RadosClient.cc index 6aeba57c14e67..8be0c761a2279 100644 --- a/src/librados/RadosClient.cc +++ b/src/librados/RadosClient.cc @@ -569,6 +569,31 @@ int librados::RadosClient::pool_create_async(string& name, PoolAsyncCompletionIm return r; } +int librados::RadosClient::pool_get_base_tier(int64_t pool_id, int64_t* base_tier) +{ + int r = wait_for_osdmap(); + if (r < 0) { + return r; + } + + const OSDMap *osdmap = objecter->get_osdmap_read(); + + const pg_pool_t* pool = osdmap->get_pg_pool(pool_id); + if (pool) { + if (pool->tier_of < 0) { + *base_tier = pool_id; + } else { + *base_tier = pool->tier_of; + } + r = 0; + } else { + r = -ENOENT; + } + + objecter->put_osdmap_read(); + return r; +} + int librados::RadosClient::pool_delete(const char *name) { int r = wait_for_osdmap(); diff --git a/src/librados/RadosClient.h b/src/librados/RadosClient.h index 9a394b3d5b703..c4410f4b74f2e 100755 --- a/src/librados/RadosClient.h +++ b/src/librados/RadosClient.h @@ -102,6 +102,7 @@ public: int pool_create(string& name, unsigned long long auid=0, __u8 crush_rule=0); int pool_create_async(string& name, PoolAsyncCompletionImpl *c, unsigned long long auid=0, __u8 crush_rule=0); + int pool_get_base_tier(int64_t pool_id, int64_t* base_tier); int pool_delete(const char *name); int pool_delete_async(const char *name, PoolAsyncCompletionImpl *c); diff --git a/src/librados/librados.cc b/src/librados/librados.cc index c7405df0d70e9..d029fe19f5693 100644 --- a/src/librados/librados.cc +++ b/src/librados/librados.cc @@ -1647,6 +1647,14 @@ int librados::Rados::pool_create_async(const char *name, uint64_t auid, __u8 cru return client->pool_create_async(str, c->pc, auid, crush_rule); } +int librados::Rados::pool_get_base_tier(int64_t pool_id, int64_t* base_tier) +{ + tracepoint(librados, rados_pool_get_base_tier_enter, (rados_t)client, pool_id); + int retval = client->pool_get_base_tier(pool_id, base_tier); + tracepoint(librados, rados_pool_get_base_tier_exit, retval, *base_tier); + return retval; +} + int librados::Rados::pool_delete(const char *name) { return client->pool_delete(name); @@ -2611,6 +2619,15 @@ extern "C" int rados_pool_create_with_all(rados_t cluster, const char *name, return retval; } +extern "C" int rados_pool_get_base_tier(rados_t cluster, int64_t pool_id, int64_t* base_tier) +{ + tracepoint(librados, rados_pool_get_base_tier_enter, cluster, pool_id); + librados::RadosClient *client = (librados::RadosClient *)cluster; + int retval = client->pool_get_base_tier(pool_id, base_tier); + tracepoint(librados, rados_pool_get_base_tier_exit, retval, *base_tier); + return retval; +} + extern "C" int rados_pool_delete(rados_t cluster, const char *pool_name) { tracepoint(librados, rados_pool_delete_enter, cluster, pool_name); diff --git a/src/pybind/rados.py b/src/pybind/rados.py index 93e5040873e8e..dcd19ac2140d5 100644 --- a/src/pybind/rados.py +++ b/src/pybind/rados.py @@ -5,7 +5,7 @@ Copyright 2011, Hannu Valtonen """ from ctypes import CDLL, c_char_p, c_size_t, c_void_p, c_char, c_int, c_long, \ c_ulong, create_string_buffer, byref, Structure, c_uint64, c_ubyte, \ - pointer, CFUNCTYPE + pointer, CFUNCTYPE, c_int64 from ctypes.util import find_library import ctypes import errno @@ -470,6 +470,56 @@ Rados object in state %s." % (self.state)) else: raise make_ex(ret, "error looking up pool '%s'" % pool_name) + def pool_lookup(self, pool_name): + """ + Returns a pool's ID based on its name. + + :param pool_name: name of the pool to look up + :type pool_name: str + + :raises: :class:`TypeError`, :class:`Error` + :returns: int - pool ID, or None if it doesn't exist + """ + self.require_state("connected") + if not isinstance(pool_name, str): + raise TypeError('pool_name must be a string') + ret = run_in_thread(self.librados.rados_pool_lookup, + (self.cluster, c_char_p(pool_name))) + if (ret >= 0): + return int(ret) + elif (ret == -errno.ENOENT): + return None + else: + raise make_ex(ret, "error looking up pool '%s'" % pool_name) + + def pool_reverse_lookup(self, pool_id): + """ + Returns a pool's name based on its ID. + + :param pool_id: ID of the pool to look up + :type pool_id: int + + :raises: :class:`TypeError`, :class:`Error` + :returns: string - pool name, or None if it doesn't exist + """ + self.require_state("connected") + if not isinstance(pool_id, int): + raise TypeError('pool_id must be an integer') + size = c_size_t(512) + while True: + c_name = create_string_buffer(size.value) + ret = run_in_thread(self.librados.rados_pool_reverse_lookup, + (self.cluster, c_int64(pool_id), byref(c_name), size)) + if ret > size.value: + size = c_size_t(ret) + elif ret == -errno.ENOENT: + return None + elif ret < 0: + raise make_ex(ret, "error reverse looking up pool '%s'" % pool_id) + else: + return c_name.value + break + def create_pool(self, pool_name, auid=None, crush_rule=None): """ Create a pool: @@ -513,6 +563,22 @@ Rados object in state %s." % (self.state)) if ret < 0: raise make_ex(ret, "error creating pool '%s'" % pool_name) + def get_pool_base_tier(self, pool_id): + """ + Get base pool + + :returns: base pool, or pool_id if tiering is not configured for the pool + """ + self.require_state("connected") + if not isinstance(pool_id, int): + raise TypeError('pool_id must be an int') + base_tier = c_int64(0) + ret = run_in_thread(self.librados.rados_pool_get_base_tier, + (self.cluster, c_int64(pool_id), byref(base_tier))) + if ret < 0: + raise make_ex(ret, "get_pool_base_tier(%d)" % pool_id) + return base_tier.value + def delete_pool(self, pool_name): """ Delete a pool and all data inside it. @@ -685,6 +751,10 @@ Rados object in state %s." % (self.state)) return (ret, my_outbuf, my_outs) + def wait_for_latest_osdmap(self): + self.require_state("connected") + return run_in_thread(self.librados.rados_wait_for_latest_osdmap, (self.cluster,)) + class ObjectIterator(object): """rados.Ioctx Object iterator""" def __init__(self, ioctx): diff --git a/src/test/librados/pool.cc b/src/test/librados/pool.cc index 04286fcf32a54..c314720ad53b1 100644 --- a/src/test/librados/pool.cc +++ b/src/test/librados/pool.cc @@ -104,3 +104,51 @@ TEST(LibRadosPools, PoolCreateWithCrushRule) { rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } + +TEST(LibRadosPools, PoolGetBaseTier) { + rados_t cluster; + std::string pool_name = get_temp_pool_name(); + ASSERT_EQ("", create_one_pool(pool_name, &cluster)); + std::string tier_pool_name = pool_name + "-cache"; + ASSERT_EQ(0, rados_pool_create(cluster, tier_pool_name.c_str())); + + int64_t pool_id = rados_pool_lookup(cluster, pool_name.c_str()); + ASSERT_GE(pool_id, 0); + + int64_t tier_pool_id = rados_pool_lookup(cluster, tier_pool_name.c_str()); + ASSERT_GE(tier_pool_id, 0); + + + int64_t base_tier = 0; + EXPECT_EQ(0, rados_pool_get_base_tier(cluster, pool_id, &base_tier)); + EXPECT_EQ(pool_id, base_tier); + + std::string cmdstr = "{\"prefix\": \"osd tier add\", \"pool\": \"" + + pool_name + "\", \"tierpool\":\"" + tier_pool_name + "\", \"force_nonempty\":\"\"}"; + char *cmd[1]; + cmd[0] = (char *)cmdstr.c_str(); + ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0)); + + cmdstr = "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + + tier_pool_name + "\", \"mode\":\"readonly\"}"; + cmd[0] = (char *)cmdstr.c_str(); + ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0)); + + EXPECT_EQ(0, rados_wait_for_latest_osdmap(cluster)); + + EXPECT_EQ(0, rados_pool_get_base_tier(cluster, pool_id, &base_tier)); + EXPECT_EQ(pool_id, base_tier); + + EXPECT_EQ(0, rados_pool_get_base_tier(cluster, tier_pool_id, &base_tier)); + EXPECT_EQ(pool_id, base_tier); + + int64_t nonexistent_pool_id = (int64_t)((-1ULL) >> 1); + EXPECT_EQ(-ENOENT, rados_pool_get_base_tier(cluster, nonexistent_pool_id, &base_tier)); + + cmdstr = "{\"prefix\": \"osd tier remove\", \"pool\": \"" + + pool_name + "\", \"tierpool\":\"" + tier_pool_name + "\"}"; + cmd[0] = (char *)cmdstr.c_str(); + ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0)); + ASSERT_EQ(0, rados_pool_delete(cluster, tier_pool_name.c_str())); + ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); +} diff --git a/src/test/pybind/test_rados.py b/src/test/pybind/test_rados.py index d6c9b148148fa..00813dc2270d0 100644 --- a/src/test/pybind/test_rados.py +++ b/src/test/pybind/test_rados.py @@ -88,6 +88,36 @@ class TestRados(object): eq(set(['a' * 500]), self.list_non_default_pools()) self.rados.delete_pool('a' * 500) + def test_get_pool_base_tier(self): + self.rados.create_pool('foo') + try: + self.rados.create_pool('foo-cache') + try: + pool_id = self.rados.pool_lookup('foo') + tier_pool_id = self.rados.pool_lookup('foo-cache') + + cmd = {"prefix":"osd tier add", "pool":"foo", "tierpool":"foo-cache", "force_nonempty":""} + ret, buf, errs = self.rados.mon_command(json.dumps(cmd), '', timeout=30) + eq(ret, 0) + + try: + cmd = {"prefix":"osd tier cache-mode", "pool":"foo-cache", "tierpool":"foo-cache", "mode":"readonly"} + ret, buf, errs = self.rados.mon_command(json.dumps(cmd), '', timeout=30) + eq(ret, 0) + + eq(self.rados.wait_for_latest_osdmap(), 0) + + eq(pool_id, self.rados.get_pool_base_tier(pool_id)) + eq(pool_id, self.rados.get_pool_base_tier(tier_pool_id)) + finally: + cmd = {"prefix":"osd tier remove", "pool":"foo", "tierpool":"foo-cache"} + ret, buf, errs = self.rados.mon_command(json.dumps(cmd), '', timeout=30) + eq(ret, 0) + finally: + self.rados.delete_pool('foo-cache') + finally: + self.rados.delete_pool('foo') + def test_get_fsid(self): fsid = self.rados.get_fsid() eq(len(fsid), 36) diff --git a/src/tracing/librados.tp b/src/tracing/librados.tp index 9f3e54980f0d1..f3189a120c625 100644 --- a/src/tracing/librados.tp +++ b/src/tracing/librados.tp @@ -980,6 +980,26 @@ TRACEPOINT_EVENT(librados, rados_pool_create_with_all_exit, ) ) +TRACEPOINT_EVENT(librados, rados_pool_get_base_tier_enter, + TP_ARGS( + rados_t, cluster, + int64_t, pool_id), + TP_FIELDS( + ctf_integer_hex(rados_t, cluster, cluster) + ctf_integer(int64_t, pool_id, pool_id) + ) +) + +TRACEPOINT_EVENT(librados, rados_pool_get_base_tier_exit, + TP_ARGS( + int, retval, + int64_t, base_tier), + TP_FIELDS( + ctf_integer(int, retval, retval) + ctf_integer(int64_t, base_tier, base_tier) + ) +) + TRACEPOINT_EVENT(librados, rados_pool_delete_enter, TP_ARGS( rados_t, cluster, -- 2.39.5