From 8a0b399896bc157668c356ec038fa741701822a1 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Tue, 30 Jun 2015 18:50:26 +0300 Subject: [PATCH 01/10] Added code for MySQL 5.1 replication detection. --- server/modules/monitor/mysql_mon.c | 651 ++++++++++++++++++----------- server/modules/monitor/mysqlmon.h | 1 + 2 files changed, 400 insertions(+), 252 deletions(-) diff --git a/server/modules/monitor/mysql_mon.c b/server/modules/monitor/mysql_mon.c index 2ba70a499..2fd66766e 100644 --- a/server/modules/monitor/mysql_mon.c +++ b/server/modules/monitor/mysql_mon.c @@ -156,6 +156,7 @@ startMonitor(void *arg, void* opt) handle->detectStaleMaster = 0; handle->master = NULL; handle->script = NULL; + handle->mysql51_replication = false; memset(handle->events,false,sizeof(handle->events)); spinlock_init(&handle->lock); } @@ -199,6 +200,10 @@ startMonitor(void *arg, void* opt) else have_events = true; } + else if(!strcmp(params->name,"mysql51_only")) + { + handle->mysql51_replication = config_truth_value(params->value); + } params = params->next; } if(script_error) @@ -281,7 +286,281 @@ static void diagnostics(DCB *dcb, void *arg) } dcb_printf(dcb, "\n"); } +/** + * Connect to a database + * @param mon Monitor + * @param database Monitored database + * @return true if connection was successful, false if there was an error + */ +static inline bool connect_to_db(MONITOR* mon,MONITOR_SERVERS *database) +{ + char *uname = mon->user; + char *passwd = mon->password; + char *dpwd = decryptPassword(passwd); + int connect_timeout = mon->connect_timeout; + int read_timeout = mon->read_timeout; + int write_timeout = mon->write_timeout; + if(database->con) + mysql_close(database->con); + database->con = mysql_init(NULL); + + mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&connect_timeout); + mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout); + mysql_options(database->con, MYSQL_OPT_WRITE_TIMEOUT, (void *)&write_timeout); + + return (mysql_real_connect(database->con, + database->server->name, + uname, + dpwd, + NULL, + database->server->port, + NULL, + 0) != NULL); +} + +inline void monitor_mysql100_db(MONITOR_SERVERS* database) +{ + bool isslave = false; + MYSQL_RES* result; + MYSQL_ROW row; + + if (mysql_query(database->con, "SHOW ALL SLAVES STATUS") == 0 + && (result = mysql_store_result(database->con)) != NULL) + { + int i = 0; + long master_id = -1; + + if(mysql_field_count(database->con) < 42) + { + mysql_free_result(result); + skygw_log_write(LE,"Error: \"SHOW ALL SLAVES STATUS\" " + "returned less than the expected amount of columns. Expected 42 columns." + " MySQL Version: %s",version_str); + return; + } + + while ((row = mysql_fetch_row(result))) + { + /* get Slave_IO_Running and Slave_SQL_Running values*/ + if (strncmp(row[12], "Yes", 3) == 0 + && strncmp(row[13], "Yes", 3) == 0) { + isslave += 1; + } + + /* If Slave_IO_Running = Yes, assign the master_id to current server: this allows building + * the replication tree, slaves ids will be added to master(s) and we will have at least the + * root master server. + * Please note, there could be no slaves at all if Slave_SQL_Running == 'No' + */ + if (strncmp(row[12], "Yes", 3) == 0) { + /* get Master_Server_Id values */ + master_id = atol(row[41]); + if (master_id == 0) + master_id = -1; + } + + i++; + } + /* store master_id of current node */ + memcpy(&database->server->master_id, &master_id, sizeof(long)); + + mysql_free_result(result); + + /* If all configured slaves are running set this node as slave */ + if (isslave > 0 && isslave == i) + isslave = 1; + else + isslave = 0; + } + + /* Remove addition info */ + monitor_clear_pending_status(database, SERVER_SLAVE_OF_EXTERNAL_MASTER); + monitor_clear_pending_status(database, SERVER_STALE_STATUS); + + /* Please note, the MASTER status and SERVER_SLAVE_OF_EXTERNAL_MASTER + * will be assigned in the monitorMain() via get_replication_tree() routine + */ + + /* Set the Slave Role */ + if (isslave) + { + monitor_set_pending_status(database, SERVER_SLAVE); + /* Avoid any possible stale Master state */ + monitor_clear_pending_status(database, SERVER_MASTER); + } else { + /* Avoid any possible Master/Slave stale state */ + monitor_clear_pending_status(database, SERVER_SLAVE); + monitor_clear_pending_status(database, SERVER_MASTER); + } +} + +inline void monitor_mysql55_db(MONITOR_SERVERS* database) +{ + bool isslave = false; + MYSQL_RES* result; + MYSQL_ROW row; + + if (mysql_query(database->con, "SHOW SLAVE STATUS") == 0 + && (result = mysql_store_result(database->con)) != NULL) + { + long master_id = -1; + if(mysql_field_count(database->con) < 40) + { + mysql_free_result(result); + skygw_log_write(LE,"Error: \"SHOW SLAVE STATUS\" " + "returned less than the expected amount of columns. Expected 40 columns." + " MySQL Version: %s",version_str); + return; + } + + while ((row = mysql_fetch_row(result))) + { + /* get Slave_IO_Running and Slave_SQL_Running values*/ + if (strncmp(row[10], "Yes", 3) == 0 + && strncmp(row[11], "Yes", 3) == 0) { + isslave = 1; + } + + /* If Slave_IO_Running = Yes, assign the master_id to current server: this allows building + * the replication tree, slaves ids will be added to master(s) and we will have at least the + * root master server. + * Please note, there could be no slaves at all if Slave_SQL_Running == 'No' + */ + if (strncmp(row[10], "Yes", 3) == 0) { + /* get Master_Server_Id values */ + master_id = atol(row[39]); + if (master_id == 0) + master_id = -1; + } + } + /* store master_id of current node */ + memcpy(&database->server->master_id, &master_id, sizeof(long)); + + mysql_free_result(result); + } + + /* Remove addition info */ + monitor_clear_pending_status(database, SERVER_SLAVE_OF_EXTERNAL_MASTER); + monitor_clear_pending_status(database, SERVER_STALE_STATUS); + + /* Please note, the MASTER status and SERVER_SLAVE_OF_EXTERNAL_MASTER + * will be assigned in the monitorMain() via get_replication_tree() routine + */ + + /* Set the Slave Role */ + if (isslave) + { + monitor_set_pending_status(database, SERVER_SLAVE); + /* Avoid any possible stale Master state */ + monitor_clear_pending_status(database, SERVER_MASTER); + } else { + /* Avoid any possible Master/Slave stale state */ + monitor_clear_pending_status(database, SERVER_SLAVE); + monitor_clear_pending_status(database, SERVER_MASTER); + } +} + +inline void monitor_mysql51_db(MONITOR_SERVERS* database) +{ + bool isslave = false; + MYSQL_RES* result; + MYSQL_ROW row; + + if (mysql_query(database->con, "SHOW SLAVE STATUS") == 0 + && (result = mysql_store_result(database->con)) != NULL) + { + if(mysql_field_count(database->con) < 38) + { + mysql_free_result(result); + + skygw_log_write(LE,"Error: \"SHOW SLAVE STATUS\" " + "returned less than the expected amount of columns. Expected 38 columns." + " MySQL Version: %s",version_str); + return; + } + + while ((row = mysql_fetch_row(result))) + { + /* get Slave_IO_Running and Slave_SQL_Running values*/ + if (strncmp(row[10], "Yes", 3) == 0 + && strncmp(row[11], "Yes", 3) == 0) { + isslave = 1; + } + } + mysql_free_result(result); + } + + /* Remove addition info */ + monitor_clear_pending_status(database, SERVER_SLAVE_OF_EXTERNAL_MASTER); + monitor_clear_pending_status(database, SERVER_STALE_STATUS); + + /* Please note, the MASTER status and SERVER_SLAVE_OF_EXTERNAL_MASTER + * will be assigned in the monitorMain() via get_replication_tree() routine + */ + + /* Set the Slave Role */ + if (isslave) + { + monitor_set_pending_status(database, SERVER_SLAVE); + /* Avoid any possible stale Master state */ + monitor_clear_pending_status(database, SERVER_MASTER); + } else { + /* Avoid any possible Master/Slave stale state */ + monitor_clear_pending_status(database, SERVER_SLAVE); + monitor_clear_pending_status(database, SERVER_MASTER); + } +} + +static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) +{ + MONITOR_SERVERS* database = mon->databases; + + while(database) + { + bool ismaster = false; + MYSQL_RES* result; + MYSQL_ROW row; + unsigned long *slaves; + int nslaves = 0; + if(database->con) + { + if (mysql_query(database->con, "SHOW SLAVE HOSTS") == 0 + && (result = mysql_store_result(database->con)) != NULL) + { + if(mysql_field_count(database->con) < 4) + { + mysql_free_result(result); + skygw_log_write(LE,"Error: \"SHOW SLAVE HOSTS\" " + "returned less than the expected amount of columns. Expected 4 columns." + " MySQL Version: %s",version_str); + return; + } + + if(mysql_num_rows(result) > 0) + { + ismaster = true; + while ((row = mysql_fetch_row(result))) + { + /* get Slave_IO_Running and Slave_SQL_Running values*/ + database->server->slaves[nslaves] = atol(row[0]); + nslaves++; + } + } + + mysql_free_result(result); + } + + + /* Set the Slave Role */ + if (ismaster) + { + monitor_set_pending_status(database, SERVER_MASTER); + } + } + database = database->next; + } +} /** * Monitor an individual server * @@ -292,271 +571,135 @@ static void monitorDatabase(MONITOR *mon, MONITOR_SERVERS *database) { MYSQL_MONITOR* handle = mon->handle; -MYSQL_ROW row; -MYSQL_RES *result; -int isslave = 0; -char *uname = mon->user; -char *passwd = mon->password; -unsigned long int server_version = 0; -char *server_string; + MYSQL_ROW row; + MYSQL_RES *result; + int isslave = 0; + char *uname = mon->user; + char *passwd = mon->password; + unsigned long int server_version = 0; + char *server_string; - if (database->server->monuser != NULL) + if (database->server->monuser != NULL) + { + uname = database->server->monuser; + passwd = database->server->monpw; + } + + if (uname == NULL) + return; + + /* Don't probe servers in maintenance mode */ + if (SERVER_IN_MAINT(database->server)) + return; + + /** Store previous status */ + database->mon_prev_status = database->server->status; + + if (database->con == NULL || mysql_ping(database->con) != 0) + { + if(connect_to_db(mon,database)) { - uname = database->server->monuser; - passwd = database->server->monpw; + server_clear_status(database->server, SERVER_AUTH_ERROR); + monitor_clear_pending_status(database, SERVER_AUTH_ERROR); } - - if (uname == NULL) - return; - - /* Don't probe servers in maintenance mode */ - if (SERVER_IN_MAINT(database->server)) - return; - - /** Store previous status */ - database->mon_prev_status = database->server->status; - - if (database->con == NULL || mysql_ping(database->con) != 0) + else { - char *dpwd = decryptPassword(passwd); - int connect_timeout = mon->connect_timeout; - int read_timeout = mon->read_timeout; - int write_timeout = mon->write_timeout; + /* The current server is not running + * + * Store server NOT running in server and monitor server pending struct + * + */ + if (mysql_errno(database->con) == ER_ACCESS_DENIED_ERROR) + { + server_set_status(database->server, SERVER_AUTH_ERROR); + monitor_set_pending_status(database, SERVER_AUTH_ERROR); + } + server_clear_status(database->server, SERVER_RUNNING); + monitor_clear_pending_status(database, SERVER_RUNNING); - if(database->con) - mysql_close(database->con); - database->con = mysql_init(NULL); + /* Also clear M/S state in both server and monitor server pending struct */ + server_clear_status(database->server, SERVER_SLAVE); + server_clear_status(database->server, SERVER_MASTER); + monitor_clear_pending_status(database, SERVER_SLAVE); + monitor_clear_pending_status(database, SERVER_MASTER); - mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&connect_timeout); - mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout); - mysql_options(database->con, MYSQL_OPT_WRITE_TIMEOUT, (void *)&write_timeout); - - if (mysql_real_connect(database->con, - database->server->name, - uname, - dpwd, - NULL, - database->server->port, - NULL, - 0) == NULL) - { - free(dpwd); - - /* The current server is not running - * - * Store server NOT running in server and monitor server pending struct - * - */ - if (mysql_errno(database->con) == ER_ACCESS_DENIED_ERROR) - { - server_set_status(database->server, SERVER_AUTH_ERROR); - monitor_set_pending_status(database, SERVER_AUTH_ERROR); - } - server_clear_status(database->server, SERVER_RUNNING); - monitor_clear_pending_status(database, SERVER_RUNNING); + /* Clean addition status too */ + server_clear_status(database->server, SERVER_SLAVE_OF_EXTERNAL_MASTER); + server_clear_status(database->server, SERVER_STALE_STATUS); + monitor_clear_pending_status(database, SERVER_SLAVE_OF_EXTERNAL_MASTER); + monitor_clear_pending_status(database, SERVER_STALE_STATUS); - /* Also clear M/S state in both server and monitor server pending struct */ - server_clear_status(database->server, SERVER_SLAVE); - server_clear_status(database->server, SERVER_MASTER); - monitor_clear_pending_status(database, SERVER_SLAVE); - monitor_clear_pending_status(database, SERVER_MASTER); + /* Log connect failure only once */ + if (mon_status_changed(database) && mon_print_fail_status(database)) + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error : Monitor was unable to connect to " + "server %s:%d : \"%s\"", + database->server->name, + database->server->port, + mysql_error(database->con)))); + } - /* Clean addition status too */ - server_clear_status(database->server, SERVER_SLAVE_OF_EXTERNAL_MASTER); - server_clear_status(database->server, SERVER_STALE_STATUS); - monitor_clear_pending_status(database, SERVER_SLAVE_OF_EXTERNAL_MASTER); - monitor_clear_pending_status(database, SERVER_STALE_STATUS); - - /* Log connect failure only once */ - if (mon_status_changed(database) && mon_print_fail_status(database)) - { - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "Error : Monitor was unable to connect to " - "server %s:%d : \"%s\"", - database->server->name, - database->server->port, - mysql_error(database->con)))); - } - - return; - } - else - { - server_clear_status(database->server, SERVER_AUTH_ERROR); - monitor_clear_pending_status(database, SERVER_AUTH_ERROR); - } - free(dpwd); + return; } - /* Store current status in both server and monitor server pending struct */ - server_set_status(database->server, SERVER_RUNNING); - monitor_set_pending_status(database, SERVER_RUNNING); + } + /* Store current status in both server and monitor server pending struct */ + server_set_status(database->server, SERVER_RUNNING); + monitor_set_pending_status(database, SERVER_RUNNING); - /* get server version from current server */ - server_version = mysql_get_server_version(database->con); + /* get server version from current server */ + server_version = mysql_get_server_version(database->con); - /* get server version string */ - server_string = (char *)mysql_get_server_info(database->con); - if (server_string) { - database->server->server_string = realloc(database->server->server_string, strlen(server_string)+1); - if (database->server->server_string) - strcpy(database->server->server_string, server_string); - } + /* get server version string */ + server_string = (char *)mysql_get_server_info(database->con); + if (server_string) { + database->server->server_string = realloc(database->server->server_string, strlen(server_string)+1); + if (database->server->server_string) + strcpy(database->server->server_string, server_string); + } + + /* get server_id form current node */ + if (mysql_query(database->con, "SELECT @@server_id") == 0 + && (result = mysql_store_result(database->con)) != NULL) + { + long server_id = -1; - /* get server_id form current node */ - if (mysql_query(database->con, "SELECT @@server_id") == 0 - && (result = mysql_store_result(database->con)) != NULL) - { - long server_id = -1; - if(mysql_field_count(database->con) != 1) - { - mysql_free_result(result); - skygw_log_write(LE,"Error: Unexpected result for \"SELECT @@server_id\". Expected 1 columns." - " MySQL Version: %s",version_str); - return; - } - while ((row = mysql_fetch_row(result))) - { - server_id = strtol(row[0], NULL, 10); - if ((errno == ERANGE && (server_id == LONG_MAX - || server_id == LONG_MIN)) || (errno != 0 && server_id == 0)) - { - server_id = -1; - } - database->server->node_id = server_id; - } - mysql_free_result(result); - } - - /* Check if the Slave_SQL_Running and Slave_IO_Running status is - * set to Yes - */ - - /* Check first for MariaDB 10.x.x and get status for multimaster replication */ - if (server_version >= 100000) { - - if (mysql_query(database->con, "SHOW ALL SLAVES STATUS") == 0 - && (result = mysql_store_result(database->con)) != NULL) - { - int i = 0; - long master_id = -1; - - if(mysql_field_count(database->con) < 42) - { - mysql_free_result(result); - skygw_log_write(LE,"Error: \"SHOW ALL SLAVES STATUS\" " - "returned less than the expected amount of columns. Expected 42 columns." - " MySQL Version: %s",version_str); - return; - } - - while ((row = mysql_fetch_row(result))) - { - /* get Slave_IO_Running and Slave_SQL_Running values*/ - if (strncmp(row[12], "Yes", 3) == 0 - && strncmp(row[13], "Yes", 3) == 0) { - isslave += 1; - } - - /* If Slave_IO_Running = Yes, assign the master_id to current server: this allows building - * the replication tree, slaves ids will be added to master(s) and we will have at least the - * root master server. - * Please note, there could be no slaves at all if Slave_SQL_Running == 'No' - */ - if (strncmp(row[12], "Yes", 3) == 0) { - /* get Master_Server_Id values */ - master_id = atol(row[41]); - if (master_id == 0) - master_id = -1; - } - - i++; - } - /* store master_id of current node */ - memcpy(&database->server->master_id, &master_id, sizeof(long)); - - mysql_free_result(result); - - /* If all configured slaves are running set this node as slave */ - if (isslave > 0 && isslave == i) - isslave = 1; - else - isslave = 0; - } - } else { - if (mysql_query(database->con, "SHOW SLAVE STATUS") == 0 - && (result = mysql_store_result(database->con)) != NULL) - { - long master_id = -1; - if(mysql_field_count(database->con) < 40) - { - mysql_free_result(result); - if(server_version < 5*10000 + 5*100) - { - if(database->log_version_err) - { - skygw_log_write(LE,"Error: \"SHOW SLAVE STATUS\" " - " for versions less than 5.5 does not have master_server_id, " - "replication tree cannot be resolved for server %s." - " MySQL Version: %s",database->server->unique_name,version_str); - database->log_version_err = false; - } - } - else - { - skygw_log_write(LE,"Error: \"SHOW SLAVE STATUS\" " - "returned less than the expected amount of columns. Expected 40 columns." - " MySQL Version: %s",version_str); - } - return; - } - - while ((row = mysql_fetch_row(result))) - { - /* get Slave_IO_Running and Slave_SQL_Running values*/ - if (strncmp(row[10], "Yes", 3) == 0 - && strncmp(row[11], "Yes", 3) == 0) { - isslave = 1; - } - - /* If Slave_IO_Running = Yes, assign the master_id to current server: this allows building - * the replication tree, slaves ids will be added to master(s) and we will have at least the - * root master server. - * Please note, there could be no slaves at all if Slave_SQL_Running == 'No' - */ - if (strncmp(row[10], "Yes", 3) == 0) { - /* get Master_Server_Id values */ - master_id = atol(row[39]); - if (master_id == 0) - master_id = -1; - } - } - /* store master_id of current node */ - memcpy(&database->server->master_id, &master_id, sizeof(long)); - - mysql_free_result(result); - } - } - - /* Remove addition info */ - monitor_clear_pending_status(database, SERVER_SLAVE_OF_EXTERNAL_MASTER); - monitor_clear_pending_status(database, SERVER_STALE_STATUS); - - /* Please note, the MASTER status and SERVER_SLAVE_OF_EXTERNAL_MASTER - * will be assigned in the monitorMain() via get_replication_tree() routine - */ - - /* Set the Slave Role */ - if (isslave) + if(mysql_field_count(database->con) != 1) { - monitor_set_pending_status(database, SERVER_SLAVE); - /* Avoid any possible stale Master state */ - monitor_clear_pending_status(database, SERVER_MASTER); - } else { - /* Avoid any possible Master/Slave stale state */ - monitor_clear_pending_status(database, SERVER_SLAVE); - monitor_clear_pending_status(database, SERVER_MASTER); + mysql_free_result(result); + skygw_log_write(LE,"Error: Unexpected result for 'SELECT @@server_id'. Expected 1 column." + " MySQL Version: %s",version_str); + return; } + + while ((row = mysql_fetch_row(result))) + { + server_id = strtol(row[0], NULL, 10); + if ((errno == ERANGE && (server_id == LONG_MAX + || server_id == LONG_MIN)) || (errno != 0 && server_id == 0)) + { + server_id = -1; + } + database->server->node_id = server_id; + } + mysql_free_result(result); + } + + /* Check first for MariaDB 10.x.x and get status for multi-master replication */ + if (server_version >= 100000) + { + monitor_mysql100_db(database); + } + else if(server_version >= 5*10000 + 5*100) + { + monitor_mysql55_db(database); + } + else + { + monitor_mysql51_db(database); + } + } /** @@ -723,7 +866,11 @@ detect_stale_master = handle->detectStaleMaster; } } else { /* Compute the replication tree */ + if(handle->mysql51_replication) + root_master = build_mysql51_replication_tree(mon); + else root_master = get_replication_tree(mon, num_servers); + } /* Update server status from monitor pending status on that server*/ @@ -1302,4 +1449,4 @@ bool isMySQLEvent(monitor_event_t event) return true; } return false; -} \ No newline at end of file +} diff --git a/server/modules/monitor/mysqlmon.h b/server/modules/monitor/mysqlmon.h index 0510a13cf..227b693c9 100644 --- a/server/modules/monitor/mysqlmon.h +++ b/server/modules/monitor/mysqlmon.h @@ -67,6 +67,7 @@ typedef struct { int disableMasterFailback; /**< Monitor flag for Galera Cluster Master failback */ int availableWhenDonor; /**< Monitor flag for Galera Cluster Donor availability */ int disableMasterRoleSetting; /**< Monitor flag to disable setting master role */ + bool mysql51_replication; /**< Use MySQL 5.1 replication */ MONITOR_SERVERS *master; /**< Master server for MySQL Master/Slave replication */ char* script; /*< Script to call when state changes occur on servers */ bool events[MAX_MONITOR_EVENT]; /*< enabled events */ From 2b0f0b89abb6327f64050e8c59541f8bc5ba1858 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Wed, 1 Jul 2015 16:07:27 +0300 Subject: [PATCH 02/10] Added master server id to mysql 5.1 monitoring. --- server/modules/monitor/mysql_mon.c | 39 ++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/server/modules/monitor/mysql_mon.c b/server/modules/monitor/mysql_mon.c index 2fd66766e..07418253d 100644 --- a/server/modules/monitor/mysql_mon.c +++ b/server/modules/monitor/mysql_mon.c @@ -319,7 +319,7 @@ static inline bool connect_to_db(MONITOR* mon,MONITOR_SERVERS *database) 0) != NULL); } -inline void monitor_mysql100_db(MONITOR_SERVERS* database) +static inline void monitor_mysql100_db(MONITOR_SERVERS* database) { bool isslave = false; MYSQL_RES* result; @@ -395,7 +395,7 @@ inline void monitor_mysql100_db(MONITOR_SERVERS* database) } } -inline void monitor_mysql55_db(MONITOR_SERVERS* database) +static inline void monitor_mysql55_db(MONITOR_SERVERS* database) { bool isslave = false; MYSQL_RES* result; @@ -461,7 +461,7 @@ inline void monitor_mysql55_db(MONITOR_SERVERS* database) } } -inline void monitor_mysql51_db(MONITOR_SERVERS* database) +static inline void monitor_mysql51_db(MONITOR_SERVERS* database) { bool isslave = false; MYSQL_RES* result; @@ -515,13 +515,13 @@ inline void monitor_mysql51_db(MONITOR_SERVERS* database) static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) { MONITOR_SERVERS* database = mon->databases; + MONITOR_SERVERS* ptr; while(database) { bool ismaster = false; MYSQL_RES* result; MYSQL_ROW row; - unsigned long *slaves; int nslaves = 0; if(database->con) { @@ -540,12 +540,13 @@ static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) if(mysql_num_rows(result) > 0) { ismaster = true; - while ((row = mysql_fetch_row(result))) + while (nslaves < MONITOR_MAX_NUM_SLAVES && (row = mysql_fetch_row(result))) { /* get Slave_IO_Running and Slave_SQL_Running values*/ database->server->slaves[nslaves] = atol(row[0]); nslaves++; } + database->server->slaves[nslaves] = 0; } mysql_free_result(result); @@ -560,6 +561,32 @@ static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) } database = database->next; } + + database = mon->databases; + + /** */ + while(database) + { + ptr = mon->databases; + + while(ptr) + { + for(int i = 0;ptr->server->slaves[i];i++) + { + if(ptr->server->slaves[i] == database->server->node_id) + { + database->server->master_id = ptr->server->node_id; + break; + } + } + ptr = ptr->next; + } + if(database->server->master_id <= 0) + { + monitor_set_pending_status(database, SERVER_SLAVE_OF_EXTERNAL_MASTER); + } + database = database->next; + } } /** * Monitor an individual server @@ -575,14 +602,12 @@ monitorDatabase(MONITOR *mon, MONITOR_SERVERS *database) MYSQL_RES *result; int isslave = 0; char *uname = mon->user; - char *passwd = mon->password; unsigned long int server_version = 0; char *server_string; if (database->server->monuser != NULL) { uname = database->server->monuser; - passwd = database->server->monpw; } if (uname == NULL) From 0621e33cb0ac00364d56cbea80e1ef3d24af748e Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Wed, 1 Jul 2015 19:38:45 +0300 Subject: [PATCH 03/10] Updated documentation and set C99 mode as the default. --- Documentation/monitors/MySQL-Monitor.md | 8 ++++++++ cmake/macros.cmake | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Documentation/monitors/MySQL-Monitor.md b/Documentation/monitors/MySQL-Monitor.md index 7228c1b10..6c7e70500 100644 --- a/Documentation/monitors/MySQL-Monitor.md +++ b/Documentation/monitors/MySQL-Monitor.md @@ -98,6 +98,14 @@ A list of event names which cause the script to be executed. If this option is n events=master_down,slave_down ``` +### `mysql51_only` + +Enable support for MySQL 5.1 replication monitoring. This is needed if a MySQL server older than 5.5 is used as a slave in replication. + +``` +mysql51_only=true +``` + ## Script events Here is a table of all possible event types and their descriptions. diff --git a/cmake/macros.cmake b/cmake/macros.cmake index d7921f1c4..3c9d16cc0 100644 --- a/cmake/macros.cmake +++ b/cmake/macros.cmake @@ -21,7 +21,7 @@ endmacro() macro(set_variables) # Use C99 - set(USE_C99 FALSE CACHE BOOL "Use C99 standard") + set(USE_C99 TRUE CACHE BOOL "Use C99 standard") # hostname or IP address of MaxScale's host set(TEST_HOST "127.0.0.1" CACHE STRING "hostname or IP address of MaxScale's host") From c8173ec4f7a272e5e4a5bc0288b9767f56bd084f Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Thu, 2 Jul 2015 10:00:38 +0300 Subject: [PATCH 04/10] Added missing return value. --- server/modules/monitor/mysql_mon.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/server/modules/monitor/mysql_mon.c b/server/modules/monitor/mysql_mon.c index 07418253d..b5bbed4dd 100644 --- a/server/modules/monitor/mysql_mon.c +++ b/server/modules/monitor/mysql_mon.c @@ -512,10 +512,18 @@ static inline void monitor_mysql51_db(MONITOR_SERVERS* database) } } +/** + * Build the replication tree for a MySQL 5.1 cluster + * + * This function queries each server with SHOW SLAVE HOSTS to determine which servers + * have slaves replicating from them. + * @param mon Monitor + * @return Lowest server ID master in the monitor + */ static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) { MONITOR_SERVERS* database = mon->databases; - MONITOR_SERVERS* ptr; + MONITOR_SERVERS *ptr,*rval = NULL; while(database) { @@ -534,7 +542,7 @@ static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) skygw_log_write(LE,"Error: \"SHOW SLAVE HOSTS\" " "returned less than the expected amount of columns. Expected 4 columns." " MySQL Version: %s",version_str); - return; + return NULL; } if(mysql_num_rows(result) > 0) @@ -557,6 +565,8 @@ static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) if (ismaster) { monitor_set_pending_status(database, SERVER_MASTER); + if(rval == NULL || rval->server->node_id > database->server->node_id) + rval = database; } } database = database->next; @@ -587,6 +597,7 @@ static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) } database = database->next; } + return rval; } /** * Monitor an individual server From 058f49eb88aa25031ff6b76f898f8865fa5f8e41 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Tue, 7 Jul 2015 20:14:57 +0300 Subject: [PATCH 05/10] Added error message about MySQL versions lower than 5.5 and monitors without the 'mysql51_replication' enabled. --- Documentation/monitors/MySQL-Monitor.md | 4 ++-- server/core/config.c | 1 + server/modules/monitor/mysql_mon.c | 26 ++++++++++++++++++++----- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Documentation/monitors/MySQL-Monitor.md b/Documentation/monitors/MySQL-Monitor.md index 6c7e70500..e53b7c336 100644 --- a/Documentation/monitors/MySQL-Monitor.md +++ b/Documentation/monitors/MySQL-Monitor.md @@ -98,12 +98,12 @@ A list of event names which cause the script to be executed. If this option is n events=master_down,slave_down ``` -### `mysql51_only` +### `mysql51_replication` Enable support for MySQL 5.1 replication monitoring. This is needed if a MySQL server older than 5.5 is used as a slave in replication. ``` -mysql51_only=true +mysql51_replication=true ``` ## Script events diff --git a/server/core/config.c b/server/core/config.c index 58dd42b7a..e6034445d 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -2039,6 +2039,7 @@ static char *monitor_params[] = "passwd", "script", "events", + "mysql51_replication", "monitor_interval", "detect_replication_lag", "detect_stale_master", diff --git a/server/modules/monitor/mysql_mon.c b/server/modules/monitor/mysql_mon.c index b5bbed4dd..8cc78340f 100644 --- a/server/modules/monitor/mysql_mon.c +++ b/server/modules/monitor/mysql_mon.c @@ -81,6 +81,7 @@ static void set_master_heartbeat(MYSQL_MONITOR *, MONITOR_SERVERS *); static void set_slave_heartbeat(MONITOR *, MONITOR_SERVERS *); static int add_slave_to_master(long *, int, long); bool isMySQLEvent(monitor_event_t event); +static bool report_version_err = true; static MONITOR_OBJECT MyObject = { startMonitor, stopMonitor, @@ -200,7 +201,7 @@ startMonitor(void *arg, void* opt) else have_events = true; } - else if(!strcmp(params->name,"mysql51_only")) + else if(!strcmp(params->name,"mysql51_replication")) { handle->mysql51_replication = config_truth_value(params->value); } @@ -539,7 +540,7 @@ static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) if(mysql_field_count(database->con) < 4) { mysql_free_result(result); - skygw_log_write(LE,"Error: \"SHOW SLAVE HOSTS\" " + skygw_log_write_flush(LE,"Error: \"SHOW SLAVE HOSTS\" " "returned less than the expected amount of columns. Expected 4 columns." " MySQL Version: %s",version_str); return NULL; @@ -553,6 +554,7 @@ static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) /* get Slave_IO_Running and Slave_SQL_Running values*/ database->server->slaves[nslaves] = atol(row[0]); nslaves++; + LOGIF(LD,(skygw_log_write_flush(LD,"Found slave at %s:%d",row[1],row[2]))); } database->server->slaves[nslaves] = 0; } @@ -564,6 +566,10 @@ static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) /* Set the Slave Role */ if (ismaster) { + LOGIF(LD,(skygw_log_write(LD,"Master server found at %s:%d with %d slaves", + database->server->name, + database->server->port, + nslaves))); monitor_set_pending_status(database, SERVER_MASTER); if(rval == NULL || rval->server->node_id > database->server->node_id) rval = database; @@ -574,7 +580,7 @@ static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) database = mon->databases; - /** */ + /** Set master server IDs */ while(database) { ptr = mon->databases; @@ -591,7 +597,7 @@ static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) } ptr = ptr->next; } - if(database->server->master_id <= 0) + if(database->server->master_id <= 0 && SERVER_IS_SLAVE(database->server)) { monitor_set_pending_status(database, SERVER_SLAVE_OF_EXTERNAL_MASTER); } @@ -733,7 +739,17 @@ monitorDatabase(MONITOR *mon, MONITOR_SERVERS *database) } else { - monitor_mysql51_db(database); + if(handle->mysql51_replication) + { + monitor_mysql51_db(database); + } + else if(report_version_err) + { + report_version_err = false; + skygw_log_write(LE,"Error: MySQL version is lower than 5.5 and 'mysql51_replication' option is not enabled," + " replication tree cannot be resolved. To enable MySQL 5.1 replication detection, " + "add 'mysql51_replication=true' to the monitor section."); + } } } From a1801237a8135cc277eb0748e6dbcf2c58d3e2bf Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Mon, 13 Jul 2015 19:35:38 +0300 Subject: [PATCH 06/10] Fixed error messages being printed for existing directories. --- server/core/service.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/server/core/service.c b/server/core/service.c index 4e36708f8..84e6f9b13 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -278,10 +278,13 @@ GWPROTOCOL *funcs; if(mkdir_rval) { - skygw_log_write(LOGFILE_ERROR,"Error : Failed to create directory '%s': [%d] %s", - path, - errno, - strerror(errno)); + if(errno != EEXIST) + { + skygw_log_write(LOGFILE_ERROR,"Error : Failed to create directory '%s': [%d] %s", + path, + errno, + strerror(errno)); + } mkdir_rval = 0; } @@ -293,10 +296,13 @@ GWPROTOCOL *funcs; if(mkdir_rval) { - skygw_log_write(LOGFILE_ERROR,"Error : Failed to create directory '%s': [%d] %s", - path, - errno, - strerror(errno)); + if(errno != EEXIST) + { + skygw_log_write(LOGFILE_ERROR,"Error : Failed to create directory '%s': [%d] %s", + path, + errno, + strerror(errno)); + } mkdir_rval = 0; } strncat(path, "/dbusers", PATH_MAX); From b592e226e2c56b4b80215cdc37459e5e79beeb21 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Tue, 14 Jul 2015 12:05:56 +0300 Subject: [PATCH 07/10] converted inline functions to normal functions. --- server/modules/routing/binlog/blr_master.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/modules/routing/binlog/blr_master.c b/server/modules/routing/binlog/blr_master.c index 86bee0b6b..89b6f8c75 100644 --- a/server/modules/routing/binlog/blr_master.c +++ b/server/modules/routing/binlog/blr_master.c @@ -77,7 +77,7 @@ static int blr_rotate_event(ROUTER_INSTANCE *router, uint8_t *pkt, REP_HEADER * void blr_distribute_binlog_record(ROUTER_INSTANCE *router, REP_HEADER *hdr, uint8_t *ptr); static void *CreateMySQLAuthData(char *username, char *password, char *database); void blr_extract_header(uint8_t *pkt, REP_HEADER *hdr); -inline uint32_t extract_field(uint8_t *src, int bits); +static uint32_t extract_field(uint8_t *src, int bits); static void blr_log_packet(logfile_id_t file, char *msg, uint8_t *ptr, int len); static void blr_master_close(ROUTER_INSTANCE *); static char *blr_extract_column(GWBUF *buf, int col); @@ -1166,7 +1166,7 @@ blr_extract_header(register uint8_t *ptr, register REP_HEADER *hdr) * @param src The raw packet source * @param bits The number of bits to extract (multiple of 8) */ -inline uint32_t +static uint32_t extract_field(register uint8_t *src, int bits) { register uint32_t rval = 0, shift = 0; From 40f4d8ee8f88f3bca6fa2b7f6c9da0644f52ba87 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Tue, 14 Jul 2015 12:10:41 +0300 Subject: [PATCH 08/10] Revert "converted inline functions to normal functions." This reverts commit b592e226e2c56b4b80215cdc37459e5e79beeb21. --- server/modules/routing/binlog/blr_master.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/modules/routing/binlog/blr_master.c b/server/modules/routing/binlog/blr_master.c index 89b6f8c75..86bee0b6b 100644 --- a/server/modules/routing/binlog/blr_master.c +++ b/server/modules/routing/binlog/blr_master.c @@ -77,7 +77,7 @@ static int blr_rotate_event(ROUTER_INSTANCE *router, uint8_t *pkt, REP_HEADER * void blr_distribute_binlog_record(ROUTER_INSTANCE *router, REP_HEADER *hdr, uint8_t *ptr); static void *CreateMySQLAuthData(char *username, char *password, char *database); void blr_extract_header(uint8_t *pkt, REP_HEADER *hdr); -static uint32_t extract_field(uint8_t *src, int bits); +inline uint32_t extract_field(uint8_t *src, int bits); static void blr_log_packet(logfile_id_t file, char *msg, uint8_t *ptr, int len); static void blr_master_close(ROUTER_INSTANCE *); static char *blr_extract_column(GWBUF *buf, int col); @@ -1166,7 +1166,7 @@ blr_extract_header(register uint8_t *ptr, register REP_HEADER *hdr) * @param src The raw packet source * @param bits The number of bits to extract (multiple of 8) */ -static uint32_t +inline uint32_t extract_field(register uint8_t *src, int bits) { register uint32_t rval = 0, shift = 0; From 96edaca90c0d5c36999599929962b1aec2ac5bb5 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Tue, 14 Jul 2015 12:14:01 +0300 Subject: [PATCH 09/10] Disabled C99. --- cmake/macros.cmake | 2 +- server/modules/monitor/mysql_mon.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/macros.cmake b/cmake/macros.cmake index 848b3290f..49f4096dc 100644 --- a/cmake/macros.cmake +++ b/cmake/macros.cmake @@ -21,7 +21,7 @@ endmacro() macro(set_variables) # Use C99 - set(USE_C99 TRUE CACHE BOOL "Use C99 standard") + set(USE_C99 FALSE CACHE BOOL "Use C99 standard") # Install the template maxscale.cnf file set(WITH_MAXSCALE_CNF TRUE CACHE BOOL "Install the template maxscale.cnf file") diff --git a/server/modules/monitor/mysql_mon.c b/server/modules/monitor/mysql_mon.c index 8cc78340f..a37526bb5 100644 --- a/server/modules/monitor/mysql_mon.c +++ b/server/modules/monitor/mysql_mon.c @@ -525,7 +525,7 @@ static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) { MONITOR_SERVERS* database = mon->databases; MONITOR_SERVERS *ptr,*rval = NULL; - + int i; while(database) { bool ismaster = false; @@ -587,7 +587,7 @@ static MONITOR_SERVERS *build_mysql51_replication_tree(MONITOR *mon) while(ptr) { - for(int i = 0;ptr->server->slaves[i];i++) + for(i = 0;ptr->server->slaves[i];i++) { if(ptr->server->slaves[i] == database->server->node_id) { From 124ad82de491adf1f6d5d675d737f83d2b64be6c Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Wed, 15 Jul 2015 11:02:59 +0300 Subject: [PATCH 10/10] Small fix to readwritesplit session command handling. --- server/modules/routing/readwritesplit/readwritesplit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/modules/routing/readwritesplit/readwritesplit.c b/server/modules/routing/readwritesplit/readwritesplit.c index b35a674c4..d6dba8e01 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.c +++ b/server/modules/routing/readwritesplit/readwritesplit.c @@ -4049,12 +4049,11 @@ static bool execute_sescmd_in_backend( sescmd_cursor_set_active(scur, true); } - buf = sescmd_cursor_clone_querybuf(scur); - switch (scur->scmd_cur_cmd->my_sescmd_packet_type) { case MYSQL_COM_CHANGE_USER: /** This makes it possible to handle replies correctly */ gwbuf_set_type(scur->scmd_cur_cmd->my_sescmd_buf, GWBUF_TYPE_SESCMD); + buf = sescmd_cursor_clone_querybuf(scur); rc = dcb->func.auth( dcb, NULL, @@ -4087,6 +4086,7 @@ static bool execute_sescmd_in_backend( */ gwbuf_set_type(scur->scmd_cur_cmd->my_sescmd_buf, GWBUF_TYPE_SESCMD); + buf = sescmd_cursor_clone_querybuf(scur); rc = dcb->func.write( dcb, buf);