From f36eb318b95218ca0a9f212d682f85d50e4bde06 Mon Sep 17 00:00:00 2001 From: Rene Cannao Date: Sun, 22 Feb 2026 13:12:43 +0000 Subject: [PATCH] test: implement and document internal_noise_mysql_traffic_v2 Added a high-concurrency MySQL load generator with: - Automatic table creation and 10k row population. - Multi-threaded workers with randomized CRUD operations. - Configurable delays and periodic reconnections. - Synchronized summary reporting at exit. Also updated NOISE_TESTING.md to document the v2 traffic routines and the REST Prometheus poller. --- test/tap/NOISE_TESTING.md | 3 + test/tap/tap/noise_utils.cpp | 144 +++++++++++++++++++++++++++++++++++ test/tap/tap/noise_utils.h | 5 ++ 3 files changed, 152 insertions(+) diff --git a/test/tap/NOISE_TESTING.md b/test/tap/NOISE_TESTING.md index acf6882ef..d1fef3000 100644 --- a/test/tap/NOISE_TESTING.md +++ b/test/tap/NOISE_TESTING.md @@ -43,6 +43,9 @@ Internal routines run as threads within the TAP test process. This is **highly r - `internal_noise_random_stats_poller`: Shuffles and queries a set of MySQL and PostgreSQL stats tables (default 500ms). - `internal_noise_mysql_traffic`: Generates unprivileged query load on the main MySQL port (default 100ms). - `internal_noise_pgsql_traffic`: Generates unprivileged query load on the main PostgreSQL port (default 100ms). +- `internal_noise_pgsql_traffic_v2`: High-concurrency PostgreSQL load generator with automatic table setup, row population (10k rows), and multi-threaded workers (default 20 connections, 200ms delay). +- `internal_noise_mysql_traffic_v2`: High-concurrency MySQL load generator with automatic table setup, row population (10k rows), and multi-threaded workers (default 20 connections, 200ms delay). +- `internal_noise_rest_prometheus_poller`: Periodically scrapes metrics via the REST API (default 1000ms). Supports `enable_rest_api` auto-configuration. ## Usage in C++ TAP Tests diff --git a/test/tap/tap/noise_utils.cpp b/test/tap/tap/noise_utils.cpp index 8ef1c06d6..425a9cb0b 100644 --- a/test/tap/tap/noise_utils.cpp +++ b/test/tap/tap/noise_utils.cpp @@ -283,6 +283,150 @@ void internal_noise_prometheus_poller(const CommandLine& cl, const NoiseOptions& noise_log("[NOISE] Prometheus Poller report: total_scrapes=" + std::to_string(total_scrapes) + "\n"); } +void internal_noise_mysql_traffic_v2(const CommandLine& cl, const NoiseOptions& opt, std::atomic& stop) { + std::string tablename = get_opt_str(opt, "tablename", "mysql_noise_test"); + int num_connections = get_opt_int(opt, "num_connections", 20); + int reconnect_interval = get_opt_int(opt, "reconnect_interval", 200); + if (reconnect_interval <= 0) reconnect_interval = 1; + int max_retries = get_opt_int(opt, "max_retries", 5); + int avg_delay_ms = get_opt_int(opt, "avg_delay_ms", 200); + + // --- Phase A: Ensure table exists --- + MYSQL* setup_conn = mysql_init(NULL); + if (!mysql_real_connect(setup_conn, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) { + noise_log("[NOISE] MySQL Traffic v2: Setup connection failure: " + std::string(mysql_error(setup_conn)) + "\n"); + mysql_close(setup_conn); + register_noise_failure("MySQL Traffic v2 (Setup)"); + return; + } + + std::string create_sql = "CREATE TABLE IF NOT EXISTS " + tablename + " (id INT AUTO_INCREMENT PRIMARY KEY, val TEXT, counter INT)"; + if (mysql_query(setup_conn, create_sql.c_str())) { + noise_log("[NOISE] MySQL Traffic v2: Table creation failed: " + std::string(mysql_error(setup_conn)) + "\n"); + mysql_close(setup_conn); + register_noise_failure("MySQL Traffic v2 (Create)"); + return; + } + noise_log("[NOISE] MySQL Traffic v2: Table " + tablename + " verified\n"); + + // --- Phase B: Ensure 10,000 rows --- + while (!stop) { + std::string count_sql = "SELECT COUNT(*) FROM " + tablename; + if (mysql_query(setup_conn, count_sql.c_str()) == 0) { + MYSQL_RES* res = mysql_store_result(setup_conn); + MYSQL_ROW row = mysql_fetch_row(res); + long current_rows = row ? std::stol(row[0]) : 0; + mysql_free_result(res); + + if (current_rows < 10000) { + noise_log("[NOISE] MySQL Traffic v2: " + std::to_string(current_rows) + " rows found, adding 5000...\n"); + // MySQL doesn't have generate_series like PgSQL, so we use a loop or multiple inserts. + // For simplicity in noise, we just do one bulk insert of 5000 rows if possible, or multiple small ones. + // A better way is to use a recursive CTE or just a simple loop of 5000 inserts (slow) or one big INSERT with 5000 values. + std::string insert_sql = "INSERT INTO " + tablename + " (val, counter) VALUES "; + for (int i = 0; i < 5000; ++i) { + insert_sql += "('noise_data', " + std::to_string(i) + ")"; + if (i < 4999) insert_sql += ","; + } + if (mysql_query(setup_conn, insert_sql.c_str())) { + noise_log("[NOISE] MySQL Traffic v2: Row insertion failed: " + std::string(mysql_error(setup_conn)) + "\n"); + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } else { + break; + } + } else { + noise_log("[NOISE] MySQL Traffic v2: Row count failed: " + std::string(mysql_error(setup_conn)) + "\n"); + break; + } + } + mysql_close(setup_conn); + + if (stop) return; + + // --- Phase C, D, E: Multi-threaded load --- + std::atomic total_queries{0}; + std::atomic total_connections_opened{0}; + std::atomic total_connections_closed{0}; + std::vector workers; + + for (int i = 0; i < num_connections; ++i) { + workers.emplace_back([&, tablename, reconnect_interval, avg_delay_ms]() { + MYSQL* conn = nullptr; + uint64_t worker_queries = 0; + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> op_dist(0, 3); + std::uniform_int_distribution<> id_dist(1, 10000); + + int min_delay = avg_delay_ms / 2; + int max_delay = avg_delay_ms + (avg_delay_ms / 2); + if (min_delay < 1) min_delay = 1; + std::uniform_int_distribution<> delay_dist(min_delay, max_delay); + + std::uniform_int_distribution<> start_dist(0, 500); + std::this_thread::sleep_for(std::chrono::milliseconds(start_dist(gen))); + + auto connect = [&]() { + if (conn) { + mysql_close(conn); + total_connections_closed++; + } + conn = mysql_init(NULL); + if (mysql_real_connect(conn, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) { + total_connections_opened++; + return true; + } + return false; + }; + + if (!connect()) { + noise_log("[NOISE] MySQL Traffic v2: Worker failed initial connection\n"); + return; + } + + while (!stop) { + int op = op_dist(gen); + std::string sql; + int target_id = id_dist(gen); + + switch (op) { + case 0: sql = "SELECT * FROM " + tablename + " WHERE id = " + std::to_string(target_id); break; + case 1: sql = "INSERT INTO " + tablename + " (val, counter) VALUES ('extra_noise', " + std::to_string(target_id) + ")"; break; + case 2: sql = "UPDATE " + tablename + " SET counter = counter + 1 WHERE id = " + std::to_string(target_id); break; + case 3: sql = "DELETE FROM " + tablename + " WHERE id = " + std::to_string(target_id); break; + } + + if (mysql_query(conn, sql.c_str()) == 0) { + MYSQL_RES* r = mysql_store_result(conn); + if (r) mysql_free_result(r); + } + + worker_queries++; + total_queries++; + + if (worker_queries % reconnect_interval == 0) { + if (!connect()) break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(delay_dist(gen))); + } + if (conn) { + mysql_close(conn); + total_connections_closed++; + } + }); + } + + for (auto& w : workers) { + if (w.joinable()) w.join(); + } + + noise_log("[NOISE] MySQL Traffic v2 report: total_queries=" + std::to_string(total_queries) + + ", total_connections_opened=" + std::to_string(total_connections_opened) + + ", total_connections_closed=" + std::to_string(total_connections_closed) + "\n"); +} + void internal_noise_rest_prometheus_poller(const CommandLine& cl, const NoiseOptions& opt, std::atomic& stop) { int interval_ms = get_opt_int(opt, "interval_ms", 1000); int max_retries = get_opt_int(opt, "max_retries", 5); diff --git a/test/tap/tap/noise_utils.h b/test/tap/tap/noise_utils.h index 8f10a46e4..31fac2de7 100644 --- a/test/tap/tap/noise_utils.h +++ b/test/tap/tap/noise_utils.h @@ -100,6 +100,11 @@ void internal_noise_pgsql_traffic(const CommandLine& cl, const NoiseOptions& opt */ void internal_noise_pgsql_traffic_v2(const CommandLine& cl, const NoiseOptions& opt, std::atomic& stop); +/** + * @brief Version 2 of MySQL Traffic: complex multi-threaded load with table setup and reconnections. + */ +void internal_noise_mysql_traffic_v2(const CommandLine& cl, const NoiseOptions& opt, std::atomic& stop); + /** * @brief Periodically fetches Prometheus metrics via the REST API. */