From: Jon Bailey Date: Fri, 10 Jan 2025 13:24:04 +0000 (+0000) Subject: src/test/osd: Split reader classes for program options into a seperate class X-Git-Tag: v20.3.0~425^2~2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=4cc245e43c70fce639bf978d4b0f88c12af88715;p=ceph.git src/test/osd: Split reader classes for program options into a seperate class Split the program option readers out into a seperate class from the main logic controlling the operationg of ceph_test_rados_io_sequence Signed-off-by: Jon Bailey --- diff --git a/src/test/osd/ceph_test_rados_io_sequence/ProgramOptionReader.h b/src/test/osd/ceph_test_rados_io_sequence/ProgramOptionReader.h new file mode 100644 index 0000000000000..e226203e46d1d --- /dev/null +++ b/src/test/osd/ceph_test_rados_io_sequence/ProgramOptionReader.h @@ -0,0 +1,99 @@ +#pragma once + +#include +#include + +#include + +#include "include/ceph_assert.h" +#include "include/random.h" + +/* Overview + * + * class ProgramOptionReader + * Base class that is constructed using a variable_map from + * boost::program_options and the name of an option. + * This class extracts the named option from the variable map into the + * force_value variable. + * It is necissairy to override this class and implement the pure virtual + * select() function to convert the input type to the return type as well as + * implement how to calculate a default value if no input is given. + * + * ProgramOptionSelector + * Implementation of the above ProgramOptionReader. + * This is constructed with a list of options and implements the select + * function to return randomly from this list when called and no argument is + * given in the variables_map. + * The first time this is called, we will always return the first item of the + * list when select_first is true and no value is found in the variables_map. + * This takes an random_number_generator so that randomness can be controlled + * and reproduced if desired. + * + */ + +namespace po = boost::program_options; + +namespace ceph { +namespace io_sequence { +namespace tester { +template +class ProgramOptionReader { + public: + ProgramOptionReader(po::variables_map& vm, + const std::string& option_name) + : option_name(option_name) { + if (vm.count(option_name) > 0) { + force_value = vm[option_name].as(); + } + } + + virtual ~ProgramOptionReader() = default; + + bool isForced() { return force_value.has_value(); } + + virtual const return_type select() = 0; + + protected: + std::optional force_value; + + std::string option_name; +}; + +template & selections_array> +class ProgramOptionSelector : public ProgramOptionReader { + public: + ProgramOptionSelector(ceph::util::random_number_generator& rng, + po::variables_map& vm, + const std::string& option_name, + bool select_first) + : ProgramOptionReader(vm, option_name), rng(rng) { + if (select_first) { + ceph_assert(selections_array.size() > 0); + first_value = selections_array[0]; + } + } + + virtual ~ProgramOptionSelector() = default; + + virtual const option_type select() override { + if (this->force_value.has_value()) { + return *this->force_value; + } else if (first_value.has_value()) { + return *std::exchange(first_value, std::nullopt); + } else { + return selections_array[rng(num_selections - 1)]; + } + } + + protected: + ceph::util::random_number_generator& rng; + + std::optional first_value; +}; +} // namespace io_sequence +} // namespace tester +} // namespace ceph \ No newline at end of file diff --git a/src/test/osd/ceph_test_rados_io_sequence/ceph_test_rados_io_sequence.cc b/src/test/osd/ceph_test_rados_io_sequence/ceph_test_rados_io_sequence.cc index 3212e399cca8b..7f7a10f649e46 100644 --- a/src/test/osd/ceph_test_rados_io_sequence/ceph_test_rados_io_sequence.cc +++ b/src/test/osd/ceph_test_rados_io_sequence/ceph_test_rados_io_sequence.cc @@ -219,7 +219,8 @@ int parse_io_seq_options(po::variables_map& vm, int argc, char** argv) { template int send_mon_command(S& s, librados::Rados& rados, const char* name, - ceph::buffer::list& inbl, ceph::buffer::list* outbl, Formatter* f) { + ceph::buffer::list& inbl, ceph::buffer::list* outbl, + Formatter* f) { std::ostringstream oss; encode_json(name, s, f); f->flush(oss); @@ -229,52 +230,10 @@ int send_mon_command(S& s, librados::Rados& rados, const char* name, } // namespace -template & Ts> -ceph::io_sequence::tester::ProgramOptionSelector:: - ProgramOptionSelector(ceph::util::random_number_generator& rng, - po::variables_map vm, const std::string& option_name, - bool set_forced, bool select_first) - : rng(rng), option_name(option_name) { - if (set_forced && vm.count(option_name)) { - force_value = vm[option_name].as(); - } - if (select_first) { - ceph_assert(choices.size() > 0); - first_value = choices[0]; - } -} - -template & Ts> -bool ceph::io_sequence::tester::ProgramOptionSelector::isForced() { - return force_value.has_value(); -} - -template & Ts> -const T ceph::io_sequence::tester::ProgramOptionSelector::choose() { - if (force_value.has_value()) { - return *force_value; - } else if (first_value.has_value()) { - return *std::exchange(first_value, std::nullopt); - } else { - return choices[rng(N - 1)]; - } -} - -ceph::io_sequence::tester::SelectObjectSize::SelectObjectSize( - ceph::util::random_number_generator& rng, po::variables_map vm) - : ProgramOptionSelector(rng, vm, "objectsize", true, true) {} - -ceph::io_sequence::tester::SelectBlockSize::SelectBlockSize( - ceph::util::random_number_generator& rng, po::variables_map vm) - : ProgramOptionSelector(rng, vm, "blocksize", true, true) {} - -ceph::io_sequence::tester::SelectNumThreads::SelectNumThreads( - ceph::util::random_number_generator& rng, po::variables_map vm) - : ProgramOptionSelector(rng, vm, "threads", true, true) {} - -ceph::io_sequence::tester::SelectSeqRange::SelectSeqRange( - ceph::util::random_number_generator& rng, po::variables_map vm) - : ProgramOptionSelector(rng, vm, "sequence", false, false) { +ceph::io_sequence::tester::SelectSeqRange::SelectSeqRange(po::variables_map& vm) + : ProgramOptionReader>(vm, + "sequence") { if (vm.count(option_name)) { ceph::io_exerciser::Sequence s = static_cast(vm["sequence"].as()); @@ -291,7 +250,7 @@ ceph::io_sequence::tester::SelectSeqRange::SelectSeqRange( } const std::pair -ceph::io_sequence::tester::SelectSeqRange::choose() { +ceph::io_sequence::tester::SelectSeqRange::select() { if (force_value.has_value()) { return *force_value; } else { @@ -300,24 +259,12 @@ ceph::io_sequence::tester::SelectSeqRange::choose() { } } -ceph::io_sequence::tester::SelectErasureKM::SelectErasureKM( - ceph::util::random_number_generator& rng, po::variables_map vm) - : ProgramOptionSelector(rng, vm, "km", true, true) {} - -ceph::io_sequence::tester::SelectErasurePlugin::SelectErasurePlugin( - ceph::util::random_number_generator& rng, po::variables_map vm) - : ProgramOptionSelector(rng, vm, "plugin", true, false) {} - -ceph::io_sequence::tester::SelectErasureChunkSize::SelectErasureChunkSize( - ceph::util::random_number_generator& rng, po::variables_map vm) - : ProgramOptionSelector(rng, vm, "chunksize", true, true) {} - -ceph::io_sequence::tester::SelectECPool::SelectECPool( +ceph::io_sequence::tester::SelectErasurePool::SelectErasurePool( ceph::util::random_number_generator& rng, po::variables_map vm, librados::Rados& rados, bool dry_run, bool allow_pool_autoscaling, bool allow_pool_balancer, bool allow_pool_deep_scrubbing, bool allow_pool_scrubbing, bool test_recovery) - : ProgramOptionSelector(rng, vm, "pool", false, false), + : ProgramOptionReader(vm, "pool"), rados(rados), dry_run(dry_run), allow_pool_autoscaling(allow_pool_autoscaling), @@ -325,9 +272,9 @@ ceph::io_sequence::tester::SelectECPool::SelectECPool( allow_pool_deep_scrubbing(allow_pool_deep_scrubbing), allow_pool_scrubbing(allow_pool_scrubbing), test_recovery(test_recovery), - skm(SelectErasureKM(rng, vm)), - spl(SelectErasurePlugin(rng, vm)), - scs(SelectErasureChunkSize(rng, vm)) { + skm{rng, vm, "km", true}, + spl{rng, vm, "plugin", true}, + scs{rng, vm, "chunksize", true} { if (!skm.isForced()) { if (vm.count("pool")) { force_value = vm["pool"].as(); @@ -335,7 +282,7 @@ ceph::io_sequence::tester::SelectECPool::SelectECPool( } } -const std::string ceph::io_sequence::tester::SelectECPool::choose() { +const std::string ceph::io_sequence::tester::SelectErasurePool::select() { std::pair value; if (!skm.isForced() && force_value.has_value()) { int rc; @@ -370,13 +317,13 @@ const std::string ceph::io_sequence::tester::SelectECPool::choose() { m = reply.m; return *force_value; } else { - value = skm.choose(); + value = skm.select(); } k = value.first; m = value.second; - const std::string plugin = std::string(spl.choose()); - const uint64_t chunk_size = scs.choose(); + const std::string plugin = std::string(spl.select()); + const uint64_t chunk_size = scs.select(); std::string pool_name = "ec_" + plugin + "_cs" + std::to_string(chunk_size) + "_k" + std::to_string(k) + "_m" + std::to_string(m); @@ -386,7 +333,7 @@ const std::string ceph::io_sequence::tester::SelectECPool::choose() { return pool_name; } -void ceph::io_sequence::tester::SelectECPool::create_pool( +void ceph::io_sequence::tester::SelectErasurePool::create_pool( librados::Rados& rados, const std::string& pool_name, const std::string& plugin, uint64_t chunk_size, int k, int m) { int rc; @@ -456,22 +403,20 @@ void ceph::io_sequence::tester::SelectECPool::create_pool( ceph::messaging::config::ConfigSetRequest configSetBluestoreDebugRequest{ "global", "bluestore_debug_inject_read_err", "true", std::nullopt}; rc = send_mon_command(configSetBluestoreDebugRequest, rados, - "ConfigSetRequest", inbl, &outbl, - formatter.get()); + "ConfigSetRequest", inbl, &outbl, formatter.get()); ceph_assert(rc == 0); ceph::messaging::config::ConfigSetRequest configSetMaxMarkdownRequest{ "global", "osd_max_markdown_count", "99999999", std::nullopt}; - rc = - send_mon_command(configSetMaxMarkdownRequest, rados, "ConfigSetRequest", - inbl, &outbl, formatter.get()); + rc = send_mon_command(configSetMaxMarkdownRequest, rados, + "ConfigSetRequest", inbl, &outbl, formatter.get()); ceph_assert(rc == 0); } } ceph::io_sequence::tester::TestObject::TestObject( const std::string oid, librados::Rados& rados, - boost::asio::io_context& asio, SelectBlockSize& sbs, SelectECPool& spo, + boost::asio::io_context& asio, SelectBlockSize& sbs, SelectErasurePool& spo, SelectObjectSize& sos, SelectNumThreads& snt, SelectSeqRange& ssr, ceph::util::random_number_generator& rng, ceph::mutex& lock, ceph::condition_variable& cond, bool dryrun, bool verbose, @@ -479,13 +424,13 @@ ceph::io_sequence::tester::TestObject::TestObject( : rng(rng), verbose(verbose), seqseed(seqseed), testrecovery(testrecovery) { if (dryrun) { exerciser_model = std::make_unique( - oid, sbs.choose(), rng()); + oid, sbs.select(), rng()); } else { - const std::string pool = spo.choose(); + const std::string pool = spo.select(); poolK = spo.getChosenK(); poolM = spo.getChosenM(); - int threads = snt.choose(); + int threads = snt.select(); bufferlist inbl, outbl; auto formatter = std::make_unique(false); @@ -510,14 +455,14 @@ ceph::io_sequence::tester::TestObject::TestObject( } exerciser_model = std::make_unique( - rados, asio, pool, oid, cached_shard_order, sbs.choose(), rng(), + rados, asio, pool, oid, cached_shard_order, sbs.select(), rng(), threads, lock, cond); dout(0) << "= " << oid << " pool=" << pool << " threads=" << threads << " blocksize=" << exerciser_model->get_block_size() << " =" << dendl; } - obj_size_range = sos.choose(); - seq_range = ssr.choose(); + obj_size_range = sos.select(); + seq_range = ssr.select(); curseq = seq_range.first; if (testrecovery) { @@ -588,8 +533,8 @@ ceph::io_sequence::tester::TestRunner::TestRunner(po::variables_map& vm, : rados(rados), seed(vm.contains("seed") ? vm["seed"].as() : time(nullptr)), rng(ceph::util::random_number_generator(seed)), - sbs{rng, vm}, - sos{rng, vm}, + sbs{rng, vm, "blocksize", true}, + sos{rng, vm, "objectsize", true}, spo{rng, vm, rados, @@ -599,8 +544,8 @@ ceph::io_sequence::tester::TestRunner::TestRunner(po::variables_map& vm, vm.contains("allow_pool_deep_scrubbing"), vm.contains("allow_pool_scrubbing"), vm.contains("test_recovery")}, - snt{rng, vm}, - ssr{rng, vm} { + snt{rng, vm, "threads", true}, + ssr{vm} { dout(0) << "Test using seed " << seed << dendl; verbose = vm.contains("verbose"); @@ -647,7 +592,7 @@ void ceph::io_sequence::tester::TestRunner::help() { void ceph::io_sequence::tester::TestRunner::list_sequence(bool testrecovery) { // List seqeunces - std::pair obj_size_range = sos.choose(); + std::pair obj_size_range = sos.select(); ceph::io_exerciser::Sequence s = ceph::io_exerciser::Sequence::SEQUENCE_BEGIN; std::unique_ptr seq; if (testrecovery) { @@ -742,9 +687,9 @@ bool ceph::io_sequence::tester::TestRunner::run_interactive_test() { if (dryrun) { model = std::make_unique( - object_name, sbs.choose(), rng()); + object_name, sbs.select(), rng()); } else { - const std::string pool = spo.choose(); + const std::string pool = spo.select(); bufferlist inbl, outbl; auto formatter = std::make_unique(false); @@ -762,7 +707,7 @@ bool ceph::io_sequence::tester::TestRunner::run_interactive_test() { reply.decode_json(&p); model = std::make_unique( - rados, asio, pool, object_name, reply.acting, sbs.choose(), rng(), + rados, asio, pool, object_name, reply.acting, sbs.select(), rng(), 1, // 1 thread lock, cond); } diff --git a/src/test/osd/ceph_test_rados_io_sequence/ceph_test_rados_io_sequence.h b/src/test/osd/ceph_test_rados_io_sequence/ceph_test_rados_io_sequence.h index 98ebb58985ec0..40826f0d85948 100644 --- a/src/test/osd/ceph_test_rados_io_sequence/ceph_test_rados_io_sequence.h +++ b/src/test/osd/ceph_test_rados_io_sequence/ceph_test_rados_io_sequence.h @@ -2,6 +2,7 @@ #include #include +#include "ProgramOptionReader.h" #include "common/io_exerciser/IoOp.h" #include "common/io_exerciser/IoSequence.h" #include "common/io_exerciser/Model.h" @@ -17,37 +18,44 @@ #include /* Overview - * - * class ProgramOptionSelector - * Base class for selector objects below with common code for - * selecting options * * class SelectObjectSize * Selects min and max object sizes for a test * + * class SelectBlockSize + * Selects a block size for a test + * + * class SelectNumThreads + * Selects number of threads for a test + * * class SelectErasureKM * Selects an EC k and m value for a test * + * class SelectErasureChunkSize + * Selects a chunk size/stripe unit for the test + * * class SelectErasurePlugin * Selects an plugin for a test * - * class SelectECPool + * class SelectErasurePool * Selects an EC pool (plugin,k and m) for a test. Also creates the * pool as well. * - * class SelectBlockSize - * Selects a block size for a test - * - * class SelectNumThreads - * Selects number of threads for a test - * * class SelectSeqRange * Selects a sequence or range of sequences for a test * + * class SelectErasurePool + * Selects a pool name for a test + * * class TestObject * Runs a test against an object, generating IOSequence * and applying them to an IoExerciser * + * class TestRunner + * Determines test type to run, creates and orchestrates automated and + * interactive tests as well as creating a test object for each automated test + * we want to run in parallel + * * main * Run sequences of I/O with data integrity checking to * one or more objects in parallel. Without arguments @@ -61,10 +69,12 @@ namespace po = boost::program_options; namespace ceph { -namespace io_sequence::tester { +namespace io_sequence { +namespace tester { // Choices for min and max object size -inline constexpr size_t objectSizeSize = 10; -inline constexpr std::array, objectSizeSize> +// Choices for min and max object size +inline static constexpr size_t objectSizeSize = 10; +inline static constexpr std::array, objectSizeSize> objectSizeChoices = {{{1, 32}, // Default - best for boundary checking {12, 14}, {28, 30}, @@ -76,18 +86,33 @@ inline constexpr std::array, objectSizeSize> {83, 83}, {97, 97}}}; +using SelectObjectSize = + ProgramOptionSelector, + io_sequence::tester ::objectSizeSize, + io_sequence::tester ::objectSizeChoices>; + // Choices for block size -inline constexpr int blockSizeSize = 5; -inline constexpr std::array blockSizeChoices = { +inline static constexpr int blockSizeSize = 5; +inline static constexpr std::array blockSizeChoices = { {2048, // Default - test boundaries for EC 4K chunk size 512, 3767, 4096, 32768}}; +using SelectBlockSize = + ProgramOptionSelector; + // Choices for number of threads -inline constexpr int threadArraySize = 4; -inline constexpr std::array threadCountChoices = { +inline static constexpr int threadArraySize = 4; +inline static constexpr std::array threadCountChoices = { {1, // Default 2, 4, 8}}; +using SelectNumThreads = + ProgramOptionSelector; + // Choices for EC k+m profile inline constexpr int kmSize = 6; inline constexpr std::array, kmSize> kmChoices = { @@ -98,115 +123,52 @@ inline constexpr std::array, kmSize> kmChoices = { {4, 2}, {5, 1}}}; +using SelectErasureKM = + ProgramOptionSelector, + io_sequence::tester ::kmSize, + io_sequence::tester::kmChoices>; + // Choices for EC chunk size -inline constexpr int chunkSizeSize = 3; -inline constexpr std::array chunkSizeChoices = { +inline static constexpr int chunkSizeSize = 3; +inline static constexpr std::array chunkSizeChoices = { {4 * 1024, 64 * 1024, 256 * 1024}}; -// Choices for plugin -inline constexpr int pluginListSize = 2; -inline constexpr std::array pluginChoices = { - {"jerasure", "isa"}}; - -inline constexpr std::array< - std::pair, 0> - sequencePairs = {{}}; - -inline constexpr std::array poolChoices = {{}}; - -template & Ts> -class ProgramOptionSelector { - public: - ProgramOptionSelector(ceph::util::random_number_generator& rng, - po::variables_map vm, const std::string& option_name, - bool set_forced, bool select_first); - virtual ~ProgramOptionSelector() = default; - bool isForced(); - virtual const T choose(); - - protected: - ceph::util::random_number_generator& rng; - static constexpr std::array choices = Ts; - - std::optional force_value; - std::optional first_value; - - std::string option_name; -}; +using SelectErasureChunkSize = + ProgramOptionSelector; -class SelectObjectSize - : public ProgramOptionSelector, - io_sequence::tester::objectSizeSize, - io_sequence::tester::objectSizeChoices> { - public: - SelectObjectSize(ceph::util::random_number_generator& rng, - po::variables_map vm); -}; +// Choices for plugin +inline static constexpr int pluginListSize = 2; +inline static constexpr std::array + pluginChoices = {{"jerasure", "isa"}}; -class SelectBlockSize - : public ProgramOptionSelector { - public: - SelectBlockSize(ceph::util::random_number_generator& rng, - po::variables_map vm); -}; - -class SelectNumThreads - : public ProgramOptionSelector { - public: - SelectNumThreads(ceph::util::random_number_generator& rng, - po::variables_map vm); -}; +using SelectErasurePlugin = + ProgramOptionSelector; class SelectSeqRange - : public ProgramOptionSelector< - std::pair, - 0, io_sequence::tester::sequencePairs> { + : public ProgramOptionReader> { public: - SelectSeqRange(ceph::util::random_number_generator& rng, - po::variables_map vm); - + SelectSeqRange(po::variables_map& vm); const std::pair - choose() override; -}; - -class SelectErasureKM - : public ProgramOptionSelector, - io_sequence::tester::kmSize, - io_sequence::tester::kmChoices> { - public: - SelectErasureKM(ceph::util::random_number_generator& rng, - po::variables_map vm); -}; - -class SelectErasurePlugin - : public ProgramOptionSelector { - public: - SelectErasurePlugin(ceph::util::random_number_generator& rng, - po::variables_map vm); -}; - -class SelectErasureChunkSize - : public ProgramOptionSelector { - public: - SelectErasureChunkSize(ceph::util::random_number_generator& rng, - po::variables_map vm); + select() override; }; -class SelectECPool - : public ProgramOptionSelector { +class SelectErasurePool : public ProgramOptionReader { public: - SelectECPool(ceph::util::random_number_generator& rng, - po::variables_map vm, librados::Rados& rados, bool dry_run, - bool allow_pool_autoscaling, bool allow_pool_balancer, - bool allow_pool_deep_scrubbing, bool allow_pool_scrubbing, - bool test_recovery); - const std::string choose() override; + SelectErasurePool(ceph::util::random_number_generator& rng, + po::variables_map vm, + librados::Rados& rados, + bool dry_run, + bool allow_pool_autoscaling, + bool allow_pool_balancer, + bool allow_pool_deep_scrubbing, + bool allow_pool_scrubbing, + bool test_recovery); + const std::string select() override; bool get_allow_pool_autoscaling() { return allow_pool_autoscaling; } bool get_allow_pool_balancer() { return allow_pool_balancer; } @@ -216,9 +178,11 @@ class SelectECPool int getChosenM() const { return m; } private: - void create_pool(librados::Rados& rados, const std::string& pool_name, - const std::string& plugin, uint64_t chunk_size, int k, - int m); + void create_pool( librados::Rados& rados, + const std::string& pool_name, + const std::string& plugin, + uint64_t chunk_size, int k, + int m); protected: librados::Rados& rados; @@ -238,16 +202,21 @@ class SelectECPool class TestObject { public: - TestObject(const std::string oid, librados::Rados& rados, + TestObject(const std::string oid, + librados::Rados& rados, boost::asio::io_context& asio, ceph::io_sequence::tester::SelectBlockSize& sbs, - ceph::io_sequence::tester::SelectECPool& spl, + ceph::io_sequence::tester::SelectErasurePool& spl, ceph::io_sequence::tester::SelectObjectSize& sos, ceph::io_sequence::tester::SelectNumThreads& snt, ceph::io_sequence::tester::SelectSeqRange& ssr, - ceph::util::random_number_generator& rng, ceph::mutex& lock, - ceph::condition_variable& cond, bool dryrun, bool verbose, - std::optional seqseed, bool testRecovery); + ceph::util::random_number_generator& rng, + ceph::mutex& lock, + ceph::condition_variable& cond, + bool dryrun, + bool verbose, + std::optional seqseed, + bool testRecovery); int get_num_io(); bool readyForIo(); @@ -285,7 +254,7 @@ class TestRunner { ceph::io_sequence::tester::SelectBlockSize sbs; ceph::io_sequence::tester::SelectObjectSize sos; - ceph::io_sequence::tester::SelectECPool spo; + ceph::io_sequence::tester::SelectErasurePool spo; ceph::io_sequence::tester::SelectNumThreads snt; ceph::io_sequence::tester::SelectSeqRange ssr; @@ -334,5 +303,6 @@ class TestRunner { void help(); void list_sequence(bool testrecovery); }; -} // namespace io_sequence::tester +} // namespace tester +} // namespace io_sequence } // namespace ceph