#include <iostream>
#include <fstream>
+#include <cerrno>
+
#include <stdlib.h>
#include <time.h>
#include <sstream>
-const char *BENCH_DATA = "benchmark_write_data";
+const char *BENCH_METADATA = "benchmark_write_metadata";
const std::string BENCH_PREFIX = "benchmark_data";
static std::string generate_object_prefix(int pid = 0) {
return NULL;
}
-int ObjBencher::aio_bench(int operation, int secondsToRun, int concurrentios, int op_size) {
+int ObjBencher::aio_bench(int operation, int secondsToRun, int concurrentios, int op_size, bool cleanup) {
int object_size = op_size;
int num_objects = 0;
char* contentsChars = new char[op_size];
//get data from previous write run, if available
if (operation != OP_WRITE) {
- bufferlist object_data;
- r = sync_read(BENCH_DATA, object_data, sizeof(int)*3);
+ r = fetch_bench_metadata(&object_size, &num_objects, &prevPid);
if (r <= 0) {
delete[] contentsChars;
- if (r == -2)
+ if (r == -ENOENT)
cerr << "Must write data before running a read benchmark!" << std::endl;
return r;
}
- bufferlist::iterator p = object_data.begin();
- ::decode(object_size, p);
- ::decode(num_objects, p);
- ::decode(prevPid, p);
} else {
object_size = op_size;
}
r = -1;
}
+ if (OP_WRITE == operation && cleanup) {
+ r = fetch_bench_metadata(&object_size, &num_objects, &prevPid);
+ if (r <= 0) {
+ if (r == -ENOENT)
+ cerr << "Should never happen: bench metadata missing for current run!" << std::endl;
+ goto out;
+ }
+
+ r = clean_up(num_objects, prevPid);
+ if (r != 0) goto out;
+
+ r = sync_remove(BENCH_METADATA);
+ }
+
out:
delete[] contentsChars;
return r;
return sqrt(stddev);
}
+int ObjBencher::fetch_bench_metadata(int* object_size, int* num_objects, int* prevPid) {
+ int r = 0;
+ bufferlist object_data;
+
+ r = sync_read(BENCH_METADATA, object_data, sizeof(int)*3);
+ if (r <= 0) {
+ return r;
+ }
+ bufferlist::iterator p = object_data.begin();
+ ::decode(*object_size, p);
+ ::decode(*num_objects, p);
+ ::decode(*prevPid, p);
+
+ return 1;
+}
+
int ObjBencher::write_bench(int secondsToRun, int concurrentios) {
out(cout) << "Maintaining " << concurrentios << " concurrent writes of "
<< data.object_size << " bytes for at least "
::encode(data.object_size, b_write);
::encode(data.finished, b_write);
::encode(getpid(), b_write);
- sync_write(BENCH_DATA, b_write, sizeof(int)*3);
+ sync_write(BENCH_METADATA, b_write, sizeof(int)*3);
completions_done();
return -5;
}
+int ObjBencher::clean_up(int num_objects, int prevPid) {
+ int r = 0;
+
+ for (int i = 0; i < num_objects; ++i) {
+ std::string name = generate_object_name(i, prevPid);
+ r = sync_remove(name);
+
+ if (r < 0) {
+ return r;
+ }
+ }
+
+ return 0;
+}
+
struct bench_data data;
+ int fetch_bench_metadata(int* object_size, int* num_objects, int* prevPid);
+
int write_bench(int secondsToRun, int concurrentios);
int seq_read_bench(int secondsToRun, int concurrentios, int num_objects, int writePid);
+ int clean_up(int num_objects, int prevPid);
+
virtual int completions_init(int concurrentios) = 0;
virtual void completions_done() = 0;
virtual int aio_remove(const std::string& oid, int slot) = 0;
virtual int sync_read(const std::string& oid, bufferlist& bl, size_t len) = 0;
virtual int sync_write(const std::string& oid, bufferlist& bl, size_t len) = 0;
+ virtual int sync_remove(const std::string& oid) = 0;
ostream& out(ostream& os);
ostream& out(ostream& os, utime_t& t);
public:
ObjBencher() : show_time(false), lock("ObjBencher::lock") {}
virtual ~ObjBencher() {}
- int aio_bench(int operation, int secondsToRun, int concurrentios, int op_size);
+ int aio_bench(int operation, int secondsToRun, int concurrentios, int op_size, bool cleanup);
void set_show_time(bool dt) {
show_time = dt;
" rmsnap <snap-name> remove snap <snap-name>\n"
" rollback <obj-name> <snap-name> roll back object to snap <snap-name>\n"
"\n"
-" bench <seconds> write|seq|rand [-t concurrent_operations]\n"
+" bench <seconds> write|seq|rand [-t concurrent_operations] [--no-cleanup]\n"
" default is 16 concurrent IOs and 4 MB ops\n"
+" default is to clean up after write benchmark\n"
" load-gen [options] generate load on the cluster\n"
" listomapkeys <obj-name> list the keys in the object map\n"
" getomapval <obj-name> <key> show the value for the specified key\n"
return io_ctx.write(oid, bl, len, 0);
}
+ int sync_remove(const std::string& oid) {
+ return io_ctx.remove(oid);
+ }
+
bool completion_is_done(int slot) {
return completions[slot]->is_safe();
}
string oloc, target_oloc;
int concurrent_ios = 16;
int op_size = 1 << 22;
+ bool cleanup = true;
const char *snapname = NULL;
snap_t snapid = CEPH_NOSNAP;
std::map<std::string, std::string>::const_iterator i;
if (i != opts.end()) {
show_time = true;
}
+ i = opts.find("no-cleanup");
+ if (i != opts.end()) {
+ cleanup = false;
+ }
i = opts.find("pretty-format");
if (i != opts.end()) {
pretty_format = true;
usage_exit();
RadosBencher bencher(rados, io_ctx);
bencher.set_show_time(show_time);
- ret = bencher.aio_bench(operation, seconds, concurrent_ios, op_size);
+ ret = bencher.aio_bench(operation, seconds, concurrent_ios, op_size, cleanup);
if (ret != 0)
cerr << "error during benchmark: " << ret << std::endl;
}
opts["pretty-format"] = "true";
} else if (ceph_argparse_flag(args, i, "--show-time", (char*)NULL)) {
opts["show-time"] = "true";
+ } else if (ceph_argparse_flag(args, i, "--no-cleanup", (char*)NULL)) {
+ opts["no-cleanup"] = "true";
} else if (ceph_argparse_witharg(args, i, &val, "-p", "--pool", (char*)NULL)) {
opts["pool"] = val;
} else if (ceph_argparse_witharg(args, i, &val, "--target-pool", (char*)NULL)) {
" set the size of write ops for put or benchmarking\n"
" --show-time\n"
" prefix output lines with date and time\n"
+" --no-cleanup\n"
+" do not clean up data after write bench\n"
"REST CONFIG OPTIONS\n"
" --api-host=bhost\n"
" host name\n"
void process_context(req_context *ctx);
void get_obj(req_context *ctx);
void put_obj(req_context *ctx);
+ void delete_obj(req_context *ctx);
void queue(req_context *ctx) {
req_wq.queue(ctx);
case OP_PUT_OBJ:
put_obj(ctx);
break;
+ case OP_DELETE_OBJ:
+ delete_obj(ctx);
+ break;
default:
assert(0);
}
&get_obj_handler, ctx);
}
+void RESTDispatcher::delete_obj(req_context *ctx)
+{
+
+ S3_delete_object(ctx->bucket_ctx, ctx->oid.c_str(),
+ ctx->ctx, &response_handler, ctx);
+}
+
class RESTBencher : public ObjBencher {
RESTDispatcher *dispatcher;
struct req_context **completions;
ctx->put();
return ret;
}
+ int sync_remove(const std::string& oid) {
+ struct req_context *ctx = new req_context;
+ int ret = ctx->init_ctx();
+ if (ret < 0) {
+ return ret;
+ }
+ ctx->get();
+ ctx->bucket_ctx = &bucket_ctx;
+ ctx->oid = oid;
+ ctx->op = OP_DELETE_OBJ;
+
+ dispatcher->process_context(ctx);
+ ret = ctx->ret();
+ ctx->put();
+ return ret;
+ }
bool completion_is_done(int slot) {
return completions[slot]->complete;
int seconds = 60;
bool show_time = false;
+ bool cleanup = true;
for (i = args.begin(); i != args.end(); ) {
exit(0);
} else if (ceph_argparse_flag(args, i, "--show-time", (char*)NULL)) {
show_time = true;
+ } else if (ceph_argparse_flag(args, i, "--no-cleanup", (char*)NULL)) {
+ cleanup = false;
} else if (ceph_argparse_witharg(args, i, &user_agent, "--agent", (char*)NULL)) {
/* nothing */
} else if (ceph_argparse_witharg(args, i, &access_key, "--access-key", (char*)NULL)) {
exit(1);
}
- ret = bencher.aio_bench(operation, seconds, concurrent_ios, op_size);
+ ret = bencher.aio_bench(operation, seconds, concurrent_ios, op_size, cleanup);
if (ret != 0) {
cerr << "error during benchmark: " << ret << std::endl;
}