Added tables 'stats_mysql_client_host_cache' and 'stats_mysql_client_host_cache_reset' exposing entries in 'client_host_cache'

pull/3617/head
Javier Jaramago Fernández 5 years ago
parent 514ffe939a
commit 416a0470a5

@ -596,6 +596,15 @@ class MySQL_Threads_Handler
* - 'address_family' is either 'AF_INET' or 'AF_INET6'.
* - The address obtained from it isn't '127.0.0.1'.
*
* In case 'client_sockaddr' matches the previous description, the update
* of the client host cache is performed in the following way:
* 1. If the cache is full, the oldest element in the cache is searched.
* In case the oldest element address doesn't match the supplied
* address, the oldest element is removed.
* 2. The cache is searched looking for the supplied address, in case of
* being found, the entry is updated, otherwise the entry is inserted in
* the cache.
*
* @param client_sockaddr A 'sockaddr' holding the required client information
* to update the 'client_host_cache_map'.
* @param error 'true' if there was an error in the connection that should be
@ -628,6 +637,22 @@ class MySQL_Threads_Handler
* @brief Delete all the entries in the 'client_host_cache' internal map.
*/
void flush_client_host_cache();
/**
* @brief Returns the current entries of 'client_host_cache' in a
* 'SQLite3_result'. In case the param 'reset' is specified, the structure
* is cleaned after being queried.
*
* @param reset If 'true' the entries of the internal structure
* 'client_host_cache' will be cleaned after scrapping.
*
* @return SQLite3_result holding the current entries of the
* 'client_host_cache'. In the following format:
*
* [ 'client_address', 'error_num', 'last_updated' ]
*
* Where 'last_updated' is the last updated time expressed in 'ns'.
*/
SQLite3_result* get_client_host_cache(bool reset);
/**
* @brief Callback to update the metrics.
*/

@ -355,6 +355,7 @@ class ProxySQL_Admin {
void stats___proxysql_servers_metrics();
void stats___mysql_prepared_statements_info();
void stats___mysql_gtid_executed();
void stats___mysql_client_host_cache(bool reset);
// Update prometheus metrics
void p_stats___memory_metrics();

@ -2443,6 +2443,77 @@ MySQL_Client_Host_Cache_Entry MySQL_Threads_Handler::find_client_host_cache(stru
return entry;
}
/**
* @brief Number of columns for representing a 'MySQL_Client_Host_Cache_Entry'
* in a 'SQLite3_result'.
*/
const int CLIENT_HOST_CACHE_COLUMNS = 3;
/**
* @brief Helper function that converts a given client address and a
* 'MySQL_Client_Host_Cache_Entry', into a row for a 'SQLite3_result' for
* table 'STATS_SQLITE_TABLE_MYSQL_CLIENT_HOST_CACHE'.
*
* @param address The client address to be added to the resulset row.
* @param entry The 'MySQL_Client_Host_Cache_Entry' to be added to the resulset
* row.
*
* @return A pointer array holding the values for each of the columns of the
* row. It should be freed through helper function 'free_client_host_cache_row'.
*/
char** client_host_cache_entry_row(
const std::string address, const MySQL_Client_Host_Cache_Entry& entry
) {
// INET6_ADDRSTRLEN length should be enough for holding any member:
// { address: MAX INET6_ADDRSTRLEN, updated_at: uint64_t, error_count: uint32_t }
char buff[INET6_ADDRSTRLEN];
char** row =
static_cast<char**>(malloc(sizeof(char*)*CLIENT_HOST_CACHE_COLUMNS));
row[0]=strdup(address.c_str());
sprintf(buff, "%u", entry.error_count);
row[1]=strdup(buff);
sprintf(buff, "%lu", entry.updated_at);
row[2]=strdup(buff);
return row;
}
/**
* @brief Helper function to free the row returned by
* 'client_host_cache_entry_row'.
*
* @param row The pointer array holding the row values to be freed.
*/
void free_client_host_cache_row(char** row) {
for (int i = 0; i < CLIENT_HOST_CACHE_COLUMNS; i++) {
free(row[i]);
}
free(row);
}
SQLite3_result* MySQL_Threads_Handler::get_client_host_cache(bool reset) {
SQLite3_result *result = new SQLite3_result(CLIENT_HOST_CACHE_COLUMNS);
pthread_mutex_lock(&mutex_client_host_cache);
result->add_column_definition(SQLITE_TEXT,"client_address");
result->add_column_definition(SQLITE_TEXT,"error_count");
result->add_column_definition(SQLITE_TEXT,"last_updated");
for (const auto& cache_entry : client_host_cache) {
char** row = client_host_cache_entry_row(cache_entry.first, cache_entry.second);
result->add_row(row);
free_client_host_cache_row(row);
}
if (reset) {
client_host_cache.clear();
}
pthread_mutex_unlock(&mutex_client_host_cache);
return result;
}
void MySQL_Threads_Handler::update_client_host_cache(struct sockaddr* client_sockaddr, bool error) {
if (client_sockaddr->sa_family != AF_INET && client_sockaddr->sa_family != AF_INET6) {
return;

@ -490,6 +490,9 @@ static int http_handler(void *cls, struct MHD_Connection *connection, const char
#define STATS_SQLITE_TABLE_MYSQL_ERRORS "CREATE TABLE stats_mysql_errors (hostgroup INT NOT NULL , hostname VARCHAR NOT NULL , port INT NOT NULL , username VARCHAR NOT NULL , client_address VARCHAR NOT NULL , schemaname VARCHAR NOT NULL , errno INT NOT NULL , count_star INTEGER NOT NULL , first_seen INTEGER NOT NULL , last_seen INTEGER NOT NULL , last_error VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostgroup, hostname, port, username, schemaname, errno) )"
#define STATS_SQLITE_TABLE_MYSQL_ERRORS_RESET "CREATE TABLE stats_mysql_errors_reset (hostgroup INT NOT NULL , hostname VARCHAR NOT NULL , port INT NOT NULL , username VARCHAR NOT NULL , client_address VARCHAR NOT NULL , schemaname VARCHAR NOT NULL , errno INT NOT NULL , count_star INTEGER NOT NULL , first_seen INTEGER NOT NULL , last_seen INTEGER NOT NULL , last_error VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostgroup, hostname, port, username, schemaname, errno) )"
#define STATS_SQLITE_TABLE_MYSQL_CLIENT_HOST_CACHE "CREATE TABLE stats_mysql_client_host_cache (client_address VARCHAR NOT NULL, error_count INT NOT NULL, last_updated BIGINT NOT NULL)"
#define STATS_SQLITE_TABLE_MYSQL_CLIENT_HOST_CACHE_RESET "CREATE TABLE stats_mysql_client_host_cache_reset (client_address VARCHAR NOT NULL, error_count INT NOT NULL, last_updated BIGINT NOT NULL)"
#ifdef DEBUG
#define ADMIN_SQLITE_TABLE_DEBUG_LEVELS "CREATE TABLE debug_levels (module VARCHAR NOT NULL PRIMARY KEY , verbosity INT NOT NULL DEFAULT 0)"
#define ADMIN_SQLITE_TABLE_DEBUG_FILTERS "CREATE TABLE debug_filters (filename VARCHAR NOT NULL , line INT NOT NULL , funct VARCHAR NOT NULL , PRIMARY KEY (filename, line, funct) )"
@ -2936,6 +2939,8 @@ bool ProxySQL_Admin::GenericRefreshStatistics(const char *query_no_space, unsign
bool stats_mysql_query_rules=false;
bool stats_mysql_users=false;
bool stats_mysql_gtid_executed=false;
bool stats_mysql_client_host_cache=false;
bool stats_mysql_client_host_cache_reset=false;
bool dump_global_variables=false;
bool runtime_scheduler=false;
@ -3023,6 +3028,10 @@ bool ProxySQL_Admin::GenericRefreshStatistics(const char *query_no_space, unsign
{ stats_mysql_users=true; refresh=true; }
if (strstr(query_no_space,"stats_mysql_gtid_executed"))
{ stats_mysql_gtid_executed=true; refresh=true; }
if (strstr(query_no_space,"stats_mysql_client_host_cache"))
{ stats_mysql_client_host_cache=true; refresh=true; }
if (strstr(query_no_space,"stats_mysql_client_host_cache_reset"))
{ stats_mysql_client_host_cache_reset=true; refresh=true; }
if (strstr(query_no_space,"stats_proxysql_servers_checksums"))
{ stats_proxysql_servers_checksums = true; refresh = true; }
@ -3163,6 +3172,13 @@ bool ProxySQL_Admin::GenericRefreshStatistics(const char *query_no_space, unsign
stats___mysql_prepared_statements_info();
}
if (stats_mysql_client_host_cache) {
stats___mysql_client_host_cache(false);
}
if (stats_mysql_client_host_cache_reset) {
stats___mysql_client_host_cache(true);
}
if (admin) {
if (dump_global_variables) {
pthread_mutex_lock(&GloVars.checksum_mutex);
@ -5537,6 +5553,8 @@ 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
insert_into_tables_defs(tables_defs_stats,"stats_mysql_prepared_statements_info", ADMIN_SQLITE_TABLE_STATS_MYSQL_PREPARED_STATEMENTS_INFO);
insert_into_tables_defs(tables_defs_stats,"stats_mysql_client_host_cache", STATS_SQLITE_TABLE_MYSQL_CLIENT_HOST_CACHE);
insert_into_tables_defs(tables_defs_stats,"stats_mysql_client_host_cache_reset", STATS_SQLITE_TABLE_MYSQL_CLIENT_HOST_CACHE_RESET);
// ProxySQL Cluster
insert_into_tables_defs(tables_defs_admin,"proxysql_servers", ADMIN_SQLITE_TABLE_PROXYSQL_SERVERS);
@ -8770,6 +8788,50 @@ void ProxySQL_Admin::stats___mysql_query_digests(bool reset, bool copy) {
delete resultset;
}
void ProxySQL_Admin::stats___mysql_client_host_cache(bool reset) {
if (!GloQPro) return;
SQLite3_result* resultset = GloMTH->get_client_host_cache(reset);
if (resultset==NULL) return;
statsdb->execute("BEGIN");
int rc = 0;
sqlite3_stmt* statement=NULL;
char* query = NULL;
if (reset) {
query=(char*)"INSERT INTO stats_mysql_client_host_cache_reset VALUES (?1, ?2, ?3)";
} else {
query=(char*)"INSERT INTO stats_mysql_client_host_cache VALUES (?1, ?2, ?3)";
}
if (reset) {
statsdb->execute("DELETE FROM stats_mysql_client_host_cache_reset");
} else {
statsdb->execute("DELETE FROM stats_mysql_client_host_cache");
}
rc = statsdb->prepare_v2(query, &statement);
ASSERT_SQLITE_OK(rc, statsdb);
for (std::vector<SQLite3_row *>::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) {
SQLite3_row *row = *it;
rc=(*proxy_sqlite3_bind_text)(statement, 1, row->fields[0], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb);
rc=(*proxy_sqlite3_bind_int64)(statement, 2, atoll(row->fields[1])); ASSERT_SQLITE_OK(rc, statsdb);
rc=(*proxy_sqlite3_bind_int64)(statement, 3, atoll(row->fields[2])); ASSERT_SQLITE_OK(rc, statsdb);
SAFE_SQLITE3_STEP2(statement);
rc=(*proxy_sqlite3_clear_bindings)(statement);
rc=(*proxy_sqlite3_reset)(statement);
}
(*proxy_sqlite3_finalize)(statement);
statsdb->execute("COMMIT");
delete resultset;
}
void ProxySQL_Admin::stats___mysql_errors(bool reset) {
if (!GloQPro) return;
SQLite3_result * resultset=NULL;

Loading…
Cancel
Save