mirror of
https://github.com/ceph/ceph
synced 2024-12-29 23:12:27 +00:00
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 <josh.durgin@dreamhost.com>
This commit is contained in:
parent
9112405130
commit
0e470c50e5
3
src/.gitignore
vendored
3
src/.gitignore
vendored
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
230
src/test/osd/TestRados.cc
Normal file
230
src/test/osd/TestRados.cc
Normal file
@ -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 <iostream>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "test/osd/RadosModel.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class WeightedTestGenerator : public TestOpGenerator
|
||||
{
|
||||
public:
|
||||
|
||||
WeightedTestGenerator(int ops,
|
||||
int objects,
|
||||
map<TestOpType, unsigned int> 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<TestOpType, unsigned int>::const_iterator it = op_weights.begin();
|
||||
it != op_weights.end();
|
||||
++it) {
|
||||
m_total_weight += it->second;
|
||||
m_weight_sums.insert(pair<TestOpType, unsigned int>(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<TestOpType, unsigned int>::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<TestOpType, unsigned int> 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<TestOpType, unsigned int> 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<TestOpType, unsigned int>(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;
|
||||
}
|
@ -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 <iostream>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
@ -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 <iostream>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user