]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librados: Add rados_pool_get_base_tier call 2552/head
authorAdam Crume <adamcrume@gmail.com>
Mon, 22 Sep 2014 18:10:48 +0000 (11:10 -0700)
committerAdam Crume <adamcrume@gmail.com>
Wed, 1 Oct 2014 16:40:34 +0000 (09:40 -0700)
Fixes: #8188
Signed-off-by: Adam Crume <adamcrume@gmail.com>
src/include/rados/librados.h
src/include/rados/librados.hpp
src/librados/RadosClient.cc
src/librados/RadosClient.h
src/librados/librados.cc
src/pybind/rados.py
src/test/librados/pool.cc
src/test/pybind/test_rados.py
src/tracing/librados.tp

index 6ed12c2f9189f0e9d3c8933cee018d5a28adf98c..c4d4d6b102465d6ca643d94aa49de6537da18e79 100644 (file)
@@ -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
  *
index e6e40b2cb63d214ab719a6f35bf7294cc19417c1..bf00c3aa65cf2eec2b1c6ca8b90d880c731202dc 100644 (file)
@@ -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);
index 6aeba57c14e67719224b63e1e378f2251417c099..8be0c761a2279c6ac61700265100cbc13fd2b354 100644 (file)
@@ -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();
index 9a394b3d5b70313bbe16f13e0077a742238056c1..c4410f4b74f2e6708a86f7903c6b37b3682bbcf7 100755 (executable)
@@ -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);
index c7405df0d70e96a6c40321fc1f649019d5446b06..d029fe19f5693c36612011c4a3089bd76690eba7 100644 (file)
@@ -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);
index 93e5040873e8e72e5e1ad3f2485dea78ddeda1bb..dcd19ac2140d56114aa9fd06511750f4ccf6a89d 100644 (file)
@@ -5,7 +5,7 @@ Copyright 2011, Hannu Valtonen <hannu.valtonen@ormod.com>
 """
 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):
index 04286fcf32a54a868473b92414f95f1deab5bd8f..c314720ad53b1eec82f6b57584e4f14d803b5bd9 100644 (file)
@@ -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));
+}
index d6c9b148148fa6e1cf859843a174cfb7e40a4bd3..00813dc2270d0675e080969de441264b4b016dbf 100644 (file)
@@ -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)
index 9f3e54980f0d1c9f8db198d4ae5a26e0a18eedf0..f3189a120c62506008f327912e845882b58c85e3 100644 (file)
@@ -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,