mirror of
https://github.com/ceph/ceph
synced 2025-03-25 11:48:05 +00:00
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:
commit
ec132a7986
@ -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
|
||||
===============
|
||||
|
@ -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"
|
||||
|
@ -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_.*'
|
||||
|
@ -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
|
||||
|
95
src/test/libradosstriper/rados-striper.sh
Executable file
95
src/test/libradosstriper/rados-striper.sh
Executable 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 "$@"
|
@ -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
|
||||
|
||||
|
||||
|
@ -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)) {
|
||||
|
Loading…
Reference in New Issue
Block a user