From 0e470c50e5db1037baf0b4dee8d36bcf17148a78 Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Tue, 3 Jan 2012 11:09:00 -0800 Subject: [PATCH] testrados: replace testreadwrite and testsnaps with testrados testrados can act as testreadwrite or testsnaps by changing the command line options for the weight of each operation type. Signed-off-by: Josh Durgin --- src/.gitignore | 3 +- src/Makefile.am | 10 +- src/test/osd/RadosModel.h | 13 +- src/test/osd/TestRados.cc | 230 ++++++++++++++++++++++++++++++++++ src/test/osd/TestReadWrite.cc | 145 --------------------- src/test/osd/TestSnaps.cc | 157 ----------------------- 6 files changed, 245 insertions(+), 313 deletions(-) create mode 100644 src/test/osd/TestRados.cc delete mode 100644 src/test/osd/TestReadWrite.cc delete mode 100644 src/test/osd/TestSnaps.cc diff --git a/src/.gitignore b/src/.gitignore index 3376c586f64af..575e2468db088 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -41,8 +41,7 @@ /test_libceph_build /test_librados_build /test_librgw_build -/testsnaps -/testreadwrite +/testrados /test_str_list /test_stress_watch /multi_stress_watch diff --git a/src/Makefile.am b/src/Makefile.am index 5213b5e2d2db1..4977665f862f5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -196,13 +196,9 @@ test_trans_SOURCES = test_trans.cc test_trans_LDADD = libos.la $(LIBGLOBAL_LDA) bin_DEBUGPROGRAMS += test_trans -testsnaps_SOURCES = test/osd/TestSnaps.cc test/osd/TestOpStat.cc test/osd/Object.cc test/osd/RadosModel.cc -testsnaps_LDADD = librados.la $(LIBGLOBAL_LDA) -bin_DEBUGPROGRAMS += testsnaps - -testreadwrite_SOURCES = test/osd/TestReadWrite.cc test/osd/TestOpStat.cc test/osd/Object.cc test/osd/RadosModel.cc -testreadwrite_LDADD = librados.la $(LIBGLOBAL_LDA) -bin_DEBUGPROGRAMS += testreadwrite +testrados_SOURCES = test/osd/TestRados.cc test/osd/TestOpStat.cc test/osd/Object.cc test/osd/RadosModel.cc +testrados_LDADD = librados.la $(LIBGLOBAL_LDA) +bin_DEBUGPROGRAMS += testrados multi_stress_watch_SOURCES = test/multi_stress_watch.cc test/rados-api/test.cc multi_stress_watch_LDADD = librados.la $(LIBGLOBAL_LDA) diff --git a/src/test/osd/RadosModel.h b/src/test/osd/RadosModel.h index bd1ed2a1759ea..bb6bf6022f4a5 100644 --- a/src/test/osd/RadosModel.h +++ b/src/test/osd/RadosModel.h @@ -36,6 +36,15 @@ typename T::iterator rand_choose(T &cont) { return retval; } +enum TestOpType { + TEST_OP_READ, + TEST_OP_WRITE, + TEST_OP_DELETE, + TEST_OP_SNAP_CREATE, + TEST_OP_SNAP_REMOVE, + TEST_OP_ROLLBACK +}; + class TestOp { public: RadosTestContext *context; @@ -48,7 +57,7 @@ public: done(0) {} - virtual ~TestOp(); + virtual ~TestOp() {}; /** * This struct holds data to be passed by a callback @@ -85,7 +94,7 @@ public: class TestOpGenerator { public: - virtual ~TestOpGenerator(); + virtual ~TestOpGenerator() {}; virtual TestOp *next(RadosTestContext &context) = 0; }; diff --git a/src/test/osd/TestRados.cc b/src/test/osd/TestRados.cc new file mode 100644 index 0000000000000..183641d4cbbf4 --- /dev/null +++ b/src/test/osd/TestRados.cc @@ -0,0 +1,230 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +#include "common/Mutex.h" +#include "common/Cond.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test/osd/RadosModel.h" + +using namespace std; + +class WeightedTestGenerator : public TestOpGenerator +{ +public: + + WeightedTestGenerator(int ops, + int objects, + map op_weights, + TestOpStat *stats) : + m_nextop(NULL), m_op(0), m_ops(ops), m_objects(objects), m_stats(stats), + m_total_weight(0) + { + for (map::const_iterator it = op_weights.begin(); + it != op_weights.end(); + ++it) { + m_total_weight += it->second; + m_weight_sums.insert(pair(it->first, + m_total_weight)); + } + } + + TestOp *next(RadosTestContext &context) + { + TestOp *retval = NULL; + + ++m_op; + if (m_op <= m_objects) { + stringstream oid; + oid << m_op; + cout << "Writing initial " << oid.str() << std::endl; + return new WriteOp(&context, oid.str()); + } else if (m_op >= m_ops) { + return NULL; + } + + if (m_nextop) { + retval = m_nextop; + m_nextop = NULL; + return retval; + } + + while (retval == NULL) { + unsigned int rand_val = rand() % m_total_weight; + for (map::const_iterator it = m_weight_sums.begin(); + it != m_weight_sums.end(); + ++it) { + if (rand_val < it->second) { + retval = gen_op(context, it->first); + break; + } + } + } + return retval; + } + +private: + + TestOp *gen_op(RadosTestContext &context, TestOpType type) + { + string oid; + switch (type) { + case TEST_OP_READ: + oid = *(rand_choose(context.oid_not_in_use)); + cout << "Reading " << oid << std::endl; + return new ReadOp(&context, oid, m_stats); + + case TEST_OP_WRITE: + oid = *(rand_choose(context.oid_not_in_use)); + cout << "Writing " << oid << " current snap is " + << context.current_snap << std::endl; + return new WriteOp(&context, oid, m_stats); + + case TEST_OP_DELETE: + oid = *(rand_choose(context.oid_not_in_use)); + cout << "Deleting " << oid << " current snap is " + << context.current_snap << std::endl; + return new DeleteOp(&context, oid, m_stats); + + case TEST_OP_SNAP_CREATE: + cout << "Snapping" << std::endl; + return new SnapCreateOp(&context, m_stats); + + case TEST_OP_SNAP_REMOVE: + if (context.snaps.empty()) { + return NULL; + } else { + int snap = rand_choose(context.snaps)->first; + cout << "RemovingSnap " << snap << std::endl; + return new SnapRemoveOp(&context, snap, m_stats); + } + + case TEST_OP_ROLLBACK: + if (context.snaps.empty()) { + return NULL; + } else { + int snap = rand_choose(context.snaps)->first; + string oid = *(rand_choose(context.oid_not_in_use)); + cout << "RollingBack " << oid << " to " << snap << std::endl; + m_nextop = new ReadOp(&context, oid, m_stats); + return new RollbackOp(&context, oid, snap); + } + + default: + cerr << "Invalid op type " << type << std::endl; + assert(0); + } + } + + TestOp *m_nextop; + int m_op; + int m_ops; + int m_objects; + TestOpStat *m_stats; + map m_weight_sums; + unsigned int m_total_weight; +}; + +int main(int argc, char **argv) +{ + int ops = 1000; + int objects = 50; + int max_in_flight = 16; + uint64_t size = 4000000; // 4 MB + uint64_t min_stride_size, max_stride_size; + + const int NUM_OP_TYPES = 6; + TestOpType op_types[NUM_OP_TYPES] = { + TEST_OP_READ, TEST_OP_WRITE, TEST_OP_DELETE, + TEST_OP_SNAP_CREATE, TEST_OP_SNAP_REMOVE, TEST_OP_ROLLBACK + }; + + map op_weights; + + for (int i = 0; i < NUM_OP_TYPES; ++i) { + if (argc > i + 1) { + int weight = atoi(argv[i + 1]); + if (weight < 0) { + cerr << "Weights must be nonnegative." << std::endl; + return 1; + } + cout << "adding op weight " << op_types[i] << " -> " << weight << std::endl; + op_weights.insert(pair(op_types[i], weight)); + } + } + + if (argc > 1 + NUM_OP_TYPES) { + ops = atoi(argv[1 + NUM_OP_TYPES]); + } + + if (argc > 2 + NUM_OP_TYPES) { + objects = atoi(argv[2 + NUM_OP_TYPES]); + } + + if (argc > 3 + NUM_OP_TYPES) { + max_in_flight = atoi(argv[3 + NUM_OP_TYPES]); + } + + if (argc > 4 + NUM_OP_TYPES) { + size = atoi(argv[4 + NUM_OP_TYPES]); + } + + if (argc > 5 + NUM_OP_TYPES) { + min_stride_size = atoi(argv[5 + NUM_OP_TYPES]); + } else { + min_stride_size = size / 10; + } + + if (argc > 6 + NUM_OP_TYPES) { + max_stride_size = atoi(argv[6 + NUM_OP_TYPES]); + } else { + max_stride_size = size / 5; + } + + cout << "Configuration:" << std::endl + << "\tNumber of operations: " << ops << std::endl + << "\tNumber of objects: " << objects << std::endl + << "\tMax in flight operations: " << max_in_flight << std::endl + << "\tObject size (in bytes): " << size << std::endl + << "\tWrite stride min: " << min_stride_size << std::endl + << "\tWrite stride max: " << max_stride_size << std::endl; + + if (min_stride_size > max_stride_size) { + cerr << "Error: min_stride_size cannot be more than max_stride_size" + << std::endl; + return 1; + } + + if (min_stride_size > size || max_stride_size > size) { + cerr << "Error: min_stride_size and max_stride_size must be " + << "smaller than object size" << std::endl; + return 1; + } + + if (max_in_flight > objects) { + cerr << "Error: max_in_flight must be less than the number of objects" + << std::endl; + return 1; + } + + char *id = getenv("CEPH_CLIENT_ID"); + string pool_name = "data"; + VarLenGenerator cont_gen(size, min_stride_size, max_stride_size); + RadosTestContext context(pool_name, max_in_flight, cont_gen, id); + + TestOpStat stats; + WeightedTestGenerator gen = WeightedTestGenerator(ops, objects, + op_weights, &stats); + context.loop(&gen); + + context.shutdown(); + cerr << context.errors << " errors." << std::endl; + cerr << stats << std::endl; + return 0; +} diff --git a/src/test/osd/TestReadWrite.cc b/src/test/osd/TestReadWrite.cc deleted file mode 100644 index 36e38420d6eb4..0000000000000 --- a/src/test/osd/TestReadWrite.cc +++ /dev/null @@ -1,145 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -#include "common/Mutex.h" -#include "common/Cond.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "test/osd/RadosModel.h" - -using namespace std; - -TestOp::~TestOp() -{ -} - -TestOpGenerator::~TestOpGenerator() -{ -} - -struct ReadWriteGenerator : public TestOpGenerator -{ - TestOp *nextop; - int op; - int ops; - int objects; - int read_percent; - ReadWriteGenerator(int ops, int objects, int read_percent) : - nextop(0), op(0), ops(ops), objects(objects), read_percent(read_percent) - {} - - - TestOp *next(RadosTestContext &context) - { - op++; - if (op <= objects) { - stringstream oid; - oid << op; - cout << "Writing initial " << oid.str() << std::endl; - return new WriteOp(&context, oid.str()); - } else if (op >= ops) { - return 0; - } - - if (nextop) { - TestOp *retval = nextop; - nextop = 0; - return retval; - } - int switchval = rand() % 110; - if (switchval < read_percent) { - string oid = *(rand_choose(context.oid_not_in_use)); - cout << "Reading " << oid << std::endl; - return new ReadOp(&context, oid, 0); - } else if (switchval < 100) { - string oid = *(rand_choose(context.oid_not_in_use)); - cout << "Writing " << oid << " current snap is " - << context.current_snap << std::endl; - return new WriteOp(&context, oid, 0); - } else { - string oid = *(rand_choose(context.oid_not_in_use)); - cout << "Deleting " << oid << " current snap is " - << context.current_snap << std::endl; - return new DeleteOp(&context, oid, 0); - } - } -}; - -int main(int argc, char **argv) -{ - int ops = 10000; - int objects = 500; - int read_percent = 50; - int max_in_flight = 16; - uint64_t size = 4000000; // 4 MB - uint64_t min_stride_size, max_stride_size; - - if (argc > 1) { - ops = atoi(argv[1]); - } - - if (argc > 2) { - objects = atoi(argv[2]); - } - - if (argc > 3) { - read_percent = atoi(argv[3]); - } - - if (argc > 4) { - max_in_flight = atoi(argv[4]); - } - - if (argc > 5) { - size = atoi(argv[5]); - } - - if (argc > 6) { - min_stride_size = atoi(argv[6]); - } else { - min_stride_size = size / 10; - } - - if (argc > 7) { - max_stride_size = atoi(argv[7]); - } else { - max_stride_size = size / 5; - } - - if (min_stride_size > max_stride_size) { - cerr << "Error: min_stride_size cannot be more than max_stride_size" - << std::endl; - return 1; - } - - if (min_stride_size > size || max_stride_size > size) { - cerr << "Error: min_stride_size and max_stride_size must be " - << "smaller than object size" << std::endl; - return 1; - } - - if (max_in_flight > objects) { - cerr << "Error: max_in_flight must be less than the number of objects" - << std::endl; - return 1; - } - - char *id = getenv("CEPH_CLIENT_ID"); - if (id) cerr << "Client id is: " << id << std::endl; - string pool_name = "data"; - VarLenGenerator cont_gen(size, min_stride_size, max_stride_size); - RadosTestContext context(pool_name, max_in_flight, cont_gen, id); - - ReadWriteGenerator gen = ReadWriteGenerator(ops, objects, read_percent); - context.loop(&gen); - - context.shutdown(); - cerr << context.errors << " errors." << std::endl; - return 0; -} diff --git a/src/test/osd/TestSnaps.cc b/src/test/osd/TestSnaps.cc deleted file mode 100644 index 0c17ed321814f..0000000000000 --- a/src/test/osd/TestSnaps.cc +++ /dev/null @@ -1,157 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -#include "common/Mutex.h" -#include "common/Cond.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "test/osd/RadosModel.h" - -using namespace std; - -TestOp::~TestOp() -{ -} - -TestOpGenerator::~TestOpGenerator() -{ -} - -struct SnapTestGenerator : public TestOpGenerator -{ - TestOp *nextop; - int op; - int ops; - int objects; - TestOpStat *stats; - SnapTestGenerator(int ops, int objects, TestOpStat *stats) : - nextop(0), op(0), ops(ops), objects(objects), stats(stats) - {} - - - TestOp *next(RadosTestContext &context) - { - op++; - if (op <= objects) { - stringstream oid; - oid << op; - cout << "Writing initial " << oid.str() << std::endl; - return new WriteOp(&context, oid.str()); - } else if (op >= ops) { - return 0; - } - - if (nextop) { - TestOp *retval = nextop; - nextop = 0; - return retval; - } - - int switchval = rand() % 60; - if (switchval < 20) { - string oid = *(rand_choose(context.oid_not_in_use)); - cout << "Reading " << oid << std::endl; - return new ReadOp(&context, oid, stats); - } else if (switchval < 40) { - string oid = *(rand_choose(context.oid_not_in_use)); - cout << "Writing " << oid << " current snap is " - << context.current_snap << std::endl; - return new WriteOp(&context, oid, stats); - } else if ((switchval < 45) && !context.snaps.empty()) { - int snap = rand_choose(context.snaps)->first; - string oid = *(rand_choose(context.oid_not_in_use)); - cout << "RollingBack " << oid << " to " << snap << std::endl; - nextop = new ReadOp(&context, oid, stats); - return new RollbackOp(&context, oid, snap); - } else if ((switchval < 47) && !context.snaps.empty()) { - int snap = rand_choose(context.snaps)->first; - cout << "RemovingSnap " << snap << std::endl; - return new SnapRemoveOp(&context, snap, stats); - } else if (switchval < 57) { - string oid = *(rand_choose(context.oid_not_in_use)); - cout << "Deleting " << oid << " current snap is " - << context.current_snap << std::endl; - return new DeleteOp(&context, oid, stats); - } else { - cout << "Snapping" << std::endl; - return new SnapCreateOp(&context, stats); - } - } -}; - -int main(int argc, char **argv) -{ - int ops = 1000; - int objects = 50; - int max_in_flight = 16; - uint64_t size = 4000000; // 4 MB - uint64_t min_stride_size, max_stride_size; - - if (argc > 1) { - ops = atoi(argv[1]); - } - - if (argc > 2) { - objects = atoi(argv[2]); - } - - if (argc > 3) { - max_in_flight = atoi(argv[3]); - } - - if (argc > 4) { - size = atoi(argv[4]); - } - - if (argc > 5) { - min_stride_size = atoi(argv[5]); - } else { - min_stride_size = size / 10; - } - - if (argc > 6) { - max_stride_size = atoi(argv[6]); - } else { - max_stride_size = size / 5; - } - - if (min_stride_size > max_stride_size) { - cerr << "Error: min_stride_size cannot be more than max_stride_size" - << std::endl; - return 1; - } - - if (min_stride_size > size || max_stride_size > size) { - cerr << "Error: min_stride_size and max_stride_size must be " - << "smaller than object size" << std::endl; - return 1; - } - - if (max_in_flight > objects) { - cerr << "Error: max_in_flight must be less than the number of objects" - << std::endl; - return 1; - } - - char *id = getenv("CEPH_CLIENT_ID"); - if (id) cerr << "Client id is: " << id << std::endl; - - string pool_name = "data"; - VarLenGenerator cont_gen(size, min_stride_size, max_stride_size); - RadosTestContext context(pool_name, max_in_flight, cont_gen, id); - - TestOpStat stats; - SnapTestGenerator gen = SnapTestGenerator(ops, objects, &stats); - context.loop(&gen); - - context.shutdown(); - cerr << context.errors << " errors." << std::endl; - cerr << stats << std::endl; - return 0; -} -- 2.39.5