diff --git a/include/ProxySQL_Cluster.hpp b/include/ProxySQL_Cluster.hpp index eab5292cce..92d81efdec 100644 --- a/include/ProxySQL_Cluster.hpp +++ b/include/ProxySQL_Cluster.hpp @@ -378,6 +378,11 @@ struct fetch_query { std::string msgs[3]; }; +struct cluster_creds_t { + string user; + string pass; +}; + class ProxySQL_Cluster { private: SQLite3DB* mydb; @@ -444,7 +449,7 @@ class ProxySQL_Cluster { MySQL_Monitor::trigger_dns_cache_update(); } - void get_credentials(char**, char**); + cluster_creds_t get_credentials(); void set_username(char*); void set_password(char*); void set_admin_mysql_ifaces(char*); diff --git a/lib/GTID_Server_Data.cpp b/lib/GTID_Server_Data.cpp index 6dbf572354..d721bfd1b0 100644 --- a/lib/GTID_Server_Data.cpp +++ b/lib/GTID_Server_Data.cpp @@ -113,7 +113,6 @@ void connect_cb(EV_P_ ev_io *w, int revents) { } struct ev_io * new_connector(char *address, uint16_t gtid_port, uint16_t mysql_port) { - //struct sockaddr_in a; int s; if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { @@ -121,16 +120,7 @@ struct ev_io * new_connector(char *address, uint16_t gtid_port, uint16_t mysql_p close(s); return NULL; } -/* - memset(&a, 0, sizeof(a)); - a.sin_port = htons(gtid_port); - a.sin_family = AF_INET; - if (!inet_aton(address, (struct in_addr *) &a.sin_addr.s_addr)) { - perror("bad IP address format"); - close(s); - return NULL; - } -*/ + ioctl_FIONBIO(s,1); struct addrinfo hints; @@ -142,6 +132,7 @@ struct ev_io * new_connector(char *address, uint16_t gtid_port, uint16_t mysql_p char str_port[NI_MAXSERV+1]; sprintf(str_port,"%d", gtid_port); + int gai_rc = getaddrinfo(address, str_port, &hints, &res); if (gai_rc) { freeaddrinfo(res); @@ -149,8 +140,11 @@ struct ev_io * new_connector(char *address, uint16_t gtid_port, uint16_t mysql_p return NULL; } - //int status = connect(s, (struct sockaddr *) &a, sizeof(a)); int status = connect(s, res->ai_addr, res->ai_addrlen); + + // Free linked list + freeaddrinfo(res); + if ((status == 0) || ((status == -1) && (errno == EINPROGRESS))) { struct ev_io *c = (struct ev_io *)malloc(sizeof(struct ev_io)); if (c) { diff --git a/lib/MySQL_Monitor.cpp b/lib/MySQL_Monitor.cpp index a943f10a98..2d518109b0 100644 --- a/lib/MySQL_Monitor.cpp +++ b/lib/MySQL_Monitor.cpp @@ -4091,6 +4091,14 @@ void* monitor_GR_thread_HG(void *arg) { // 3. Delegate the async fetching + actions of 'MySQL_Monitor_State_Data' with conns on 'Monitor_Poll'. /////////////////////////////////////////////////////////////////////////////////////// + // NOTE: This is just a best effort to avoid invalid memory accesses during 'SHUTDOWN SLOW'. Since the + // previous section is 'time consuming', there are good changes that we can detect a shutdown before + // trying to perform the monitoring actions on the acquired 'mmsd'. This exact scenario and timing has + // been previously observed in the CI. + if (GloMyMon->shutdown) { + break; + } + // Handle 'mmsds' that failed to optain conns for (const unique_ptr& mmsd : fail_mmsds) { async_gr_mon_actions_handler(mmsd.get()); diff --git a/lib/ProxySQL_Admin.cpp b/lib/ProxySQL_Admin.cpp index 39e4175201..61fe3af6ed 100644 --- a/lib/ProxySQL_Admin.cpp +++ b/lib/ProxySQL_Admin.cpp @@ -6033,6 +6033,7 @@ ProxySQL_Admin::ProxySQL_Admin() : variables.p_memory_metrics_interval = 61; #ifdef DEBUG variables.debug=GloVars.global.gdbg; + all_modules_started = false; debug_output = 1; proxysql_set_admin_debug_output(debug_output); #endif /* DEBUG */ @@ -6388,6 +6389,8 @@ bool ProxySQL_Admin::init(const bootstrap_info_t& bootstrap_info) { Admin_HTTP_Server = NULL; AdminRestApiServer = NULL; + AdminHTTPServer = NULL; + /* AdminRestApiServer = new ProxySQL_RESTAPI_Server(); AdminRestApiServer->print_version(); diff --git a/lib/ProxySQL_Cluster.cpp b/lib/ProxySQL_Cluster.cpp index 514182b491..64a870c9e3 100644 --- a/lib/ProxySQL_Cluster.cpp +++ b/lib/ProxySQL_Cluster.cpp @@ -63,28 +63,20 @@ void * ProxySQL_Cluster_Monitor_thread(void *args) { char *query1 = (char *)"SELECT GLOBAL_CHECKSUM()"; // in future this will be used for "light check" char *query2 = (char *)"SELECT * FROM stats_mysql_global ORDER BY Variable_Name"; char *query3 = (char *)"SELECT * FROM runtime_checksums_values ORDER BY name"; - char *username = NULL; - char *password = NULL; bool rc_bool = true; int query_error_counter = 0; char *query_error = NULL; int cluster_check_status_frequency_count = 0; 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; - bool update_checksum = false; - if (username) { free(username); } - if (password) { free(password); } - GloProxyCluster->get_credentials(&username, &password); - if (strlen(username)) { // do not monitor if the username is empty - unsigned int timeout = 1; - // unsigned int timeout_long = 60; + cluster_creds_t creds(GloProxyCluster->get_credentials()); + + if (creds.user.size()) { // do not monitor if the username is empty if (conn == NULL) { conn = mysql_init(NULL); if (conn==NULL) { @@ -92,23 +84,22 @@ void * ProxySQL_Cluster_Monitor_thread(void *args) { goto __exit_monitor_thread; } } + // READ/WRITE timeouts were enforced as an attempt to prevent deadlocks in the original + // implementation. They were proven unnecessary, leaving only 'CONNECT_TIMEOUT'. + unsigned int timeout = 1; mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &timeout); - //mysql_options(conn, MYSQL_OPT_READ_TIMEOUT, &timeout_long); - //mysql_options(conn, MYSQL_OPT_WRITE_TIMEOUT, &timeout); { unsigned char val = 1; mysql_options(conn, MYSQL_OPT_SSL_ENFORCE, &val); mysql_options(conn, MARIADB_OPT_SSL_KEYLOG_CALLBACK, (void*)proxysql_keylog_write_line_callback); } - //rc_conn = mysql_real_connect(conn, node->hostname, username, password, NULL, node->port, NULL, CLIENT_COMPRESS); // FIXME: add optional support for compression + // FIXME: add optional support for compression proxy_debug(PROXY_DEBUG_CLUSTER, 5, "Connecting to peer %s:%d\n", node->hostname, node->port); - rc_conn = mysql_real_connect(conn, node->get_host_address(), username, password, NULL, node->port, NULL, 0); -// if (rc_conn) { -// } - //char *query = query1; + MYSQL* rc_conn = mysql_real_connect(conn, node->get_host_address(), creds.user.c_str(), creds.pass.c_str(), NULL, node->port, NULL, 0); + if (rc_conn) { MySQL_Monitor::update_dns_cache_from_mysql_conn(conn); - rc_query = mysql_query(conn,(char *)"SELECT @@version"); + int rc_query = mysql_query(conn,(char *)"SELECT @@version"); if (rc_query == 0) { query_error = NULL; query_error_counter = 0; @@ -151,7 +142,7 @@ void * ProxySQL_Cluster_Monitor_thread(void *args) { } while ( glovars.shutdown == 0 && rc_query == 0 && rc_bool == true) { unsigned long long start_time=monotonic_time(); - //unsigned long long before_query_time=monotonic_time(); + rc_query = mysql_query(conn,query1); if ( rc_query == 0 ) { query_error = NULL; @@ -159,23 +150,11 @@ void * ProxySQL_Cluster_Monitor_thread(void *args) { 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); - update_checksum = GloProxyCluster->Update_Global_Checksum(node->hostname, node->port, result); + bool update_checksum = GloProxyCluster->Update_Global_Checksum(node->hostname, node->port, result); mysql_free_result(result); // FIXME: update metrics are not updated for now. We only check checksum //rc_bool = GloProxyCluster->Update_Node_Metrics(node->hostname, node->port, result, elapsed_time_us); - //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 - } - } -*/ - //query = query3; - //unsigned long long before_query_time2=monotonic_time(); + if (update_checksum) { unsigned long long before_query_time=monotonic_time(); rc_query = mysql_query(conn,query3); @@ -183,37 +162,22 @@ void * ProxySQL_Cluster_Monitor_thread(void *args) { query_error = NULL; query_error_counter = 0; MYSQL_RES *result = mysql_store_result(conn); - //unsigned long long after_query_time2=monotonic_time(); - //unsigned long long elapsed_time_us2 = (after_query_time2 - before_query_time2); rc_bool = GloProxyCluster->Update_Node_Checksums(node->hostname, node->port, result); mysql_free_result(result); - //unsigned long long elapsed_time_ms2 = elapsed_time_us2 / 1000; - //int e_ms = (int)elapsed_time_ms + int(elapsed_time_ms2); - //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) { - // tts = 1; - // //usleep((ci-e_ms)*1000); // remember, usleep is in us - // } - //} } else { query_error = query3; if (query_error_counter == 0) { unsigned long long after_query_time=monotonic_time(); unsigned long long elapsed_time_us = (after_query_time - before_query_time); - proxy_error("Cluster: unable to run query on %s:%d using user %s after %llums : %s . Error: %s\n", node->hostname, node->port , username, elapsed_time_us/1000 , query_error, mysql_error(conn)); + proxy_error( + "Cluster: unable to run query on %s:%d using user %s after %llums : %s . Error: %s\n", + node->hostname, node->port, creds.user.c_str(), elapsed_time_us/1000, query_error, mysql_error(conn) + ); } if (++query_error_counter == QUERY_ERROR_RATE) query_error_counter = 0; } } else { GloProxyCluster->Update_Node_Checksums(node->hostname, node->port); - //int ci = __sync_fetch_and_add(&GloProxyCluster->cluster_check_interval_ms,0); - //if (ci > elapsed_time_ms) { - // if (rc_bool) { - // usleep((ci-elapsed_time_ms)*1000); // remember, usleep is in us - // } - //} } if (rc_query == 0) { cluster_check_status_frequency_count++; @@ -235,7 +199,10 @@ void * ProxySQL_Cluster_Monitor_thread(void *args) { if (query_error_counter == 0) { unsigned long long after_query_time=monotonic_time(); unsigned long long elapsed_time_us = (after_query_time - before_query_time); - proxy_error("Cluster: unable to run query on %s:%d using user %s after %llums : %s . Error: %s\n", node->hostname, node->port , username, elapsed_time_us/1000 , query_error, mysql_error(conn)); + proxy_error( + "Cluster: unable to run query on %s:%d using user %s after %llums : %s . Error: %s\n", + node->hostname, node->port, creds.user.c_str(), elapsed_time_us/1000, query_error, mysql_error(conn) + ); } if (++query_error_counter == QUERY_ERROR_RATE) query_error_counter = 0; } @@ -246,7 +213,10 @@ void * ProxySQL_Cluster_Monitor_thread(void *args) { if (query_error_counter == 0) { unsigned long long after_query_time=monotonic_time(); unsigned long long elapsed_time_us = (after_query_time - start_time); - proxy_error("Cluster: unable to run query on %s:%d using user %s after %llums : %s . Error: %s\n", node->hostname, node->port , username, elapsed_time_us/1000, query_error, mysql_error(conn)); + proxy_error( + "Cluster: unable to run query on %s:%d using user %s after %llums : %s . Error: %s\n", + node->hostname, node->port, creds.user.c_str(), elapsed_time_us/1000, query_error, mysql_error(conn) + ); } if (++query_error_counter == QUERY_ERROR_RATE) query_error_counter = 0; } @@ -290,9 +260,7 @@ void * ProxySQL_Cluster_Monitor_thread(void *args) { } proxy_info("Cluster: closing thread for peer %s:%d\n", node->hostname, node->port); delete node; - //pthread_exit(0); mysql_thread_end(); - //GloProxyCluster->thread_ending(node->thrid); __sync_fetch_and_sub(&GloVars.statuses.stack_memory_cluster_threads,tmp_stack_size); @@ -1176,40 +1144,38 @@ void ProxySQL_Cluster::pull_mysql_query_rules_from_peer(const string& expected_c pthread_mutex_lock(&GloProxyCluster->update_mysql_query_rules_mutex); nodes.get_peer_to_sync_mysql_query_rules(&hostname, &port, &ip_address); if (hostname) { - char *username = NULL; - char *password = NULL; - // bool rc_bool = true; - MYSQL *rc_conn; - int rc_query; - int rc; + cluster_creds_t creds {}; + MYSQL *conn = mysql_init(NULL); if (conn==NULL) { proxy_error("Unable to run mysql_init()\n"); goto __exit_pull_mysql_query_rules_from_peer; } - GloProxyCluster->get_credentials(&username, &password); - if (strlen(username)) { // do not monitor if the username is empty + + creds = GloProxyCluster->get_credentials(); + if (creds.user.size()) { // do not monitor if the username is empty + // READ/WRITE timeouts were enforced as an attempt to prevent deadlocks in the original + // implementation. They were proven unnecessary, leaving only 'CONNECT_TIMEOUT'. unsigned int timeout = 1; - // unsigned int timeout_long = 60; mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &timeout); - //mysql_options(conn, MYSQL_OPT_READ_TIMEOUT, &timeout_long); - //mysql_options(conn, MYSQL_OPT_WRITE_TIMEOUT, &timeout); { unsigned char val = 1; mysql_options(conn, MYSQL_OPT_SSL_ENFORCE, &val); mysql_options(conn, MARIADB_OPT_SSL_KEYLOG_CALLBACK, (void*)proxysql_keylog_write_line_callback); } proxy_debug(PROXY_DEBUG_CLUSTER, 5, "Fetching MySQL Query Rules from peer %s:%d started. Expected checksum: %s\n", hostname, port, expected_checksum.c_str()); proxy_info("Cluster: Fetching MySQL Query Rules from peer %s:%d started. Expected checksum: %s\n", hostname, port, expected_checksum.c_str()); - rc_conn = mysql_real_connect(conn, ip_address ? ip_address : hostname, username, password, NULL, port, NULL, 0); + MYSQL* rc_conn = mysql_real_connect( + conn, ip_address ? ip_address : hostname, creds.user.c_str(), creds.pass.c_str(), NULL, port, NULL, 0 + ); if (rc_conn) { MySQL_Monitor::update_dns_cache_from_mysql_conn(conn); MYSQL_RES *result1 = NULL; MYSQL_RES *result2 = NULL; //rc_query = mysql_query(conn,"SELECT rule_id, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, ok_msg, sticky_conn, multiplex, gtid_from_hostgroup, log, apply, attributes, comment FROM runtime_mysql_query_rules"); - rc_query = mysql_query(conn,CLUSTER_QUERY_MYSQL_QUERY_RULES); + int rc_query = mysql_query(conn,CLUSTER_QUERY_MYSQL_QUERY_RULES); if ( rc_query == 0 ) { - MYSQL_RES *result1 = mysql_store_result(conn); + result1 = mysql_store_result(conn); rc_query = mysql_query(conn,CLUSTER_QUERY_MYSQL_QUERY_RULES_FAST_ROUTING); if ( rc_query == 0) { result2 = mysql_store_result(conn); @@ -1237,7 +1203,7 @@ void ProxySQL_Cluster::pull_mysql_query_rules_from_peer(const string& expected_c sqlite3_stmt *statement1 = NULL; //sqlite3 *mydb3 = GloAdmin->admindb->get_db(); //rc=(*proxy_sqlite3_prepare_v2)(mydb3, q, -1, &statement1, 0); - rc = GloAdmin->admindb->prepare_v2(q, &statement1); + int rc = GloAdmin->admindb->prepare_v2(q, &statement1); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); GloAdmin->admindb->execute("BEGIN TRANSACTION"); while ((row = mysql_fetch_row(result1))) { @@ -1280,6 +1246,7 @@ void ProxySQL_Cluster::pull_mysql_query_rules_from_peer(const string& expected_c rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); } + (*proxy_sqlite3_finalize)(statement1); GloAdmin->admindb->execute("COMMIT"); @@ -1323,6 +1290,8 @@ void ProxySQL_Cluster::pull_mysql_query_rules_from_peer(const string& expected_c } row_idx++; } + (*proxy_sqlite3_finalize)(statement1fr); + (*proxy_sqlite3_finalize)(statement32fr); //GloAdmin->admindb->execute("PRAGMA integrity_check"); GloAdmin->admindb->execute("COMMIT"); @@ -1470,22 +1439,20 @@ void ProxySQL_Cluster::pull_mysql_users_from_peer(const string& expected_checksu pthread_mutex_lock(&GloProxyCluster->update_mysql_users_mutex); nodes.get_peer_to_sync_mysql_users(&hostname, &port, &ip_address); if (hostname) { - char *username = NULL; - char *password = NULL; - MYSQL *rc_conn; - int rc_query; + cluster_creds_t creds {}; + MYSQL *conn = mysql_init(NULL); if (conn==NULL) { proxy_error("Unable to run mysql_init()\n"); goto __exit_pull_mysql_users_from_peer; } - GloProxyCluster->get_credentials(&username, &password); - if (strlen(username)) { // do not monitor if the username is empty + + creds = GloProxyCluster->get_credentials(); + if (creds.user.size()) { // do not monitor if the username is empty + // READ/WRITE timeouts were enforced as an attempt to prevent deadlocks in the original + // implementation. They were proven unnecessary, leaving only 'CONNECT_TIMEOUT'. unsigned int timeout = 1; - // unsigned int timeout_long = 60; mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &timeout); - //mysql_options(conn, MYSQL_OPT_READ_TIMEOUT, &timeout_long); - //mysql_options(conn, MYSQL_OPT_WRITE_TIMEOUT, &timeout); { unsigned char val = 1; mysql_options(conn, MYSQL_OPT_SSL_ENFORCE, &val); mysql_options(conn, MARIADB_OPT_SSL_KEYLOG_CALLBACK, (void*)proxysql_keylog_write_line_callback); @@ -1493,7 +1460,7 @@ void ProxySQL_Cluster::pull_mysql_users_from_peer(const string& expected_checksu proxy_debug(PROXY_DEBUG_CLUSTER, 5, "Fetching MySQL Users from peer %s:%d started. Expected checksum: %s\n", hostname, port, expected_checksum.c_str()); proxy_info("Cluster: Fetching MySQL Users from peer %s:%d started. Expected checksum: %s\n", hostname, port, expected_checksum.c_str()); - rc_conn = mysql_real_connect(conn, ip_address ? ip_address : hostname, username, password, NULL, port, NULL, 0); + MYSQL* rc_conn = mysql_real_connect(conn, ip_address ? ip_address : hostname, creds.user.c_str(), creds.pass.c_str(), NULL, port, NULL, 0); if (rc_conn == nullptr) { proxy_debug(PROXY_DEBUG_CLUSTER, 5, "Fetching MySQL Users from peer %s:%d failed: %s\n", hostname, port, mysql_error(conn)); proxy_info("Cluster: Fetching MySQL Users from peer %s:%d failed: %s\n", hostname, port, mysql_error(conn)); @@ -1512,7 +1479,7 @@ void ProxySQL_Cluster::pull_mysql_users_from_peer(const string& expected_checksu MySQL_Monitor::update_dns_cache_from_mysql_conn(conn); - rc_query = mysql_query(conn, CLUSTER_QUERY_MYSQL_USERS); + int rc_query = mysql_query(conn, CLUSTER_QUERY_MYSQL_USERS); if (rc_query == 0) { MYSQL_RES* mysql_users_result = mysql_store_result(conn); MYSQL_RES* ldap_mapping_result = nullptr; @@ -1621,12 +1588,6 @@ void ProxySQL_Cluster::pull_mysql_users_from_peer(const string& expected_checksu } } } - if (username) { - free(username); - } - if (password) { - free(password); - } __exit_pull_mysql_users_from_peer: if (conn) { if (conn->net.pvio) { @@ -1771,17 +1732,18 @@ void ProxySQL_Cluster::pull_runtime_mysql_servers_from_peer(const runtime_mysql_ pthread_mutex_lock(&GloProxyCluster->update_runtime_mysql_servers_mutex); nodes.get_peer_to_sync_runtime_mysql_servers(&hostname, &port, &peer_checksum, &ip_address); if (hostname) { - char *username = NULL; - char *password = NULL; - // bool rc_bool = true; - MYSQL *rc_conn; + cluster_creds_t creds {}; + MYSQL *conn = mysql_init(NULL); if (conn==NULL) { proxy_error("Unable to run mysql_init()\n"); goto __exit_pull_mysql_servers_from_peer; } - GloProxyCluster->get_credentials(&username, &password); - if (strlen(username)) { // do not monitor if the username is empty + + creds = GloProxyCluster->get_credentials(); + if (creds.user.size()) { // do not monitor if the username is empty + // READ/WRITE timeouts were enforced as an attempt to prevent deadlocks in the original + // implementation. They were proven unnecessary, leaving only 'CONNECT_TIMEOUT'. unsigned int timeout = 1; mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &timeout); { @@ -1790,7 +1752,9 @@ void ProxySQL_Cluster::pull_runtime_mysql_servers_from_peer(const runtime_mysql_ } proxy_debug(PROXY_DEBUG_CLUSTER, 5, "Fetching 'MySQL Servers' from peer %s:%d started. Expected checksum %s\n", hostname, port, peer_checksum); proxy_info("Cluster: Fetching 'MySQL Servers' from peer %s:%d started. Expected checksum %s\n", hostname, port, peer_checksum); - rc_conn = mysql_real_connect(conn, ip_address ? ip_address : hostname, username, password, NULL, port, NULL, 0); + MYSQL* rc_conn = mysql_real_connect( + conn, ip_address ? ip_address : hostname, creds.user.c_str(), creds.pass.c_str(), NULL, port, NULL, 0 + ); if (rc_conn) { MySQL_Monitor::update_dns_cache_from_mysql_conn(conn); @@ -1856,12 +1820,6 @@ void ProxySQL_Cluster::pull_runtime_mysql_servers_from_peer(const runtime_mysql_ fetch_failed = true; } } - if (username) { - free(username); - } - if (password) { - free(password); - } __exit_pull_mysql_servers_from_peer: if (conn) { if (conn->net.pvio) { @@ -1924,29 +1882,29 @@ void ProxySQL_Cluster::pull_mysql_servers_v2_from_peer(const mysql_servers_v2_ch nodes.get_peer_to_sync_mysql_servers_v2(&hostname, &port, &peer_mysql_servers_v2_checksum, &peer_runtime_mysql_servers_checksum, &ip_address); if (hostname) { - char* username = NULL; - char* password = NULL; - // bool rc_bool = true; - MYSQL* rc_conn; + cluster_creds_t creds {}; + MYSQL* conn = mysql_init(NULL); if (conn == NULL) { proxy_error("Unable to run mysql_init()\n"); goto __exit_pull_mysql_servers_v2_from_peer; } - GloProxyCluster->get_credentials(&username, &password); - if (strlen(username)) { // do not monitor if the username is empty + + creds = GloProxyCluster->get_credentials(); + if (creds.user.size()) { // do not monitor if the username is empty + // READ/WRITE timeouts were enforced as an attempt to prevent deadlocks in the original + // implementation. They were proven unnecessary, leaving only 'CONNECT_TIMEOUT'. unsigned int timeout = 1; - // unsigned int timeout_long = 60; mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &timeout); - //mysql_options(conn, MYSQL_OPT_READ_TIMEOUT, &timeout_long); - //mysql_options(conn, MYSQL_OPT_WRITE_TIMEOUT, &timeout); { unsigned char val = 1; mysql_options(conn, MYSQL_OPT_SSL_ENFORCE, &val); mysql_options(conn, MARIADB_OPT_SSL_KEYLOG_CALLBACK, (void*)proxysql_keylog_write_line_callback); } proxy_debug(PROXY_DEBUG_CLUSTER, 5, "Fetching MySQL Servers v2 from peer %s:%d started. Expected checksum %s\n", hostname, port, peer_mysql_servers_v2_checksum); proxy_info("Cluster: Fetching MySQL Servers v2 from peer %s:%d started. Expected checksum %s\n", hostname, port, peer_mysql_servers_v2_checksum); - rc_conn = mysql_real_connect(conn, ip_address ? ip_address : hostname, username, password, NULL, port, NULL, 0); + MYSQL* rc_conn = mysql_real_connect( + conn, ip_address ? ip_address : hostname, creds.user.c_str(), creds.pass.c_str(), NULL, port, NULL, 0 + ); if (rc_conn) { MySQL_Monitor::update_dns_cache_from_mysql_conn(conn); @@ -2395,12 +2353,6 @@ void ProxySQL_Cluster::pull_mysql_servers_v2_from_peer(const mysql_servers_v2_ch fetch_failed = true; } } - if (username) { - free(username); - } - if (password) { - free(password); - } __exit_pull_mysql_servers_v2_from_peer: if (conn) { if (conn->net.pvio) { @@ -2461,31 +2413,28 @@ void ProxySQL_Cluster::pull_global_variables_from_peer(const string& var_type, c } if (hostname) { - char *username = NULL; - char *password = NULL; - MYSQL *rc_conn = nullptr; - int rc_query = 0; - int rc = 0; - MYSQL *conn = mysql_init(NULL); + cluster_creds_t creds {}; + MYSQL *conn = mysql_init(NULL); if (conn == NULL) { proxy_error("Unable to run mysql_init()\n"); goto __exit_pull_mysql_variables_from_peer; } - GloProxyCluster->get_credentials(&username, &password); - if (strlen(username)) { // do not monitor if the username is empty + creds = GloProxyCluster->get_credentials(); + if (creds.user.size()) { // do not monitor if the username is empty + // READ/WRITE timeouts were enforced as an attempt to prevent deadlocks in the original + // implementation. They were proven unnecessary, leaving only 'CONNECT_TIMEOUT'. unsigned int timeout = 1; - // unsigned int timeout_long = 60; mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &timeout); - //mysql_options(conn, MYSQL_OPT_READ_TIMEOUT, &timeout_long); - //mysql_options(conn, MYSQL_OPT_WRITE_TIMEOUT, &timeout); { unsigned char val = 1; mysql_options(conn, MYSQL_OPT_SSL_ENFORCE, &val); mysql_options(conn, MARIADB_OPT_SSL_KEYLOG_CALLBACK, (void*)proxysql_keylog_write_line_callback); } proxy_info("Cluster: Fetching %s variables from peer %s:%d started\n", vars_type_str, hostname, port); - rc_conn = mysql_real_connect(conn, ip_address ? ip_address : hostname, username, password, NULL, port, NULL, 0); + MYSQL* rc_conn = mysql_real_connect( + conn, ip_address ? ip_address : hostname, creds.user.c_str(), creds.pass.c_str(), NULL, port, NULL, 0 + ); if (rc_conn) { MySQL_Monitor::update_dns_cache_from_mysql_conn(conn); @@ -2503,7 +2452,7 @@ void ProxySQL_Cluster::pull_global_variables_from_peer(const string& var_type, c } } s_query += " ORDER BY variable_name"; - mysql_query(conn, s_query.c_str()); + int rc_query = mysql_query(conn, s_query.c_str()); if (rc_query == 0) { MYSQL_RES *result = mysql_store_result(conn); @@ -2535,7 +2484,7 @@ void ProxySQL_Cluster::pull_global_variables_from_peer(const string& var_type, c MYSQL_ROW row; char *q = (char *)"INSERT OR REPLACE INTO global_variables (variable_name, variable_value) VALUES (?1 , ?2)"; sqlite3_stmt *statement1 = NULL; - rc = GloAdmin->admindb->prepare_v2(q, &statement1); + int rc = GloAdmin->admindb->prepare_v2(q, &statement1); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); while ((row = mysql_fetch_row(result))) { @@ -2604,12 +2553,6 @@ void ProxySQL_Cluster::pull_global_variables_from_peer(const string& var_type, c fetch_failed = true; } } - if (username) { - free(username); - } - if (password) { - free(password); - } __exit_pull_mysql_variables_from_peer: if (conn) { if (conn->net.pvio) { @@ -2633,23 +2576,20 @@ void ProxySQL_Cluster::pull_proxysql_servers_from_peer(const std::string& expect pthread_mutex_lock(&GloProxyCluster->update_proxysql_servers_mutex); nodes.get_peer_to_sync_proxysql_servers(&hostname, &port, &ip_address); if (hostname) { - char *username = NULL; - char *password = NULL; - // bool rc_bool = true; - MYSQL *rc_conn; - int rc_query; + cluster_creds_t creds {}; + MYSQL *conn = mysql_init(NULL); if (conn==NULL) { proxy_error("Unable to run mysql_init()\n"); goto __exit_pull_proxysql_servers_from_peer; } - GloProxyCluster->get_credentials(&username, &password); - if (strlen(username)) { // do not monitor if the username is empty + + creds = GloProxyCluster->get_credentials(); + if (creds.user.size()) { // do not monitor if the username is empty + // READ/WRITE timeouts were enforced as an attempt to prevent deadlocks in the original + // implementation. They were proven unnecessary, leaving only 'CONNECT_TIMEOUT'. unsigned int timeout = 1; - // unsigned int timeout_long = 60; mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &timeout); - //mysql_options(conn, MYSQL_OPT_READ_TIMEOUT, &timeout_long); - //mysql_options(conn, MYSQL_OPT_WRITE_TIMEOUT, &timeout); { unsigned char val = 1; mysql_options(conn, MYSQL_OPT_SSL_ENFORCE, &val); mysql_options(conn, MARIADB_OPT_SSL_KEYLOG_CALLBACK, (void*)proxysql_keylog_write_line_callback); @@ -2660,11 +2600,13 @@ void ProxySQL_Cluster::pull_proxysql_servers_from_peer(const std::string& expect "Cluster: Fetching ProxySQL Servers from peer %s:%d started. Expected checksum: %s\n", hostname, port, expected_checksum.c_str() ); - rc_conn = mysql_real_connect(conn, ip_address ? ip_address : hostname, username, password, NULL, port, NULL, 0); + MYSQL* rc_conn = mysql_real_connect( + conn, ip_address ? ip_address : hostname, creds.user.c_str(), creds.pass.c_str(), NULL, port, NULL, 0 + ); if (rc_conn) { MySQL_Monitor::update_dns_cache_from_mysql_conn(conn); - rc_query = mysql_query(conn,"SELECT hostname, port, weight, comment FROM runtime_proxysql_servers ORDER BY hostname, port"); + int rc_query = mysql_query(conn,"SELECT hostname, port, weight, comment FROM runtime_proxysql_servers ORDER BY hostname, port"); if ( rc_query == 0 ) { MYSQL_RES* result = mysql_store_result(conn); uint64_t proxy_servers_hash = mysql_raw_checksum(result); @@ -2738,12 +2680,6 @@ void ProxySQL_Cluster::pull_proxysql_servers_from_peer(const std::string& expect fetch_failed = true; } } - if (username) { - free(username); - } - if (password) { - free(password); - } __exit_pull_proxysql_servers_from_peer: if (conn) { if (conn->net.pvio) { @@ -4467,11 +4403,13 @@ void ProxySQL_Cluster::p_update_metrics() { }; // this function returns credentials to the caller, used by monitoring threads -void ProxySQL_Cluster::get_credentials(char **username, char **password) { +cluster_creds_t ProxySQL_Cluster::get_credentials() { pthread_mutex_lock(&mutex); - *username = strdup(cluster_username); - *password = strdup(cluster_password); + const string user { cluster_username }; + const string pass { cluster_password }; pthread_mutex_unlock(&mutex); + + return { user, pass }; } void ProxySQL_Cluster::set_username(char *_username) { diff --git a/lib/debug.cpp b/lib/debug.cpp index 7d236f6a0f..e4eda648f5 100644 --- a/lib/debug.cpp +++ b/lib/debug.cpp @@ -46,24 +46,28 @@ static inline unsigned long long debug_monotonic_time() { #ifdef DEBUG -// this set will have all the filters related to debug -// for convention, the key is: -// filename:line:function -// this key structure applies also if line is 0 or function is empty -// filename is mandatory -std::set debug_filters; +/** + * @brief Contains all filters related to debug. + * @details The convention for key value is `filename:line:function`. This key structure also applies also + * applies if the line is `0` or function is empty, the `filename` is always mandatory. + * + * IMPORTANT: This structure is a pointer to avoid race conditions during process termination, otherwise the + * destruction of the object may be performed before working threads have exited. This structure will leak, + * this is intentional, since we can't synchronize the exit of the working threads with its destruction. + */ +std::set* debug_filters = nullptr; static bool filter_debug_entry(const char *__file, int __line, const char *__func) { //pthread_mutex_lock(&debug_mutex); pthread_rwlock_rdlock(&filters_rwlock); bool to_filter = false; - if (debug_filters.size()) { // if the set is empty we aren't performing any filter, so we won't search + if (debug_filters && debug_filters->size()) { // if the set is empty we aren't performing any filter, so we won't search std::string key(__file); key += ":" + std::to_string(__line); key += ":"; key += __func; // we start with a full search - if (debug_filters.find(key) != debug_filters.end()) { + if (debug_filters->find(key) != debug_filters->end()) { to_filter = true; } else { // we now search filename + line @@ -71,7 +75,7 @@ static bool filter_debug_entry(const char *__file, int __line, const char *__fun key += ":" + std::to_string(__line); // remember to add the final ":" key += ":"; - if (debug_filters.find(key) != debug_filters.end()) { + if (debug_filters->find(key) != debug_filters->end()) { to_filter = true; } else { // we now search filename + function @@ -79,14 +83,14 @@ static bool filter_debug_entry(const char *__file, int __line, const char *__fun // no line = 0 key += ":0:"; key += __func; - if (debug_filters.find(key) != debug_filters.end()) { + if (debug_filters->find(key) != debug_filters->end()) { to_filter = true; } else { // we now search filename only key = __file; // remember to add ":" even if no line key += ":0:"; - if (debug_filters.find(key) != debug_filters.end()) { + if (debug_filters->find(key) != debug_filters->end()) { to_filter = true; } else { // if we reached here, we couldn't find any filter @@ -105,7 +109,9 @@ static bool filter_debug_entry(const char *__file, int __line, const char *__fun void proxy_debug_get_filters(std::set& f) { //pthread_mutex_lock(&debug_mutex); pthread_rwlock_rdlock(&filters_rwlock); - f = debug_filters; + if (debug_filters) { + f = *debug_filters; + } pthread_rwlock_unlock(&filters_rwlock); //pthread_mutex_unlock(&debug_mutex); } @@ -115,8 +121,12 @@ void proxy_debug_get_filters(std::set& f) { void proxy_debug_load_filters(std::set& f) { //pthread_mutex_lock(&debug_mutex); pthread_rwlock_wrlock(&filters_rwlock); - debug_filters.erase(debug_filters.begin(), debug_filters.end()); - debug_filters = f; + if (debug_filters) { + debug_filters->erase(debug_filters->begin(), debug_filters->end()); + *debug_filters = f; + } else { + debug_filters = new std::set(f); + } pthread_rwlock_unlock(&filters_rwlock); //pthread_mutex_unlock(&debug_mutex); } diff --git a/test/tap/tap/utils.cpp b/test/tap/tap/utils.cpp index 60fda98e4f..a3f7e9d78d 100644 --- a/test/tap/tap/utils.cpp +++ b/test/tap/tap/utils.cpp @@ -522,6 +522,39 @@ ext_val_t ext_single_row_val(const mysql_res_row& row, const string& def } } +ext_val_t ext_single_row_val(const mysql_res_row& row, const int32_t& def_val) { + if (row.empty() || row.front().empty()) { + return { -1, def_val, {} }; + } else { + errno = 0; + char* p_end {}; + const int32_t val = std::strtol(row.front().c_str(), &p_end, 10); + + if (row[0] == p_end || errno == ERANGE) { + return { -2, def_val, string { row[0] } }; + } else { + return { EXIT_SUCCESS, val, string { row[0] } }; + } + } +} + +ext_val_t ext_single_row_val(const mysql_res_row& row, const uint32_t& def_val) { + if (row.empty() || row.front().empty()) { + return { -1, def_val, {} }; + } else { + errno = 0; + char* p_end {}; + const uint32_t val = std::strtoul(row.front().c_str(), &p_end, 10); + + if (row[0] == p_end || errno == ERANGE) { + return { -2, def_val, string { row[0] } }; + } else { + return { EXIT_SUCCESS, val, string { row[0] } }; + } + } +} + + ext_val_t ext_single_row_val(const mysql_res_row& row, const int64_t& def_val) { if (row.empty() || row.front().empty()) { return { -1, def_val, {} }; @@ -544,7 +577,7 @@ ext_val_t ext_single_row_val(const mysql_res_row& row, const uint64_t& } else { errno = 0; char* p_end {}; - const uint64_t val = std::strtoll(row.front().c_str(), &p_end, 10); + const uint64_t val = std::strtoull(row.front().c_str(), &p_end, 10); if (row[0] == p_end || errno == ERANGE) { return { -2, def_val, string { row[0] } }; diff --git a/test/tap/tap/utils.h b/test/tap/tap/utils.h index 7422abe146..afa804074e 100644 --- a/test/tap/tap/utils.h +++ b/test/tap/tap/utils.h @@ -171,6 +171,8 @@ struct ext_val_t { * @return An `ext_val_t` where T is the type of the provided default value. */ ext_val_t ext_single_row_val(const mysql_res_row& row, const std::string& def_val); +ext_val_t ext_single_row_val(const mysql_res_row& row, const int32_t& def_val); +ext_val_t ext_single_row_val(const mysql_res_row& row, const uint32_t& def_val); ext_val_t ext_single_row_val(const mysql_res_row& row, const int64_t& def_val); ext_val_t ext_single_row_val(const mysql_res_row& row, const uint64_t& def_val); diff --git a/test/tap/tests/reg_test_3223-restapi_return_codes-t.cpp b/test/tap/tests/reg_test_3223-restapi_return_codes-t.cpp index 6eac9c9d73..bd6fa98ba5 100644 --- a/test/tap/tests/reg_test_3223-restapi_return_codes-t.cpp +++ b/test/tap/tests/reg_test_3223-restapi_return_codes-t.cpp @@ -48,7 +48,7 @@ const vector honest_requests { { { "partial_output_flush_script", "%s.py", "POST", 10000 }, { "{}" } }, }; -const vector invalid_requests { +vector invalid_requests { // Checks that 'POST' fails for: // 1 - Empty parameters. // 2 - Invalid JSON input. @@ -279,6 +279,17 @@ int main(int argc, char** argv) { vector i_epts_info {}; const auto ext_i_epts_info = [] (const faulty_req_t& req) { return req.ept_info; }; + + // Failed scripts may require to read the full output from ASAN leaks report. This in combination with the + // forked process shutdown slowdown can take a considerable amount of time. A cleaner solution would be + // to disable 'detect_leaks' at runtime, but doesn't look feasible at the moment. + int wasan = get_env_int("WITHASAN", 0); + if (wasan) { + for (auto& req : invalid_requests) { + req.ept_info.timeout += 8000; + } + } + std::transform( invalid_requests.begin(), invalid_requests.end(), std::back_inserter(i_epts_info), ext_i_epts_info ); diff --git a/test/tap/tests/reg_test_3765_ssl_pollout-t.cpp b/test/tap/tests/reg_test_3765_ssl_pollout-t.cpp index 4a42904d97..898c56f4ed 100644 --- a/test/tap/tests/reg_test_3765_ssl_pollout-t.cpp +++ b/test/tap/tests/reg_test_3765_ssl_pollout-t.cpp @@ -109,6 +109,11 @@ int main(int argc, char** argv) { plan(6); + // For ASAN builds we don't care about correctness in this measurement. + if (get_env_int("WITHASAN", 0)) { + MAX_ALLOWED_CPU_USAGE = 80; + } + double idle_cpu_ms = 0; double final_cpu_ms = 0; diff --git a/test/tap/tests/test_backend_conn_ping-t.cpp b/test/tap/tests/test_backend_conn_ping-t.cpp index 5c2be5634c..fc09701920 100644 --- a/test/tap/tests/test_backend_conn_ping-t.cpp +++ b/test/tap/tests/test_backend_conn_ping-t.cpp @@ -11,19 +11,60 @@ * over time. I.e. connections are not getting destroyed due to not being kept alive. * 3. Perform a query per each created connection exahusting the backend connections while checking for * any error reported by the client due to broken connections. + * + * Backend Connection Pinging Algorithm: + * ==================================== + * + * The algorithm used for pinging backend connections is simple: + * + * 1. Pinging is done for 'idle_session' in batches of SESSIONS_FOR_CONNECTIONS_HANDLER. + * 2. The pinging interval is determined by 'ping_interval_server_msec'. + * 3. Oldest sessions are always selected first for pinging. + * + * With this approach, it should be possible to ping a very large number of backend connections before + * losing them due to inactivity (wait_timeout), this will be defined by: + * + * ``` + * (NUM_THREADS * SESSIONS_FOR_CONNECTIONS_HANDLER)*floor((MYSQL_wait_timeout-1)/ping_interval_server_msec) + * ``` + * + * This means that, for example, for a config like: `num_threads=4,wait_timeout=60,batch_size=64`, we can + * expect: `15104` connections. Of course, this suggests that this algorithm wont have any issues holding a + * healthy connection pool of any size when using real `wait_timeout` values. + * + * Algorithm - Special Cases: + * ========================= + * + * This algorithm has a expected behavior that might seems unexpected when pushing the limits of the + * connections that are being maintained; like we can accidentally do in this test. If the number of + * connections being maintained exceeds the number that can be pinged within the `MySQL_wait_timeout` + * interval, this will cause a cascading effect, that will result in extra connections timing out. The + * number of connections from the connection pool that will timeout will be proportional to the fraction of + * the batch (NUM_THREADS*SESSIONS_FOR_CONNECTIONS_HANDLER) filled with connections that exceeded the + * interval processing capacity. + * + * If for example, the number of connections exceeded the ones that can be maintained by 50% of the batching + * interval, for the case of 4 threads, this will be 128 connections, then 50% of the connection pool will + * be lost due to this cascading effect. Elaborating a little bit further, when the number of connections + * being maintained exceeds the number of connections that can be pinged, the connections exceeding the + * interval capabilities will timeout, since these connections will be the oldest, they will be the first to + * be selected for the next interval. This will shift all subsequent batching intervals by this number of + * connections, since we are operating at maximum capacity (maximum number exceeded), all the intervals were + * selecting connections that should be pinged, otherwise will timeout. This is why the previously mentioned + * shift will result in the timeout of these connections, causing the mentioned cascading effect. + * + * This is expected behavior, and **it's not an issue**. The number of connections ProxySQL can ping is + * mainly determined by the interval that defines `wait_timeout` in the MySQL server and + * `ping_interval_server_msec`, which default value is `1000`. With reasonable values for these two + * parameters this number is very high, even with extremely low values for `wait_timeout`, like + * `num_threads=4,wait_timeout=60,batch_size=64`, a large number of connections(`15104`) would still be + * maintained without issues. This is what makes this issue an artificial one. */ -/* -NOTE: the parameters in this test are tuned in a way that if proxysql starts -with only 1 worker thread, it is unlikely to ping all connections on time. -See note on wait_timeout -*/ - #include #include #include #include -#include #include #include @@ -39,49 +80,20 @@ using std::pair; using srv_cfg = vector>; -int wait_timeout = 10; - -#ifndef SESSIONS_FOR_CONNECTIONS_HANDLER -#define SESSIONS_FOR_CONNECTIONS_HANDLER 64 -#endif +#define SESSIONS_FOR_CONNECTIONS_HANDLER 64 -// if only 1 worker thread is running, wait_timeout should be bigger -// 1 worker thread : wait_timeout = 45 -// 4 worker threads : wait_timeout = 10 -int compute_wait_timeout(MYSQL *my_conn) { - int res = EXIT_SUCCESS; - res = mysql_query(my_conn, "SELECT @@mysql-threads"); - if (res != EXIT_SUCCESS) { - fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(my_conn)); - res = EXIT_FAILURE; - return res; - } - MYSQL_RES* my_res = mysql_store_result(my_conn); - if (my_res == nullptr) { - fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(my_conn)); - res = EXIT_FAILURE; - return res; - } +// IMPORTANT: We **always** gives ourselves `1` second grace period. Depending on MySQL connection killing +// policy for `wait_timeout`, connections could already be killed on the edge of the interval. Also, for extra +// safety, we gave `1` extra second to avoid possible rounding errors on time computations within MySQL. +uint32_t grace_period = 2; +int wait_timeout = 10 + grace_period; - MYSQL_ROW row = mysql_fetch_row(my_res); - if (row == nullptr || row[0] == nullptr) { - fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(my_conn)); - res = EXIT_FAILURE; - return res; - } else { - const char *val = row[0]; - diag("mysql-threads = %s", val); - if (strcmp(val,"1")==0) { - diag("Setting wait_timeout to 45 instead of 10"); - wait_timeout = 45; - } - } - mysql_free_result(my_res); +int max_pinged_conns(uint32_t num_threads, uint32_t ping_interval_server_msec, uint32_t wait_timeout) { + uint32_t ping_proc_batches = floor((wait_timeout- (grace_period+1))/float(ping_interval_server_msec/1000.0)); - return res; + return (num_threads * SESSIONS_FOR_CONNECTIONS_HANDLER) * ping_proc_batches; } - int change_mysql_cfg( const CommandLine& cl, const string& host, const string& port, const srv_cfg& new_srv_cfg, srv_cfg& out_old_srv_cfg ) { @@ -233,7 +245,6 @@ int check_backend_conns( // 2. Check that the connections remain steady for a period of time MYSQL* admin = mysql_init(NULL); - vector svrs_conns {}; { if (!mysql_real_connect(admin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) { @@ -241,19 +252,6 @@ int check_backend_conns( return EXIT_FAILURE; } - for (const auto& svr_addr : svrs_addrs) { - MYSQL* mysql = mysql_init(NULL); - -// if (!mysql_real_connect(mysql, svr_addr.first.c_str(), cl.username, cl.password, NULL, svr_addr.second, NULL, 0)) { - if (!mysql_real_connect(mysql, svr_addr.first.c_str(), cl.mysql_username, cl.mysql_password, NULL, svr_addr.second, NULL, 0)) { - fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(mysql)); - res = EXIT_FAILURE; - goto cleanup; - } - - svrs_conns.push_back(mysql); - } - sleep(5); uint64_t exp_conn_count = test_params.init_batch_size + test_params.batch_size * test_params.its; @@ -263,8 +261,8 @@ int check_backend_conns( uint64_t act_proxy_free_conn_count = 0; uint64_t act_proxy_used_conn_count = 0; + uint32_t intv = 5; uint32_t total_wait_time = 40; - uint32_t intv = 10; uint32_t total_checks = total_wait_time / intv; for (uint32_t check_num = 0; check_num < total_checks; check_num++) { @@ -272,12 +270,30 @@ int check_backend_conns( act_mysql_conn_count = 0; const string mysql_query_string { - "SELECT count(*) FROM information_schema.processlist WHERE" + "SELECT count(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE" " USER=\"" + string { cl.username } + "\"" //" USER=\"" + string { cl.username } + "\" and DB=\"backend_conn_ping_test\"" //" COMMAND=\"Sleep\" and USER=\"" + string { cl.username } + "\" and DB=\"backend_conn_ping_test\"" }; diag("Line:%d : Running: %s", __LINE__ , mysql_query_string.c_str()); + + vector svrs_conns {}; + + // Recreate the connections at each interval + for (const auto& svr_addr : svrs_addrs) { + const char* c_svr_addr { svr_addr.first.c_str() }; + + MYSQL* mysql = mysql_init(NULL); + + if (!mysql_real_connect(mysql, c_svr_addr, cl.mysql_username, cl.mysql_password, NULL, svr_addr.second, NULL, 0)) { + fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(mysql)); + res = EXIT_FAILURE; + goto cleanup; + } + + svrs_conns.push_back(mysql); + } + for (MYSQL* mysql : svrs_conns) { uint64_t tmp_mysql_conn_count = 0; @@ -290,6 +306,10 @@ int check_backend_conns( act_mysql_conn_count += tmp_mysql_conn_count; } + for (MYSQL* mysql : svrs_conns) { + mysql_close(mysql); + } + const string srv_ports { std::accumulate(std::begin(svrs_addrs), std::end(svrs_addrs), string {}, [](const string& s1, const svr_addr& addr) -> string { @@ -342,12 +362,6 @@ int check_backend_conns( diag("act_proxy_free_conn_count = %lu", act_proxy_free_conn_count); diag("act_proxy_used_conn_count = %lu", act_proxy_used_conn_count); - if ( - act_mysql_conn_count >= exp_conn_count || - (act_proxy_free_conn_count + act_proxy_used_conn_count + SESSIONS_FOR_CONNECTIONS_HANDLER) >= exp_conn_count - ) { - break; - } if (intv) { diag("Line:%d : Sleeping %d" , __LINE__ , intv); sleep(intv); @@ -357,9 +371,7 @@ int check_backend_conns( ok( q_res == EXIT_SUCCESS && act_mysql_conn_count >= ((float) exp_conn_count * 0.95) // allow 5% margin of error && - ((act_proxy_free_conn_count + act_proxy_used_conn_count + SESSIONS_FOR_CONNECTIONS_HANDLER) >= exp_conn_count) - //&& act_mysql_conn_count == act_proxy_free_conn_count // they can't be equal - , + ((act_proxy_free_conn_count + act_proxy_used_conn_count) >= exp_conn_count), "Created server connections should be properly maintained (pinged) by ProxySQL:" " { ExpConns: %ld, ActMySQLConns: %ld, ActProxyConns: %ld }", exp_conn_count, act_mysql_conn_count, act_proxy_free_conn_count @@ -390,9 +402,6 @@ int check_backend_conns( cleanup: mysql_close(admin); - for (MYSQL* mysql : svrs_conns) { - mysql_close(mysql); - } for (MYSQL* mysql : mysql_conns) { mysql_close(mysql); @@ -457,38 +466,65 @@ int main(int, char**) { // Close no longer required connection mysql_close(proxy_mysql); - MYSQL* proxy_admin = mysql_init(NULL); - if (!proxy_admin) { - fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxy_admin)); - return exit_status(); - } - - 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)); + MYSQL* admin = mysql_init(NULL); + if (!admin) { + fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(admin)); return exit_status(); } - if (compute_wait_timeout(proxy_admin) != EXIT_SUCCESS) { + if (!mysql_real_connect(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(admin)); return exit_status(); } - double intv = 5; - double b = 128; double b_0 = 256; + double b = 128; double freq = 1000; - double rate = 64 / ( freq / 1000 ); - double conn_creation_intv = 30; + double rate = 64 / (freq / 1000); + + const char q_mysql_threads[] { "SELECT @@mysql-threads" }; + ext_val_t ext_threads { mysql_query_ext_val(admin, q_mysql_threads, int32_t(0)) }; + + if (ext_threads.err != EXIT_SUCCESS) { + const string err { get_ext_val_err(admin, ext_threads) }; + diag("Failed query query:`%s`, err:`%s`", q_mysql_threads, err.c_str()); + return EXIT_FAILURE; + } + + // IMPORTANT-NOTE: + // Variable 'ping_interval_server_msec' isn't relevant because ProxySQL isn't under load. The relevant + // variable passes to be `mysql-poll_timeout`; with each timeout threads will process idle sessions. If we + // wished to extend this test with a dummy load on ProxySQL, this should be uncommented. + // =================================================================================================== + // const char q_ping_intv[] { "SELECT @@mysql-ping_interval_server_msec" }; + const char q_ping_intv[] { "SELECT @@mysql-poll_timeout" }; + // =================================================================================================== + ext_val_t ext_ping_intv { mysql_query_ext_val(admin, q_ping_intv, int32_t(0)) }; - double its = (conn_creation_intv - b_0/rate) / ( b / rate ); + if (ext_ping_intv.err != EXIT_SUCCESS) { + const string err { get_ext_val_err(admin, ext_ping_intv) }; + diag("Failed query query:`%s`, err:`%s`", q_ping_intv, err.c_str()); + return EXIT_FAILURE; + } + + uint32_t max_conns = max_pinged_conns(ext_threads.val, 2000, wait_timeout); + uint32_t server_max_conns = max_conns + 1000; + double its = floor((max_conns - b_0) / b); + + double conn_creation_intv = b_0/rate + (b/rate)*its; double delay_s = conn_creation_intv / its; + diag("ProxySQL config mysql_threads:%d, ping_intv:%d", ext_threads.val, ext_ping_intv.val); + diag("Selected test params b_0:%lf, b:%lf, freq:%lf, rate:%lf", b_0, b, freq, rate); + diag("Computed test params max_conns=%d, intv=%lf, its=%lf", max_conns, conn_creation_intv, its); + // Cleanup previous backend connections diag("Cleaning up previous backend connections..."); - MYSQL_QUERY(proxy_admin, "UPDATE mysql_servers SET max_connections=0"); - MYSQL_QUERY(proxy_admin, "LOAD MYSQL SERVERS TO RUNTIME"); + MYSQL_QUERY(admin, "UPDATE mysql_servers SET max_connections=0"); + MYSQL_QUERY(admin, "LOAD MYSQL SERVERS TO RUNTIME"); // Wait for backend connection cleanup - int w_res = wait_target_backend_conns(proxy_admin, 0, 10); + int w_res = wait_target_backend_conns(admin, 0, 10); if (w_res != EXIT_SUCCESS) { if (w_res == -2) { const char* err_msg = "'wait_target_backend_conns()' timed out"; @@ -499,12 +535,12 @@ int main(int, char**) { } diag("Setting mysql_servers config..."); { - string query = "UPDATE mysql_servers SET max_connections=2500"; + string query { "UPDATE mysql_servers SET max_connections=" + std::to_string(server_max_conns) }; diag("Running: %s", query.c_str()); - MYSQL_QUERY(proxy_admin, query.c_str()); + MYSQL_QUERY(admin, query.c_str()); query = "LOAD MYSQL SERVERS TO RUNTIME"; diag("Running: %s", query.c_str()); - MYSQL_QUERY(proxy_admin, query.c_str()); + MYSQL_QUERY(admin, query.c_str()); } diag("Setting ProxySQL config..."); @@ -512,27 +548,30 @@ int main(int, char**) { // Set the backend connections ping frequency string query = string { "SET mysql-ping_interval_server_msec=" + std::to_string(freq) }; diag("%s", query.c_str()); - MYSQL_QUERY(proxy_admin, query.c_str()); + MYSQL_QUERY(admin, query.c_str()); // Make sure no connection cleanup takes place query = "SET mysql-free_connections_pct=100"; diag("%s", query.c_str()); - MYSQL_QUERY(proxy_admin, query.c_str()); + MYSQL_QUERY(admin, query.c_str()); // Don't retry on failure query = "SET mysql-query_retries_on_failure=0"; diag("%s", query.c_str()); - MYSQL_QUERY(proxy_admin, query.c_str()); + MYSQL_QUERY(admin, query.c_str()); + query = "SET mysql-max_connections=" + std::to_string(server_max_conns*3); + diag("%s", query.c_str()); + MYSQL_QUERY(admin, query.c_str()); // Set a higher max_connection number for the servers query = "LOAD MYSQL VARIABLES TO RUNTIME"; diag("%s", query.c_str()); - MYSQL_QUERY(proxy_admin, query.c_str()); + MYSQL_QUERY(admin, query.c_str()); } // Configure MySQL infra servers with: 'wait_timeout' and 'max_connections' vector> servers_old_configs {}; diag("Configure 'MYSQL' infra servers..."); { - MYSQL_QUERY(proxy_admin, "SELECT DISTINCT hostname, port FROM mysql_servers WHERE hostgroup_id IN (0,1)"); - MYSQL_RES* my_servers_res = mysql_store_result(proxy_admin); + MYSQL_QUERY(admin, "SELECT DISTINCT hostname, port FROM mysql_servers WHERE hostgroup_id IN (0,1)"); + MYSQL_RES* my_servers_res = mysql_store_result(admin); vector servers_rows = extract_mysql_rows(my_servers_res); mysql_free_result(my_servers_res); @@ -541,7 +580,7 @@ int main(int, char**) { return exit_status(); } - srv_cfg new_srv_cfg { { "wait_timeout", wait_timeout }, { "max_connections", 2500 } }; + srv_cfg new_srv_cfg { { "wait_timeout", wait_timeout }, { "max_connections", 5000 } }; for (const mysql_res_row& srv_row : servers_rows) { srv_cfg old_srv_cfg {}; @@ -565,7 +604,11 @@ int main(int, char**) { const string docker_mode = getenv("DOCKER_MODE"); if (docker_mode.find("dns") == docker_mode.size() - 3) { s_server_test.assign({ { "mysql1.infra-mysql57", 3306 } }); - m_server_test.assign({ { "mysql1.infra-mysql57", 3306 }, { "mysql2.infra-mysql57", 3306 }, { "mysql3.infra-mysql57", 3306 } }); + m_server_test.assign({ + { "mysql1.infra-mysql57", 3306 }, + { "mysql2.infra-mysql57", 3306 }, + { "mysql3.infra-mysql57", 3306 } + }); } else { s_server_test.assign({ { "127.0.0.1", 13306 } }); m_server_test.assign({ { "127.0.0.1", 13306 }, { "127.0.0.1", 13307 }, { "127.0.0.1", 13308 } }); @@ -584,12 +627,12 @@ int main(int, char**) { diag("Cleaning up previous backend connections..."); string query = "UPDATE mysql_servers SET max_connections=0"; diag("Line:%d : Running: %s", __LINE__ , query.c_str()); - MYSQL_QUERY(proxy_admin, query.c_str()); + MYSQL_QUERY(admin, query.c_str()); query = "LOAD MYSQL SERVERS TO RUNTIME"; diag("Line:%d : Running: %s", __LINE__ , query.c_str()); - MYSQL_QUERY(proxy_admin, query.c_str()); + MYSQL_QUERY(admin, query.c_str()); - int w_res = wait_target_backend_conns(proxy_admin, 0, 10); + int w_res = wait_target_backend_conns(admin, 0, 10); if (w_res != EXIT_SUCCESS) { string err_msg {}; if (w_res == -2) { @@ -600,12 +643,13 @@ int main(int, char**) { fprintf(stderr, "File %s, line %d, Error: \"%s\"\n", __FILE__, __LINE__, err_msg.c_str()); } - query = "UPDATE mysql_servers SET max_connections=2500"; + diag("Reconfiguring ProxySQL 'mysql_servers' after connection cleanup"); + query = "UPDATE mysql_servers SET max_connections=" + std::to_string(server_max_conns); diag("Line:%d : Running: %s", __LINE__ , query.c_str()); - MYSQL_QUERY(proxy_admin, query.c_str()); + MYSQL_QUERY(admin, query.c_str()); query = "LOAD MYSQL SERVERS TO RUNTIME"; diag("Line:%d : Running: %s", __LINE__ , query.c_str()); - MYSQL_QUERY(proxy_admin, query.c_str()); + MYSQL_QUERY(admin, query.c_str()); if (w_res == EXIT_SUCCESS) { diag("Performing 'check_backend_conns()' for servers: '%s'", nlohmann::json(m_server_test).dump().c_str()); @@ -634,7 +678,7 @@ int main(int, char**) { } } - mysql_close(proxy_admin); + mysql_close(admin); return exit_status(); } diff --git a/test/tap/tests/test_cacert_load_and_verify_duration-t.cpp b/test/tap/tests/test_cacert_load_and_verify_duration-t.cpp index 19da85d3d0..f75b913ee0 100644 --- a/test/tap/tests/test_cacert_load_and_verify_duration-t.cpp +++ b/test/tap/tests/test_cacert_load_and_verify_duration-t.cpp @@ -24,6 +24,10 @@ int main() { plan(1); + int32_t WASAN = get_env_int("WITHASAN", 0); + // Double the value of previously failed ASAN run: '89415ms' + int32_t EXP_TIME = WASAN == 0 ? 20000 : 180000; + MYSQL* proxysql_admin = mysql_init(NULL); // Initialize connection @@ -57,7 +61,7 @@ int main() { if (start_pos != std::string::npos && end_pos != std::string::npos) { uint64_t time = std::stoull(msg.substr(start_pos + 5, end_pos - (start_pos + 5))); - ok(time < 20000, "Total duration is '%lu ms' should be less than 20 Seconds", time); + ok(time < EXP_TIME, "Total duration is '%lu ms' should be less than %d Seconds", time, EXP_TIME/1000); } } mysql_close(proxysql_admin); diff --git a/test/tap/tests/test_cluster_sync-t.cpp b/test/tap/tests/test_cluster_sync-t.cpp index 32a449fc30..09b4bdd027 100644 --- a/test/tap/tests/test_cluster_sync-t.cpp +++ b/test/tap/tests/test_cluster_sync-t.cpp @@ -575,6 +575,8 @@ const vector module_sync_payloads { }; int wait_for_node_sync(MYSQL* admin, const vector queries, uint32_t timeout) { + diag("Starting wait for node synchronization"); + uint waited = 0; bool not_synced = false; std::string failed_query {}; @@ -584,7 +586,7 @@ int wait_for_node_sync(MYSQL* admin, const vector queries, uint32_t time // Check that all the entries have been synced for (const auto& query : queries) { - if (mysql_query(admin, query.c_str())) { + if (mysql_query_t(admin, query.c_str())) { fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(admin)); return -1; } @@ -681,6 +683,32 @@ string fetch_runtime_checksum(MYSQL* admin, const string& module) { const int def_mod_diffs_sync = 2; +int32_t get_checksum_sync_timeout(MYSQL* admin) { + const char q_check_intv[] { + "SELECT variable_value FROM global_variables WHERE variable_name='admin-cluster_check_interval_ms'" + }; + ext_val_t ext_check_intv { mysql_query_ext_val(admin, q_check_intv, int64_t(0)) }; + + if (ext_check_intv.err != EXIT_SUCCESS) { + const string err { get_ext_val_err(admin, ext_check_intv) }; + diag("Failed getting 'cluster_check_interval_ms' query:`%s`, err:`%s`", q_check_intv, err.c_str()); + return -1; + } + + const char q_sts_freq[] { + "SELECT variable_value FROM global_variables WHERE variable_name='admin-cluster_check_status_frequency'" + }; + ext_val_t ext_sts_freq { mysql_query_ext_val(admin, q_sts_freq, int64_t(0)) }; + + if (ext_sts_freq.err != EXIT_SUCCESS) { + const string err { get_ext_val_err(admin, ext_check_intv) }; + diag("Failed getting 'cluster_check_status_frequency' query:`%s`, err:`%s`", q_check_intv, err.c_str()); + return -1; + } + + return ((ext_check_intv.val/1000) * ext_sts_freq.val) + 1; +} + int check_module_checksums_sync( MYSQL* admin, MYSQL* r_admin, @@ -691,7 +719,7 @@ int check_module_checksums_sync( ) { const char new_remote_checksum_query_t[] { "SELECT count(*) FROM stats_proxysql_servers_checksums WHERE " - "hostname='%s' AND port='%d' AND name='%s' AND checksum!='%s'" + "hostname='%s' AND port='%d' AND name='%s' AND checksum!='%s' AND checksum='%s'" }; const char synced_runtime_checksums_query_t[] { "SELECT COUNT(*) FROM runtime_checksums_values WHERE name='%s' AND checksum='%s'" @@ -701,7 +729,11 @@ int check_module_checksums_sync( const string& module { module_sync.module }; // Checksum can not be present if we have just added the remote - uint32_t CHECKSUM_SYNC_TIMEOUT = 3; + uint32_t CHECKSUM_SYNC_TIMEOUT = get_checksum_sync_timeout(admin); + if (CHECKSUM_SYNC_TIMEOUT == -1) { + diag("Failed fetching values to compute 'CHECKSUM_SYNC_TIMEOUT'"); + return EXIT_FAILURE; + } const char wait_remote_checksums_init_t[] { "SELECT LENGTH(checksum) FROM stats_proxysql_servers_checksums WHERE " @@ -711,7 +743,7 @@ int check_module_checksums_sync( cstr_format(wait_remote_checksums_init_t, conn_opts.host.c_str(), conn_opts.port, module.c_str()) }; - int checksum_present = wait_for_node_sync( r_admin, { wait_remote_checksums_init.str }, CHECKSUM_SYNC_TIMEOUT); + int checksum_present = wait_for_node_sync(r_admin, { wait_remote_checksums_init.str }, CHECKSUM_SYNC_TIMEOUT); if (checksum_present) { diag("No checksum (or zero) detected int the target remote server for module '%s'", module.c_str()); return EXIT_FAILURE; @@ -736,6 +768,20 @@ int check_module_checksums_sync( return EXIT_FAILURE; } + // Get the new checksum computed after previous 'UPDATE' operation + const char q_module_checksum_t[] { + "SELECT checksum FROM main.runtime_checksums_values WHERE name='%s'" + }; + + cfmt_t q_module_checksum { cstr_format(q_module_checksum_t, module.c_str()) }; + ext_val_t ext_checksum { mysql_query_ext_val(admin, q_module_checksum.str, string()) }; + + if (ext_checksum.err != EXIT_SUCCESS) { + const string err { get_ext_val_err(admin, ext_checksum) }; + diag("Failed query query:`%s`, err:`%s`", q_module_checksum.str.c_str(), err.c_str()); + return EXIT_FAILURE; + } + // Wait for new checksum to be detected cfmt_t new_remote_checksum_query { cstr_format( @@ -743,7 +789,8 @@ int check_module_checksums_sync( conn_opts.host.c_str(), conn_opts.port, module.c_str(), - cur_remote_checksum.c_str() + cur_remote_checksum.c_str(), + ext_checksum.val.c_str() ) }; int sync_res = wait_for_node_sync(r_admin, { new_remote_checksum_query.str }, CHECKSUM_SYNC_TIMEOUT); @@ -910,6 +957,19 @@ int check_all_modules_sync( const sync_payload_t& sync_payload = module_sync_payloads[j]; const int diffs_sync = j == dis_module ? 0 : def_mod_diffs_sync; + // REQUIRE-WAIT: All checks make use of the 'admin_variables' to enable/disable module + // synchronization. The previous module check only waits for the module synchronization itself, but + // not for the propagation of the changed 'admin_variables'; not waiting the propagation of this + // previous change could interfere with the checks target to this same module. + if (module_sync_payloads[j].module == "admin_variables") { + uint32_t CHECKSUM_SYNC_TIMEOUT = get_checksum_sync_timeout(admin); + if (CHECKSUM_SYNC_TIMEOUT == -1) { + diag("Failed fetching values to compute 'CHECKSUM_SYNC_TIMEOUT'"); + return EXIT_FAILURE; + } + sleep(CHECKSUM_SYNC_TIMEOUT); + } + int check_sync = check_module_checksums_sync(admin, r_admin, conn_opts, sync_payload, diffs_sync, remote_stderr); if (check_sync) { if (diffs_sync) { @@ -968,7 +1028,8 @@ int check_modules_checksums_sync( for (size_t dis_module = 0; dis_module < module_sync_payloads.size(); dis_module++) { printf("\n"); - diag("Start test with sync DISABLED for module '%s'", module_sync_payloads[dis_module].module.c_str()); + const string dis_module_str { module_sync_payloads[dis_module].module }; + diag("Start test with sync DISABLED for module '%s'", dis_module_str.c_str()); for (const sync_payload_t& sync_payload : module_sync_payloads) { const string set_query { "SET " + sync_payload.sync_variable + "=" + def_syncs }; @@ -981,9 +1042,11 @@ int check_modules_checksums_sync( MYSQL_QUERY_T(r_admin, "LOAD ADMIN VARIABLES TO RUNTIME"); // Check that ALL modules sync, but 'dis_module' in both ways - Main-To-Remote and Remote-To-Main + diag("Checking ALL modules SYNC but DISABLED module '%s'", dis_module_str.c_str()); check_all_modules_sync(admin, r_admin, m_conn_opts.first, dis_module, main_stderr, remote_stderr); // Enable back the module + diag("Renable module '%s' synchronization", dis_module_str.c_str()); const string enable_query { "SET " + module_sync_payloads[dis_module].sync_variable + "=" + std::to_string(def_mod_diffs_sync) }; @@ -1005,15 +1068,22 @@ int check_modules_checksums_sync( } // Check that the module syncs again in both ways + diag("Checking module '%s' syncs again - MAIN to REMOTE", dis_module_str.c_str()); check_module_checksums_sync( admin, r_admin, m_conn_opts.first, module_sync_payloads[dis_module], def_mod_diffs_sync, remote_stderr ); + // A wait IS NOT required. The checks perform the required waiting, ensuring that the new computed + // checksum after the module update has been propagated to the other server. Previously the check + // didn't take into account the exact checksum, only the change, this led to invalid change + // detections. + diag("Checking module '%s' syncs again - REMOTE to MAIN", dis_module_str.c_str()); check_module_checksums_sync( r_admin, admin, r_conn_opts.first, module_sync_payloads[dis_module], def_mod_diffs_sync, main_stderr ); if (module_sync_payloads[dis_module].module != "proxysql_servers") { // Disable the module using checksums + diag("Disable module '%s' using checksums", dis_module_str.c_str()); const string disable_checksum_query { "SET " + module_sync_payloads[dis_module].checksum_variable + "=false" }; @@ -1021,6 +1091,7 @@ int check_modules_checksums_sync( MYSQL_QUERY_T(r_admin, "LOAD ADMIN VARIABLES TO RUNTIME"); // Check that ALL modules sync, but 'dis_module' in both ways - Main-To-Remote and Remote-To-Main + diag("Checking ALL modules SYNC but DISABLED module '%s'", dis_module_str.c_str()); check_all_modules_sync(admin, r_admin, m_conn_opts.first, dis_module, main_stderr, remote_stderr); // Enable back the module @@ -1044,9 +1115,11 @@ int check_modules_checksums_sync( } // Check that the module syncs again in both ways + diag("Checking module '%s' syncs again - MAIN to REMOTE", dis_module_str.c_str()); check_module_checksums_sync( admin, r_admin, m_conn_opts.first, module_sync_payloads[dis_module], def_mod_diffs_sync, remote_stderr ); + diag("Checking module '%s' syncs again - REMOTE to MAIN", dis_module_str.c_str()); check_module_checksums_sync( r_admin, admin, r_conn_opts.first, module_sync_payloads[dis_module], def_mod_diffs_sync, main_stderr ); diff --git a/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp b/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp index e46e2d3f94..51c68ade70 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp +++ b/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp @@ -1,11 +1,8 @@ -#include #include #include #include #include #include -#include -#include #include "mysql.h" #include "mysqld_error.h" diff --git a/test/tap/tests_with_deps/deprecate_eof_support/eof_fast_forward-t.cpp b/test/tap/tests_with_deps/deprecate_eof_support/eof_fast_forward-t.cpp index 3a50ce1d80..82b5cf14dc 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/eof_fast_forward-t.cpp +++ b/test/tap/tests_with_deps/deprecate_eof_support/eof_fast_forward-t.cpp @@ -18,7 +18,6 @@ #include #include "mysql.h" -#include "mysqld_error.h" #include "proxysql_utils.h" @@ -57,7 +56,6 @@ int create_testing_tables(MYSQL* mysql_server) { int perform_workload_on_connection(MYSQL* proxy, MYSQL* admin) { // Change default query rules to avoid replication issues -// MYSQL_QUERY(admin, "UPDATE mysql_query_rules SET destination_hostgroup=0 WHERE rule_id=2"); MYSQL_QUERY(admin, "UPDATE mysql_query_rules SET active=0"); MYSQL_QUERY(admin, "LOAD MYSQL QUERY RULES TO RUNTIME"); @@ -175,7 +173,6 @@ int perform_workload_on_connection(MYSQL* proxy, MYSQL* admin) { ok(ops_err_msg.empty() == true, "Operations should complete successfully - '%s'", ops_err_msg.c_str()); // Recover default query rules -// MYSQL_QUERY(admin, "UPDATE mysql_query_rules SET destination_hostgroup=0 WHERE rule_id=2"); MYSQL_QUERY(admin, "UPDATE mysql_query_rules SET active=1"); MYSQL_QUERY(admin, "LOAD MYSQL QUERY RULES TO RUNTIME"); diff --git a/test/tap/tests_with_deps/deprecate_eof_support/eof_packet_mixed_queries-t.cpp b/test/tap/tests_with_deps/deprecate_eof_support/eof_packet_mixed_queries-t.cpp index d55fa7f2f6..bba026eba2 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/eof_packet_mixed_queries-t.cpp +++ b/test/tap/tests_with_deps/deprecate_eof_support/eof_packet_mixed_queries-t.cpp @@ -11,7 +11,6 @@ * - Fast forward */ -#include #include #include #include @@ -150,13 +149,14 @@ pair perform_stmt_select_query( p_binds[0].is_null = 0; p_binds[0].length = 0; - if (mysql_stmt_bind_param(stmts, p_binds)) { - string_format("'mysql_stmt_bind_param' at line %d failed: %s", err_msg, __LINE__, mysql_stmt_error(stmts)); + int myerr = 0; + + if ((myerr = mysql_stmt_bind_param(stmts, p_binds))) { + string_format("'mysql_stmt_bind_param' at line %d failed with error %d", err_msg, __LINE__, myerr); return { EXIT_FAILURE, err_msg }; } - int s_err = mysql_stmt_execute(stmts); - if (s_err != EXIT_SUCCESS) { + if ((myerr = mysql_stmt_execute(stmts))) { string_format("'mysql_stmt_execute' at line %d failed: %s", err_msg, __LINE__, mysql_stmt_error(stmts)); return { EXIT_FAILURE, err_msg }; } @@ -184,20 +184,18 @@ pair perform_stmt_select_query( r_binds[2].length= &length[2]; r_binds[2].error= &error[2]; - s_err = mysql_stmt_bind_result(stmts, r_binds); - if (s_err != EXIT_SUCCESS) { - string_format("'mysql_stmt_bind_result' at line %d failed: %s", err_msg, __LINE__, mysql_stmt_error(stmts)); + if ((myerr = mysql_stmt_bind_result(stmts, r_binds))) { + string_format("'mysql_stmt_bind_result' at line %d failed with error %d", err_msg, __LINE__, myerr); return { EXIT_FAILURE, err_msg }; } - if (mysql_stmt_store_result(stmts) || mysql_errno(mysql_server) != EXIT_SUCCESS) { - string_format("'mysql_stmt_store_result' at line %d failed: %s", err_msg, __LINE__, mysql_stmt_error(stmts)); + if ((myerr = mysql_stmt_store_result(stmts)) || mysql_errno(mysql_server) != EXIT_SUCCESS) { + string_format("'mysql_stmt_store_result' at line %d failed with error %d", err_msg, __LINE__, myerr); return { EXIT_FAILURE, err_msg }; } - s_err = mysql_stmt_fetch(stmts); - if (s_err != EXIT_SUCCESS) { - string_format("'mysql_stmt_fetch' at line %d failed: %s", err_msg, __LINE__, mysql_stmt_error(stmts)); + if ((myerr = mysql_stmt_fetch(stmts))) { + string_format("'mysql_stmt_fetch' at line %d failed with error %d", err_msg, __LINE__, myerr); return { EXIT_FAILURE, err_msg }; } @@ -313,8 +311,10 @@ pair perform_stmt_update_query( bindsu[2].is_null = 0; bindsu[2].length = 0; - if (mysql_stmt_bind_param(stmtu, bindsu)) { - string_format("'mysql_stmt_bind_param' at line %d failed: %s", err_msg, __LINE__, mysql_stmt_error(stmtu)); + int myerr = 0; + + if ((myerr=mysql_stmt_bind_param(stmtu, bindsu))) { + string_format("'mysql_stmt_bind_param' at line %d failed with error %d", err_msg, __LINE__, myerr); return { EXIT_FAILURE, err_msg }; } @@ -497,9 +497,6 @@ int test_target_queries(MYSQL* proxy) { return !(op_res.first == EXIT_SUCCESS); } -// NOTE: Test hardcoded to hostgroup '0' -const uint32_t HG_ID = 0; - int main(int argc, char** argv) { CommandLine cl; @@ -524,8 +521,8 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } - // Change default query rules to avoid replication issues - MYSQL_QUERY(admin, "UPDATE mysql_query_rules SET destination_hostgroup=0 WHERE rule_id=2"); + // Change default query rules to avoid replication issues; This test only requires the default hostgroup + MYSQL_QUERY(admin, "UPDATE mysql_query_rules SET active=0"); MYSQL_QUERY(admin, "LOAD MYSQL QUERY RULES TO RUNTIME"); MYSQL* proxy = mysql_init(NULL); @@ -578,7 +575,7 @@ int main(int argc, char** argv) { cleanup: // Recover default query rules - MYSQL_QUERY(admin, "UPDATE mysql_query_rules SET destination_hostgroup=0 WHERE rule_id=2"); + MYSQL_QUERY(admin, "UPDATE mysql_query_rules SET active=1"); MYSQL_QUERY(admin, "LOAD MYSQL QUERY RULES TO RUNTIME"); mysql_close(admin);