#define dout_subsys ceph_subsys_rados
#define dout_context g_ceph_context
+namespace {
+ struct Size {};
+ void validate(boost::any& v, const std::vector<std::string>& values,
+ Size *target_type, int) {
+ po::validators::check_first_occurrence(v);
+ const std::string &s = po::validators::get_single_string(values);
+
+ std::string parse_error;
+ uint64_t size = strict_iecstrtoll(s, &parse_error);
+ if (!parse_error.empty()) {
+ throw po::validation_error(po::validation_error::invalid_option_value);
+ }
+ v = boost::any(size);
+ }
+
+ struct Pair {};
+ void validate(boost::any& v, const std::vector<std::string>& values,
+ Pair *target_type, int) {
+ po::validators::check_first_occurrence(v);
+ const std::string &s = po::validators::get_single_string(values);
+ auto part = ceph::split(s).begin();
+ std::string parse_error;
+ int first = strict_iecstrtoll(*part++, &parse_error);
+ int second = strict_iecstrtoll(*part, &parse_error);
+ if (!parse_error.empty()) {
+ throw po::validation_error(po::validation_error::invalid_option_value);
+ }
+ v = boost::any(std::pair<int,int>{first,second});
+ }
+
+ struct PluginString {};
+ void validate(boost::any& v, const std::vector<std::string>& values,
+ PluginString *target_type, int) {
+ po::validators::check_first_occurrence(v);
+ const std::string &s = po::validators::get_single_string(values);
+
+ const std::string_view* pluginIt = std::find(
+ ceph::io_sequence::tester::pluginChoices.begin(),
+ ceph::io_sequence::tester::pluginChoices.end(),
+ s
+ );
+ if(ceph::io_sequence::tester::pluginChoices.end() == pluginIt)
+ {
+ throw po::validation_error(po::validation_error::invalid_option_value);
+ }
+
+ v = boost::any(*pluginIt);
+ }
+
+ constexpr std::string_view usage[] = {
+ "Basic usage:",
+ "",
+ "ceph_test_rados_io_sequence",
+ "\t Test I/O to a single object using default settings. Good for",
+ "\t testing boundary conditions",
+ "",
+ "ceph_test_rados_io_sequence --parallel <n>",
+ "\t Run parallel test to multiple objects. First object is tested with",
+ "\t default settings, other objects are tested with random settings",
+ "",
+ "Advanced usage:",
+ "",
+ "ceph_test_rados_io_sequence --blocksize <b> --km <k,m> --plugin <p>",
+ " --objectsize <min,max> --threads <t>",
+ "ceph_test_rados_io_sequence --blocksize <b> --pool <p> --object <oid>",
+ " --objectsize <min,max> --threads <t>",
+ "\tCustomize the test, if a pool is specified then it defines the",
+ "\tReplica/EC configuration",
+ "",
+ "ceph_test_rados_io_sequence --listsequence",
+ "\t Display list of supported I/O sequences",
+ "",
+ "ceph_test_rados_io_sequence --dryrun --sequence <n>",
+ "\t Show I/O that will be generated for a sequence, validate",
+ "\t seqeunce has correct I/O barriers to restrict concurrency",
+ "",
+ "ceph_test_rados_io_sequence --seed <seed>",
+ "\t Repeat a previous test with the same random numbers (seed is",
+ "\t displayed at start of test), if threads = 1 then this will produce",
+ "\t the exact same sequence of I/O, if threads > 1 then I/Os are issued",
+ "\t in parallel so ordering might be slightly different",
+ "",
+ "ceph_test_rados_io_sequence --sequence <n> --seqseed <n>",
+ "\t Repeat a sequence from a previous test with the same random",
+ "\t numbers (seqseed is displayed at start of sequence)",
+ "",
+ "ceph_test_rados_io_sequence --pool <p> --object <oid> --interactive",
+ "\t Execute sequence of I/O commands from stdin. Offset and length",
+ "\t are specified with unit of blocksize. Supported commands:",
+ "\t\t create <len>",
+ "\t\t remove",
+ "\t\t read|write <off> <len>",
+ "\t\t read2|write2 <off> <len> <off> <len>",
+ "\t\t read3|write3 <off> <len> <off> <len> <off> <len>",
+ "\t\t done"
+ };
+
+ po::options_description get_options_description()
+ {
+ po::options_description desc("ceph_test_rados_io options");
+ desc.add_options()
+ ("help,h",
+ "show help message")
+ ("listsequence,l",
+ "show list of sequences")
+ ("dryrun,d",
+ "test sequence, do not issue any I/O")
+ ("verbose",
+ "more verbose output during test")
+ ("sequence,s", po::value<int>(),
+ "test specified sequence")
+ ("seed", po::value<int>(),
+ "seed for whole test")
+ ("seqseed", po::value<int>(),
+ "seed for sequence")
+ ("blocksize,b", po::value<Size>(),
+ "block size (default 2048)")
+ ("chunksize,c", po::value<Size>(),
+ "chunk size (default 4096)")
+ ("pool,p", po::value<std::string>(),
+ "pool name")
+ ("object,o", po::value<std::string>()->default_value("test"),
+ "object name")
+ ("km", po::value<Pair>(),
+ "k,m EC pool profile (default 2,2)")
+ ("plugin", po::value<PluginString>(),
+ "EC plugin (isa or jerasure)")
+ ("objectsize", po::value<Pair>(),
+ "min,max object size in blocks (default 1,32)")
+ ("threads,t", po::value<int>(),
+ "number of threads of I/O per object (default 1)")
+ ("parallel,p", po::value<int>()->default_value(1),
+ "number of objects to exercise in parallel")
+ ("interactive",
+ "interactive mode, execute IO commands from stdin");
+
+ return desc;
+ }
+
+ int parse_io_seq_options(
+ po::variables_map& vm,
+ int argc,
+ char** argv)
+ {
+ std::vector<std::string> unrecognized_options;
+ try {
+ po::options_description desc = get_options_description();
+
+ auto parsed = po::command_line_parser(argc, argv)
+ .options(desc)
+ .allow_unregistered()
+ .run();
+ po::store(parsed, vm);
+ po::notify(vm);
+ unrecognized_options = po::collect_unrecognized(parsed.options,
+ po::include_positional);
+
+ if (!unrecognized_options.empty())
+ {
+ std::stringstream ss;
+ ss << "Unrecognised command options supplied: ";
+ while (unrecognized_options.size() > 1)
+ {
+ ss << unrecognized_options.back().c_str() << ", ";
+ unrecognized_options.pop_back();
+ }
+ ss << unrecognized_options.back();
+ dout(0) << ss.str() << dendl;
+ return 1;
+ }
+ } catch(const po::error& e) {
+ std::cerr << "error: " << e.what() << std::endl;
+ return 1;
+ }
+
+ return 0;
+ }
+}
+
template <typename T, int N, const std::array<T, N>& Ts>
ceph::io_sequence::tester::ProgramOptionSelector<T, N, Ts>
::ProgramOptionSelector(ceph::util::random_number_generator<int>& rng,
bool set_forced,
bool select_first)
: rng(rng),
- // choices(choices),
option_name(option_name) {
if (set_forced && vm.count(option_name)) {
force_value = vm[option_name].as<T>();
}
int k = value.first;
int m = value.second;
-
+
const std::string plugin = std::string(spl.choose());
const uint64_t chunk_size = scs.choose();
ceph::condition_variable& cond,
bool dryrun,
bool verbose,
- bool has_seqseed,
- int seqseed) :
- rng(rng), verbose(verbose), has_seqseed(has_seqseed), seqseed(seqseed)
+ std::optional<int> seqseed) :
+ rng(rng), verbose(verbose), seqseed(seqseed)
{
if (dryrun) {
verbose = true;
curseq = seq_range.first;
seq = ceph::io_exerciser::IoSequence::generate_sequence(curseq,
obj_size_range,
- has_seqseed ?
- seqseed :
- rng());
+ seqseed.value_or(rng()));
op = seq->next();
done = false;
dout(0) << "== " << exerciser_model->get_oid() << " "
} else {
seq = ceph::io_exerciser::IoSequence::generate_sequence(curseq,
obj_size_range,
- has_seqseed ?
- seqseed :
- rng());
+ seqseed.value_or(rng()));
dout(0) << "== " << exerciser_model->get_oid() << " "
<< curseq << " " << seq->get_name()
<< " ==" <<dendl;
return exerciser_model->get_num_io();
}
-struct Size {};
-void validate(boost::any& v, const std::vector<std::string>& values,
- Size *target_type, int) {
- po::validators::check_first_occurrence(v);
- const std::string &s = po::validators::get_single_string(values);
+ceph::io_sequence::tester::TestRunner::TestRunner(po::variables_map& vm,
+ librados::Rados& rados) :
+ rados(rados),
+ seed(vm.contains("seed") ? vm["seed"].as<int>() : time(nullptr)),
+ rng(ceph::util::random_number_generator<int>(seed)),
+ sbs{rng, vm},
+ sos{rng, vm},
+ spo{rng, vm, rados, vm.contains("dryrun")},
+ snt{rng, vm},
+ ssr{rng, vm}
+{
+ dout(0) << "Test using seed " << seed << dendl;
- std::string parse_error;
- uint64_t size = strict_iecstrtoll(s, &parse_error);
- if (!parse_error.empty()) {
- throw po::validation_error(po::validation_error::invalid_option_value);
+ verbose = vm.contains("verbose");
+ dryrun = vm.contains("dryrun");
+
+ seqseed = std::nullopt;
+ if (vm.contains("seqseed")) {
+ seqseed = vm["seqseed"].as<int>();
+ }
+ num_objects = vm["parallel"].as<int>();
+ object_name = vm["object"].as<std::string>();
+ interactive = vm.contains("interactive");
+
+ if (!dryrun)
+ {
+ guard.emplace(boost::asio::make_work_guard(asio));
+ thread = make_named_thread("io_thread",[&asio = asio] { asio.run(); });
+ }
+
+ show_help = vm.contains("help");
+ show_sequence = vm.contains("listsequence");
+}
+
+ceph::io_sequence::tester::TestRunner::~TestRunner()
+{
+ if (!dryrun) {
+ guard = std::nullopt;
+ asio.stop();
+ thread.join();
+ rados.shutdown();
+ }
+}
+
+void ceph::io_sequence::tester::TestRunner::help()
+{
+ std::cout << get_options_description() << std::endl;
+ for (auto line : usage) {
+ std::cout << line << std::endl;
+ }
+}
+
+void ceph::io_sequence::tester::TestRunner::list_sequence()
+{
+ // List seqeunces
+ std::pair<int,int> obj_size_range = sos.choose();
+ for (ceph::io_exerciser::Sequence s
+ = ceph::io_exerciser::Sequence::SEQUENCE_BEGIN;
+ s < ceph::io_exerciser::Sequence::SEQUENCE_END; ++s) {
+ std::unique_ptr<ceph::io_exerciser::IoSequence> seq =
+ ceph::io_exerciser::IoSequence::generate_sequence(s,
+ obj_size_range,
+ seqseed.value_or(rng()));
+ dout(0) << s << " " << seq->get_name() << dendl;
}
- v = boost::any(size);
}
-struct Pair {};
-void validate(boost::any& v, const std::vector<std::string>& values,
- Pair *target_type, int) {
- po::validators::check_first_occurrence(v);
- const std::string &s = po::validators::get_single_string(values);
- auto part = ceph::split(s).begin();
+std::string ceph::io_sequence::tester::TestRunner::get_token()
+{
+ static std::string line;
+ static ceph::split split = ceph::split("");
+ static ceph::spliterator tokens;
+ while (line.empty() || tokens == split.end()) {
+ if (!std::getline(std::cin, line)) {
+ throw std::runtime_error("End of input");
+ }
+ split = ceph::split(line);
+ tokens = split.begin();
+ }
+ return std::string(*tokens++);
+}
+
+uint64_t ceph::io_sequence::tester::TestRunner::get_numeric_token()
+{
std::string parse_error;
- int first = strict_iecstrtoll(*part++, &parse_error);
- int second = strict_iecstrtoll(*part, &parse_error);
+ std::string token = get_token();
+ uint64_t num = strict_iecstrtoll(token, &parse_error);
if (!parse_error.empty()) {
- throw po::validation_error(po::validation_error::invalid_option_value);
+ throw std::runtime_error("Invalid number "+token);
}
- v = boost::any(std::pair<int,int>{first,second});
+ return num;
}
-struct PluginString {};
-void validate(boost::any& v, const std::vector<std::string>& values,
- PluginString *target_type, int) {
- po::validators::check_first_occurrence(v);
- const std::string &s = po::validators::get_single_string(values);
-
- const std::string_view* pluginIt = std::find(
- ceph::io_sequence::tester::pluginChoices.begin(),
- ceph::io_sequence::tester::pluginChoices.end(),
- s
- );
- if(ceph::io_sequence::tester::pluginChoices.end() == pluginIt)
+bool ceph::io_sequence::tester::TestRunner::run_test()
+{
+ if (show_help)
{
- throw po::validation_error(po::validation_error::invalid_option_value);
+ help();
+ return true;
+ }
+ else if (show_sequence)
+ {
+ list_sequence();
+ return true;
+ }
+ else if (interactive)
+ {
+ return run_interactive_test();
+ }
+ else
+ {
+ return run_automated_test();
}
-
- v = boost::any(*pluginIt);
}
-int parse_io_seq_options(
- po::variables_map& vm,
- const po::options_description& desc,
- int argc,
- char** argv)
-{
- std::vector<std::string> unrecognized_options;
- try {
- auto parsed = po::command_line_parser(argc, argv)
- .options(desc)
- .allow_unregistered()
- .run();
- po::store(parsed, vm);
- po::notify(vm);
- unrecognized_options = po::collect_unrecognized(parsed.options,
- po::include_positional);
-
- if (!unrecognized_options.empty())
- {
- std::stringstream ss;
- ss << "Unrecognised command options supplied: ";
- while (unrecognized_options.size() > 1)
- {
- ss << unrecognized_options.back().c_str() << ", ";
- unrecognized_options.pop_back();
- }
- ss << unrecognized_options.back();
- dout(0) << ss.str() << dendl;
- return 1;
+bool ceph::io_sequence::tester::TestRunner::run_interactive_test()
+{
+ bool done = false;
+ std::unique_ptr<ceph::io_exerciser::IoOp> ioop;
+ std::unique_ptr<ceph::io_exerciser::Model> model;
+
+ if (dryrun) {
+ model = std::make_unique<ceph::io_exerciser::ObjectModel>(object_name,
+ sbs.choose(),
+ rng());
+ } else {
+ const std::string pool = spo.choose();
+ model = std::make_unique<ceph::io_exerciser::RadosIo>(rados, asio, pool,
+ object_name, sbs.choose(),
+ rng(), 1, // 1 thread
+ lock, cond);
+ }
+
+ while (!done) {
+ const std::string op = get_token();
+ if (!op.compare("done") || !op.compare("q") || !op.compare("quit")) {
+ ioop = ceph::io_exerciser::IoOp::generate_done();
+ } else if (!op.compare("create")) {
+ ioop = ceph::io_exerciser::IoOp::generate_create(get_numeric_token());
+ } else if (!op.compare("remove") || !op.compare("delete")) {
+ ioop = ceph::io_exerciser::IoOp::generate_remove();
+ } else if (!op.compare("read")) {
+ uint64_t offset = get_numeric_token();
+ uint64_t length = get_numeric_token();
+ ioop = ceph::io_exerciser::IoOp::generate_read(offset, length);
+ } else if (!op.compare("read2")) {
+ uint64_t offset1 = get_numeric_token();
+ uint64_t length1 = get_numeric_token();
+ uint64_t offset2 = get_numeric_token();
+ uint64_t length2 = get_numeric_token();
+ ioop = ceph::io_exerciser::IoOp::generate_read2(offset1, length1,
+ offset2, length2);
+ } else if (!op.compare("read3")) {
+ uint64_t offset1 = get_numeric_token();
+ uint64_t length1 = get_numeric_token();
+ uint64_t offset2 = get_numeric_token();
+ uint64_t length2 = get_numeric_token();
+ uint64_t offset3 = get_numeric_token();
+ uint64_t length3 = get_numeric_token();
+ ioop = ceph::io_exerciser::IoOp::generate_read3(offset1, length1,
+ offset2, length2,
+ offset3, length3);
+ } else if (!op.compare("write")) {
+ uint64_t offset = get_numeric_token();
+ uint64_t length = get_numeric_token();
+ ioop = ceph::io_exerciser::IoOp::generate_write(offset, length);
+ } else if (!op.compare("write2")) {
+ uint64_t offset1 = get_numeric_token();
+ uint64_t length1 = get_numeric_token();
+ uint64_t offset2 = get_numeric_token();
+ uint64_t length2 = get_numeric_token();
+ ioop = ceph::io_exerciser::IoOp::generate_write2(offset1, length1,
+ offset2, length2);
+ } else if (!op.compare("write3")) {
+ uint64_t offset1 = get_numeric_token();
+ uint64_t length1 = get_numeric_token();
+ uint64_t offset2 = get_numeric_token();
+ uint64_t length2 = get_numeric_token();
+ uint64_t offset3 = get_numeric_token();
+ uint64_t length3 = get_numeric_token();
+ ioop = ceph::io_exerciser::IoOp::generate_write3(offset1, length1,
+ offset2, length2,
+ offset3, length3);
+ } else {
+ throw std::runtime_error("Invalid operation "+op);
+ }
+ dout(0) << ioop->to_string(model->get_block_size()) << dendl;
+ model->applyIoOp(*ioop);
+ done = ioop->done();
+ if (!done) {
+ ioop = ceph::io_exerciser::IoOp::generate_barrier();
+ model->applyIoOp(*ioop);
}
- } catch(const po::error& e) {
- std::cerr << "error: " << e.what() << std::endl;
- return 1;
}
- return 0;
+ return true;
}
-void run_test(const std::vector<
- std::shared_ptr<ceph::io_sequence::tester::TestObject>
- >& test_objects,
- ceph::mutex& lock)
+bool ceph::io_sequence::tester::TestRunner::run_automated_test()
{
+ // Create a test for each object
+ std::vector<std::shared_ptr<
+ ceph::io_sequence::tester::TestObject>> test_objects;
+
+ for (int obj = 0; obj < num_objects; obj++) {
+ std::string name;
+ if (obj == 0) {
+ name = object_name;
+ } else {
+ name = object_name + std::to_string(obj);
+ }
+ test_objects.push_back(
+ std::make_shared<ceph::io_sequence::tester::TestObject>(
+ name,
+ rados, asio,
+ sbs, spo, sos, snt, ssr,
+ rng, lock, cond,
+ dryrun, verbose,
+ seqseed
+ )
+ );
+ }
+ if (!dryrun) {
+ rados.wait_for_latest_osdmap();
+ }
+
// Main loop of test - while not all test objects have finished
// check to see if any are able to start a new I/O. If all test
// objects are waiting for I/O to complete then wait on a cond
ceph_assert(to->finished());
}
dout(0) << "Total number of IOs = " << total_io << dendl;
-}
-namespace {
- constexpr std::string_view usage[] = {
- "Basic usage:",
- "",
- "ceph_test_rados_io_sequence",
- "\t Test I/O to a single object using default settings. Good for",
- "\t testing boundary conditions",
- "",
- "ceph_test_rados_io_sequence --parallel <n>",
- "\t Run parallel test to multiple objects. First object is tested with",
- "\t default settings, other objects are tested with random settings",
- "",
- "Advanced usage:",
- "",
- "ceph_test_rados_io_sequence --blocksize <b> --km <k,m> --plugin <p>",
- " --objectsize <min,max> --threads <t>",
- "ceph_test_rados_io_sequence --blocksize <b> --pool <p> --object <oid>",
- " --objectsize <min,max> --threads <t>",
- "\tCustomize the test, if a pool is specified then it defines the",
- "\tReplica/EC configuration",
- "",
- "ceph_test_rados_io_sequence --listsequence",
- "\t Display list of supported I/O sequences",
- "",
- "ceph_test_rados_io_sequence --dryrun --sequence <n>",
- "\t Show I/O that will be generated for a sequence, validate",
- "\t seqeunce has correct I/O barriers to restrict concurrency",
- "",
- "ceph_test_rados_io_sequence --seed <seed>",
- "\t Repeat a previous test with the same random numbers (seed is",
- "\t displayed at start of test), if threads = 1 then this will produce",
- "\t the exact same sequence of I/O, if threads > 1 then I/Os are issued",
- "\t in parallel so ordering might be slightly different",
- "",
- "ceph_test_rados_io_sequence --sequence <n> --seqseed <n>",
- "\t Repeat a sequence from a previous test with the same random",
- "\t numbers (seqseed is displayed at start of sequence)",
- "",
- "ceph_test_rados_io_sequence --pool <p> --object <oid> --interactive",
- "\t Execute sequence of I/O commands from stdin. Offset and length",
- "\t are specified with unit of blocksize. Supported commands:",
- "\t\t create <len>",
- "\t\t remove",
- "\t\t read|write <off> <len>",
- "\t\t read2|write2 <off> <len> <off> <len>",
- "\t\t read3|write3 <off> <len> <off> <len> <off> <len>",
- "\t\t done"
- };
+ return true;
}
int main(int argc, char **argv)
CODE_ENVIRONMENT_UTILITY, 0);
common_init_finish(cct.get());
- librados::Rados rados;
- boost::asio::io_context asio;
- std::thread thread;
- std::optional<boost::asio::executor_work_guard<
- boost::asio::io_context::executor_type>> guard;
- ceph::mutex lock = ceph::make_mutex("RadosIo::lock");
- ceph::condition_variable cond;
-
- po::options_description desc("ceph_test_rados_io options");
-
- desc.add_options()
- ("help,h",
- "show help message")
- ("listsequence,l",
- "show list of sequences")
- ("dryrun,d",
- "test sequence, do not issue any I/O")
- ("verbose",
- "more verbose output during test")
- ("sequence,s", po::value<int>(),
- "test specified sequence")
- ("seed", po::value<int>(),
- "seed for whole test")
- ("seqseed", po::value<int>(),
- "seed for sequence")
- ("blocksize,b", po::value<Size>(),
- "block size (default 2048)")
- ("chunksize,c", po::value<Size>(),
- "chunk size (default 4096)")
- ("pool,p", po::value<std::string>(),
- "pool name")
- ("km", po::value<Pair>(),
- "k,m EC pool profile (default 2,2)")
- ("plugin", po::value<PluginString>(),
- "EC plugin (isa or jerasure)")
- ("objectsize", po::value<Pair>(),
- "min,max object size in blocks (default 1,32)")
- ("threads,t", po::value<int>(),
- "number of threads of I/O per object (default 1)")
- ("objects,o", po::value<int>()->default_value(1),
- "number of objects to exercise in parallel");
-
po::variables_map vm;
- int rc = parse_io_seq_options(vm, desc, argc, argv);
+ int rc = parse_io_seq_options(vm, argc, argv);
if (rc != 0)
{
return rc;
}
- if (vm.count("help")) {
- std::cout << desc << std::endl;
- for (auto line : usage) {
- std::cout << line << std::endl;
- }
- return 0;
- }
-
- // Seed
- int seed = time(nullptr);
- if (vm.count("seed")) {
- seed = vm["seed"].as<int>();
- }
- dout(0) << "Test using seed " << seed << dendl;
- auto rng = ceph::util::random_number_generator<int>(seed);
-
- bool verbose = vm.count("verbose");
- bool dryrun = vm.count("dryrun");
- bool has_seqseed = vm.count("seqseed");
- int seqseed = 0;
- if (has_seqseed) {
- seqseed = vm["seqseed"].as<int>();
- }
- int num_objects = vm["objects"].as<int>();
-
- if (!dryrun) {
+ librados::Rados rados;
+ if (!vm.contains("dryrun")) {
rc = rados.init_with_context(g_ceph_context);
ceph_assert(rc == 0);
rc = rados.connect();
ceph_assert(rc == 0);
+ }
- guard.emplace(boost::asio::make_work_guard(asio));
- thread = make_named_thread("io_thread",[&asio] { asio.run(); });
- }
-
- // Select block size
- std::unique_ptr<ceph::io_sequence::tester::SelectBlockSize> sbs
- = std::make_unique<ceph::io_sequence::tester::SelectBlockSize>(rng, vm);
-
- // Select pool
- std::unique_ptr<ceph::io_sequence::tester::SelectECPool> spo
- = std::make_unique<ceph::io_sequence::tester::SelectECPool>(rng, vm,
- rados,
- dryrun);
-
- // Select object size range
- std::unique_ptr<ceph::io_sequence::tester::SelectObjectSize> sos
- = std::make_unique<ceph::io_sequence::tester::SelectObjectSize>(rng,
- vm);
-
- // Select number of threads
- std::unique_ptr<ceph::io_sequence::tester::SelectNumThreads> snt =
- std::make_unique<ceph::io_sequence::tester::SelectNumThreads>(rng, vm);
-
- // Select range of sequences
- std::unique_ptr<ceph::io_sequence::tester::SelectSeqRange> ssr;
+ std::unique_ptr<ceph::io_sequence::tester::TestRunner> runner;
try {
- ssr = std::make_unique<ceph::io_sequence::tester::SelectSeqRange>(rng, vm);
+ runner = std::make_unique<ceph::io_sequence::tester::TestRunner>(vm, rados);
} catch(const po::error& e) {
return 1;
}
+ runner->run_test();
- // List seqeunces
- if (vm.count("listsequence")) {
- std::pair<int,int> obj_size_range = sos->choose();
- for (ceph::io_exerciser::Sequence s
- = ceph::io_exerciser::Sequence::SEQUENCE_BEGIN;
- s < ceph::io_exerciser::Sequence::SEQUENCE_END; ++s) {
- std::unique_ptr<ceph::io_exerciser::IoSequence> seq =
- ceph::io_exerciser::IoSequence::generate_sequence(s,
- obj_size_range,
- has_seqseed ?
- seqseed :
- rng());
- dout(0) << s << " " << seq->get_name() << dendl;
- }
- return 0;
- }
-
- // Create a test for each object
- std::vector<std::shared_ptr<
- ceph::io_sequence::tester::TestObject>> test_objects;
-
- for (int obj = 0; obj < num_objects; obj++) {
- test_objects.push_back(
- std::make_shared<ceph::io_sequence::tester::TestObject>(
- "test" + std::to_string(obj),
- rados, asio,
- *sbs, *spo, *sos, *snt, *ssr,
- rng, lock, cond,
- dryrun, verbose,
- has_seqseed, seqseed
- )
- );
- }
- if (!dryrun) {
- rados.wait_for_latest_osdmap();
- }
-
- run_test(test_objects, lock);
-
- if (!dryrun) {
- guard = std::nullopt;
- asio.stop();
- thread.join();
- rados.shutdown();
- }
return 0;
}