]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
tools: implement rados import/export
authorJohn Spray <john.spray@redhat.com>
Mon, 23 Mar 2015 13:20:35 +0000 (13:20 +0000)
committerJohn Spray <john.spray@redhat.com>
Wed, 10 Jun 2015 21:37:41 +0000 (22:37 +0100)
New PoolDump (export) class to dump pool contents
in format compatible with ceph-objectstore-tool,
and wire up RadosImport class (import).

Signed-off-by: John Spray <john.spray@redhat.com>
src/common/hobject.h
src/tools/Makefile-client.am
src/tools/Makefile.am
src/tools/rados/PoolDump.cc [new file with mode: 0644]
src/tools/rados/PoolDump.h [new file with mode: 0644]
src/tools/rados/rados.cc

index c6123d4ff7f4f43c35201be2a2b036d887fc5cce..d2d3153bc92ae2b1966b01f3b4b61267341f8d3d 100644 (file)
@@ -49,6 +49,10 @@ public:
     return key;
   }
 
+  void set_key(const std::string &key_) {
+    key = key_;
+  }
+
   string to_str() const;
   
   uint32_t get_hash() const { 
index b1b43dec9ea843214e65ad8ad02c71b75570f7e2..7d09a9825bf354bde0dde3f1d38eca444412e815 100644 (file)
@@ -16,7 +16,10 @@ rados_SOURCES = \
        tools/rados/rados.cc \
        tools/rados/rados_import.cc \
        tools/rados/rados_export.cc \
-       tools/rados/rados_sync.cc
+       tools/rados/rados_sync.cc \
+       tools/RadosDump.cc \
+       tools/RadosImport.cc \
+       tools/rados/PoolDump.cc
 rados_SOURCES += common/obj_bencher.cc # needs cleanup so it can go in libcommon.la
 rados_LDADD = libcls_lock_client.la $(LIBRADOS) $(CEPH_GLOBAL)
 bin_PROGRAMS += rados
index df3ed892aac3adddd275ea06581ca61c8b4dd01f..508bcc7c0bd0b9c897ff015d2b298f37510b5457 100644 (file)
@@ -57,4 +57,5 @@ noinst_HEADERS += \
        tools/rados/rados_sync.h \
        tools/RadosDump.h \
        tools/RadosImport.h\
-       tools/ceph_objectstore_tool.h
+       tools/ceph_objectstore_tool.h \
+       tools/rados/PoolDump.h
diff --git a/src/tools/rados/PoolDump.cc b/src/tools/rados/PoolDump.cc
new file mode 100644 (file)
index 0000000..4fac45c
--- /dev/null
@@ -0,0 +1,157 @@
+// -*- 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) 2015 Red Hat
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "include/rados/librados.hpp"
+#include "common/errno.h"
+
+#include "PoolDump.h"
+
+using namespace librados;
+
+#define dout_subsys ceph_subsys_rados
+
+/**
+ * Export RADOS objects from a live cluster
+ * to a serialized format via a file descriptor.
+ *
+ * @returns 0 on success, else error code
+ */
+int PoolDump::dump(IoCtx *io_ctx)
+{
+  assert(io_ctx != NULL);
+
+  int r = 0;
+  write_super();
+
+  r = write_simple(TYPE_POOL_BEGIN, file_fd);
+  if (r != 0) {
+    return r;
+  }
+
+  librados::NObjectIterator i = io_ctx->nobjects_begin();
+
+  librados::NObjectIterator i_end = io_ctx->nobjects_end();
+  for (; i != i_end; ++i) {
+    const std::string oid = i->get_oid();
+    dout(10) << "OID '" << oid << "'" << dendl;
+
+    // Compose OBJECT_BEGIN
+    // ====================
+    object_begin obj_begin;
+    obj_begin.hoid.hobj.oid = i->get_oid();
+    obj_begin.hoid.hobj.nspace = i->get_nspace();
+    obj_begin.hoid.hobj.set_key(i->get_locator());
+
+    // Only output head, RadosImport only wants that
+    obj_begin.hoid.hobj.snap = CEPH_NOSNAP;
+
+    // Skip setting object_begin.oi, RadosImport doesn't care
+
+    r = write_section(TYPE_OBJECT_BEGIN, obj_begin, file_fd);
+    if (r != 0) {
+      return r;
+    }
+
+    // Compose TYPE_DATA chunks
+    // ========================
+    const uint32_t op_size = 4096 * 1024;
+    uint64_t offset = 0;
+    while (true) {
+      bufferlist outdata;
+      r = io_ctx->read(oid, outdata, op_size, offset);
+      if (r <= 0) {
+        // Error or no data
+        break;
+      }
+
+      r = write_section(TYPE_DATA,
+          data_section(offset, outdata.length(), outdata), file_fd);
+      if (r != 0) {
+        // Output stream error
+        return r;
+      }
+
+      if (outdata.length() < op_size) {
+        // No more data
+        r = 0;
+        break;
+      }
+      offset += outdata.length();
+    }
+
+    // Compose TYPE_ATTRS chunk
+    // ========================
+    std::map<std::string, bufferlist> xattrs;
+    r = io_ctx->getxattrs(oid, xattrs);
+    if (r < 0) {
+      cerr << "error getting xattr set " << oid << ": " << cpp_strerror(r)
+           << std::endl;
+      return r;
+    }
+    r = write_section(TYPE_ATTRS, attr_section(xattrs), file_fd);
+    if (r != 0) {
+      return r;
+    }
+
+    // Compose TYPE_OMAP_HDR section
+    // =============================
+    bufferlist omap_header;
+    r = io_ctx->omap_get_header(oid, &omap_header);
+    if (r < 0) {
+      cerr << "error getting omap header " << oid
+          << ": " << cpp_strerror(r) << std::endl;
+      return r;
+    }
+    r = write_section(TYPE_OMAP_HDR, omap_hdr_section(omap_header), file_fd);
+    if (r != 0) {
+      return r;
+    }
+
+    // Compose TYPE_OMAP
+    int MAX_READ = 512;
+    string last_read = "";
+    do {
+      map<string, bufferlist> values;
+      r = io_ctx->omap_get_vals(oid, last_read, MAX_READ, &values);
+      if (r < 0) {
+       cerr << "error getting omap keys " << oid << ": "
+            << cpp_strerror(r) << std::endl;
+       return r;
+      }
+      if (values.size()) {
+        last_read = values.rbegin()->first;
+      } else {
+        break;
+      }
+
+      r = write_section(TYPE_OMAP, omap_section(values), file_fd);
+      if (r != 0) {
+        return r;
+      }
+      r = values.size();
+    } while (r == MAX_READ);
+    r = 0;
+
+    // Close object
+    // =============
+    r = write_simple(TYPE_OBJECT_END, file_fd);
+    if (r != 0) {
+      return r;
+    }
+  }
+
+  r = write_simple(TYPE_POOL_END, file_fd);
+
+  return r;
+}
diff --git a/src/tools/rados/PoolDump.h b/src/tools/rados/PoolDump.h
new file mode 100644 (file)
index 0000000..6b4eae5
--- /dev/null
@@ -0,0 +1,32 @@
+// -*- 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) 2015 Red Hat
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+
+#ifndef POOL_DUMP_H_
+#define POOL_DUMP_H_
+
+#include "tools/RadosDump.h"
+
+namespace librados {
+    class IoCtx;
+}
+
+class PoolDump : public RadosDump
+{
+  public:
+    PoolDump(int file_fd_) : RadosDump(file_fd_, false) {}
+    int dump(librados::IoCtx *io_ctx);
+};
+
+#endif // POOL_DUMP_H_
index 9125d9a4841fd46da3e1a7a3a547993f0a463ebb..2071c9703c6fde9390de42168797a7a3a6a7b40e 100644 (file)
@@ -17,7 +17,6 @@
 #include "include/rados/librados.hpp"
 #include "include/rados/rados_types.hpp"
 #include "rados_sync.h"
-using namespace librados;
 
 #include "common/config.h"
 #include "common/ceph_argparse.h"
@@ -45,9 +44,14 @@ using namespace librados;
 #include "include/compat.h"
 #include "common/hobject.h"
 
+#include "PoolDump.h"
+#include "tools/RadosImport.h"
+
 int rados_tool_sync(const std::map < std::string, std::string > &opts,
                              std::vector<const char*> &args);
 
+using namespace librados;
+
 // two steps seem to be necessary to do this right
 #define STR(x) _STR(x)
 #define _STR(x) #x
@@ -113,17 +117,10 @@ void usage(ostream& out)
 "                                    set allocation hint for an object\n"
 "\n"
 "IMPORT AND EXPORT\n"
-"   import [options] <local-directory> <rados-pool>\n"
-"       Upload <local-directory> to <rados-pool>\n"
-"   export [options] <rados-pool> <local-directory>\n"
-"       Download <rados-pool> to <local-directory>\n"
-"   options:\n"
-"       -f / --force                 Copy everything, even if it hasn't changed.\n"
-"       -d / --delete-after          After synchronizing, delete unreferenced\n"
-"                                    files or objects from the target bucket\n"
-"                                    or directory.\n"
-"       --workers                    Number of worker threads to spawn \n"
-"                                    (default " STR(DEFAULT_NUM_RADOS_WORKER_THREADS) ")\n"
+"   export [filename]\n"
+"       Serialize pool contents to a file or standard out.\n"
+"   import [filename]\n"
+"       Load pool contents from a file or standard in\n"
 "\n"
 "ADVISORY LOCKS\n"
 "   lock list <obj-name>\n"
@@ -1434,7 +1431,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       vec.push_back(pool_name);
     }
 
-    map<string,pool_stat_t> stats;
+    map<string,librados::pool_stat_t> stats;
     ret = rados.get_pool_stats(vec, stats);
     if (ret < 0) {
       cerr << "error fetching pool stats: " << cpp_strerror(ret) << std::endl;
@@ -1452,11 +1449,11 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       formatter->open_object_section("stats");
       formatter->open_array_section("pools");
     }
-    for (map<string,pool_stat_t>::iterator i = stats.begin();
+    for (map<string,librados::pool_stat_t>::iterator i = stats.begin();
         i != stats.end();
         ++i) {
       const char *pool_name = i->first.c_str();
-      pool_stat_t& s = i->second;
+      librados::pool_stat_t& s = i->second;
       if (!formatter) {
        printf("%-15s "
               "%12lld %12lld %12lld %12lld"
@@ -2627,6 +2624,56 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
           << cpp_strerror(ret) << std::endl;
       goto out;
     }
+  } else if (strcmp(nargs[0], "export") == 0) {
+    // export [filename]
+    if (!pool_name || nargs.size() > 2) {
+      usage_exit();
+    }
+
+    int file_fd;
+    if (nargs.size() < 2 || std::string(nargs[1]) == "-") {
+      file_fd = STDOUT_FILENO;
+    } else {
+      file_fd = open(nargs[1], O_WRONLY|O_CREAT|O_TRUNC, 0666);
+      if (file_fd < 0) {
+        cerr << "Error opening '" << nargs[1] << "': "
+          << cpp_strerror(file_fd) << std::endl;
+        ret = file_fd;
+        goto out;
+      }
+    }
+
+    ret = PoolDump(file_fd).dump(&io_ctx);
+    if (ret < 0) {
+      cerr << "error from export: "
+          << cpp_strerror(ret) << std::endl;
+      goto out;
+    }
+  } else if (strcmp(nargs[0], "import") == 0) {
+    // import [filename]
+    if (!pool_name || nargs.size() > 2) {
+      usage_exit();
+    }
+
+    int file_fd;
+    if (nargs.size() < 2 || std::string(nargs[1]) == "-") {
+      file_fd = STDIN_FILENO;
+    } else {
+      file_fd = open(nargs[1], O_RDONLY);
+      if (file_fd < 0) {
+        cerr << "Error opening '" << nargs[1] << "': "
+          << cpp_strerror(file_fd) << std::endl;
+        ret = file_fd;
+        goto out;
+      }
+    }
+
+    ret = RadosImport(file_fd, 0, false).import(io_ctx, false);
+    if (ret < 0) {
+      cerr << "error from import: "
+          << cpp_strerror(ret) << std::endl;
+      goto out;
+    }
   } else {
     cerr << "unrecognized command " << nargs[0] << "; -h or --help for usage" << std::endl;
     ret = -EINVAL;
@@ -2749,11 +2796,6 @@ int main(int argc, const char **argv)
     cerr << "rados: you must give an action. Try --help" << std::endl;
     return 1;
   }
-  if ((strcmp(args[0], "import") == 0) || (strcmp(args[0], "export") == 0)) {
-    cout << "The import and export operations are not available" << std::endl;
-    exit(1);
-    //return rados_tool_sync(opts, args);
-  } else {
-    return rados_tool_common(opts, args);
-  }
+
+  return rados_tool_common(opts, args);
 }