diff options
Diffstat (limited to 'src/third_party/wiredtiger/test/cppsuite/test_harness/core')
8 files changed, 824 insertions, 0 deletions
diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/component.cpp b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/component.cpp new file mode 100644 index 00000000000..aeb691fe674 --- /dev/null +++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/component.cpp @@ -0,0 +1,85 @@ +/*- + * Public Domain 2014-present MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "component.h" +#include "test_harness/util/api_const.h" + +namespace test_harness { +component::component(const std::string &name, configuration *config) : _config(config), _name(name) +{ +} + +component::~component() +{ + delete _config; +} + +void +component::load() +{ + logger::log_msg(LOG_INFO, "Loading component: " + _name); + _enabled = _config->get_optional_bool(ENABLED, true); + _throttle = throttle(_config); + /* If we're not enabled we shouldn't be running. */ + _running = _enabled; +} + +void +component::run() +{ + logger::log_msg(LOG_INFO, "Running component: " + _name); + while (_enabled && _running) { + do_work(); + _throttle.sleep(); + } +} + +void +component::do_work() +{ + /* Not implemented. */ +} + +bool +component::enabled() const +{ + return (_enabled); +} + +void +component::end_run() +{ + _running = false; +} + +void +component::finish() +{ + logger::log_msg(LOG_INFO, "Running finish stage of component: " + _name); +} +} // namespace test_harness diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/component.h b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/component.h new file mode 100644 index 00000000000..5a8f8f81cf5 --- /dev/null +++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/component.h @@ -0,0 +1,95 @@ +/*- + * Public Domain 2014-present MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef COMPONENT_H +#define COMPONENT_H + +#include "configuration.h" +#include "throttle.h" + +namespace test_harness { +/* + * A component is a class that defines 4 unique stages in its life-cycle, the stages must be run in + * the following order: load, run, end_run, finish. + * + * + */ +class component { + public: + explicit component(const std::string &name, configuration *config); + virtual ~component(); + + /* Delete the copy constructor and the assignment operator. */ + component(const component &) = delete; + component &operator=(const component &) = delete; + + /* + * The load function should perform all tasks required to setup the component for the main phase + * of the test. An example operation performed in the load phase would be populating a database. + */ + virtual void load(); + + /* + * The run function provides a top level loop that calls the do_work function every X seconds as + * defined by the throttle. Each run() method defined by the components is called in its own + * thread by the top level test class. + * + * If a component does not wish to use the standard run function, it can be overloaded. + */ + virtual void run(); + + /* end_run informs the component that is no longer running which closes out its run loop. */ + void end_run(); + + /* + * do_work is called every X seconds as defined by the throttle. Generally most components + * should do their "operation" in the do_work function. + */ + virtual void do_work(); + + /* Gets the value of the _enabled variable. */ + bool enabled() const; + + /* + * The finish phase is a cleanup phase. Created objects are destroyed here and any final testing + * requirements can be performed in this phase. An example could be the verification of the + * database, or checking some relevant statistics. + */ + virtual void finish(); + + protected: + bool _enabled = false; + volatile bool _running = false; + throttle _throttle; + configuration *_config; + + private: + std::string _name; +}; +} // namespace test_harness +#endif diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/configuration.cpp b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/configuration.cpp new file mode 100644 index 00000000000..f508dc76bea --- /dev/null +++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/configuration.cpp @@ -0,0 +1,305 @@ +/*- + * Public Domain 2014-present MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <algorithm> +#include <stack> + +#include "configuration.h" + +namespace test_harness { +/* Static methods implementation. */ +static bool +config_item_to_bool(const WT_CONFIG_ITEM item) +{ + return (item.val != 0); +} + +static int64_t +config_item_to_int(const WT_CONFIG_ITEM item) +{ + return (item.val); +} + +static std::string +config_item_to_string(const WT_CONFIG_ITEM item) +{ + return std::string(item.str, item.len); +} + +static std::vector<std::string> +config_item_to_list(const WT_CONFIG_ITEM item) +{ + auto str = config_item_to_string(item); + + /* Get rid of the brackets. */ + testutil_assert(!str.empty() && str.front() == '[' && str.back() == ']'); + str.pop_back(); + str.erase(0, 1); + + return (split_string(str, ',')); +} + +/* configuration class implementation. */ +configuration::configuration(const std::string &test_config_name, const std::string &config) +{ + const auto *config_entry = __wt_test_config_match(test_config_name.c_str()); + if (config_entry == nullptr) + testutil_die(EINVAL, "failed to match test config name"); + std::string default_config = std::string(config_entry->base); + /* Merge in the default configuration. */ + _config = merge_default_config(default_config, config); + logger::log_msg(LOG_INFO, "Full config: " + _config); + + int ret = + wiredtiger_test_config_validate(nullptr, nullptr, test_config_name.c_str(), _config.c_str()); + if (ret != 0) + testutil_die(EINVAL, "failed to validate given config, ensure test config exists"); + ret = wiredtiger_config_parser_open(nullptr, _config.c_str(), _config.size(), &_config_parser); + if (ret != 0) + testutil_die(EINVAL, "failed to create configuration parser for provided config"); +} + +configuration::configuration(const WT_CONFIG_ITEM &nested) +{ + if (nested.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_STRUCT) + testutil_die(EINVAL, "provided config item isn't a structure"); + int ret = wiredtiger_config_parser_open(nullptr, nested.str, nested.len, &_config_parser); + if (ret != 0) + testutil_die(EINVAL, "failed to create configuration parser for provided sub config"); +} + +configuration::~configuration() +{ + if (_config_parser != nullptr) { + _config_parser->close(_config_parser); + _config_parser = nullptr; + } +} + +std::string +configuration::get_string(const std::string &key) +{ + return get<std::string>(key, false, types::STRING, "", config_item_to_string); +} + +std::string +configuration::get_optional_string(const std::string &key, const std::string &def) +{ + return get<std::string>(key, true, types::STRING, def, config_item_to_string); +} + +bool +configuration::get_bool(const std::string &key) +{ + return get<bool>(key, false, types::BOOL, false, config_item_to_bool); +} + +bool +configuration::get_optional_bool(const std::string &key, const bool def) +{ + return get<bool>(key, true, types::BOOL, def, config_item_to_bool); +} + +int64_t +configuration::get_int(const std::string &key) +{ + return get<int64_t>(key, false, types::INT, 0, config_item_to_int); +} + +int64_t +configuration::get_optional_int(const std::string &key, const int64_t def) +{ + return get<int64_t>(key, true, types::INT, def, config_item_to_int); +} + +configuration * +configuration::get_subconfig(const std::string &key) +{ + return get<configuration *>(key, false, types::STRUCT, nullptr, + [](WT_CONFIG_ITEM item) { return new configuration(item); }); +} + +configuration * +configuration::get_optional_subconfig(const std::string &key) +{ + return get<configuration *>(key, true, types::STRUCT, nullptr, + [](WT_CONFIG_ITEM item) { return new configuration(item); }); +} + +std::vector<std::string> +configuration::get_list(const std::string &key) +{ + return get<std::vector<std::string>>(key, false, types::LIST, {}, config_item_to_list); +} + +template <typename T> +T +configuration::get( + const std::string &key, bool optional, types type, T def, T (*func)(WT_CONFIG_ITEM item)) +{ + WT_DECL_RET; + WT_CONFIG_ITEM value = {"", 0, 1, WT_CONFIG_ITEM::WT_CONFIG_ITEM_BOOL}; + + ret = _config_parser->get(_config_parser, key.c_str(), &value); + if (ret == WT_NOTFOUND && optional) + return (def); + else if (ret != 0) + testutil_die(ret, ("Error while finding config with key \"" + key + "\"").c_str()); + + const char *error_msg = "Configuration value doesn't match requested type"; + if (type == types::STRING && + (value.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_STRING && + value.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_ID)) + testutil_die(-1, error_msg); + else if (type == types::BOOL && value.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_BOOL) + testutil_die(-1, error_msg); + else if (type == types::INT && value.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_NUM) + testutil_die(-1, error_msg); + else if (type == types::STRUCT && value.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_STRUCT) + testutil_die(-1, error_msg); + else if (type == types::LIST && value.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_STRUCT) + testutil_die(-1, error_msg); + + return func(value); +} + +std::string +configuration::merge_default_config( + const std::string &default_config, const std::string &user_config) +{ + std::string merged_config; + auto split_default_config = split_config(default_config); + auto split_user_config = split_config(user_config); + auto user_it = split_user_config.begin(); + for (auto default_it = split_default_config.begin(); default_it != split_default_config.end(); + ++default_it) { + if (user_it == split_user_config.end() || user_it->first != default_it->first) + /* The default does not exist in the user configuration, add it. */ + merged_config += default_it->first + "=" + default_it->second; + else { + /* If we have a sub config merge it in. */ + if (user_it->second[0] == '(') + merged_config += default_it->first + "=(" + + merge_default_config(default_it->second, user_it->second) + ')'; + else + /* Add the user configuration as it exists. */ + merged_config += user_it->first + "=" + user_it->second; + ++user_it; + } + /* Add a comma after every item we add except the last one. */ + if (split_default_config.end() - default_it != 1) + merged_config += ","; + } + /* Add any remaining user config items. */ + while (user_it != split_user_config.end()) { + merged_config += "," + user_it->first + "=" + user_it->second; + ++user_it; + } + return (merged_config); +} + +std::vector<std::pair<std::string, std::string>> +configuration::split_config(const std::string &config) +{ + std::string cut_config = config; + std::vector<std::pair<std::string, std::string>> split_config; + std::string key = "", value = ""; + bool in_subconfig = false; + bool expect_value = false; + std::stack<char> parens; + + /* All configuration strings must be at least 2 characters. */ + testutil_assert(config.size() > 1); + + /* Remove prefix and trailing "()". */ + if (config[0] == '(') + cut_config = config.substr(1, config.size() - 2); + + size_t start = 0, len = 0; + for (size_t i = 0; i < cut_config.size(); ++i) { + if (cut_config[i] == '(' || cut_config[i] == '[') { + parens.push(cut_config[i]); + in_subconfig = true; + } + if (cut_config[i] == ')' || cut_config[i] == ']') { + parens.pop(); + in_subconfig = !parens.empty(); + } + if (cut_config[i] == '=' && !in_subconfig) { + if (len == 0) { + testutil_die(EINVAL, "error parsing config: detected empty key"); + } + if (expect_value) { + testutil_die(EINVAL, + "error parsing config: syntax error parsing value for key ['%s']: '%s'", + key.c_str(), cut_config.substr(start, len).c_str()); + } + expect_value = true; + key = cut_config.substr(start, len); + start += len + 1; + len = 0; + continue; + } + if (cut_config[i] == ',' && !in_subconfig) { + if (len == 0) { + testutil_die( + EINVAL, "error parsing config: detected empty value for key:'%s'", key.c_str()); + } + if (!expect_value) { + testutil_die(EINVAL, + "error parsing config: syntax error parsing key value pair: '%s'", + cut_config.substr(start, len).c_str()); + } + expect_value = false; + if (start + len >= cut_config.size()) + break; + value = cut_config.substr(start, len); + start += len + 1; + len = 0; + split_config.push_back(std::make_pair(key, value)); + continue; + } + ++len; + } + if (expect_value) { + value = cut_config.substr(start, len); + split_config.push_back(std::make_pair(key, value)); + } + + /* We have to sort the config here otherwise we will match incorrectly while merging. */ + std::sort(split_config.begin(), split_config.end(), comparator); + return (split_config); +} + +bool +configuration::comparator( + std::pair<std::string, std::string> a, std::pair<std::string, std::string> b) +{ + return (a.first < b.first); +} +} // namespace test_harness diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/configuration.h b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/configuration.h new file mode 100644 index 00000000000..b61defc9d3f --- /dev/null +++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/configuration.h @@ -0,0 +1,114 @@ +/*- + * Public Domain 2014-present MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +#include <string> +#include <vector> + +#include "test_harness/util/logger.h" + +extern "C" { +#include "test_util.h" +} + +namespace test_harness { +inline std::vector<std::string> +split_string(const std::string &str, const char delim) +{ + std::vector<std::string> splits; + std::string current_str; + for (const auto c : str) { + if (c == delim) { + if (!current_str.empty()) { + splits.push_back(current_str); + current_str.clear(); + } + } else + current_str.push_back(c); + } + if (!current_str.empty()) + splits.push_back(std::move(current_str)); + return (splits); +} + +class configuration { + public: + explicit configuration(const std::string &test_config_name, const std::string &config); + explicit configuration(const WT_CONFIG_ITEM &nested); + + ~configuration(); + + /* + * Wrapper functions for retrieving basic configuration values. Ideally tests can avoid using + * the config item struct provided by wiredtiger. + * + * When getting a configuration value that may not exist for that configuration string or + * component, the optional forms of the functions can be used. In this case a default value must + * be passed and it will be set to that value. + */ + std::string get_string(const std::string &key); + std::string get_optional_string(const std::string &key, const std::string &def); + bool get_bool(const std::string &key); + bool get_optional_bool(const std::string &key, const bool def); + int64_t get_int(const std::string &key); + int64_t get_optional_int(const std::string &key, const int64_t def); + configuration *get_subconfig(const std::string &key); + configuration *get_optional_subconfig(const std::string &key); + std::vector<std::string> get_list(const std::string &key); + std::vector<std::string> get_optional_list(const std::string &key); + + private: + enum class types { BOOL, INT, LIST, STRING, STRUCT }; + + template <typename T> + T get(const std::string &key, bool optional, types type, T def, T (*func)(WT_CONFIG_ITEM item)); + + /* + * Merge together two configuration strings, the user one and the default one. + */ + static std::string merge_default_config( + const std::string &default_config, const std::string &user_config); + + /* + * Split a config string into keys and values, taking care to not split incorrectly when we have + * a sub config or array. + */ + static std::vector<std::pair<std::string, std::string>> split_config(const std::string &config); + + static bool comparator( + std::pair<std::string, std::string> a, std::pair<std::string, std::string> b); + + private: + std::string _config; + WT_CONFIG_PARSER *_config_parser = nullptr; +}; +} // namespace test_harness + +#endif diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/op_tracker.cpp b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/op_tracker.cpp new file mode 100644 index 00000000000..af806927768 --- /dev/null +++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/op_tracker.cpp @@ -0,0 +1,37 @@ +#include "test_harness/test.h" +#include "test_harness/util/perf_plotter.h" +#include "op_tracker.h" + +namespace test_harness { +op_tracker::op_tracker(const std::string id, const std::string &test_name) + : _id(id), _test_name(test_name), _it_count(0), _total_time_taken(0) +{ +} + +void +op_tracker::append_stats() +{ + uint64_t avg = (uint64_t)_total_time_taken / _it_count; + std::string stat = "{\"name\":\"" + _id + "\",\"value\":" + std::to_string(avg) + "}"; + perf_plotter::instance().add_stat(stat); +} + +template <typename T> +auto +op_tracker::track(T lambda) +{ + auto _start_time = std::chrono::steady_clock::now(); + int ret = lambda(); + auto _end_time = std::chrono::steady_clock::now(); + _total_time_taken += (_end_time - _start_time).count(); + _it_count += 1; + + return ret; +} + +op_tracker::~op_tracker() +{ + if (_it_count != 0) + append_stats(); +} +}; // namespace test_harness diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/op_tracker.h b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/op_tracker.h new file mode 100644 index 00000000000..eea99b2414c --- /dev/null +++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/op_tracker.h @@ -0,0 +1,58 @@ +/*- + * Public Domain 2014-present MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <chrono> +#include <fstream> +#include <string> + +namespace test_harness { + +/* + * Class that tracks the performance of given operations and appends the stats to the perf file. + */ +class op_tracker { + public: + explicit op_tracker(const std::string id, const std::string &test_name); + virtual ~op_tracker(); + + /* Calculates the average time and appends the stat to the perf file. */ + void append_stats(); + + /* + * Does timing for a given operation and keeps track of how many operations have been executed + * as well as total time taken. + */ + template <typename T> auto track(T lambda); + + private: + std::string _id; + std::string _test_name; + int _it_count; + uint64_t _total_time_taken; +}; +} // namespace test_harness diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/throttle.cpp b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/throttle.cpp new file mode 100644 index 00000000000..af7b94e8f98 --- /dev/null +++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/throttle.cpp @@ -0,0 +1,75 @@ +/*- + * Public Domain 2014-present MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <thread> + +#include "configuration.h" +#include "test_harness/util/api_const.h" +#include "throttle.h" + +namespace test_harness { +throttle::throttle(const std::string &throttle_rate) +{ + std::string magnitude; + uint64_t multiplier = 0; + /* + * Find the ms, s, or m in the string. Searching for "ms" first as the following two searches + * would match as well. + */ + size_t pos = throttle_rate.find("ms"); + if (pos != std::string::npos) + multiplier = 1; + else { + pos = throttle_rate.find("s"); + if (pos != std::string::npos) + multiplier = 1000; + else { + pos = throttle_rate.find("m"); + if (pos != std::string::npos) + multiplier = 60 * 1000; + else + testutil_die(-1, "no rate specifier given"); + } + } + magnitude = throttle_rate.substr(0, pos); + /* This will throw if it can't cast, which is fine. */ + _ms = std::stoi(magnitude) * multiplier; +} + +/* Use optional and default to 1s per op in case something doesn't define this. */ +throttle::throttle(configuration *config) : throttle(config->get_optional_string(OP_RATE, "1s")) {} + +/* Default to a second per operation. */ +throttle::throttle() : throttle("1s") {} + +void +throttle::sleep() +{ + std::this_thread::sleep_for(std::chrono::milliseconds(_ms)); +} +} // namespace test_harness diff --git a/src/third_party/wiredtiger/test/cppsuite/test_harness/core/throttle.h b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/throttle.h new file mode 100644 index 00000000000..24161ea956e --- /dev/null +++ b/src/third_party/wiredtiger/test/cppsuite/test_harness/core/throttle.h @@ -0,0 +1,55 @@ +/*- + * Public Domain 2014-present MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef THROTTLE_H +#define THROTTLE_H + +#include <string> + +/* Forward declarations for classes to reduce compilation time and modules coupling. */ +class configuration; + +namespace test_harness { +class throttle { + public: + explicit throttle(const std::string &throttle_rate); + + /* Use optional and default to 1s per op in case something doesn't define this. */ + explicit throttle(configuration *config); + + /* Default to a second per operation. */ + throttle(); + + void sleep(); + + private: + uint64_t _ms = 1000; +}; +} // namespace test_harness + +#endif |