]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rados: Added --striper option to the command line
authorSebastien Ponce <Sebastien.Ponce@cern.ch>
Thu, 29 Jan 2015 03:51:37 +0000 (04:51 +0100)
committerSebastien Ponce <sebastien.ponce@cern.ch>
Tue, 23 Jun 2015 11:04:21 +0000 (13:04 +0200)
Fixes: #10759
the new --striper option allows to use the striping API provided by libradosstriper.

Signed-off-by: Sebastien Ponce <sebastien.ponce@cern.ch>
doc/man/8/rados.rst
src/test/Makefile.am
src/test/libradosstriper/rados-striper.sh [new file with mode: 0755]
src/tools/Makefile-client.am
src/tools/rados/rados.cc

index 6dec6ca80773637d829fab58d585cc76e0fdeca0..ce8a8032a95a334433e44ed7e67ddf7605efc657 100644 (file)
@@ -57,6 +57,11 @@ Options
 
   Set the block size for put/get ops and for write benchmarking.
 
+.. option:: --striper
+
+   Uses the striping API of rados rather than the default one.
+   Available for stat, get, put, truncate, rm, ls and all xattr related operation
+
 
 Global commands
 ===============
index 9d56f055b9869cdb39ba22a9e561a85e5a9ffe46..3c8d630feb218192cfe405ea2379daecf52b3eea 100644 (file)
@@ -79,7 +79,8 @@ check_SCRIPTS += \
        test/osd/osd-config.sh \
        test/osd/osd-bench.sh \
        test/osd/osd-copy-from.sh \
-       test/mon/mon-handle-forward.sh
+       test/mon/mon-handle-forward.sh \
+       test/libradosstriper/rados-striper.sh
 
 if ENABLE_ROOT_MAKE_CHECK
 check_SCRIPTS += test/ceph-disk-root.sh
diff --git a/src/test/libradosstriper/rados-striper.sh b/src/test/libradosstriper/rados-striper.sh
new file mode 100755 (executable)
index 0000000..b682027
--- /dev/null
@@ -0,0 +1,89 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 Red Hat <contact@redhat.com>
+#
+# Author: Sebastien Ponce <sebastien.ponce@cern.ch>
+#
+# 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.
+#
+source test/ceph-helpers.sh
+
+function run() {
+    local dir=$1
+    shift
+
+    export CEPH_MON="127.0.0.1:7112"
+    export CEPH_ARGS
+    CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none "
+    CEPH_ARGS+="--mon-host=$CEPH_MON "
+   
+    # create a cluster with one monitor and three osds
+    run_mon $dir a || return 1
+    run_osd $dir 0 || return 1
+    run_osd $dir 1 || return 1
+    run_osd $dir 2 || return 1
+
+    # create toyfile
+    dd if=/dev/urandom of=$dir/toyfile bs=1234 count=1
+    
+    # put a striped object
+    rados --pool rbd --striper put toyfile $dir/toyfile || return 1
+    
+    # stat it, with and without striping
+    rados --pool rbd --striper stat toyfile | cut -d ',' -f 2 > $dir/stripedStat || return 1
+    rados --pool rbd stat toyfile.0000000000000000 | cut -d ',' -f 2 > $dir/stat || return 1
+    echo ' size 1234' > $dir/refstat
+    diff -w $dir/stripedStat $dir/refstat || return 1
+    diff -w $dir/stat $dir/refstat || return 1
+    rados --pool rbd stat toyfile >& $dir/staterror
+    grep -q 'No such file or directory' $dir/staterror ||  return 1
+    
+    # get the file back with and without striping
+    rados --pool rbd --striper get toyfile $dir/stripedGroup || return 1
+    diff -w $dir/toyfile $dir/stripedGroup || return 1
+    rados --pool rbd get toyfile.0000000000000000 $dir/nonSTripedGroup || return 1
+    diff -w $dir/toyfile $dir/nonSTripedGroup || return 1
+    
+    # test truncate
+    rados --pool rbd --striper truncate toyfile 12
+    rados --pool rbd --striper stat toyfile | cut -d ',' -f 2 > $dir/stripedStat || return 1
+    rados --pool rbd stat toyfile.0000000000000000 | cut -d ',' -f 2 > $dir/stat || return 1
+    echo ' size 12' > $dir/reftrunc
+    diff -w $dir/stripedStat $dir/reftrunc || return 1
+    diff -w $dir/stat $dir/reftrunc || return 1
+    
+    # test xattrs
+    rados --pool rbd --striper setxattr toyfile somexattr somevalue || return 1
+    rados --pool rbd --striper getxattr toyfile somexattr > $dir/xattrvalue || return 1 
+    rados --pool rbd getxattr toyfile.0000000000000000 somexattr > $dir/xattrvalue2 || return 1 
+    echo 'somevalue' > $dir/refvalue
+    diff -w $dir/xattrvalue $dir/refvalue || return 1
+    diff -w $dir/xattrvalue2 $dir/refvalue || return 1
+    rados --pool rbd --striper listxattr toyfile > $dir/xattrlist || return 1
+    echo 'somexattr' > $dir/reflist
+    diff -w $dir/xattrlist $dir/reflist || return 1
+    rados --pool rbd listxattr toyfile.0000000000000000 | grep -v striper > $dir/xattrlist2 || return 1
+    diff -w $dir/xattrlist2 $dir/reflist || return 1    
+    rados --pool rbd --striper rmxattr toyfile somexattr || return 1
+    rados --pool rbd --striper getxattr toyfile somexattr >& $dir/rmxattrerror
+    grep -q 'No data available' $dir/rmxattrerror || return 1
+    rados --pool rbd getxattr toyfile.0000000000000000 somexattr >& $dir/rmxattrerror2
+    grep -q 'No data available' $dir/rmxattrerror2 || return 1
+    
+    # test rm
+    rados --pool rbd --striper rm toyfile || return 1
+    rados --pool rbd --striper stat toyfile >& $dir/staterror2
+    grep -q 'No such file or directory' $dir/staterror2 || return 1
+    rados --pool rbd stat toyfile.0000000000000000 >& $dir/staterror3
+    grep -q 'No such file or directory' $dir/staterror3 || return 1   
+}
+
+main rados-striper "$@"
index 1fb78540e0436c2ec78d1e44d394b6a9941d3531..e417eb5fa3336b3e69378bb947b05e22eec2e065 100644 (file)
@@ -18,7 +18,7 @@ rados_SOURCES = \
        tools/rados/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)
+rados_LDADD = libcls_lock_client.la $(LIBRADOS) $(LIBRADOSSTRIPER) $(CEPH_GLOBAL)
 bin_PROGRAMS += rados
 
 
index d127bf61280b327f970a492b46a071b16a1bdabc..f0bb7accf7b3ac98c6c0e8298c1fd50d8f4625dc 100644 (file)
@@ -16,6 +16,8 @@
 
 #include "include/rados/librados.hpp"
 #include "include/rados/rados_types.hpp"
+#include "include/radosstriper/libradosstriper.hpp"
+using namespace libradosstriper;
 
 #include "common/config.h"
 #include "common/ceph_argparse.h"
@@ -174,6 +176,10 @@ void usage(ostream& out)
 "        Use with cp to specify the locator of the new object\n"
 "   --target-nspace\n"
 "        Use with cp to specify the namespace of the new object\n"
+"   --striper\n"
+"        Use radostriper interface rather than pure rados\n"
+"        Available for stat, get, put, truncate, rm, ls and \n"
+"        all xattr related operations\n"
 "\n"
 "BENCH OPTIONS:\n"
 "   -t N\n"
@@ -243,7 +249,9 @@ static int dump_data(std::string const &filename, bufferlist const &data)
 }
 
 
-static int do_get(IoCtx& io_ctx, const char *objname, const char *outfile, unsigned op_size)
+static int do_get(IoCtx& io_ctx, RadosStriper& striper,
+                 const char *objname, const char *outfile, unsigned op_size,
+                 bool use_striper)
 {
   string oid(objname);
 
@@ -263,7 +271,11 @@ static int do_get(IoCtx& io_ctx, const char *objname, const char *outfile, unsig
   int ret;
   while (true) {
     bufferlist outdata;
-    ret = io_ctx.read(oid, outdata, op_size, offset);
+    if (use_striper) {
+      ret = striper.read(oid, &outdata, op_size, offset);
+    } else {
+      ret = io_ctx.read(oid, outdata, op_size, offset);
+    }
     if (ret <= 0) {
       goto out;
     }
@@ -353,7 +365,9 @@ static int do_copy_pool(Rados& rados, const char *src_pool, const char *target_p
   return 0;
 }
 
-static int do_put(IoCtx& io_ctx, const char *objname, const char *infile, int op_size)
+static int do_put(IoCtx& io_ctx, RadosStriper& striper,
+                 const char *objname, const char *infile, int op_size,
+                 bool use_striper)
 {
   string oid(objname);
   bufferlist indata;
@@ -381,7 +395,11 @@ static int do_put(IoCtx& io_ctx, const char *objname, const char *infile, int op
     }
     if (count == 0) {
       if (!offset) { // in case we have to create an empty object
-       ret = io_ctx.write_full(oid, indata); // indata is empty
+       if (use_striper) {
+         ret = striper.write_full(oid, indata); // indata is empty
+       } else {
+         ret = io_ctx.write_full(oid, indata); // indata is empty
+       }
        if (ret < 0) {
          goto out;
        }
@@ -389,10 +407,17 @@ static int do_put(IoCtx& io_ctx, const char *objname, const char *infile, int op
       continue;
     }
     indata.append(buf, count);
-    if (offset == 0)
-      ret = io_ctx.write_full(oid, indata);
-    else
-      ret = io_ctx.write(oid, indata, count, offset);
+    if (use_striper) {
+      if (offset == 0)
+       ret = striper.write_full(oid, indata);
+      else
+       ret = striper.write(oid, indata, count, offset);
+    } else {
+      if (offset == 0)
+       ret = io_ctx.write_full(oid, indata);
+      else
+       ret = io_ctx.write(oid, indata, count, offset);
+    }
     indata.clear();
 
     if (ret < 0) {
@@ -1147,6 +1172,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
   bool block_size_specified = false;
   bool cleanup = true;
   bool no_verify = false;
+  bool use_striper = false;
   const char *snapname = NULL;
   snap_t snapid = CEPH_NOSNAP;
   std::map<std::string, std::string>::const_iterator i;
@@ -1173,6 +1199,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
 
   Rados rados;
   IoCtx io_ctx;
+  RadosStriper striper;
 
   i = opts.find("create");
   if (i != opts.end()) {
@@ -1370,6 +1397,17 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       if (prev_op_size != default_op_size && prev_op_size != op_size)
        cerr << "INFO: op_size has been rounded to " << op_size << std::endl;
     }
+
+    // create striper interface
+    if (opts.find("striper") != opts.end()) {
+      ret = RadosStriper::striper_create(io_ctx, &striper);
+      if (0 != ret) {
+       cerr << "error opening pool " << pool_name << " with striper interface: "
+            << cpp_strerror(ret) << std::endl;
+       goto out;
+      }
+      use_striper = true;
+    }
   }
 
   // snapname?
@@ -1535,18 +1573,34 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
        librados::NObjectIterator i = io_ctx.nobjects_begin();
        librados::NObjectIterator i_end = io_ctx.nobjects_end();
        for (; i != i_end; ++i) {
+         if (use_striper) {
+           // in case of --striper option, we only list striped
+           // objects, so we only display the first object of
+           // each, without its suffix '.000...000'
+           size_t l = i->get_oid().length();
+           if (l <= 17 ||
+               (0 != i->get_oid().compare(l-17, 17,".0000000000000000"))) continue;
+         }
          if (!formatter) {
            // Only include namespace in output when wildcard specified
            if (wildcard)
              *outstream << i->get_nspace() << "\t";
-           *outstream << i->get_oid();
+           if (use_striper) {
+             *outstream << i->get_oid().substr(0, i->get_oid().length()-17);
+           } else {
+             *outstream << i->get_oid();
+           }
            if (i->get_locator().size())
              *outstream << "\t" << i->get_locator();
            *outstream << std::endl;
          } else {
            formatter->open_object_section("object");
            formatter->dump_string("namespace", i->get_nspace());
-           formatter->dump_string("name", i->get_oid());
+           if (use_striper) {
+             formatter->dump_string("name", i->get_oid().substr(0, i->get_oid().length()-17));
+           } else {
+             formatter->dump_string("name", i->get_oid());
+           }
            if (i->get_locator().size())
              formatter->dump_string("locator", i->get_locator());
            formatter->close_section(); //object
@@ -1608,7 +1662,11 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     string oid(nargs[1]);
     uint64_t size;
     time_t mtime;
-    ret = io_ctx.stat(oid, &size, &mtime);
+    if (use_striper) {
+      ret = striper.stat(oid, &size, &mtime);
+    } else {
+      ret = io_ctx.stat(oid, &size, &mtime);
+    }
     if (ret < 0) {
       cerr << " error stat-ing " << pool_name << "/" << oid << ": "
            << cpp_strerror(ret) << std::endl;
@@ -1622,7 +1680,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
   else if (strcmp(nargs[0], "get") == 0) {
     if (!pool_name || nargs.size() < 3)
       usage_exit();
-    ret = do_get(io_ctx, nargs[1], nargs[2], op_size);
+    ret = do_get(io_ctx, striper, nargs[1], nargs[2], op_size, use_striper);
     if (ret < 0) {
       cerr << "error getting " << pool_name << "/" << nargs[1] << ": " << cpp_strerror(ret) << std::endl;
       goto out;
@@ -1631,7 +1689,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
   else if (strcmp(nargs[0], "put") == 0) {
     if (!pool_name || nargs.size() < 3)
       usage_exit();
-    ret = do_put(io_ctx, nargs[1], nargs[2], op_size);
+    ret = do_put(io_ctx, striper, nargs[1], nargs[2], op_size, use_striper);
     if (ret < 0) {
       cerr << "error putting " << pool_name << "/" << nargs[1] << ": " << cpp_strerror(ret) << std::endl;
       goto out;
@@ -1653,7 +1711,11 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       cerr << "error, cannot truncate to negative value" << std::endl;
       usage_exit();
     }
-    ret = io_ctx.trunc(oid, size);
+    if (use_striper) {
+      ret = striper.trunc(oid, size);
+    } else {
+      ret = io_ctx.trunc(oid, size);
+    }
     if (ret < 0) {
       cerr << "error truncating oid "
           << oid << " to " << size << ": "
@@ -1680,7 +1742,11 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       } while (ret > 0);
     }
 
-    ret = io_ctx.setxattr(oid, attr_name.c_str(), bl);
+    if (use_striper) {
+      ret = striper.setxattr(oid, attr_name.c_str(), bl);
+    } else {
+      ret = io_ctx.setxattr(oid, attr_name.c_str(), bl);
+    }
     if (ret < 0) {
       cerr << "error setting xattr " << pool_name << "/" << oid << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
       goto out;
@@ -1696,7 +1762,11 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     string attr_name(nargs[2]);
 
     bufferlist bl;
-    ret = io_ctx.getxattr(oid, attr_name.c_str(), bl);
+    if (use_striper) {
+      ret = striper.getxattr(oid, attr_name.c_str(), bl);
+    } else {
+      ret = io_ctx.getxattr(oid, attr_name.c_str(), bl);
+    }
     if (ret < 0) {
       cerr << "error getting xattr " << pool_name << "/" << oid << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
       goto out;
@@ -1712,7 +1782,11 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     string oid(nargs[1]);
     string attr_name(nargs[2]);
 
-    ret = io_ctx.rmxattr(oid, attr_name.c_str());
+    if (use_striper) {
+      ret = striper.rmxattr(oid, attr_name.c_str());
+    } else {
+      ret = io_ctx.rmxattr(oid, attr_name.c_str());
+    }
     if (ret < 0) {
       cerr << "error removing xattr " << pool_name << "/" << oid << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl;
       goto out;
@@ -1724,7 +1798,11 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     string oid(nargs[1]);
     map<std::string, bufferlist> attrset;
     bufferlist bl;
-    ret = io_ctx.getxattrs(oid, attrset);
+    if (use_striper) {
+      ret = striper.getxattrs(oid, attrset);
+    } else {
+      ret = io_ctx.getxattrs(oid, attrset);
+    }
     if (ret < 0) {
       cerr << "error getting xattr set " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl;
       goto out;
@@ -2003,7 +2081,11 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
     ++iter;
     for (; iter != nargs.end(); ++iter) {
       const string & oid = *iter;
-      ret = io_ctx.remove(oid);
+      if (use_striper) {
+       ret = striper.remove(oid);
+      } else {
+       ret = io_ctx.remove(oid);
+      }
       if (ret < 0) {
         string name = (nspace.size() ? nspace + "/" : "" ) + oid;
         cerr << "error removing " << pool_name << ">" << name << ": " << cpp_strerror(ret) << std::endl;
@@ -2754,6 +2836,8 @@ int main(int argc, const char **argv)
       opts["target_locator"] = val;
     } else if (ceph_argparse_witharg(args, i, &val, "--target-nspace" , (char *)NULL)) {
       opts["target_nspace"] = val;
+    } else if (ceph_argparse_flag(args, i, "--striper" , (char *)NULL)) {
+      opts["striper"] = "true";
     } else if (ceph_argparse_witharg(args, i, &val, "-t", "--concurrent-ios", (char*)NULL)) {
       opts["concurrent-ios"] = val;
     } else if (ceph_argparse_witharg(args, i, &val, "--block-size", (char*)NULL)) {