]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: Add cg_create, cg_list, cg_remove
authorVictor Denisov <denisovenator@gmail.com>
Fri, 27 May 2016 03:51:43 +0000 (20:51 -0700)
committerVictor Denisov <denisovenator@gmail.com>
Thu, 16 Jun 2016 06:32:52 +0000 (02:32 -0400)
Signed-off-by: Victor Denisov <denisovenator@gmail.com>
12 files changed:
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/Utils.cc
src/librbd/Utils.h
src/librbd/internal.cc
src/librbd/internal.h
src/librbd/librbd.cc
src/test/Makefile-client.am
src/test/cli/rbd/help.t
src/test/librbd/test_ConsistencyGroups.cc [new file with mode: 0644]
src/test/librbd/test_main.cc
src/tracing/librbd.tp

index fb61b8f70bd3cd0b3b345d54deff5d4e6f986573..f83722b910cc04c6a1222b26dbb804f8540c8a1f 100644 (file)
@@ -641,6 +641,11 @@ CEPH_RBD_API int rbd_mirror_image_get_status(rbd_image_t image,
                                              rbd_mirror_image_status_t *mirror_image_status,
                                              size_t status_size);
 
+// RBD consistency groups support functions
+CEPH_RBD_API int rbd_group_create(rados_ioctx_t p, const char *name);
+CEPH_RBD_API int rbd_group_remove(rados_ioctx_t p, const char *name);
+CEPH_RBD_API int rbd_group_list(rados_ioctx_t p, char *names, size_t *size);
+
 #ifdef __cplusplus
 }
 #endif
index 4ce59d82d534e157372f4d750622206980c34e9f..e848fffdf9ae19d773fca34a307342c156a3b501 100644 (file)
@@ -148,6 +148,11 @@ public:
   int mirror_image_status_summary(IoCtx& io_ctx,
       std::map<mirror_image_status_state_t, int> *states);
 
+  // RBD consistency groups support functions
+  int group_create(IoCtx& io_ctx, const char *group_name);
+  int group_remove(IoCtx& io_ctx, const char *group_name);
+  int group_list(IoCtx& io_ctx, std::vector<std::string>& names);
+
 private:
   /* We don't allow assignment or copying */
   RBD(const RBD& rhs);
index 3d73830baa0f30127d426d644199dc412f61abee..9cda834ea162d5f7ee677550d09c1b5338a4a086 100644 (file)
@@ -8,6 +8,11 @@
 namespace librbd {
 namespace util {
 
+const std::string group_header_name(const std::string &group_id)
+{
+  return RBD_GROUP_HEADER_PREFIX + group_id;
+}
+
 const std::string id_obj_name(const std::string &name)
 {
   return RBD_ID_PREFIX + name;
index fd881f67f25e17d8c8b2f359689f3f7523fa5e87..9ff0b88aa8291ed88c2a93b26e6b01b76feea724 100644 (file)
@@ -5,6 +5,7 @@
 #define CEPH_LIBRBD_UTILS_H
 
 #include "include/rados/librados.hpp"
+#include "include/rbd_types.h"
 #include "include/Context.h"
 #include <type_traits>
 
@@ -93,6 +94,7 @@ struct C_AsyncCallback : public Context {
 
 } // namespace detail
 
+const std::string group_header_name(const std::string &group_id);
 const std::string id_obj_name(const std::string &name);
 const std::string header_name(const std::string &image_id);
 const std::string old_header_name(const std::string &image_name);
index 13682df4182ab9a05d96130ea64d3fa32a740448..4e18a7bb9e4b2488a2523ee52d09f58b171dbd2a 100644 (file)
@@ -3599,4 +3599,108 @@ int mirror_image_disable_internal(ImageCtx *ictx, bool force,
       ictx->perfcounter->inc(l_librbd_readahead_bytes, readahead_length);
     }
   }
+
+  // Consistency groups functions
+
+  int group_create(librados::IoCtx& io_ctx, const char *group_name)
+  {
+    CephContext *cct = (CephContext *)io_ctx.cct();
+
+    Rados rados(io_ctx);
+    uint64_t bid = rados.get_instance_id();
+
+    uint32_t extra = rand() % 0xFFFFFFFF;
+    ostringstream bid_ss;
+    bid_ss << std::hex << bid << std::hex << extra;
+    string id = bid_ss.str();
+
+    ldout(cct, 2) << "adding consistency group to directory..." << dendl;
+
+    int r = cls_client::group_dir_add(&io_ctx, RBD_GROUP_DIRECTORY, group_name, id);
+    if (r < 0) {
+      lderr(cct) << "error adding consistency group to directory: "
+                << cpp_strerror(r)
+                << dendl;
+      return r;
+    }
+    string header_oid = util::group_header_name(id);
+
+    r = cls_client::group_create(&io_ctx, header_oid);
+    if (r < 0) {
+      lderr(cct) << "error writing header: " << cpp_strerror(r) << dendl;
+      goto err_remove_from_dir;
+    }
+
+    return 0;
+
+  err_remove_from_dir:
+    int remove_r = cls_client::group_dir_remove(&io_ctx, RBD_GROUP_DIRECTORY,
+                                               group_name, id);
+    if (remove_r < 0) {
+      lderr(cct) << "error cleaning up consistency group from rbd_directory "
+                << "object after creation failed: " << cpp_strerror(remove_r)
+                << dendl;
+    }
+
+    return r;
+  }
+
+  int group_remove(librados::IoCtx& io_ctx, const char *group_name)
+  {
+    CephContext *cct((CephContext *)io_ctx.cct());
+    ldout(cct, 20) << "group_remove " << &io_ctx << " " << group_name << dendl;
+
+    std::string group_id;
+    int r = cls_client::dir_get_id(&io_ctx, RBD_GROUP_DIRECTORY,
+                              std::string(group_name), &group_id);
+    if (r < 0 && r != -ENOENT) {
+      lderr(cct) << "error getting id of group" << dendl;
+      return r;
+    }
+
+    string header_oid = util::group_header_name(group_id);
+
+    r = io_ctx.remove(header_oid);
+    if (r < 0 && r != -ENOENT) {
+      lderr(cct) << "error removing header: " << cpp_strerror(-r) << dendl;
+      return r;
+    }
+
+    r = cls_client::group_dir_remove(&io_ctx, RBD_GROUP_DIRECTORY,
+                                        group_name, group_id);
+    if (r < 0 && r != -ENOENT) {
+      lderr(cct) << "error removing group from directory" << dendl;
+      return r;
+    }
+
+    return 0;
+  }
+
+  int group_list(IoCtx& io_ctx, vector<string>& names)
+  {
+    CephContext *cct = (CephContext *)io_ctx.cct();
+    ldout(cct, 20) << "group_list " << &io_ctx << dendl;
+
+    int max_read = 1024;
+    string last_read = "";
+    int r;
+    do {
+      map<string, string> groups;
+      r = cls_client::group_dir_list(&io_ctx, RBD_GROUP_DIRECTORY, last_read, max_read, &groups);
+      if (r < 0) {
+        lderr(cct) << "error listing group in directory: "
+                   << cpp_strerror(r) << dendl;
+        return r;
+      }
+      for (pair<string, string> group : groups) {
+       names.push_back(group.first);
+      }
+      if (!groups.empty()) {
+       last_read = groups.rbegin()->first;
+      }
+      r = groups.size();
+    } while (r == max_read);
+
+    return 0;
+  }
 }
index 3fd068691fe0db0212d2fa270dfa82174afb3ea1..bd676be5fd0df7096e395715d05eab6415f276d8 100644 (file)
@@ -215,6 +215,11 @@ namespace librbd {
                             size_t info_size);
   int mirror_image_get_status(ImageCtx *ictx, mirror_image_status_t *status,
                              size_t status_size);
+
+  // Consistency groups functions
+  int group_create(librados::IoCtx& io_ctx, const char *imgname);
+  int group_remove(librados::IoCtx& io_ctx, const char *group_name);
+  int group_list(librados::IoCtx& io_ctx, std::vector<std::string>& names);
 }
 
 #endif
index 6711b39db1702e06bc1e4fcc711ea169a37b95c3..982fb11ac498bde7cf3d8cd060142bee2877677c 100644 (file)
@@ -438,6 +438,42 @@ namespace librbd {
     return librbd::mirror_image_status_summary(io_ctx, states);
   }
 
+  int RBD::group_create(IoCtx& io_ctx, const char *group_name)
+  {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+    tracepoint(librbd, group_create_enter, io_ctx.get_pool_name().c_str(),
+              io_ctx.get_id(), group_name);
+    int r = librbd::group_create(io_ctx, group_name);
+    tracepoint(librbd, group_create_exit, r);
+    return r;
+  }
+
+  int RBD::group_remove(IoCtx& io_ctx, const char *group_name)
+  {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+    tracepoint(librbd, group_remove_enter, io_ctx.get_pool_name().c_str(),
+              io_ctx.get_id(), group_name);
+    int r = librbd::group_remove(io_ctx, group_name);
+    tracepoint(librbd, group_remove_exit, r);
+    return r;
+  }
+
+  int RBD::group_list(IoCtx& io_ctx, vector<string>& names)
+  {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+    tracepoint(librbd, group_list_enter, io_ctx.get_pool_name().c_str(),
+              io_ctx.get_id());
+
+    int r = librbd::group_list(io_ctx, names);
+    if (r >= 0) {
+      for (auto itr : names) {
+       tracepoint(librbd, group_list_entry, itr.c_str());
+      }
+    }
+    tracepoint(librbd, group_list_exit, r);
+    return r;
+  }
+
   RBD::AioCompletion::AioCompletion(void *cb_arg, callback_t complete_cb)
   {
     pc = reinterpret_cast<void*>(librbd::AioCompletion::create(
@@ -2788,3 +2824,75 @@ extern "C" void rbd_aio_release(rbd_completion_t c)
   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
   comp->release();
 }
+
+extern "C" int rbd_group_create(rados_ioctx_t p, const char *name)
+{
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+  tracepoint(librbd, group_create_enter, io_ctx.get_pool_name().c_str(),
+             io_ctx.get_id(), name);
+  int r = librbd::group_create(io_ctx, name);
+  tracepoint(librbd, group_create_exit, r);
+  return r;
+}
+
+extern "C" int rbd_group_remove(rados_ioctx_t p, const char *name)
+{
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+  tracepoint(librbd, group_remove_enter, io_ctx.get_pool_name().c_str(),
+             io_ctx.get_id(), name);
+  int r = librbd::group_remove(io_ctx, name);
+  tracepoint(librbd, group_remove_exit, r);
+  return r;
+}
+
+extern "C" int rbd_group_list(rados_ioctx_t p, char *names, size_t *size)
+{
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+  tracepoint(librbd, group_list_enter, io_ctx.get_pool_name().c_str(),
+             io_ctx.get_id());
+
+  vector<string> cpp_names;
+  int r = librbd::list(io_ctx, cpp_names);
+
+  if (r == -ENOENT) {
+    *size = 0;
+    *names = '\0';
+    tracepoint(librbd, group_list_exit, 0);
+    return 0;
+  }
+
+  if (r < 0) {
+    tracepoint(librbd, group_list_exit, r);
+    return r;
+  }
+
+  size_t expected_size = 0;
+
+  for (size_t i = 0; i < cpp_names.size(); i++) {
+    expected_size += cpp_names[i].size() + 1;
+  }
+  if (*size < expected_size) {
+    *size = expected_size;
+    tracepoint(librbd, group_list_exit, -ERANGE);
+    return -ERANGE;
+  }
+
+  if (!names)
+    return -EINVAL;
+
+  names[expected_size] = '\0';
+  for (int i = 0; i < (int)cpp_names.size(); i++) {
+    const char* name = cpp_names[i].c_str();
+    tracepoint(librbd, group_list_entry, name);
+    strcpy(names, name);
+    names += strlen(names) + 1;
+  }
+  tracepoint(librbd, group_list_exit, (int)expected_size);
+  return (int)expected_size;
+}
index 40b7d2df31f4f2d2691febdf70900ab62646286b..0f9af334862ba28cd679df53518445fcf0ad6be5 100644 (file)
@@ -379,6 +379,7 @@ librbd_test_la_SOURCES = \
        test/librbd/test_mirroring.cc \
        test/librbd/test_MirroringWatcher.cc \
        test/librbd/test_ObjectMap.cc \
+       test/librbd/test_ConsistencyGroups.cc \
        test/librbd/journal/test_Entries.cc \
        test/librbd/journal/test_Replay.cc
 librbd_test_la_CXXFLAGS = $(UNITTEST_CXXFLAGS)
index 991b1b761c0b1ea1737727a4a642e165420864a3..2e0cabe74683ae9b4f253fb56bdcc2ec86abed3b 100644 (file)
@@ -20,6 +20,9 @@
       feature enable              Enable the specified image feature.
       flatten                     Fill clone with parent data (make it
                                   independent).
+      group create                Create a consistency group.
+      group list (group ls)       List rbd consistency groups.
+      group remove (group rm)     Delete a consistency group.
       image-meta get              Image metadata get the value associated with
                                   the key.
       image-meta list             Image metadata list keys with values.
     --image arg          image name
     --no-progress        disable progress output
   
+  rbd help group create
+  usage: rbd group create [--pool <pool>] [--group <group>] 
+                          <group-spec> 
+  
+  Create a consistency group.
+  
+  Positional arguments
+    <group-spec>         group specification
+                         (example: [<pool-name>/]<group-name>)
+  
+  Optional arguments
+    -p [ --pool ] arg    pool name
+    --group arg          group name
+  
+  rbd help group list
+  usage: rbd group list [--pool <pool>] [--format <format>] [--pretty-format] 
+  
+  List rbd consistency groups.
+  
+  Optional arguments
+    -p [ --pool ] arg    pool name
+    --format arg         output format [plain, json, or xml]
+    --pretty-format      pretty formatting (json and xml)
+  
+  rbd help group remove
+  usage: rbd group remove [--pool <pool>] [--group <group>] 
+                          <group-spec> 
+  
+  Delete a consistency group.
+  
+  Positional arguments
+    <group-spec>         group specification
+                         (example: [<pool-name>/]<group-name>)
+  
+  Optional arguments
+    -p [ --pool ] arg    pool name
+    --group arg          group name
+  
   rbd help image-meta get
   usage: rbd image-meta get [--pool <pool>] [--image <image>] 
                             <image-spec> <key> 
diff --git a/src/test/librbd/test_ConsistencyGroups.cc b/src/test/librbd/test_ConsistencyGroups.cc
new file mode 100644 (file)
index 0000000..a6a1c24
--- /dev/null
@@ -0,0 +1,63 @@
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+#include "test/librbd/test_fixture.h"
+#include "test/librbd/test_support.h"
+#include "include/int_types.h"
+#include "include/stringify.h"
+#include "include/rados/librados.h"
+#include "include/rbd/librbd.hpp"
+#include "common/Cond.h"
+#include "common/errno.h"
+#include "common/Mutex.h"
+#include "common/RWLock.h"
+#include "cls/lock/cls_lock_client.h"
+#include "cls/lock/cls_lock_types.h"
+#include "librbd/AioCompletion.h"
+#include "librbd/AioImageRequestWQ.h"
+#include "librbd/internal.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/ImageWatcher.h"
+#include "librbd/WatchNotifyTypes.h"
+#include "test/librados/test.h"
+#include "gtest/gtest.h"
+#include <boost/assign/std/set.hpp>
+#include <boost/assign/std/map.hpp>
+#include <boost/bind.hpp>
+#include <boost/scope_exit.hpp>
+#include <boost/thread/thread.hpp>
+#include <iostream>
+#include <map>
+#include <set>
+#include <sstream>
+#include <vector>
+
+using namespace ceph;
+using namespace boost::assign;
+using namespace librbd::watch_notify;
+
+void register_test_consistency_groups() {
+}
+
+class TestLibCG : public TestFixture {
+
+};
+
+TEST_F(TestLibCG, group_create)
+{
+  librados::IoCtx ioctx;
+  ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+  librbd::RBD rbd;
+  ASSERT_EQ(0, rbd.group_create(ioctx, "mygroup"));
+
+  vector<string> groups;
+  ASSERT_EQ(0, rbd.group_list(ioctx, groups));
+  ASSERT_EQ(1U, groups.size());
+  ASSERT_EQ("mygroup", groups[0]);
+
+  ASSERT_EQ(0, rbd.group_remove(ioctx, "mygroup"));
+
+  groups.clear();
+  ASSERT_EQ(0, rbd.group_list(ioctx, groups));
+  ASSERT_EQ(0U, groups.size());
+}
index 4ae9f43ee74e734612dab78bb62acecd775c630d..8338fec0b6cfbacbefae9af741a86b14f6a4507f 100644 (file)
@@ -17,6 +17,7 @@ extern void register_test_journal_replay();
 extern void register_test_object_map();
 extern void register_test_mirroring();
 extern void register_test_mirroring_watcher();
+extern void register_test_consistency_groups();
 #endif // TEST_LIBRBD_INTERNALS
 
 int main(int argc, char **argv)
@@ -30,6 +31,7 @@ int main(int argc, char **argv)
   register_test_object_map();
   register_test_mirroring();
   register_test_mirroring_watcher();
+  register_test_consistency_groups();
 #endif // TEST_LIBRBD_INTERNALS
 
   ::testing::InitGoogleTest(&argc, argv);
index f91e4e3ee93b38841cee1959867476be7a84f701..bbbfae289d3d17c6ac07e0c723e536076a24f5a7 100644 (file)
@@ -1795,3 +1795,69 @@ TRACEPOINT_EVENT(librbd, stat_exit,
         ctf_array_text(char, parent_name, info->parent_name, RBD_MAX_IMAGE_NAME_SIZE)
     )
 )
+
+TRACEPOINT_EVENT(librbd, group_create_enter,
+    TP_ARGS(
+        const char*, pool_name,
+        int64_t, id,
+        const char*, groupname),
+    TP_FIELDS(
+        ctf_string(pool_name, pool_name)
+        ctf_integer(int64_t, id, id)
+        ctf_string(groupname, groupname)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, group_create_exit,
+    TP_ARGS(
+        int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, group_remove_enter,
+    TP_ARGS(
+        const char*, pool_name,
+        int64_t, id,
+        const char*, groupname),
+    TP_FIELDS(
+        ctf_string(pool_name, pool_name)
+        ctf_integer(int64_t, id, id)
+        ctf_string(groupname, groupname)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, group_remove_exit,
+    TP_ARGS(
+        int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, group_list_enter,
+    TP_ARGS(
+        const char*, pool_name,
+        int64_t, id),
+    TP_FIELDS(
+        ctf_string(pool_name, pool_name)
+        ctf_integer(int64_t, id, id)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, group_list_entry,
+    TP_ARGS(
+        const char*, name),
+    TP_FIELDS(
+        ctf_string(name, name)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, group_list_exit,
+    TP_ARGS(
+        int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)