mirror of https://github.com/sysown/proxysql
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
978 lines
34 KiB
978 lines
34 KiB
#include <iostream> // std::cout
|
|
#include <sstream> // std::stringstream
|
|
#include <fstream>
|
|
#include <algorithm> // std::sort
|
|
#include <memory>
|
|
#include <vector> // std::vector
|
|
#include <unordered_set>
|
|
|
|
#include "MySQL_Query_Processor.h"
|
|
#include "PgSQL_Query_Processor.h"
|
|
|
|
#include "MySQL_Data_Stream.h"
|
|
|
|
static int int_cmp(const void *a, const void *b) {
|
|
const unsigned long long *ia = (const unsigned long long *)a;
|
|
const unsigned long long *ib = (const unsigned long long *)b;
|
|
if (*ia < *ib) return -1;
|
|
if (*ia > *ib) return 1;
|
|
return 0;
|
|
}
|
|
|
|
extern MySQL_Query_Processor* GloMyQPro;
|
|
extern PgSQL_Query_Processor* GloPgQPro;
|
|
extern MySQL_Monitor *GloMyMon;
|
|
extern MySQL_Threads_Handler *GloMTH;
|
|
extern PgSQL_Threads_Handler* GloPTH;
|
|
|
|
static pthread_mutex_t test_mysql_firewall_whitelist_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
static std::unordered_map<std::string, void *> map_test_mysql_firewall_whitelist_rules;
|
|
static char rand_del[6] = {0};
|
|
|
|
static void init_rand_del() {
|
|
if (rand_del[0] == 0) {
|
|
static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
rand_del[0] = '-';
|
|
for (int i = 1; i < 4; i++) {
|
|
rand_del[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
|
|
}
|
|
rand_del[4] = '-';
|
|
rand_del[5] = 0;
|
|
}
|
|
}
|
|
|
|
int ProxySQL_Test___GetDigestTable(bool reset, bool use_swap);
|
|
bool ProxySQL_Test___Refresh_MySQL_Variables(unsigned int cnt);
|
|
template<enum SERVER_TYPE>
|
|
int ProxySQL_Test___PurgeDigestTable(bool async_purge, bool parallel, char **msg);
|
|
int ProxySQL_Test___GenerateRandomQueryInDigestTable(int n);
|
|
|
|
void ProxySQL_Admin::map_test_mysql_firewall_whitelist_rules_cleanup() {
|
|
for (std::unordered_map<std::string, void*>::iterator it = map_test_mysql_firewall_whitelist_rules.begin(); it != map_test_mysql_firewall_whitelist_rules.end(); ++it) {
|
|
PtrArray* myptrarray = (PtrArray*)it->second;
|
|
delete myptrarray;
|
|
}
|
|
map_test_mysql_firewall_whitelist_rules.clear();
|
|
}
|
|
|
|
bool ProxySQL_Admin::ProxySQL_Test___Load_MySQL_Whitelist(int *ret1, int *ret2, int cmd, int loops) {
|
|
// cmd == 1 : populate the structure with a global mutex
|
|
// cmd == 2 : perform lookup with a global mutex
|
|
// cmd == 3 : perform lookup with a mutex for each call
|
|
// cmd == 4 : populate the structure with a global mutex , but without cleaning up
|
|
// all accept an extra argument that is the number of loops
|
|
char *q = (char *)"SELECT * FROM mysql_firewall_whitelist_rules ORDER BY RANDOM()";
|
|
char *error=NULL;
|
|
int cols=0;
|
|
int affected_rows=0;
|
|
SQLite3_result *resultset=NULL;
|
|
bool ret = true;
|
|
int _ret1 = 0;
|
|
// cleanup
|
|
if (cmd == 1 || cmd == 2 || cmd == 4) {
|
|
pthread_mutex_lock(&test_mysql_firewall_whitelist_mutex);
|
|
}
|
|
admindb->execute_statement(q, &error , &cols , &affected_rows , &resultset);
|
|
init_rand_del();
|
|
if (error) {
|
|
proxy_error("Error on %s : %s\n", q, error);
|
|
return false;
|
|
} else {
|
|
*ret1 = resultset->rows_count;
|
|
int loop = 0;
|
|
//if (cmd == 1) {
|
|
// loop = loops -1;
|
|
//}
|
|
for ( ; loop < loops ; loop++) {
|
|
_ret1 = 0;
|
|
if (cmd == 1) {
|
|
for (std::unordered_map<std::string, void *>::iterator it = map_test_mysql_firewall_whitelist_rules.begin() ; it != map_test_mysql_firewall_whitelist_rules.end(); ++it) {
|
|
PtrArray * myptrarray = (PtrArray *)it->second;
|
|
delete myptrarray;
|
|
}
|
|
map_test_mysql_firewall_whitelist_rules.clear();
|
|
}
|
|
if (cmd == 4) {
|
|
for (std::unordered_map<std::string, void *>::iterator it = map_test_mysql_firewall_whitelist_rules.begin() ; it != map_test_mysql_firewall_whitelist_rules.end(); ++it) {
|
|
PtrArray * myptrarray = (PtrArray *)it->second;
|
|
myptrarray->reset();
|
|
}
|
|
}
|
|
for (std::vector<SQLite3_row *>::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) {
|
|
SQLite3_row *r=*it;
|
|
int active = atoi(r->fields[0]);
|
|
if (active == 0) {
|
|
continue;
|
|
}
|
|
char * username = r->fields[1];
|
|
char * client_address = r->fields[2];
|
|
char * schemaname = r->fields[3];
|
|
char * flagIN = r->fields[4];
|
|
char * digest_hex = r->fields[5];
|
|
unsigned long long digest_num = strtoull(digest_hex,NULL,0);
|
|
string s = username;
|
|
s += rand_del;
|
|
s += client_address;
|
|
s += rand_del;
|
|
s += schemaname;
|
|
s += rand_del;
|
|
s += flagIN;
|
|
std::unordered_map<std::string, void *>:: iterator it2;
|
|
if (cmd == 1 || cmd == 4) {
|
|
it2 = map_test_mysql_firewall_whitelist_rules.find(s);
|
|
if (it2 != map_test_mysql_firewall_whitelist_rules.end()) {
|
|
PtrArray * myptrarray = (PtrArray *)it2->second;
|
|
myptrarray->add((void *)digest_num);
|
|
} else {
|
|
PtrArray * myptrarray = new PtrArray();
|
|
myptrarray->add((void *)digest_num);
|
|
map_test_mysql_firewall_whitelist_rules[s] = (void *)myptrarray;
|
|
//proxy_info("Inserted key: %s\n" , s.c_str());
|
|
}
|
|
} else if (cmd == 2 || cmd == 3) {
|
|
if (cmd == 3) {
|
|
pthread_mutex_lock(&test_mysql_firewall_whitelist_mutex);
|
|
}
|
|
it2 = map_test_mysql_firewall_whitelist_rules.find(s);
|
|
if (it2 != map_test_mysql_firewall_whitelist_rules.end()) {
|
|
PtrArray * myptrarray = (PtrArray *)it2->second;
|
|
void * r = bsearch(&digest_num, myptrarray->pdata, myptrarray->len, sizeof(unsigned long long), int_cmp);
|
|
if (r) _ret1++;
|
|
} else {
|
|
//proxy_error("Not found: %s %s %s %s\n", username, client_address, schemaname, flagIN);
|
|
proxy_error("Not found: %s\n", s.c_str());
|
|
}
|
|
if (cmd == 3) {
|
|
pthread_mutex_unlock(&test_mysql_firewall_whitelist_mutex);
|
|
}
|
|
}
|
|
}
|
|
if (cmd == 1 || cmd == 4) {
|
|
std::unordered_map<std::string, void *>::iterator it = map_test_mysql_firewall_whitelist_rules.begin();
|
|
while (it != map_test_mysql_firewall_whitelist_rules.end()) {
|
|
PtrArray * myptrarray = (PtrArray *)it->second;
|
|
switch (cmd) {
|
|
case 1:
|
|
qsort(myptrarray->pdata, myptrarray->len, sizeof(unsigned long long), int_cmp);
|
|
it++;
|
|
break;
|
|
case 4:
|
|
if (myptrarray->len) {
|
|
qsort(myptrarray->pdata, myptrarray->len, sizeof(unsigned long long), int_cmp);
|
|
it++;
|
|
} else {
|
|
delete myptrarray;
|
|
it = map_test_mysql_firewall_whitelist_rules.erase(it);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (cmd == 2 || cmd == 3) {
|
|
*ret2 = _ret1;
|
|
}
|
|
if (resultset) delete resultset;
|
|
if (cmd == 1 || cmd == 2 || cmd == 4) {
|
|
pthread_mutex_unlock(&test_mysql_firewall_whitelist_mutex);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// if dual is not 0 , we call the new search algorithm
|
|
bool ProxySQL_Admin::ProxySQL_Test___Verify_mysql_query_rules_fast_routing(
|
|
int *ret1, int *ret2, int cnt, int dual, int ths, bool lock, bool maps_per_thread
|
|
) {
|
|
// A thread param of '0' is equivalent to not testing
|
|
if (ths == 0) { ths = 1; }
|
|
char *q = (char *)"SELECT username, schemaname, flagIN, destination_hostgroup FROM mysql_query_rules_fast_routing ORDER BY RANDOM()";
|
|
|
|
bool ret = true;
|
|
int matching_rows = 0;
|
|
|
|
SQLite3_result *resultset=NULL;
|
|
{
|
|
char *error=NULL;
|
|
int cols=0;
|
|
int affected_rows=0;
|
|
admindb->execute_statement(q, &error , &cols , &affected_rows , &resultset);
|
|
|
|
if (error) {
|
|
proxy_error("Error on %s : %s\n", q, error);
|
|
*ret1 = -1;
|
|
return false;
|
|
}
|
|
}
|
|
*ret2 = resultset->rows_count;
|
|
|
|
char *query2=(char *)"SELECT username, schemaname, flagIN, destination_hostgroup, comment FROM main.mysql_query_rules_fast_routing ORDER BY username, schemaname, flagIN";
|
|
SQLite3_result* resultset2 = nullptr;
|
|
|
|
if (maps_per_thread) {
|
|
char* error2 = nullptr;
|
|
int cols2 = 0;
|
|
int affected_rows2 = 0;
|
|
admindb->execute_statement(query2, &error2 , &cols2 , &affected_rows2 , &resultset2);
|
|
|
|
if (error2) {
|
|
proxy_error("Error on %s : %s\n", query2, error2);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
vector<uint32_t> results(ths, 0);
|
|
vector<fast_routing_hashmap_t> th_hashmaps {};
|
|
|
|
if (maps_per_thread) {
|
|
for (uint32_t i = 0; i < static_cast<uint32_t>(ths); i++) {
|
|
th_hashmaps.push_back(GloMyQPro->create_fast_routing_hashmap(resultset2));
|
|
}
|
|
}
|
|
|
|
const auto perform_searches =
|
|
[&results,&dual](khash_t(khStrInt)* hashmap, SQLite3_result* resultset, uint32_t pos, bool lock) -> void
|
|
{
|
|
uint32_t matching_rows = 0;
|
|
|
|
for (std::vector<SQLite3_row *>::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) {
|
|
SQLite3_row *r=*it;
|
|
int dest_HG = atoi(r->fields[3]);
|
|
int ret_HG = -1;
|
|
if (dual) {
|
|
ret_HG = GloMyQPro->testing___find_HG_in_mysql_query_rules_fast_routing_dual(
|
|
hashmap, r->fields[0], r->fields[1], atoi(r->fields[2]), lock
|
|
);
|
|
} else {
|
|
ret_HG = GloMyQPro->testing___find_HG_in_mysql_query_rules_fast_routing(
|
|
r->fields[0], r->fields[1], atoi(r->fields[2])
|
|
);
|
|
}
|
|
|
|
if (dest_HG == ret_HG) {
|
|
matching_rows++;
|
|
}
|
|
}
|
|
|
|
results[pos] = matching_rows;
|
|
};
|
|
|
|
proxy_info("Test with params - cnt: %d, threads: %d, lock: %d, maps_per_thread: %d\n", cnt, ths, lock, maps_per_thread);
|
|
|
|
unsigned long long curtime1 = monotonic_time() / 1000;
|
|
std::vector<std::thread> workers {};
|
|
|
|
for (int i = 0; i < ths; i++) {
|
|
khash_t(khStrInt)* hashmap = maps_per_thread ? th_hashmaps[i].rules_fast_routing : nullptr;
|
|
workers.push_back(std::thread(perform_searches, hashmap, resultset, i, lock));
|
|
}
|
|
|
|
for (std::thread& w : workers) {
|
|
w.join();
|
|
}
|
|
|
|
matching_rows = results[0];
|
|
if (matching_rows != resultset->rows_count) {
|
|
ret = false;
|
|
}
|
|
*ret1 = matching_rows;
|
|
|
|
if (ret == true) {
|
|
if (cnt > 1) {
|
|
for (int i=1 ; i < cnt; i++) {
|
|
std::vector<std::thread> workers {};
|
|
|
|
for (int i = 0; i < ths; i++) {
|
|
khash_t(khStrInt)* hashmap = maps_per_thread ? th_hashmaps[i].rules_fast_routing : nullptr;
|
|
workers.push_back(std::thread(perform_searches, hashmap, resultset, i, lock));
|
|
}
|
|
|
|
for (std::thread& w : workers) {
|
|
w.join();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned long long curtime2 = monotonic_time() / 1000;
|
|
uint32_t total_maps_size = 0;
|
|
|
|
for (const fast_routing_hashmap_t& hashmap : th_hashmaps) {
|
|
total_maps_size += hashmap.rules_fast_routing___keys_values___size;
|
|
total_maps_size += kh_size(hashmap.rules_fast_routing) * ((sizeof(int) + sizeof(char *) + 4));
|
|
|
|
kh_destroy(khStrInt, hashmap.rules_fast_routing);
|
|
free(hashmap.rules_fast_routing___keys_values);
|
|
}
|
|
|
|
proxy_info("Test took %llums\n", curtime2 - curtime1);
|
|
proxy_info("Verified rows %d\n", results[0]);
|
|
proxy_info("Total maps size %dkb\n", total_maps_size / 1024);
|
|
|
|
if (resultset) delete resultset;
|
|
if (resultset2) delete resultset2;
|
|
|
|
return ret;
|
|
}
|
|
|
|
unsigned int ProxySQL_Admin::ProxySQL_Test___GenerateRandom_mysql_query_rules_fast_routing(unsigned int cnt, bool empty) {
|
|
char *a = (char *)"INSERT OR IGNORE INTO mysql_query_rules_fast_routing VALUES (?1, ?2, ?3, ?4, '')";
|
|
int rc;
|
|
sqlite3_stmt *statement1=NULL;
|
|
rc=admindb->prepare_v2(a, &statement1);
|
|
ASSERT_SQLITE_OK(rc, admindb);
|
|
admindb->execute("DELETE FROM mysql_query_rules_fast_routing");
|
|
char * username_buf = (char *)malloc(128);
|
|
char * schemaname_buf = (char *)malloc(256);
|
|
//ui.username = username_buf;
|
|
//ui.schemaname = schemaname_buf;
|
|
if (empty==false) {
|
|
strcpy(username_buf,"user_name_");
|
|
} else {
|
|
strcpy(username_buf,"");
|
|
}
|
|
strcpy(schemaname_buf,"shard_name_");
|
|
int _k;
|
|
for (unsigned int i=0; i<cnt; i++) {
|
|
_k = fastrand()%117 + 1;
|
|
if (empty == false) {
|
|
for (int _i=0 ; _i<_k ; _i++) {
|
|
int b = fastrand()%10;
|
|
username_buf[10+_i]='0' + b;
|
|
}
|
|
username_buf[10+_k]='\0';
|
|
}
|
|
_k = fastrand()%244+ 1;
|
|
for (int _i=0 ; _i<_k ; _i++) {
|
|
int b = fastrand()%10;
|
|
schemaname_buf[11+_i]='0' + b;
|
|
}
|
|
schemaname_buf[11+_k]='\0';
|
|
int flagIN = fastrand()%20;
|
|
int destHG = fastrand()%100;
|
|
rc=(*proxy_sqlite3_bind_text)(statement1, 1, username_buf, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_bind_text)(statement1, 2, schemaname_buf, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement1, 3, flagIN); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement1, 4, destHG); ASSERT_SQLITE_OK(rc, admindb);
|
|
SAFE_SQLITE3_STEP2(statement1);
|
|
if ((*proxy_sqlite3_changes)(admindb->get_db())==0) {
|
|
i--;
|
|
}
|
|
rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb);
|
|
}
|
|
(*proxy_sqlite3_finalize)(statement1);
|
|
free(username_buf);
|
|
free(schemaname_buf);
|
|
return cnt;
|
|
}
|
|
|
|
void ProxySQL_Admin::ProxySQL_Test___MySQL_HostGroups_Manager_generate_many_clusters() {
|
|
mysql_servers_wrlock();
|
|
admindb->execute("DELETE FROM mysql_servers WHERE hostgroup_id BETWEEN 10001 AND 20000");
|
|
admindb->execute("DELETE FROM mysql_replication_hostgroups WHERE writer_hostgroup BETWEEN 10001 AND 20000");
|
|
char *q1 = (char *)"INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES (?1, ?2, ?3), (?4, ?5, ?6), (?7, ?8, ?9)";
|
|
char *q2 = (char *)"INSERT INTO mysql_replication_hostgroups (writer_hostgroup, reader_hostgroup) VALUES (?1, ?2)";
|
|
int rc;
|
|
sqlite3_stmt *statement1=NULL;
|
|
sqlite3_stmt *statement2=NULL;
|
|
rc=admindb->prepare_v2(q1, &statement1);
|
|
ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=admindb->prepare_v2(q2, &statement2);
|
|
ASSERT_SQLITE_OK(rc, admindb);
|
|
char hostnamebuf1[32];
|
|
char hostnamebuf2[32];
|
|
char hostnamebuf3[32];
|
|
for (int i=1000; i<2000; i++) {
|
|
sprintf(hostnamebuf1,"hostname%d", i*10+1);
|
|
sprintf(hostnamebuf2,"hostname%d", i*10+2);
|
|
sprintf(hostnamebuf3,"hostname%d", i*10+3);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement1, 1, i*10+1); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_bind_text)(statement1, 2, hostnamebuf1, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement1, 3, 3306); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement1, 4, i*10+2); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_bind_text)(statement1, 5, hostnamebuf2, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement1, 6, 3306); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement1, 7, i*10+2); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_bind_text)(statement1, 8, hostnamebuf3, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement1, 9, 3306); ASSERT_SQLITE_OK(rc, admindb);
|
|
SAFE_SQLITE3_STEP2(statement1);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement2, 1, i*10+1); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement2, 2, i*10+2); ASSERT_SQLITE_OK(rc, admindb);
|
|
SAFE_SQLITE3_STEP2(statement2);
|
|
rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_clear_bindings)(statement2); ASSERT_SQLITE_OK(rc, admindb);
|
|
rc=(*proxy_sqlite3_reset)(statement2); ASSERT_SQLITE_OK(rc, admindb);
|
|
}
|
|
(*proxy_sqlite3_finalize)(statement1);
|
|
(*proxy_sqlite3_finalize)(statement2);
|
|
load_mysql_servers_to_runtime();
|
|
mysql_servers_wrunlock();
|
|
}
|
|
unsigned long long ProxySQL_Admin::ProxySQL_Test___MySQL_HostGroups_Manager_read_only_action() {
|
|
// we immediately exit. This is just for developer
|
|
return 0;
|
|
ProxySQL_Test___MySQL_HostGroups_Manager_generate_many_clusters();
|
|
char hostnamebuf1[32];
|
|
char hostnamebuf2[32];
|
|
char hostnamebuf3[32];
|
|
unsigned long long t1 = monotonic_time();
|
|
//for (int j=0 ; j<500; j++) {
|
|
for (int j=0 ; j<1000; j++) {
|
|
for (int i=1000; i<2000; i++) {
|
|
sprintf(hostnamebuf1,"hostname%d", i*10+1);
|
|
sprintf(hostnamebuf2,"hostname%d", i*10+2);
|
|
sprintf(hostnamebuf3,"hostname%d", i*10+3);
|
|
MyHGM->read_only_action_v2( std::list<read_only_server_t> {
|
|
read_only_server_t { std::string(hostnamebuf1), 3306, 0 },
|
|
read_only_server_t { std::string(hostnamebuf2), 3306, 1 },
|
|
read_only_server_t { std::string(hostnamebuf3), 3306, 1 }
|
|
} );
|
|
}
|
|
}
|
|
unsigned long long t2 = monotonic_time();
|
|
t1 /= 1000;
|
|
t2 /= 1000;
|
|
unsigned long long d = t2-t1;
|
|
return d;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
// NEVER USED THIS FUNCTION IN PRODUCTION.
|
|
// THIS IS FOR TESTING PURPOSE ONLY
|
|
// IT ACCESSES MyHGM without lock
|
|
unsigned long long ProxySQL_Admin::ProxySQL_Test___MySQL_HostGroups_Manager_HG_lookup() {
|
|
// we immediately exit. This is just for developer
|
|
return 0;
|
|
ProxySQL_Test___MySQL_HostGroups_Manager_generate_many_clusters();
|
|
unsigned long long t1 = monotonic_time();
|
|
unsigned int hid = 0;
|
|
MyHGC * myhgc = NULL;
|
|
for (int j=0 ; j<100000; j++) {
|
|
for (unsigned int i=1000; i<2000; i++) {
|
|
// NEVER USED THIS FUNCTION IN PRODUCTION.
|
|
// THIS IS FOR TESTING PURPOSE ONLY
|
|
// IT ACCESSES MyHGM without lock
|
|
hid = i*10+1; // writer hostgroup
|
|
myhgc = MyHGM->MyHGC_lookup(hid);
|
|
assert(myhgc);
|
|
hid++; // reader hostgroup
|
|
myhgc = MyHGM->MyHGC_lookup(hid);
|
|
assert(myhgc);
|
|
}
|
|
}
|
|
unsigned long long t2 = monotonic_time();
|
|
t1 /= 1000;
|
|
t2 /= 1000;
|
|
unsigned long long d = t2-t1;
|
|
return d;
|
|
}
|
|
|
|
// NEVER USED THIS FUNCTION IN PRODUCTION.
|
|
// THIS IS FOR TESTING PURPOSE ONLY
|
|
// IT ACCESSES MyHGM without lock
|
|
unsigned long long ProxySQL_Admin::ProxySQL_Test___MySQL_HostGroups_Manager_Balancing_HG5211() {
|
|
unsigned long long t1 = monotonic_time();
|
|
const unsigned int NS = 4;
|
|
unsigned int cu[NS] = { 50, 10, 10, 0 };
|
|
MyHGC * myhgc = NULL;
|
|
myhgc = MyHGM->MyHGC_lookup(5211);
|
|
assert(myhgc);
|
|
assert(myhgc->mysrvs->servers->len == NS);
|
|
unsigned int cnt[NS];
|
|
for (unsigned int i=0; i<NS; i++) {
|
|
cnt[i]=0;
|
|
}
|
|
for (unsigned int i=0; i<NS; i++) {
|
|
MySrvC * m = (MySrvC *)myhgc->mysrvs->servers->index(i);
|
|
m->ConnectionsUsed->conns->len=cu[i];
|
|
}
|
|
unsigned int NL = 1000;
|
|
for (unsigned int i=0; i<NL; i++) {
|
|
MySrvC * mysrvc = myhgc->get_random_MySrvC(NULL, 0, -1, NULL);
|
|
assert(mysrvc);
|
|
for (unsigned int k=0; k<NS; k++) {
|
|
MySrvC * m = (MySrvC *)myhgc->mysrvs->servers->index(k);
|
|
if (m == mysrvc)
|
|
cnt[k]++;
|
|
}
|
|
}
|
|
{
|
|
unsigned int tc = 0;
|
|
for (unsigned int k=0; k<NS; k++) {
|
|
tc += cnt[k];
|
|
}
|
|
assert(tc == NL);
|
|
}
|
|
for (unsigned int k=0; k<NS; k++) {
|
|
proxy_info("Balancing_HG5211: server %u, cnt: %u\n", k, cnt[k]);
|
|
}
|
|
unsigned long long t2 = monotonic_time();
|
|
t1 /= 1000;
|
|
t2 /= 1000;
|
|
unsigned long long d = t2-t1;
|
|
return d;
|
|
}
|
|
|
|
bool ProxySQL_Admin::ProxySQL_Test___CA_Certificate_Load_And_Verify(uint64_t* duration, int cnt, const char* cacert, const char* capath)
|
|
{
|
|
assert(duration);
|
|
assert(cacert || capath);
|
|
SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
|
|
uint64_t t1 = monotonic_time();
|
|
for (int i = 0; i < cnt; i++) {
|
|
if (0 == SSL_CTX_load_verify_locations(ctx, cacert, capath)) {
|
|
proxy_error("Unable to load CA Certificate: %s\n", ERR_error_string(ERR_get_error(), NULL));
|
|
return false;
|
|
}
|
|
}
|
|
uint64_t t2 = monotonic_time();
|
|
SSL_CTX_free(ctx);
|
|
*duration = ((t2/1000) - (t1/1000));
|
|
proxy_info("Duration: %lums\n", *duration);
|
|
return true;
|
|
}
|
|
|
|
template<typename ThreadType>
|
|
bool RunWatchdogTest(const char* label, ThreadType* worker, unsigned int poll_timeout) {
|
|
if (!worker) return false;
|
|
|
|
if (worker->watchdog_test__simulated_delay_ms > 0 ||
|
|
worker->watchdog_test__missed_heartbeats > 0) {
|
|
proxy_error("Watchdog test already running, please wait for it to finish.\n");
|
|
return false;
|
|
}
|
|
if (poll_timeout == 0) {
|
|
proxy_error("Invalid poll_timeout value: %u\n", poll_timeout);
|
|
return false;
|
|
}
|
|
|
|
proxy_info("Starting Watchdog test for %s threads...\n", label);
|
|
|
|
const unsigned int target_missed = GloVars.restart_on_missing_heartbeats;
|
|
const uint64_t time_per_miss_ms = poll_timeout + 1000 + 200;
|
|
const uint64_t total_expected_time_ms = target_missed * time_per_miss_ms;
|
|
|
|
worker->watchdog_test__simulated_delay_ms = static_cast<unsigned int>(total_expected_time_ms);
|
|
const unsigned int timeout_ms = static_cast<unsigned int>(total_expected_time_ms * 1.25);
|
|
|
|
constexpr unsigned int poll_interval_ms = 200;
|
|
unsigned int waited_ms = 0;
|
|
unsigned int last_missed = 0;
|
|
bool success = false;
|
|
|
|
while (waited_ms < timeout_ms) {
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(poll_interval_ms));
|
|
waited_ms += poll_interval_ms;
|
|
|
|
unsigned int missed = worker->watchdog_test__missed_heartbeats;
|
|
if (missed != last_missed) {
|
|
last_missed = missed;
|
|
proxy_info("Watchdog test: Missed heartbeats: %u\n", missed);
|
|
}
|
|
|
|
if (success == false && missed == target_missed) {
|
|
success = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Clean-up
|
|
worker->watchdog_test__simulated_delay_ms = 0;
|
|
worker->watchdog_test__missed_heartbeats = 0;
|
|
|
|
if (success) {
|
|
proxy_info("Watchdog test passed. Missed heartbeats: %u\n", target_missed);
|
|
} else {
|
|
proxy_error("Watchdog test failed. Timeout hit before reaching %u missed heartbeats (got: %u)\n",
|
|
target_missed, last_missed);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
bool ProxySQL_Admin::ProxySQL_Test___WatchDog(int type) {
|
|
if (GloVars.restart_on_missing_heartbeats <= 0) {
|
|
proxy_error("Watchdog test is disabled (restart_on_missing_heartbeats is 0)\n");
|
|
return false;
|
|
}
|
|
|
|
if (type == 0 && GloMTH && GloMTH->num_threads > 0) {
|
|
if (!RunWatchdogTest("MySQL", GloMTH->mysql_threads[0].worker, GloMTH->variables.poll_timeout)) {
|
|
proxy_error("MySQL Watchdog test failed.\n");
|
|
return false;
|
|
}
|
|
} else if (type == 1 && GloPTH && GloPTH->num_threads > 0) {
|
|
if (!RunWatchdogTest("PgSQL", GloPTH->pgsql_threads[0].worker, GloPTH->variables.poll_timeout)) {
|
|
proxy_error("PgSQL Watchdog test failed.\n");
|
|
return false;
|
|
}
|
|
} else {
|
|
proxy_error("Invalid type %d for ProxySQL_Test___WatchDog\n", type);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif //DEBUG
|
|
|
|
|
|
/*
|
|
Explicit Instantiation:
|
|
If the function template is used with specific template arguments in multiple
|
|
source files, we must explicitly instantiate the template for those arguments
|
|
in the source file where the function is defined. This ensures that the
|
|
compiler generates the necessary code for those template instantiations
|
|
*/
|
|
template void ProxySQL_Admin::ProxySQL_Test_Handler<MySQL_Session>(ProxySQL_Admin*, MySQL_Session*, char*, bool&);
|
|
template void ProxySQL_Admin::ProxySQL_Test_Handler<PgSQL_Session>(ProxySQL_Admin*, PgSQL_Session*, char*, bool&);
|
|
|
|
template<typename S>
|
|
void ProxySQL_Admin::ProxySQL_Test_Handler(ProxySQL_Admin *SPA, S* sess, char *query_no_space, bool& run_query) {
|
|
if constexpr (std::is_same_v<S, MySQL_Session>) {
|
|
} else if constexpr (std::is_same_v<S, PgSQL_Session>) {
|
|
} else {
|
|
assert(0);
|
|
}
|
|
int test_n = 0;
|
|
int test_arg1 = 0;
|
|
int test_arg2 = 0;
|
|
int test_arg3 = -1;
|
|
int test_arg4 = -1;
|
|
int r1 = 0;
|
|
proxy_warning("Received PROXYSQLTEST command: %s\n", query_no_space);
|
|
char *msg = NULL;
|
|
sscanf(query_no_space+strlen("PROXYSQLTEST "),"%d %d %d %d %d", &test_n, &test_arg1, &test_arg2, &test_arg3, &test_arg4);
|
|
if (test_n) {
|
|
switch (test_n) {
|
|
case 1:
|
|
// generate test_arg1*1000 entries in digest map
|
|
if (test_arg1==0) {
|
|
test_arg1=1;
|
|
}
|
|
r1 = ProxySQL_Test___GenerateRandomQueryInDigestTable(test_arg1);
|
|
SPA->send_ok_msg_to_client(sess, NULL, r1, query_no_space);
|
|
run_query=false;
|
|
break;
|
|
case 2:
|
|
// get all the entries from the digest map, but without writing to DB
|
|
// it uses multiple threads
|
|
r1 = ProxySQL_Test___GetDigestTable(false, false);
|
|
SPA->send_ok_msg_to_client(sess, NULL, r1, query_no_space);
|
|
run_query=false;
|
|
break;
|
|
case 3:
|
|
// get all the entries from the digest map and reset, but without writing to DB
|
|
// it uses multiple threads
|
|
r1 = ProxySQL_Test___GetDigestTable(true, false);
|
|
SPA->send_ok_msg_to_client(sess, NULL, r1, query_no_space);
|
|
run_query=false;
|
|
break;
|
|
case 4:
|
|
// purge the digest map, synchronously, in single thread
|
|
r1 = ProxySQL_Test___PurgeDigestTable<SERVER_TYPE_MYSQL>(false, false, NULL);
|
|
SPA->send_ok_msg_to_client(sess, NULL, r1, query_no_space);
|
|
run_query=false;
|
|
break;
|
|
case 5:
|
|
// purge the digest map, synchronously, in multiple threads
|
|
r1 = ProxySQL_Test___PurgeDigestTable<SERVER_TYPE_MYSQL>(false, true, NULL);
|
|
SPA->send_ok_msg_to_client(sess, NULL, r1, query_no_space);
|
|
run_query=false;
|
|
break;
|
|
case 6:
|
|
// purge the digest map, asynchronously, in single thread
|
|
r1 = ProxySQL_Test___PurgeDigestTable<SERVER_TYPE_MYSQL>(true, false, &msg);
|
|
SPA->send_ok_msg_to_client(sess, msg, r1, query_no_space);
|
|
free(msg);
|
|
run_query=false;
|
|
break;
|
|
case 7:
|
|
// get all the entries from the digest map and reset, but without writing to DB
|
|
// it uses multiple threads
|
|
// it locks for a very short time and doesn't use SQLite3_result, but swap
|
|
r1 = ProxySQL_Test___GetDigestTable(true, true);
|
|
SPA->send_ok_msg_to_client(sess, NULL, r1, query_no_space);
|
|
run_query=false;
|
|
break;
|
|
case 8:
|
|
// get all the entries from the digest map and reset, AND write to DB
|
|
r1 = SPA->FlushDigestTableToDisk<SERVER_TYPE_MYSQL>(SPA->statsdb_disk);
|
|
SPA->send_ok_msg_to_client(sess, NULL, r1, query_no_space);
|
|
run_query=false;
|
|
break;
|
|
case 11: // generate username
|
|
case 15: // no username, empty string
|
|
// generate random mysql_query_rules_fast_routing
|
|
if (test_arg1==0) {
|
|
test_arg1=10000;
|
|
}
|
|
if (test_n==15) {
|
|
r1 = SPA->ProxySQL_Test___GenerateRandom_mysql_query_rules_fast_routing(test_arg1, true);
|
|
} else {
|
|
r1 = SPA->ProxySQL_Test___GenerateRandom_mysql_query_rules_fast_routing(test_arg1, false);
|
|
}
|
|
SPA->send_ok_msg_to_client(sess, (char *)"Generated new mysql_query_rules_fast_routing table", r1, query_no_space);
|
|
run_query=false;
|
|
break;
|
|
case 12: // generate username
|
|
case 16: // no username, empty string
|
|
// generate random mysql_query_rules_fast_routing and LOAD TO RUNTIME
|
|
if (test_arg1==0) {
|
|
test_arg1=10000;
|
|
}
|
|
if (test_n==16) {
|
|
r1 = SPA->ProxySQL_Test___GenerateRandom_mysql_query_rules_fast_routing(test_arg1, true);
|
|
} else {
|
|
r1 = SPA->ProxySQL_Test___GenerateRandom_mysql_query_rules_fast_routing(test_arg1, false);
|
|
}
|
|
msg = SPA->load_mysql_query_rules_to_runtime();
|
|
if (msg==NULL) {
|
|
SPA->send_ok_msg_to_client(sess, (char *)"Generated new mysql_query_rules_fast_routing table and loaded to runtime", r1, query_no_space);
|
|
} else {
|
|
SPA->send_error_msg_to_client(sess, msg);
|
|
}
|
|
run_query=false;
|
|
break;
|
|
case 13:
|
|
// LOAD MYSQL QUERY RULES TO RUNTIME for N times
|
|
if (test_arg1==0) {
|
|
test_arg1=1;
|
|
}
|
|
for (int i=0; i<test_arg1; i++) {
|
|
SPA->load_mysql_query_rules_to_runtime();
|
|
}
|
|
msg = (char *)malloc(128);
|
|
sprintf(msg,"Loaded mysql_query_rules_fast_routing to runtime %d times",test_arg1);
|
|
SPA->send_ok_msg_to_client(sess, msg, 0, query_no_space);
|
|
run_query=false;
|
|
free(msg);
|
|
break;
|
|
case 14: // old algorithm
|
|
case 17: // perform dual lookup, with and without username
|
|
// Allows to verify and benchmark 'mysql_query_rules_fast_routing'. Every options
|
|
// verifies all 'mysql_query_rules_fast_routing' rules:
|
|
// - Test num: 14 old algorithm, 17 perform a dual lookup.
|
|
// - arg1: 1-N Number of times the computation should be repeated.
|
|
// - arg2: 1-N Number of parallel threads for the test.
|
|
// - arg3: 1-0 Wether or not to acquire a read_lock before searching in the hashmap.
|
|
// - arg4: 1-0 Wether or not to create thread specific hashmaps for the search.
|
|
if (test_arg1==0) {
|
|
test_arg1=1;
|
|
}
|
|
// To preserve classic mode
|
|
if (test_arg3 == -1) {
|
|
test_arg3 = 1;
|
|
}
|
|
if (test_arg4 == -1) {
|
|
test_arg4 = 0;
|
|
}
|
|
{
|
|
int ret1, ret2;
|
|
bool bret = SPA->ProxySQL_Test___Verify_mysql_query_rules_fast_routing(
|
|
&ret1, &ret2, test_arg1, (test_n==14 ? 0 : 1), test_arg2, test_arg3, test_arg4
|
|
);
|
|
if (bret) {
|
|
SPA->send_ok_msg_to_client(sess, (char *)"Verified all rules in mysql_query_rules_fast_routing", ret1, query_no_space);
|
|
} else {
|
|
if (ret1==-1) {
|
|
SPA->send_error_msg_to_client(sess, (char *)"Severe error in verifying rules in mysql_query_rules_fast_routing");
|
|
} else {
|
|
msg = (char *)malloc(256);
|
|
sprintf(msg,"Error verifying mysql_query_rules_fast_routing. Found %d rows out of %d", ret1, ret2);
|
|
SPA->send_error_msg_to_client(sess, msg);
|
|
free(msg);
|
|
}
|
|
}
|
|
}
|
|
run_query=false;
|
|
break;
|
|
case 21:
|
|
// refresh mysql variables N*1000 times
|
|
if (test_arg1==0) {
|
|
test_arg1=1;
|
|
}
|
|
test_arg1 *= 1000;
|
|
ProxySQL_Test___Refresh_MySQL_Variables(test_arg1);
|
|
msg = (char *)malloc(128);
|
|
sprintf(msg,"Refreshed MySQL Variables %d times",test_arg1);
|
|
SPA->send_ok_msg_to_client(sess, msg, 0, query_no_space);
|
|
run_query=false;
|
|
free(msg);
|
|
break;
|
|
case 22:
|
|
// get all the entries from the digest map, but WRITING to DB
|
|
// it uses multiple threads
|
|
// It locks the maps while generating the resultset
|
|
r1 = SPA->stats___mysql_query_digests(false, true);
|
|
SPA->send_ok_msg_to_client(sess, NULL, r1, query_no_space);
|
|
run_query=false;
|
|
break;
|
|
case 23:
|
|
// get all the entries from the digest map, but WRITING to DB
|
|
// it uses multiple threads for creating the resultset
|
|
r1 = SPA->stats___mysql_query_digests_v2(false, false, true);
|
|
SPA->send_ok_msg_to_client(sess, NULL, r1, query_no_space);
|
|
run_query=false;
|
|
break;
|
|
case 24:
|
|
// get all the entries from the digest map, but WRITING to DB
|
|
// Do not create a resultset, uses the digest_umap
|
|
r1 = SPA->stats___mysql_query_digests_v2(false, false, false);
|
|
SPA->send_ok_msg_to_client(sess, NULL, r1, query_no_space);
|
|
run_query=false;
|
|
break;
|
|
case 25:
|
|
// get all the entries from the digest map AND RESET, but WRITING to DB
|
|
// it uses multiple threads
|
|
// It locks the maps while generating the resultset
|
|
r1 = SPA->stats___mysql_query_digests(true, true);
|
|
SPA->send_ok_msg_to_client(sess, NULL, r1, query_no_space);
|
|
run_query=false;
|
|
break;
|
|
case 26:
|
|
// get all the entries from the digest map AND RESET, but WRITING to DB
|
|
// it uses multiple threads for creating the resultset
|
|
r1 = SPA->stats___mysql_query_digests_v2(true, true, true);
|
|
SPA->send_ok_msg_to_client(sess, NULL, r1, query_no_space);
|
|
run_query=false;
|
|
break;
|
|
case 27:
|
|
// get all the entries from the digest map AND RESET, but WRITING to DB
|
|
// Do not create a resultset, uses the digest_umap
|
|
r1 = SPA->stats___mysql_query_digests_v2(true, true, false);
|
|
SPA->send_ok_msg_to_client(sess, NULL, r1, query_no_space);
|
|
run_query=false;
|
|
break;
|
|
case 31:
|
|
{
|
|
if (test_arg1==0) {
|
|
test_arg1=1;
|
|
}
|
|
if (test_arg1 > 4) {
|
|
test_arg1=1;
|
|
}
|
|
/*
|
|
if (test_arg1 == 2 || test_arg1 == 3) {
|
|
if (test_arg2 == 0) {
|
|
test_arg2 = 1;
|
|
}
|
|
}
|
|
*/
|
|
int ret1;
|
|
int ret2;
|
|
SPA->ProxySQL_Test___Load_MySQL_Whitelist(&ret1, &ret2, test_arg1, test_arg2);
|
|
if (test_arg1==1 || test_arg1==4) {
|
|
SPA->send_ok_msg_to_client(sess, (char *)"Processed all rows from firewall whitelist", ret1, query_no_space);
|
|
} else if (test_arg1==2 || test_arg1==3) {
|
|
if (ret1 == ret2) {
|
|
SPA->send_ok_msg_to_client(sess, (char *)"Verified all rows from firewall whitelist", ret1, query_no_space);
|
|
} else {
|
|
msg = (char *)malloc(256);
|
|
sprintf(msg,"Error verifying firewall whitelist. Found %d entries out of %d", ret2, ret1);
|
|
SPA->send_error_msg_to_client(sess, msg);
|
|
free(msg);
|
|
}
|
|
}
|
|
run_query=false;
|
|
}
|
|
break;
|
|
case 41:
|
|
{
|
|
char msg[256];
|
|
unsigned long long d = SPA->ProxySQL_Test___MySQL_HostGroups_Manager_read_only_action();
|
|
sprintf(msg, "Tested in %llums\n", d);
|
|
SPA->send_ok_msg_to_client(sess, msg, 0, query_no_space);
|
|
run_query=false;
|
|
}
|
|
break;
|
|
#ifdef DEBUG
|
|
case 51:
|
|
{
|
|
char msg[256];
|
|
unsigned long long d = SPA->ProxySQL_Test___MySQL_HostGroups_Manager_HG_lookup();
|
|
sprintf(msg, "Tested in %llums\n", d);
|
|
SPA->send_ok_msg_to_client(sess, msg, 0, query_no_space);
|
|
run_query=false;
|
|
}
|
|
break;
|
|
case 52:
|
|
{
|
|
char msg[256];
|
|
SPA->mysql_servers_wrlock();
|
|
SPA->admindb->execute("DELETE FROM mysql_servers WHERE hostgroup_id=5211");
|
|
SPA->admindb->execute("INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES (5211,'127.0.0.2',3306,10000)");
|
|
SPA->admindb->execute("INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES (5211,'127.0.0.3',3306,8000)");
|
|
SPA->admindb->execute("INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES (5211,'127.0.0.4',3306,8000)");
|
|
SPA->admindb->execute("INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES (5211,'127.0.0.5',3306,7000)");
|
|
SPA->load_mysql_servers_to_runtime();
|
|
SPA->mysql_servers_wrunlock();
|
|
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql servers to RUNTIME\n");
|
|
unsigned long long d = SPA->ProxySQL_Test___MySQL_HostGroups_Manager_Balancing_HG5211();
|
|
sprintf(msg, "Tested in %llums\n", d);
|
|
SPA->mysql_servers_wrlock();
|
|
SPA->admindb->execute("DELETE FROM mysql_servers WHERE hostgroup_id=5211");
|
|
SPA->load_mysql_servers_to_runtime();
|
|
SPA->mysql_servers_wrunlock();
|
|
SPA->send_ok_msg_to_client(sess, msg, 0, query_no_space);
|
|
run_query=false;
|
|
}
|
|
break;
|
|
case 53:
|
|
{
|
|
// Test monitor tasks timeout
|
|
// test_arg1: 1 = ON, 0 = OFF
|
|
char msg[256];
|
|
GloMyMon->proxytest_forced_timeout = (test_arg1) ? true : false;
|
|
sprintf(msg, "Monitor task timeout flag is:%s\n", GloMyMon->proxytest_forced_timeout ? "ON" : "OFF");
|
|
SPA->send_ok_msg_to_client(sess, msg, 0, query_no_space);
|
|
run_query = false;
|
|
}
|
|
break;
|
|
case 54:
|
|
{
|
|
run_query = false;
|
|
if (test_arg1 == 0) {
|
|
test_arg1 = 1000;
|
|
}
|
|
if (GloMTH->variables.ssl_p2s_ca == NULL &&
|
|
GloMTH->variables.ssl_p2s_capath == NULL) {
|
|
SPA->send_error_msg_to_client(sess, (char *)"'mysql-ssl_p2s_ca' and 'mysql-ssl_p2s_capath' have not been configured");
|
|
break;
|
|
}
|
|
char msg[256];
|
|
uint64_t duration = 0ULL;
|
|
if (SPA->ProxySQL_Test___CA_Certificate_Load_And_Verify(&duration, test_arg1, GloMTH->variables.ssl_p2s_ca,
|
|
GloMTH->variables.ssl_p2s_capath)) {
|
|
sprintf(msg, "Took %lums in loading and verifying CA Certificate for %d times\n", duration, test_arg1);
|
|
SPA->send_ok_msg_to_client(sess, msg, 0, query_no_space);
|
|
}
|
|
else {
|
|
SPA->send_error_msg_to_client(sess, (char *)"Unable to verify CA Certificate");
|
|
}
|
|
}
|
|
break;
|
|
case 55:
|
|
// test_arg1: 1 = POSTGRESQL, 0 = MYSQL
|
|
if (SPA->ProxySQL_Test___WatchDog(test_arg1)) {
|
|
SPA->send_ok_msg_to_client(sess, msg, 0, query_no_space);
|
|
} else {
|
|
SPA->send_error_msg_to_client(sess, (char*)"WatchDog test failed");
|
|
}
|
|
run_query = false;
|
|
break;
|
|
#endif // DEBUG
|
|
default:
|
|
SPA->send_error_msg_to_client(sess, (char *)"Invalid test");
|
|
run_query=false;
|
|
break;
|
|
}
|
|
} else {
|
|
SPA->send_error_msg_to_client(sess, (char *)"Invalid test");
|
|
}
|
|
}
|