From fb7238eacc0c53de71cb353c4d17ce92115772e0 Mon Sep 17 00:00:00 2001 From: Mike Ryan Date: Wed, 20 Jun 2012 14:47:46 -0700 Subject: [PATCH] obj_bencher: clean up objects after a write benchmark Per #2477, objects created during rados or rest write benchmark are automatically cleaned up after the test. They can optionally be left in place. Signed-off-by: Mike Ryan --- src/common/obj_bencher.cc | 62 ++++++++++++++++++++++++++++++++------- src/common/obj_bencher.h | 7 ++++- src/rados.cc | 16 ++++++++-- src/tools/rest_bench.cc | 34 ++++++++++++++++++++- 4 files changed, 105 insertions(+), 14 deletions(-) diff --git a/src/common/obj_bencher.cc b/src/common/obj_bencher.cc index c87eb22c729ed..2f78161b8b1c6 100644 --- a/src/common/obj_bencher.cc +++ b/src/common/obj_bencher.cc @@ -20,12 +20,14 @@ #include #include +#include + #include #include #include -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) { @@ -145,7 +147,7 @@ void *ObjBencher::status_printer(void *_bencher) { 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]; @@ -154,18 +156,13 @@ int ObjBencher::aio_bench(int operation, int secondsToRun, int concurrentios, in //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; } @@ -201,6 +198,20 @@ int ObjBencher::aio_bench(int operation, int secondsToRun, int concurrentios, in 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; @@ -243,6 +254,22 @@ static double vec_stddev(vector& v) 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 " @@ -417,7 +444,7 @@ int ObjBencher::write_bench(int secondsToRun, int concurrentios) { ::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(); @@ -614,4 +641,19 @@ int ObjBencher::seq_read_bench(int seconds_to_run, int num_objects, int concurre 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; +} + diff --git a/src/common/obj_bencher.h b/src/common/obj_bencher.h index cc98cda88f37b..5802b53af09f2 100644 --- a/src/common/obj_bencher.h +++ b/src/common/obj_bencher.h @@ -58,9 +58,13 @@ protected: 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; @@ -76,13 +80,14 @@ protected: 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; diff --git a/src/rados.cc b/src/rados.cc index 6ee0e890aeed2..323d403e53e8d 100644 --- a/src/rados.cc +++ b/src/rados.cc @@ -84,8 +84,9 @@ void usage(ostream& out) " rmsnap remove snap \n" " rollback roll back object to snap \n" "\n" -" bench write|seq|rand [-t concurrent_operations]\n" +" bench 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 list the keys in the object map\n" " getomapval show the value for the specified key\n" @@ -794,6 +795,10 @@ protected: 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(); } @@ -980,6 +985,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts, 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::const_iterator i; @@ -1085,6 +1091,10 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts, 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; @@ -1822,7 +1832,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts, 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; } @@ -1952,6 +1962,8 @@ int main(int argc, const char **argv) 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)) { diff --git a/src/tools/rest_bench.cc b/src/tools/rest_bench.cc index 93ca6d8540a02..1903907a3caf1 100644 --- a/src/tools/rest_bench.cc +++ b/src/tools/rest_bench.cc @@ -47,6 +47,8 @@ void usage(ostream& out) " 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" @@ -252,6 +254,7 @@ public: 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); @@ -273,6 +276,9 @@ void RESTDispatcher::process_context(req_context *ctx) case OP_PUT_OBJ: put_obj(ctx); break; + case OP_DELETE_OBJ: + delete_obj(ctx); + break; default: assert(0); } @@ -309,6 +315,13 @@ void RESTDispatcher::get_obj(req_context *ctx) &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; @@ -457,6 +470,22 @@ protected: 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; @@ -565,6 +594,7 @@ int main(int argc, const char **argv) int seconds = 60; bool show_time = false; + bool cleanup = true; for (i = args.begin(); i != args.end(); ) { @@ -575,6 +605,8 @@ int main(int argc, const char **argv) 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)) { @@ -662,7 +694,7 @@ int main(int argc, const char **argv) 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; } -- 2.39.5