--- /dev/null
+#!/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 "$@"
#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"
" 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"
}
-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);
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;
}
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;
}
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;
}
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) {
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;
Rados rados;
IoCtx io_ctx;
+ RadosStriper striper;
i = opts.find("create");
if (i != opts.end()) {
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?
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
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;
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;
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;
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 << ": "
} 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;
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;
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;
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;
++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;
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)) {