Drafting support for ProxySQL Cluster

pull/1130/head
René Cannaò 9 years ago
parent 641b8ac1eb
commit f583982ace

@ -0,0 +1,112 @@
#ifndef CLASS_PROXYSQL_CLUSTER_H
#define CLASS_PROXYSQL_CLUSTER_H
#include "proxysql.h"
#include "cpp.h"
#include "thread.h"
#include "wqueue.h"
#define PROXYSQL_NODE_METRICS_LEN 5
class ProxySQL_Node_Metrics {
public:
unsigned long long read_time_us;
unsigned long long response_time_us;
unsigned long long ProxySQL_Uptime;
unsigned long long Questions;
unsigned long long Client_Connections_created;
unsigned long long Client_Connections_connected;
unsigned long long Servers_table_version;
void reset();
ProxySQL_Node_Metrics() {
reset();
}
~ProxySQL_Node_Metrics() {
reset();
}
};
class ProxySQL_Node_Entry {
private:
uint64_t hash;
char *hostname;
uint16_t port;
uint64_t weight;
char *comment;
uint64_t generate_hash();
bool active;
int metrics_idx_prev;
int metrics_idx;
ProxySQL_Node_Metrics **metrics;
public:
uint64_t get_hash();
ProxySQL_Node_Entry(char *_hostname, uint16_t _port, uint64_t _weight, char *_comment);
~ProxySQL_Node_Entry();
bool get_active();
void set_active(bool a);
uint64_t get_weight();
void set_weight(uint64_t a);
char * get_comment() { // note, NO strdup()
return comment;
}
void set_comment(char *a); // note, this is strdup()
void set_metrics(MYSQL_RES *_r, unsigned long long _response_time);
char *get_hostname() { // note, NO strdup()
return hostname;
}
uint16_t get_port() {
return port;
}
ProxySQL_Node_Metrics * get_metrics_curr();
ProxySQL_Node_Metrics * get_metrics_prev();
};
class ProxySQL_Cluster_Nodes {
private:
pthread_mutex_t mutex;
std::unordered_map<uint64_t, ProxySQL_Node_Entry *> umap_proxy_nodes;
void set_all_inactive();
void remove_inactives();
uint64_t generate_hash(char *_hostname, uint16_t _port);
public:
ProxySQL_Cluster_Nodes();
~ProxySQL_Cluster_Nodes();
void load_servers_list(SQLite3_result *);
bool Update_Node_Metrics(char * _h, uint16_t _p, MYSQL_RES *_r, unsigned long long _response_time);
SQLite3_result * dump_table_proxysql_servers();
SQLite3_result * stats_proxysql_servers_metrics();
};
class ProxySQL_Cluster {
private:
pthread_mutex_t mutex;
std::vector<pthread_t> term_threads;
ProxySQL_Cluster_Nodes nodes;
char *cluster_username;
char *cluster_password;
public:
int cluster_check_interval_ms;
ProxySQL_Cluster();
~ProxySQL_Cluster();
void init() {};
void print_version();
void load_servers_list(SQLite3_result *r) {
nodes.load_servers_list(r);
}
void get_credentials(char **, char **);
void set_username(char *);
void set_password(char *);
bool Update_Node_Metrics(char * _h, uint16_t _p, MYSQL_RES *_r, unsigned long long _response_time) {
return nodes.Update_Node_Metrics(_h, _p, _r, _response_time);
}
SQLite3_result *dump_table_proxysql_servers() {
return nodes.dump_table_proxysql_servers();
}
SQLite3_result * get_stats_proxysql_servers_metrics() {
return nodes.stats_proxysql_servers_metrics();
}
void thread_ending(pthread_t);
void join_term_thread();
};
#endif /* CLASS_PROXYSQL_CLUSTER_H */

@ -17,6 +17,7 @@
#include "MySQL_HostGroups_Manager.h"
#include "MySQL_Logger.hpp"
#include "MySQL_PreparedStatement.h"
#include "ProxySQL_Cluster.hpp" // cluster
#undef swap
#undef min
#undef max

@ -84,6 +84,9 @@ class ProxySQL_Admin {
bool admin_read_only;
bool hash_passwords;
char * admin_version;
char * cluster_username;
char * cluster_password;
int cluster_check_interval_ms;
#ifdef DEBUG
bool debug;
#endif /* DEBUG */
@ -198,6 +201,8 @@ class ProxySQL_Admin {
void stats___mysql_global();
void stats___mysql_users();
void stats___proxysql_servers_metrics();
int Read_Global_Variables_from_configfile(const char *prefix);
int Read_MySQL_Users_from_configfile();
int Read_MySQL_Query_Rules_from_configfile();
@ -217,5 +222,11 @@ class ProxySQL_Admin {
void flush_configdb(); // 923
// Cluster
void load_proxysql_servers_to_runtime();
void flush_proxysql_servers__from_memory_to_disk();
void flush_proxysql_servers__from_disk_to_memory();
void save_proxysql_servers_runtime_to_database(bool);
};
#endif /* __CLASS_PROXYSQL_ADMIN_H */

@ -61,7 +61,7 @@ default: libproxysql.a
_OBJ = c_tokenizer.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
_OBJ_CXX = ProxySQL_GloVars.oo network.oo debug.oo configfile.oo Query_Cache.oo SpookyV2.oo MySQL_Authentication.oo gen_utils.oo sqlite3db.oo mysql_connection.oo MySQL_HostGroups_Manager.oo mysql_data_stream.oo MySQL_Thread.oo MySQL_Session.oo MySQL_Protocol.oo mysql_backend.oo Query_Processor.oo ProxySQL_Admin.oo MySQL_Monitor.oo MySQL_Logger.oo thread.oo MySQL_PreparedStatement.oo
_OBJ_CXX = ProxySQL_GloVars.oo network.oo debug.oo configfile.oo Query_Cache.oo SpookyV2.oo MySQL_Authentication.oo gen_utils.oo sqlite3db.oo mysql_connection.oo MySQL_HostGroups_Manager.oo mysql_data_stream.oo MySQL_Thread.oo MySQL_Session.oo MySQL_Protocol.oo mysql_backend.oo Query_Processor.oo ProxySQL_Admin.oo MySQL_Monitor.oo MySQL_Logger.oo thread.oo MySQL_PreparedStatement.oo ProxySQL_Cluster.oo
OBJ_CXX = $(patsubst %,$(ODIR)/%,$(_OBJ_CXX))
%.ko: %.cpp

@ -141,6 +141,8 @@ extern MySQL_STMT_Manager_v14 *GloMyStmt;
#endif
extern MySQL_Monitor *GloMyMon;
extern ProxySQL_Cluster *GloProxyCluster;
#define PANIC(msg) { perror(msg); exit(EXIT_FAILURE); }
int rc, arg_on=1, arg_off=0;
@ -250,15 +252,15 @@ pthread_mutex_t users_mutex = PTHREAD_MUTEX_INITIALIZER;
#define ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_GROUP_REPLICATION_HOSTGROUPS "CREATE TABLE runtime_mysql_group_replication_hostgroups (writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY , backup_writer_hostgroup INT CHECK (backup_writer_hostgroup>=0 AND backup_writer_hostgroup<>writer_hostgroup) NOT NULL , reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND backup_writer_hostgroup<>reader_hostgroup AND reader_hostgroup>0) , offline_hostgroup INT NOT NULL CHECK (offline_hostgroup<>writer_hostgroup AND offline_hostgroup<>reader_hostgroup AND backup_writer_hostgroup<>offline_hostgroup AND offline_hostgroup>=0) , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1 , max_writers INT NOT NULL CHECK (max_writers >= 0) DEFAULT 1 , writer_is_also_reader INT CHECK (writer_is_also_reader IN (0,1)) NOT NULL DEFAULT 0 , max_transactions_behind INT CHECK (max_transactions_behind>=0) NOT NULL DEFAULT 0 , comment VARCHAR , UNIQUE (reader_hostgroup) , UNIQUE (offline_hostgroup) , UNIQUE (backup_writer_hostgroup))"
// cluster solution
#define ADMIN_SQLIE_TABLE_PROXY_SERVERS "CREATE TABLE proxysql_servers (hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 6032 , weight INT CHECK (weight >= 0) NOT NULL DEFAULT 0 , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostgroup_id, hostname, port) )"
// Cluster solution
#define ADMIN_SQLIE_TABLE_RUNTIME_PROXY_SERVERS "CREATE TABLE runtime_proxysql_servers (hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 6032 , weight INT CHECK (weight >= 0) NOT NULL DEFAULT 0 , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostgroup_id, hostname, port) )"
#define ADMIN_SQLITE_TABLE_PROXYSQL_SERVERS "CREATE TABLE proxysql_servers (hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 6032 , weight INT CHECK (weight >= 0) NOT NULL DEFAULT 0 , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostname, port) )"
#define STATS_SQLIE_TABLE_PROXY_SERVERS "CREATE TABLE stats_proxysql_servers (hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 6032 , weight INT CHECK (weight >= 0) NOT NULL DEFAULT 0 , global_version INT NOT NULL , check_age_ms INT NOT NULL , checks_OK INT NOT NULL , checks_ERR INT NOT NULL , PRIMARY KEY (hostgroup_id, hostname, port) )"
#define ADMIN_SQLITE_TABLE_RUNTIME_PROXYSQL_SERVERS "CREATE TABLE runtime_proxysql_servers (hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 6032 , weight INT CHECK (weight >= 0) NOT NULL DEFAULT 0 , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostname, port) )"
#define STATS_SQLITE_TABLE_PROXYSQL_SERVERS_STATUS "CREATE TABLE stats_proxysql_servers_status (hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 6032 , weight INT CHECK (weight >= 0) NOT NULL DEFAULT 0 , master VARCHAR NOT NULL , global_version INT NOT NULL , check_age_us INT NOT NULL , ping_time_us INT NOT NULL, checks_OK INT NOT NULL , checks_ERR INT NOT NULL , PRIMARY KEY (hostname, port) )"
#define STATS_SQLITE_TABLE_PROXYSQL_SERVERS_METRICS "CREATE TABLE stats_proxysql_servers_metrics (hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 6032 , weight INT CHECK (weight >= 0) NOT NULL DEFAULT 0 , comment VARCHAR NOT NULL DEFAULT '' , response_time_ms INT NOT NULL , Uptime_s INT NOT NULL , last_check_ms INT NOT NULL , Queries INT NOT NULL , Client_Connections_connected INT NOT NULL , Client_Connections_created INT NOT NULL , PRIMARY KEY (hostname, port) )"
@ -272,6 +274,9 @@ static char * admin_variables_names[]= {
(char *)"read_only",
(char *)"hash_passwords",
(char *)"version",
(char *)"cluster_username",
(char *)"cluster_password",
(char *)"cluster_check_interval_ms",
#ifdef DEBUG
(char *)"debug",
#endif /* DEBUG */
@ -1194,6 +1199,76 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query
}
}
if ((query_no_space_length>22) && ( (!strncasecmp("SAVE PROXYSQL SERVERS ", query_no_space, 22)) || (!strncasecmp("LOAD PROXYSQL SERVERS ", query_no_space, 22))) ) {
if (
(query_no_space_length==strlen("LOAD PROXYSQL SERVERS TO MEMORY") && !strncasecmp("LOAD PROXYSQL SERVERS TO MEMORY",query_no_space, query_no_space_length))
||
(query_no_space_length==strlen("LOAD PROXYSQL SERVERS TO MEM") && !strncasecmp("LOAD PROXYSQL SERVERS TO MEM",query_no_space, query_no_space_length))
||
(query_no_space_length==strlen("LOAD PROXYSQL SERVERS FROM DISK") && !strncasecmp("LOAD PROXYSQL SERVERS FROM DISK",query_no_space, query_no_space_length))
) {
proxy_info("Received %s command\n", query_no_space);
ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa;
SPA->flush_proxysql_servers__from_disk_to_memory();
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded ProxySQL servers to MEMORY\n");
SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL);
return false;
}
if (
(query_no_space_length==strlen("SAVE PROXYSQL SERVERS FROM MEMORY") && !strncasecmp("SAVE PROXYSQL SERVERS FROM MEMORY",query_no_space, query_no_space_length))
||
(query_no_space_length==strlen("SAVE PROXYSQL SERVERS FROM MEM") && !strncasecmp("SAVE PROXYSQL SERVERS FROM MEM",query_no_space, query_no_space_length))
||
(query_no_space_length==strlen("SAVE PROXYSQL SERVERS TO DISK") && !strncasecmp("SAVE PROXYSQL SERVERS TO DISK",query_no_space, query_no_space_length))
) {
proxy_info("Received %s command\n", query_no_space);
ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa;
SPA->flush_proxysql_servers__from_memory_to_disk();
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Saved ProxySQL servers to DISK\n");
SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL);
return false;
}
if (
(query_no_space_length==strlen("LOAD PROXYSQL SERVERS FROM MEMORY") && !strncasecmp("LOAD PROXYSQL SERVERS FROM MEMORY",query_no_space, query_no_space_length))
||
(query_no_space_length==strlen("LOAD PROXYSQL SERVERS FROM MEM") && !strncasecmp("LOAD PROXYSQL SERVERS FROM MEM",query_no_space, query_no_space_length))
||
(query_no_space_length==strlen("LOAD PROXYSQL SERVERS TO RUNTIME") && !strncasecmp("LOAD PROXYSQL SERVERS TO RUNTIME",query_no_space, query_no_space_length))
||
(query_no_space_length==strlen("LOAD PROXYSQL SERVERS TO RUN") && !strncasecmp("LOAD PROXYSQL SERVERS TO RUN",query_no_space, query_no_space_length))
) {
proxy_info("Received %s command\n", query_no_space);
ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa;
SPA->mysql_servers_wrlock();
SPA->load_proxysql_servers_to_runtime();
SPA->mysql_servers_wrunlock();
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded ProxySQL servers to RUNTIME\n");
SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL);
return false;
}
if (
(query_no_space_length==strlen("SAVE PROXYSQL SERVERS TO MEMORY") && !strncasecmp("SAVE PROXYSQL SERVERS TO MEMORY",query_no_space, query_no_space_length))
||
(query_no_space_length==strlen("SAVE PROXYSQL SERVERS TO MEM") && !strncasecmp("SAVE PROXYSQL SERVERS TO MEM",query_no_space, query_no_space_length))
||
(query_no_space_length==strlen("SAVE PROXYSQL SERVERS FROM RUNTIME") && !strncasecmp("SAVE PROXYSQL SERVERS FROM RUNTIME",query_no_space, query_no_space_length))
||
(query_no_space_length==strlen("SAVE PROXYSQL SERVERS FROM RUN") && !strncasecmp("SAVE PROXYSQL SERVERS FROM RUN",query_no_space, query_no_space_length))
) {
proxy_info("Received %s command\n", query_no_space);
ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa;
SPA->mysql_servers_wrlock();
SPA->save_proxysql_servers_runtime_to_database(false);
SPA->mysql_servers_wrunlock();
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Saved ProxySQL servers from RUNTIME\n");
SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL);
return false;
}
}
if ((query_no_space_length>23) && ( (!strncasecmp("SAVE MYSQL QUERY RULES ", query_no_space, 23)) || (!strncasecmp("LOAD MYSQL QUERY RULES ", query_no_space, 23))) ) {
if (
@ -1394,8 +1469,13 @@ void ProxySQL_Admin::GenericRefreshStatistics(const char *query_no_space, unsign
bool runtime_mysql_servers=false;
bool runtime_mysql_query_rules=false;
bool runtime_proxysql_servers=false;
bool monitor_mysql_server_group_replication_log=false;
bool stats_proxysql_servers_metrics = false;
bool stats_proxysql_servers_status = false;
if (strcasestr(query_no_space,"processlist"))
// This will match the following usecases:
// SHOW PROCESSLIST
@ -1423,6 +1503,12 @@ void ProxySQL_Admin::GenericRefreshStatistics(const char *query_no_space, unsign
{ stats_mysql_query_rules=true; refresh=true; }
if (strstr(query_no_space,"stats_mysql_users"))
{ stats_mysql_users=true; refresh=true; }
if (strstr(query_no_space,"stats_proxysql_servers_metrics"))
{ stats_proxysql_servers_metrics = true; refresh = true; }
if (strstr(query_no_space,"stats_proxysql_servers_status"))
{ stats_proxysql_servers_status = true; refresh = true; }
if (admin) {
if (strstr(query_no_space,"global_variables"))
{ dump_global_variables=true; refresh=true; }
@ -1445,6 +1531,9 @@ void ProxySQL_Admin::GenericRefreshStatistics(const char *query_no_space, unsign
if (strstr(query_no_space,"runtime_scheduler")) {
runtime_scheduler=true; refresh=true;
}
if (strstr(query_no_space,"runtime_proxysql_servers")) {
runtime_proxysql_servers=true; refresh=true;
}
}
}
if (strstr(query_no_space,"mysql_server_group_replication_log")) {
@ -1476,6 +1565,15 @@ void ProxySQL_Admin::GenericRefreshStatistics(const char *query_no_space, unsign
stats___mysql_commands_counters();
if (stats_mysql_users)
stats___mysql_users();
// cluster
if (stats_proxysql_servers_metrics) {
stats___proxysql_servers_metrics();
}
// if (stats_proxysql_servers_status) {
// stats___proxysql_servers_status();
// }
if (admin) {
if (dump_global_variables) {
admindb->execute("DELETE FROM runtime_global_variables"); // extra
@ -1487,6 +1585,11 @@ void ProxySQL_Admin::GenericRefreshStatistics(const char *query_no_space, unsign
save_mysql_servers_runtime_to_database(true);
mysql_servers_wrunlock();
}
if (runtime_proxysql_servers) {
mysql_servers_wrlock();
save_proxysql_servers_runtime_to_database(true);
mysql_servers_wrunlock();
}
if (runtime_mysql_users) {
save_mysql_users_runtime_to_database(true);
}
@ -2621,6 +2724,9 @@ ProxySQL_Admin::ProxySQL_Admin() {
variables.hash_passwords=true; // issue #676
variables.admin_read_only=false; // by default, the admin interface accepts writes
variables.admin_version=(char *)PROXYSQL_VERSION;
variables.cluster_username=strdup((char *)"");
variables.cluster_password=strdup((char *)"");
variables.cluster_check_interval_ms=1000;
#ifdef DEBUG
variables.debug=GloVars.global.gdbg;
#endif /* DEBUG */
@ -2766,6 +2872,14 @@ bool ProxySQL_Admin::init() {
insert_into_tables_defs(tables_defs_stats,"stats_mysql_users", STATS_SQLITE_TABLE_MYSQL_USERS);
insert_into_tables_defs(tables_defs_stats,"global_variables", ADMIN_SQLITE_TABLE_GLOBAL_VARIABLES); // workaround for issue #708
// ProxySQL Cluster
insert_into_tables_defs(tables_defs_admin,"proxysql_servers", ADMIN_SQLITE_TABLE_PROXYSQL_SERVERS);
insert_into_tables_defs(tables_defs_config,"proxysql_servers", ADMIN_SQLITE_TABLE_PROXYSQL_SERVERS);
insert_into_tables_defs(tables_defs_admin,"runtime_proxysql_servers", ADMIN_SQLITE_TABLE_RUNTIME_PROXYSQL_SERVERS);
insert_into_tables_defs(tables_defs_stats,"stats_proxysql_servers_metrics", STATS_SQLITE_TABLE_PROXYSQL_SERVERS_METRICS);
insert_into_tables_defs(tables_defs_stats,"stats_proxysql_servers_status", STATS_SQLITE_TABLE_PROXYSQL_SERVERS_STATUS);
// upgrade mysql_servers if needed (upgrade from previous version)
disk_upgrade_mysql_servers();
@ -2906,6 +3020,12 @@ void ProxySQL_Admin::admin_shutdown() {
// delete the scheduler
delete scheduler;
scheduler=NULL;
if (variables.cluster_username) {
free(variables.cluster_username);
}
if (variables.cluster_password) {
free(variables.cluster_password);
}
if (variables.mysql_ifaces) {
free(variables.mysql_ifaces);
}
@ -3174,11 +3294,17 @@ char * ProxySQL_Admin::get_variable(char *name) {
#define INTBUFSIZE 4096
char intbuf[INTBUFSIZE];
if (!strcasecmp(name,"version")) return s_strdup(variables.admin_version);
if (!strcasecmp(name,"cluster_username")) return s_strdup(variables.cluster_username);
if (!strcasecmp(name,"cluster_password")) return s_strdup(variables.cluster_password);
if (!strcasecmp(name,"admin_credentials")) return s_strdup(variables.admin_credentials);
if (!strcasecmp(name,"stats_credentials")) return s_strdup(variables.stats_credentials);
if (!strcasecmp(name,"mysql_ifaces")) return s_strdup(variables.mysql_ifaces);
if (!strcasecmp(name,"telnet_admin_ifaces")) return s_strdup(variables.telnet_admin_ifaces);
if (!strcasecmp(name,"telnet_stats_ifaces")) return s_strdup(variables.telnet_stats_ifaces);
if (!strcasecmp(name,"cluster_check_interval_ms")) {
sprintf(intbuf,"%lu",variables.cluster_check_interval_ms);
return strdup(intbuf);
}
if (!strcasecmp(name,"refresh_interval")) {
sprintf(intbuf,"%d",variables.refresh_interval);
return strdup(intbuf);
@ -3310,6 +3436,26 @@ bool ProxySQL_Admin::set_variable(char *name, char *value) { // this is the pub
return false;
}
}
if (!strcasecmp(name,"cluster_username")) {
if (vallen) {
free(variables.cluster_username);
variables.cluster_username=strdup(value);
GloProxyCluster->set_username(variables.cluster_username);
return true;
} else {
return false;
}
}
if (!strcasecmp(name,"cluster_password")) {
if (vallen) {
free(variables.cluster_password);
variables.cluster_password=strdup(value);
GloProxyCluster->set_password(variables.cluster_password);
return true;
} else {
return false;
}
}
if (!strcasecmp(name,"telnet_admin_ifaces")) {
if (vallen) {
bool update_creds=false;
@ -3350,6 +3496,16 @@ bool ProxySQL_Admin::set_variable(char *name, char *value) { // this is the pub
return false;
}
}
if (!strcasecmp(name,"cluster_check_interval_ms")) {
int intv=atoi(value);
if (intv >= 10 && intv <= 300000) {
variables.cluster_check_interval_ms=intv;
__sync_lock_test_and_set(&GloProxyCluster->cluster_check_interval_ms, intv);
return true;
} else {
return false;
}
}
if (!strcasecmp(name,"version")) {
if (strcasecmp(value,(char *)PROXYSQL_VERSION)==0) {
return true;
@ -3752,6 +3908,47 @@ void ProxySQL_Admin::stats___mysql_query_rules() {
delete resultset;
}
void ProxySQL_Admin::stats___proxysql_servers_metrics() {
//SQLite3_result * resultset=GloProxyCluster->get_stats_proxysql_servers_metrics();
//if (resultset==NULL) return;
statsdb->execute("BEGIN");
statsdb->execute("DELETE FROM stats_proxysql_servers_metrics");
char *a=(char *)"INSERT INTO stats_proxysql_servers_metrics VALUES (\"%s\",\"%s\",)";
// make sure that the caller has called mysql_servers_wrlock()
char *query=NULL;
SQLite3_result *resultset=NULL;
resultset=GloProxyCluster->get_stats_proxysql_servers_metrics();
if (resultset) {
int rc;
sqlite3_stmt *statement1=NULL;
//sqlite3_stmt *statement32=NULL;
sqlite3 *mydb3=statsdb->get_db();
char *query1=NULL;
query1=(char *)"INSERT INTO stats_proxysql_servers_metrics VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)";
rc=sqlite3_prepare_v2(mydb3, query1, -1, &statement1, 0);
assert(rc==SQLITE_OK);
for (std::vector<SQLite3_row *>::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) {
SQLite3_row *r1=*it;
rc=sqlite3_bind_text(statement1, 1, r1->fields[0], -1, SQLITE_TRANSIENT); assert(rc==SQLITE_OK);
rc=sqlite3_bind_int64(statement1, 2, atoi(r1->fields[1])); assert(rc==SQLITE_OK);
rc=sqlite3_bind_int64(statement1, 3, atoi(r1->fields[2])); assert(rc==SQLITE_OK);
rc=sqlite3_bind_text(statement1, 4, r1->fields[3], -1, SQLITE_TRANSIENT); assert(rc==SQLITE_OK);
rc=sqlite3_bind_int64(statement1, 5, atoi(r1->fields[4])); assert(rc==SQLITE_OK);
rc=sqlite3_bind_int64(statement1, 6, atoi(r1->fields[5])); assert(rc==SQLITE_OK);
rc=sqlite3_bind_int64(statement1, 7, atoi(r1->fields[6])); assert(rc==SQLITE_OK);
rc=sqlite3_bind_int64(statement1, 8, atoi(r1->fields[7])); assert(rc==SQLITE_OK);
rc=sqlite3_bind_int64(statement1, 9, atoi(r1->fields[8])); assert(rc==SQLITE_OK);
rc=sqlite3_bind_int64(statement1, 10, atoi(r1->fields[9])); assert(rc==SQLITE_OK);
SAFE_SQLITE3_STEP(statement1);
rc=sqlite3_clear_bindings(statement1); assert(rc==SQLITE_OK);
rc=sqlite3_reset(statement1); assert(rc==SQLITE_OK);
}
sqlite3_finalize(statement1);
}
statsdb->execute("COMMIT");
delete resultset;
}
void ProxySQL_Admin::stats___mysql_query_digests(bool reset) {
if (!GloQPro) return;
SQLite3_result * resultset=NULL;
@ -5909,3 +6106,104 @@ unsigned long long ProxySQL_External_Scheduler::run_once() {
#endif
return next_run;
}
void ProxySQL_Admin::load_proxysql_servers_to_runtime() {
// make sure that the caller has called mysql_servers_wrlock()
char *error=NULL;
int cols=0;
int affected_rows=0;
SQLite3_result *resultset=NULL;
char *query=(char *)"SELECT hostname,port,weight,comment FROM proxysql_servers";
proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query);
admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset);
if (error) {
proxy_error("Error on %s : %s\n", query, error);
} else {
GloProxyCluster->load_servers_list(resultset);
}
if (resultset) delete resultset;
resultset=NULL;
}
void ProxySQL_Admin::flush_proxysql_servers__from_memory_to_disk() {
admindb->wrlock();
admindb->execute("PRAGMA foreign_keys = OFF");
admindb->execute("DELETE FROM disk.proxysql_servers");
admindb->execute("INSERT INTO disk.proxysql_servers SELECT * FROM main.proxysql_servers");
admindb->execute("PRAGMA foreign_keys = ON");
admindb->wrunlock();
}
void ProxySQL_Admin::flush_proxysql_servers__from_disk_to_memory() {
admindb->wrlock();
admindb->execute("PRAGMA foreign_keys = OFF");
admindb->execute("DELETE FROM main.proxysql_servers");
admindb->execute("INSERT INTO main.proxysql_servers SELECT * FROM disk.proxysql_servers");
admindb->execute("PRAGMA foreign_keys = ON");
admindb->wrunlock();
}
void ProxySQL_Admin::save_proxysql_servers_runtime_to_database(bool _runtime) {
// make sure that the caller has called mysql_servers_wrlock()
char *query=NULL;
SQLite3_result *resultset=NULL;
// dump proxysql_servers
if (_runtime) {
query=(char *)"DELETE FROM main.runtime_proxysql_servers";
} else {
query=(char *)"DELETE FROM main.proxysql_servers";
}
proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query);
admindb->execute(query);
resultset=GloProxyCluster->dump_table_proxysql_servers();
if (resultset) {
int rc;
sqlite3_stmt *statement1=NULL;
sqlite3_stmt *statement32=NULL;
sqlite3 *mydb3=admindb->get_db();
char *query1=NULL;
char *query32=NULL;
if (_runtime) {
query1=(char *)"INSERT INTO runtime_proxysql_servers VALUES (?1, ?2, ?3, ?4)";
query32=(char *)"INSERT INTO runtime_proxysql_servers VALUES (?1, ?2, ?3, ?4), (?5, ?6, ?7, ?8), (?9, ?10, ?11, ?12), (?13, ?14, ?15, ?16), (?17, ?18, ?19, ?20), (?21, ?22, ?23, ?24), (?25, ?26, ?27, ?28), (?29, ?30, ?31, ?32), (?33, ?34, ?35, ?36), (?37, ?38, ?39, ?40), (?41, ?42, ?43, ?44), (?45, ?46, ?47, ?48), (?49, ?50, ?51, ?52), (?53, ?54, ?55, ?56), (?57, ?58, ?59, ?60), (?61, ?62, ?63, ?64), (?65, ?66, ?67, ?68), (?69, ?70, ?71, ?72), (?73, ?74, ?75, ?76), (?77, ?78, ?79, ?80), (?81, ?82, ?83, ?84), (?85, ?86, ?87, ?88), (?89, ?90, ?91, ?92), (?93, ?94, ?95, ?96), (?97, ?98, ?99, ?100), (?101, ?102, ?103, ?104), (?105, ?106, ?107, ?108), (?109, ?110, ?111, ?112), (?113, ?114, ?115, ?116), (?117, ?118, ?119, ?120), (?121, ?122, ?123, ?124), (?125, ?126, ?127, ?128)";
} else {
query1=(char *)"INSERT INTO proxysql_servers VALUES (?1, ?2, ?3, ?4)";
query32=(char *)"INSERT INTO proxysql_servers VALUES (?1, ?2, ?3, ?4), (?5, ?6, ?7, ?8), (?9, ?10, ?11, ?12), (?13, ?14, ?15, ?16), (?17, ?18, ?19, ?20), (?21, ?22, ?23, ?24), (?25, ?26, ?27, ?28), (?29, ?30, ?31, ?32), (?33, ?34, ?35, ?36), (?37, ?38, ?39, ?40), (?41, ?42, ?43, ?44), (?45, ?46, ?47, ?48), (?49, ?50, ?51, ?52), (?53, ?54, ?55, ?56), (?57, ?58, ?59, ?60), (?61, ?62, ?63, ?64), (?65, ?66, ?67, ?68), (?69, ?70, ?71, ?72), (?73, ?74, ?75, ?76), (?77, ?78, ?79, ?80), (?81, ?82, ?83, ?84), (?85, ?86, ?87, ?88), (?89, ?90, ?91, ?92), (?93, ?94, ?95, ?96), (?97, ?98, ?99, ?100), (?101, ?102, ?103, ?104), (?105, ?106, ?107, ?108), (?109, ?110, ?111, ?112), (?113, ?114, ?115, ?116), (?117, ?118, ?119, ?120), (?121, ?122, ?123, ?124), (?125, ?126, ?127, ?128)";
}
rc=sqlite3_prepare_v2(mydb3, query1, -1, &statement1, 0);
assert(rc==SQLITE_OK);
rc=sqlite3_prepare_v2(mydb3, query32, -1, &statement32, 0);
assert(rc==SQLITE_OK);
int row_idx=0;
int max_bulk_row_idx=resultset->rows_count/32;
max_bulk_row_idx=max_bulk_row_idx*32;
for (std::vector<SQLite3_row *>::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) {
SQLite3_row *r1=*it;
int idx=row_idx%32;
if (row_idx<max_bulk_row_idx) { // bulk
rc=sqlite3_bind_text(statement32, (idx*4)+1, r1->fields[0], -1, SQLITE_TRANSIENT); assert(rc==SQLITE_OK);
rc=sqlite3_bind_int64(statement32, (idx*4)+2, atoi(r1->fields[1])); assert(rc==SQLITE_OK);
rc=sqlite3_bind_int64(statement32, (idx*4)+3, atoi(r1->fields[2])); assert(rc==SQLITE_OK);
rc=sqlite3_bind_text(statement32, (idx*4)+4, r1->fields[3], -1, SQLITE_TRANSIENT); assert(rc==SQLITE_OK);
if (idx==31) {
SAFE_SQLITE3_STEP(statement32);
rc=sqlite3_clear_bindings(statement32); assert(rc==SQLITE_OK);
rc=sqlite3_reset(statement32); assert(rc==SQLITE_OK);
}
} else { // single row
rc=sqlite3_bind_text(statement1, 1, r1->fields[0], -1, SQLITE_TRANSIENT); assert(rc==SQLITE_OK);
rc=sqlite3_bind_int64(statement1, 2, atoi(r1->fields[1])); assert(rc==SQLITE_OK);
rc=sqlite3_bind_int64(statement1, 3, atoi(r1->fields[2])); assert(rc==SQLITE_OK);
rc=sqlite3_bind_text(statement1, 4, r1->fields[3], -1, SQLITE_TRANSIENT); assert(rc==SQLITE_OK);
SAFE_SQLITE3_STEP(statement1);
rc=sqlite3_clear_bindings(statement1); assert(rc==SQLITE_OK);
rc=sqlite3_reset(statement1); assert(rc==SQLITE_OK);
}
row_idx++;
}
sqlite3_finalize(statement1);
sqlite3_finalize(statement32);
}
if(resultset) delete resultset;
resultset=NULL;
}

@ -0,0 +1,472 @@
#include "proxysql.h"
#include "cpp.h"
#include "SpookyV2.h"
#ifdef DEBUG
#define DEB "_DEBUG"
#else
#define DEB ""
#endif /* DEBUG */
#define PROXYSQL_CLUSTER_VERSION "0.1.0702" DEB
static char *NODE_COMPUTE_DELIMITER=(char *)"-gtyw23a-"; // a random string used for hashing
extern ProxySQL_Cluster * GloProxyCluster;
typedef struct _proxy_node_address_t {
pthread_t thrid;
uint64_t hash; // unused for now
char *hostname;
uint16_t port;
} proxy_node_address_t;
void * ProxySQL_Cluster_Monitor_thread(void *args) {
proxy_node_address_t * node = (proxy_node_address_t *)args;
mysql_thread_init();
pthread_detach(pthread_self());
//char *query1 = (char *)"SELECT 1"; // in future this will be used for "light check"
char *query2 = (char *)"SELECT * FROM stats_mysql_global ORDER BY Variable_Name";
char *username = NULL;
char *password = NULL;
bool rc_bool = true;
MYSQL *conn = mysql_init(NULL);
// goto __exit_monitor_thread;
if (conn==NULL) {
proxy_error("Unable to run mysql_init()\n");
goto __exit_monitor_thread;
}
while (glovars.shutdown == 0 && rc_bool == true) {
MYSQL * rc_conn = NULL;
int rc_query = 0;
if (username) { free(username); }
if (password) { free(password); }
GloProxyCluster->get_credentials(&username, &password);
// TODO: add options, like timeout
if (strlen(username)) { // do not monitor if the username is empty
rc_conn = mysql_real_connect(conn, node->hostname, username, password, NULL, node->port, NULL, 0);
char *query = query2;
if (rc_conn) {
while ( glovars.shutdown == 0 && rc_query == 0 && rc_bool == true) {
unsigned long long before_query_time=monotonic_time();
rc_query = mysql_query(conn,query);
if ( rc_query == 0 ) {
MYSQL_RES *result = mysql_store_result(conn);
unsigned long long after_query_time=monotonic_time();
unsigned long long elapsed_time_us = (after_query_time - before_query_time);
rc_bool = GloProxyCluster->Update_Node_Metrics(node->hostname, node->port, result, elapsed_time_us);
mysql_free_result(result);
unsigned long long elapsed_time_ms = elapsed_time_us / 1000;
int e_ms = (int)elapsed_time_ms;
//fprintf(stderr,"Elapsed time = %d ms\n", e_ms);
int ci = __sync_fetch_and_add(&GloProxyCluster->cluster_check_interval_ms,0);
if (ci > e_ms) {
if (rc_bool) {
usleep((ci-e_ms)*1000); // remember, usleep is in us
}
}
}
}
if (glovars.shutdown == 0) {
// we arent' shutting down, but the query failed
}
if (conn->net.vio) {
mysql_close(conn);
}
} else {
mysql_close(conn);
conn = mysql_init(NULL);
int ci = __sync_fetch_and_add(&GloProxyCluster->cluster_check_interval_ms,0);
usleep((ci)*1000); // remember, usleep is in us
}
} else {
sleep(1); // do not monitor if the username is empty
}
}
__exit_monitor_thread:
//if (conn) {
if (conn->net.vio) {
mysql_close(conn);
}
free(node->hostname);
free(node);
//pthread_exit(0);
mysql_thread_end();
//GloProxyCluster->thread_ending(node->thrid);
return NULL;
}
static uint64_t generate_hash_proxysql_node(char *_hostname, uint16_t _port) {
uint64_t hash1, hash2;
SpookyHash myhash;
myhash.Init(21,12); // rand
myhash.Update(_hostname, strlen(_hostname));
myhash.Update(NODE_COMPUTE_DELIMITER, strlen(NODE_COMPUTE_DELIMITER));
myhash.Update(&_port, sizeof(_port));
myhash.Final(&hash1,&hash2);
return hash1;
}
void ProxySQL_Node_Metrics::reset() {
memset(this, 0, sizeof(ProxySQL_Node_Metrics));
}
ProxySQL_Node_Entry::ProxySQL_Node_Entry(char *_hostname, uint16_t _port, uint64_t _weight, char * _comment) {
hash = 0;
hostname = NULL;
if (_hostname) {
hostname = strdup(_hostname);
}
port = _port;
weight = _weight;
if (_comment == NULL) {
comment = strdup((char *)"");
} else {
comment = strdup(_comment);
}
active = false;
hash = generate_hash_proxysql_node(_hostname, _port);
metrics_idx = 0;
metrics = (ProxySQL_Node_Metrics **)malloc(sizeof(ProxySQL_Node_Metrics *)*PROXYSQL_NODE_METRICS_LEN);
for (int i = 0; i < PROXYSQL_NODE_METRICS_LEN ; i++) {
metrics[i] = new ProxySQL_Node_Metrics();
}
}
ProxySQL_Node_Entry::~ProxySQL_Node_Entry() {
if (hostname) {
free(hostname);
hostname = NULL;
}
if (comment) {
free(comment);
comment = NULL;
}
for (int i = 0; i < PROXYSQL_NODE_METRICS_LEN ; i++) {
delete metrics[i];
metrics[i] = NULL;
}
free(metrics);
metrics = NULL;
}
bool ProxySQL_Node_Entry::get_active() {
return active;
}
void ProxySQL_Node_Entry::set_active(bool a) {
active = a;
}
uint64_t ProxySQL_Node_Entry::get_weight() {
return weight;
}
void ProxySQL_Node_Entry::set_weight(uint64_t w) {
weight = w;
}
void ProxySQL_Node_Entry::set_comment(char *s) {
if (comment) {
free(comment);
}
if (s==NULL) {
comment = strdup((char *)"");
} else {
comment = strdup(s);
}
}
ProxySQL_Node_Metrics * ProxySQL_Node_Entry::get_metrics_curr() {
ProxySQL_Node_Metrics *m = metrics[metrics_idx];
return m;
}
ProxySQL_Node_Metrics * ProxySQL_Node_Entry::get_metrics_prev() {
ProxySQL_Node_Metrics *m = metrics[metrics_idx_prev];
return m;
}
void ProxySQL_Node_Entry::set_metrics(MYSQL_RES *_r, unsigned long long _response_time) {
MYSQL_ROW row;
metrics_idx_prev = metrics_idx;
metrics_idx++;
if (metrics_idx == PROXYSQL_NODE_METRICS_LEN) {
metrics_idx = 0;
}
ProxySQL_Node_Metrics *m = metrics[metrics_idx];
m->reset();
m->read_time_us = monotonic_time();
m->response_time_us = _response_time;
while ((row = mysql_fetch_row(_r))) {
char c = row[0][0];
switch (c) {
case 'C':
if (strcmp(row[0],"Client_Connections_connected")==0) {
m->Client_Connections_connected = atoll(row[1]);
break;
}
if (strcmp(row[0],"Client_Connections_created")==0) {
m->Client_Connections_created = atoll(row[1]);
break;
}
break;
case 'P':
if (strcmp(row[0],"ProxySQL_Uptime")==0) {
m->ProxySQL_Uptime = atoll(row[1]);
}
break;
case 'Q':
if (strcmp(row[0],"Questions")==0) {
m->Questions = atoll(row[1]);
}
break;
case 'S':
if (strcmp(row[0],"Servers_table_version")==0) {
m->Servers_table_version = atoll(row[1]);
}
break;
default:
break;
}
}
}
ProxySQL_Cluster_Nodes::ProxySQL_Cluster_Nodes() {
pthread_mutex_init(&mutex,NULL);
}
void ProxySQL_Cluster_Nodes::set_all_inactive() {
for( std::unordered_map<uint64_t, ProxySQL_Node_Entry *>::iterator it = umap_proxy_nodes.begin(); it != umap_proxy_nodes.end(); ) {
ProxySQL_Node_Entry *node = it->second;
node->set_active(false);
it++;
}
}
void ProxySQL_Cluster_Nodes::remove_inactives() {
for( std::unordered_map<uint64_t, ProxySQL_Node_Entry *>::iterator it = umap_proxy_nodes.begin(); it != umap_proxy_nodes.end(); ) {
ProxySQL_Node_Entry *node = it->second;
if (node->get_active() == false) {
delete node;
it = umap_proxy_nodes.erase(it);
} else {
it++;
}
}
}
ProxySQL_Cluster_Nodes::~ProxySQL_Cluster_Nodes() {
for( std::unordered_map<uint64_t, ProxySQL_Node_Entry *>::iterator it = umap_proxy_nodes.begin(); it != umap_proxy_nodes.end(); ) {
ProxySQL_Node_Entry *node = it->second;
delete node;
it = umap_proxy_nodes.erase(it);
}
}
uint64_t ProxySQL_Cluster_Nodes::generate_hash(char *_hostname, uint16_t _port) {
uint64_t hash_ = generate_hash_proxysql_node(_hostname, _port);
return hash_;
}
void ProxySQL_Cluster_Nodes::load_servers_list(SQLite3_result *resultset) {
pthread_mutex_lock(&mutex);
set_all_inactive();
for (std::vector<SQLite3_row *>::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) {
SQLite3_row *r=*it;
ProxySQL_Node_Entry *node = NULL;
char * h_ = r->fields[0];
uint16_t p_ = atoi(r->fields[1]);
uint64_t w_ = atoi(r->fields[2]);
char * c_ = r->fields[3];
uint64_t hash_ = generate_hash(h_, p_);
std::unordered_map<uint64_t, ProxySQL_Node_Entry *>::iterator ite = umap_proxy_nodes.find(hash_);
if (ite == umap_proxy_nodes.end()) {
node = new ProxySQL_Node_Entry(h_, p_, w_ , c_);
node->set_active(true);
umap_proxy_nodes.insert(std::make_pair(hash_, node));
proxy_node_address_t * a = (proxy_node_address_t *)malloc(sizeof(proxy_node_address_t));
a->hash = 0; // usused for now
a->hostname = strdup(h_);
a->port = p_;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&a->thrid, &attr, ProxySQL_Cluster_Monitor_thread, (void *)a);
//pthread_create(&a->thrid, NULL, ProxySQL_Cluster_Monitor_thread, (void *)a);
//pthread_detach(a->thrid);
} else {
node = ite->second;
node->set_active(true);
node->set_weight(w_);
node->set_comment(c_);
}
}
remove_inactives();
pthread_mutex_unlock(&mutex);
}
// if it returns false , the node doesn't exist anymore and the monitor should stop
bool ProxySQL_Cluster_Nodes::Update_Node_Metrics(char * _h, uint16_t _p, MYSQL_RES *_r, unsigned long long _response_time) {
bool ret = false;
uint64_t hash_ = generate_hash(_h, _p);
pthread_mutex_lock(&mutex);
std::unordered_map<uint64_t, ProxySQL_Node_Entry *>::iterator ite = umap_proxy_nodes.find(hash_);
if (ite != umap_proxy_nodes.end()) {
ProxySQL_Node_Entry * node = ite->second;
node->set_metrics(_r, _response_time);
ret = true;
}
pthread_mutex_unlock(&mutex);
return ret;
}
SQLite3_result * ProxySQL_Cluster_Nodes::stats_proxysql_servers_metrics() {
const int colnum=10;
SQLite3_result *result=new SQLite3_result(colnum);
result->add_column_definition(SQLITE_TEXT,"hostname");
result->add_column_definition(SQLITE_TEXT,"port");
result->add_column_definition(SQLITE_TEXT,"weight");
result->add_column_definition(SQLITE_TEXT,"comment");
result->add_column_definition(SQLITE_TEXT,"response_time_ms");
result->add_column_definition(SQLITE_TEXT,"uptime_s");
result->add_column_definition(SQLITE_TEXT,"last_check_ms");
result->add_column_definition(SQLITE_TEXT,"Queries");
result->add_column_definition(SQLITE_TEXT,"Client_Connections_connected");
result->add_column_definition(SQLITE_TEXT,"Client_Connections_created");
char buf[32];
int k;
pthread_mutex_lock(&mutex);
unsigned long long curtime = monotonic_time();
for( std::unordered_map<uint64_t, ProxySQL_Node_Entry *>::iterator it = umap_proxy_nodes.begin(); it != umap_proxy_nodes.end(); ) {
ProxySQL_Node_Entry * node = it->second;
char **pta=(char **)malloc(sizeof(char *)*colnum);
pta[0]=strdup(node->get_hostname());
sprintf(buf,"%d", node->get_port());
pta[1]=strdup(buf);
sprintf(buf,"%d", node->get_weight());
pta[2]=strdup(buf);
pta[3]=strdup(node->get_comment());
ProxySQL_Node_Metrics *curr = node->get_metrics_curr();
// ProxySQL_Node_Metrics *prev = node->get_metrics_prev();
sprintf(buf,"%llu", curr->response_time_us/1000);
pta[4]=strdup(buf);
sprintf(buf,"%llu", curr->ProxySQL_Uptime);
pta[5]=strdup(buf);
sprintf(buf,"%llu", (curtime - curr->read_time_us)/1000);
pta[6]=strdup(buf);
sprintf(buf,"%llu", curr->Questions);
pta[7]=strdup(buf);
sprintf(buf,"%llu", curr->Client_Connections_connected);
pta[8]=strdup(buf);
sprintf(buf,"%llu", curr->Client_Connections_created);
pta[9]=strdup(buf);
result->add_row(pta);
for (k=0; k<colnum; k++) {
if (pta[k])
free(pta[k]);
}
free(pta);
it++;
}
pthread_mutex_unlock(&mutex);
return result;
}
SQLite3_result * ProxySQL_Cluster_Nodes::dump_table_proxysql_servers() {
const int colnum=4;
SQLite3_result *result=new SQLite3_result(colnum);
result->add_column_definition(SQLITE_TEXT,"hostname");
result->add_column_definition(SQLITE_TEXT,"port");
result->add_column_definition(SQLITE_TEXT,"weight");
result->add_column_definition(SQLITE_TEXT,"comment");
char buf[32];
int k;
pthread_mutex_lock(&mutex);
for( std::unordered_map<uint64_t, ProxySQL_Node_Entry *>::iterator it = umap_proxy_nodes.begin(); it != umap_proxy_nodes.end(); ) {
ProxySQL_Node_Entry * node = it->second;
char **pta=(char **)malloc(sizeof(char *)*colnum);
pta[0]=strdup(node->get_hostname());
sprintf(buf,"%d", node->get_port());
pta[1]=strdup(buf);
sprintf(buf,"%d", node->get_weight());
pta[2]=strdup(buf);
pta[3]=strdup(node->get_comment());
result->add_row(pta);
for (k=0; k<colnum; k++) {
if (pta[k])
free(pta[k]);
}
free(pta);
it++;
}
pthread_mutex_unlock(&mutex);
return result;
}
ProxySQL_Cluster::ProxySQL_Cluster() {
pthread_mutex_init(&mutex,NULL);
cluster_username = strdup((char *)"");
cluster_password = strdup((char *)"");
cluster_check_interval_ms = 1000;
}
ProxySQL_Cluster::~ProxySQL_Cluster() {
if (cluster_username) {
free(cluster_username);
cluster_username = NULL;
}
if (cluster_password) {
free(cluster_password);
cluster_password = NULL;
}
}
// this function returns credentials to the caller, used by monitoring threads
void ProxySQL_Cluster::get_credentials(char **username, char **password) {
pthread_mutex_lock(&mutex);
*username = strdup(cluster_username);
*password = strdup(cluster_password);
pthread_mutex_unlock(&mutex);
}
void ProxySQL_Cluster::set_username(char *_username) {
pthread_mutex_lock(&mutex);
free(cluster_username);
cluster_username=strdup(_username);
pthread_mutex_unlock(&mutex);
}
void ProxySQL_Cluster::set_password(char *_password) {
pthread_mutex_lock(&mutex);
free(cluster_password);
cluster_password=strdup(_password);
pthread_mutex_unlock(&mutex);
}
void ProxySQL_Cluster::print_version() {
fprintf(stderr,"Standard ProxySQL Cluster rev. %s -- %s -- %s\n", PROXYSQL_CLUSTER_VERSION, __FILE__, __TIMESTAMP__);
};
void ProxySQL_Cluster::thread_ending(pthread_t _t) {
pthread_mutex_lock(&mutex);
term_threads.push_back(_t);
pthread_mutex_unlock(&mutex);
}
void ProxySQL_Cluster::join_term_thread() {
pthread_mutex_lock(&mutex);
while (!term_threads.empty()) {
pthread_t t = term_threads.back();
term_threads.pop_back();
pthread_join(t,NULL);
}
pthread_mutex_unlock(&mutex);
}

@ -189,6 +189,9 @@ std::thread *MyMon_thread;
MySQL_Logger *GloMyLogger;
ProxySQL_Cluster *GloProxyCluster = NULL;
void * mysql_worker_thread_func(void *arg) {
// __thr_sfp=l_mem_init();
@ -314,9 +317,12 @@ void ProxySQL_Main_init_main_modules() {
void ProxySQL_Main_init_Admin_module() {
// cluster module needs to be initialized before
GloProxyCluster = new ProxySQL_Cluster();
GloProxyCluster->init();
GloProxyCluster->print_version();
GloAdmin = new ProxySQL_Admin();
GloAdmin->init();
// GloAdmin->flush_error_log();
GloAdmin->print_version();
}

Loading…
Cancel
Save