-
Notifications
You must be signed in to change notification settings - Fork 977
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
204 additions
and
0 deletions.
There are no files selected for viewing
204 changes: 204 additions & 0 deletions
204
test/tap/tests/test_query_cache_soft_ttl_percentage-t.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
/** | ||
* @file test_query_cache_soft_ttl_percentage-t.cpp | ||
* @brief This test that query cache entries are refreshed when soft ttl is | ||
* reached. | ||
* @details This test configures a query rule with cache and configures the | ||
* global variable mysql-query_cache_soft_ttl_percentage. Then, caches a | ||
* "SELECT SLEEP(1) and creates 4 threads to send this same query when the soft | ||
* ttl have been reached. Finally, checks that only one of the threads has hit | ||
* the hostgroup looking at how long it has taken for each thread to execute | ||
* the query, and looking in the table "stats_mysql_query_digest" | ||
*/ | ||
|
||
#include <unistd.h> | ||
#include <iostream> | ||
#include <mysql.h> | ||
#include <vector> | ||
#include <string> | ||
#include <chrono> | ||
#include <thread> | ||
|
||
#include "proxysql_utils.h" | ||
#include "command_line.h" | ||
#include "utils.h" | ||
#include "tap.h" | ||
|
||
using std::vector; | ||
using std::string; | ||
|
||
double timer_result_one = 0; | ||
double timer_result_two = 0; | ||
double timer_result_three = 0; | ||
double timer_result_four = 0; | ||
|
||
const string DUMMY_QUERY = "SELECT SLEEP(1)"; | ||
|
||
class timer { | ||
public: | ||
std::chrono::time_point<std::chrono::high_resolution_clock> lastTime; | ||
timer() : lastTime(std::chrono::high_resolution_clock::now()) {} | ||
inline double elapsed() { | ||
std::chrono::time_point<std::chrono::high_resolution_clock> thisTime = std::chrono::high_resolution_clock::now(); | ||
double deltaTime = std::chrono::duration<double>(thisTime-lastTime).count(); | ||
lastTime = thisTime; | ||
return deltaTime; | ||
} | ||
}; | ||
|
||
void run_dummy_query( | ||
const char* host, const char* username, const char* password, const int port, double* timer_result | ||
) { | ||
MYSQL* proxy_mysql = mysql_init(NULL); | ||
|
||
if (!mysql_real_connect(proxy_mysql, host, username, password, NULL, port, NULL, 0)) { | ||
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxy_mysql)); | ||
*timer_result = -1.0; | ||
return; | ||
} | ||
|
||
int soft_ttl_seconds = 2; | ||
|
||
for (int i = 0; i < 2; i++) { | ||
sleep(1); | ||
|
||
timer stopwatch; | ||
int err = mysql_query(proxy_mysql, DUMMY_QUERY.c_str()); | ||
if (err) { | ||
diag("Failed to executed query `%s`", DUMMY_QUERY.c_str()); | ||
*timer_result = -1.0; | ||
mysql_close(proxy_mysql); | ||
return; | ||
} | ||
*timer_result += stopwatch.elapsed(); | ||
|
||
MYSQL_RES* res = NULL; | ||
res = mysql_store_result(proxy_mysql); | ||
mysql_free_result(res); | ||
} | ||
|
||
mysql_close(proxy_mysql); | ||
} | ||
|
||
int main(int argc, char** argv) { | ||
CommandLine cl; | ||
|
||
if (cl.getEnv()) { | ||
diag("Failed to get the required environmental variables."); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
MYSQL* proxy_admin = mysql_init(NULL); | ||
if (!mysql_real_connect(proxy_admin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) { | ||
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxy_admin)); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
vector<string> admin_queries = { | ||
"UPDATE mysql_query_rules SET cache_ttl = 4000 WHERE rule_id = 2", | ||
"LOAD MYSQL QUERY RULES TO RUNTIME", | ||
"UPDATE global_variables SET variable_value=50 WHERE variable_name='mysql-query_cache_soft_ttl_percentage'", | ||
"LOAD MYSQL VARIABLES TO RUNTIME", | ||
}; | ||
|
||
for (const auto &query : admin_queries) { | ||
diag("Running: %s", query.c_str()); | ||
MYSQL_QUERY(proxy_admin, query.c_str()); | ||
} | ||
|
||
// Clean the 'stats_mysql_query_digest' table | ||
string reset_query_digest_stats = "SELECT null FROM stats_mysql_query_digest_reset LIMIT 0"; | ||
diag("Running: %s", reset_query_digest_stats.c_str()); | ||
MYSQL_QUERY(proxy_admin, reset_query_digest_stats.c_str()); | ||
MYSQL_RES* reset_result = mysql_store_result(proxy_admin); | ||
mysql_free_result(reset_result); | ||
|
||
MYSQL* proxy_mysql = mysql_init(NULL); | ||
if (!mysql_real_connect(proxy_mysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) { | ||
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxy_mysql)); | ||
mysql_close(proxy_admin); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
diag("Running: %s", DUMMY_QUERY.c_str()); | ||
MYSQL_QUERY(proxy_mysql, DUMMY_QUERY.c_str()); // We want to cache query "SELECT SLEEP(1)" | ||
|
||
MYSQL_RES* res = NULL; | ||
res = mysql_store_result(proxy_mysql); | ||
mysql_free_result(res); | ||
mysql_close(proxy_mysql); | ||
|
||
std::thread client_one( | ||
run_dummy_query, cl.host, cl.username, cl.password, cl.port, &timer_result_one | ||
); | ||
std::thread client_two( | ||
run_dummy_query, cl.host, cl.username, cl.password, cl.port, &timer_result_two | ||
); | ||
std::thread client_three( | ||
run_dummy_query, cl.host, cl.username, cl.password, cl.port, &timer_result_three | ||
); | ||
std::thread client_four( | ||
run_dummy_query, cl.host, cl.username, cl.password, cl.port, &timer_result_four | ||
); | ||
client_one.join(); | ||
client_two.join(); | ||
client_three.join(); | ||
client_four.join(); | ||
|
||
if ( | ||
timer_result_one == -1.0 || | ||
timer_result_two == -1.0 || | ||
timer_result_three == -1.0 || | ||
timer_result_four == -1.0 | ||
) { | ||
fprintf( | ||
stderr, "File %s, line %d, Error: one or more threads finished with errors", __FILE__, __LINE__ | ||
); | ||
mysql_close(proxy_admin); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
// Get the number of clients that take more 1 second or more to execute the | ||
// query by casting double to int. | ||
int num_slow_clients = | ||
(int)(timer_result_one + timer_result_two + timer_result_three + timer_result_four); | ||
int expected_num_slow_clients = 1; | ||
ok( | ||
num_slow_clients == expected_num_slow_clients, | ||
"Only one client should take 1 second to execute the query. " | ||
"Number of clients that take more than 1 second - Exp:'%d', Act:'%d'", | ||
expected_num_slow_clients, num_slow_clients | ||
); | ||
|
||
string stats_query_digest = "SELECT hostgroup, count_star FROM stats_mysql_query_digest"; | ||
diag("Running: %s", stats_query_digest.c_str()); | ||
MYSQL_QUERY(proxy_admin, stats_query_digest.c_str()); | ||
|
||
res = mysql_store_result(proxy_admin); | ||
if (mysql_num_rows(res) != 2 || mysql_num_fields(res) != 2) { | ||
fprintf(stderr, "File %s, line %d, Error: Unexpected number of rows or columns", __FILE__, __LINE__); | ||
mysql_free_result(res); | ||
mysql_close(proxy_admin); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
const vector<int> expected_hostgroups = {-1, 1}; | ||
const vector<int> expected_count_stars = {7, 2}; | ||
|
||
diag("Hostgroup -1 represents the Query Cache"); | ||
MYSQL_ROW row; | ||
for (int i = 0; i < 2; i++) { | ||
row = mysql_fetch_row(res); | ||
int hostgroup = atoi(row[0]); | ||
int count_star = atoi(row[1]); | ||
ok( | ||
expected_count_stars[i] == count_star, | ||
"Hostgroup %d should have been hit %d times. Number of hits - Exp:'%d', Act:'%d'", | ||
hostgroup, expected_count_stars[i], expected_count_stars[i], count_star | ||
); | ||
} | ||
|
||
mysql_free_result(res); | ||
mysql_close(proxy_admin); | ||
|
||
return exit_status(); | ||
} |