Merge pull request #4166 from sponce/wip-10759

tools: rados cli --striper

Reviewed-by: Josh Durgin <jdurgin@redhat.com>
Reviewed-by: Kefu Chai <kchai@redhat.com>
Reviewed-by: Loic Dachary <ldachary@redhat.com>
This commit is contained in:
Kefu Chai 2015-07-01 23:32:57 +08:00
commit ec132a7986
7 changed files with 209 additions and 23 deletions

View 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
===============

View File

@ -491,6 +491,7 @@ function activate_osd() {
ceph_args+=" --osd-data=$osd_data"
ceph_args+=" --chdir="
ceph_args+=" --osd-pool-default-erasure-code-directory=.libs"
ceph_args+=" --osd-class-dir=.libs"
ceph_args+=" --run-dir=$dir"
ceph_args+=" --debug-osd=20"
ceph_args+=" --log-file=$dir/\$name.log"

View File

@ -10,8 +10,8 @@ libradosstriper_la_SOURCES = \
# We need this to avoid basename conflicts with the libradosstriper build tests in test/Makefile.am
libradosstriper_la_CXXFLAGS = ${AM_CXXFLAGS}
LIBRADOSSTRIPER_DEPS = $(LIBRADOS_DEPS) librados_api.la
libradosstriper_la_LIBADD = $(LIBRADOSSTRIPER_DEPS) $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(EXTRALIBS)
LIBRADOSSTRIPER_DEPS = librados_internal.la libcls_lock_client.la $(LIBOSDC) $(LIBCOMMON_DEPS)
libradosstriper_la_LIBADD = $(LIBRADOSSTRIPER_DEPS) $(LIBRADOS) $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(EXTRALIBS)
libradosstriper_la_LDFLAGS = ${AM_LDFLAGS} -version-info 1:0:0
if LINUX
libradosstriper_la_LDFLAGS += -export-symbols-regex '^radosstriper_.*'

View 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

View File

@ -0,0 +1,95 @@
#!/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 ../qa/workunits/ceph-helpers.sh
function run() {
local dir=$1
shift
export CEPH_MON="127.0.0.1:7113"
export CEPH_ARGS
CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none "
CEPH_ARGS+="--mon-host=$CEPH_MON "
# setup
setup $dir || return 1
# 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
# cleanup
teardown $dir || return 1
}
main rados-striper "$@"

View 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

View 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)) {