From 23e40dc0f8b4f10362b71155ba2e7318ab0f2f44 Mon Sep 17 00:00:00 2001 From: MassimilianoPinto Date: Tue, 17 Jan 2017 10:38:32 +0100 Subject: [PATCH] MXS-406: slave nodes are sorted before setting 'wsrep_sst_donor' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The slave nodes par od the cluster are sorted by wsrep_local_index or server priority. The sorted list od nodes is then used in ‘wsrep_sst_donor’ variable. Note: candidate master servers are always at the end of the list --- server/modules/monitor/galeramon/galeramon.c | 218 ++++++++++++++----- 1 file changed, 169 insertions(+), 49 deletions(-) diff --git a/server/modules/monitor/galeramon/galeramon.c b/server/modules/monitor/galeramon/galeramon.c index ec2b1a030..0000873ff 100644 --- a/server/modules/monitor/galeramon/galeramon.c +++ b/server/modules/monitor/galeramon/galeramon.c @@ -55,6 +55,7 @@ static MONITOR_SERVERS *set_cluster_master(MONITOR_SERVERS *, MONITOR_SERVERS *, static void disableMasterFailback(void *, int); bool isGaleraEvent(monitor_event_t event); static void update_sst_donor_nodes(MONITOR*, int); +static int compare_cluster_node_index (const void*, const void*, void *); /** * The module entry point routine. It is this routine that @@ -614,7 +615,9 @@ static MONITOR_SERVERS *get_candidate_master(MONITOR* mon) * This means that we can't connect to the root node of the cluster. * * If the node is down, the cluster would recalculate the index values - * and we would find it. In this case, we just can't connect to it. */ + * and we would find it. In this case, we just can't connect to it. + */ + candidate_master = NULL; } @@ -635,7 +638,8 @@ static MONITOR_SERVERS *get_candidate_master(MONITOR* mon) * @param candidate_master The candidate master server accordingly to the selection rule * @return The master node pointer (could be NULL) */ -static MONITOR_SERVERS *set_cluster_master(MONITOR_SERVERS *current_master, MONITOR_SERVERS *candidate_master, +static MONITOR_SERVERS *set_cluster_master(MONITOR_SERVERS *current_master, + MONITOR_SERVERS *candidate_master, int master_stickiness) { /* @@ -687,12 +691,17 @@ static void update_sst_donor_nodes(MONITOR *mon, int is_cluster) MONITOR_SERVERS *ptr; MYSQL_ROW row; MYSQL_RES *result; + GALERA_MONITOR *handle = mon->handle; + bool ignore_priority = true; + if (is_cluster == 1) { MXS_DEBUG("Only one server in the cluster: update_sst_donor_nodes is not performed"); return; } + unsigned int found_slaves = 0; + MONITOR_SERVERS *node_list[is_cluster-1]; /* Donor list size = DONOR_LIST_SET_VAR + n_hosts * max_host_len + n_hosts + 1 */ char *donor_list = MXS_CALLOC(1, strlen(DONOR_LIST_SET_VAR) + @@ -709,46 +718,76 @@ static void update_sst_donor_nodes(MONITOR *mon, int is_cluster) ptr = mon->databases; + /* Create an array of slave nodes */ while (ptr) { if (SERVER_IS_JOINED(ptr->server) && SERVER_IS_SLAVE(ptr->server)) { + node_list[found_slaves] = (MONITOR_SERVERS *)ptr; + found_slaves++; - /* Get the Galera node name */ - if (mysql_query(ptr->con, "SHOW VARIABLES LIKE 'wsrep_node_name'") == 0 - && (result = mysql_store_result(ptr->con)) != NULL) + /* Check the server parameter "priority" + * If no server has "priority" set, then + * the server list will be order by default method. + */ + if (handle->use_priority && + server_get_parameter(ptr->server, "priority")) { - if (mysql_field_count(ptr->con) < 2) - { - mysql_free_result(result); - MXS_ERROR("Unexpected result for \"SHOW VARIABLES LIKE 'wsrep_node_name'\". " - "Expected 2 columns"); - return; - } - - while ((row = mysql_fetch_row(result))) - { - MXS_DEBUG("wsrep_node_name name for %s is [%s]", - ptr->server->unique_name, - row[1]); - - strncat(donor_list, row[1], DONOR_NODE_NAME_MAX_LEN); - strcat(donor_list, ","); - } - - mysql_free_result(result); - } - else - { - MXS_ERROR("Error while selecting 'wsrep_node_name' from node %s: %s", - ptr->server->unique_name, - mysql_error(ptr->con)); + ignore_priority = false; } } - ptr = ptr->next; } + if (ignore_priority) + { + MXS_DEBUG("Use priority is set but no server has priority parameter. " + "Donor server list will be ordered by 'wsrep_local_index'"); + } + + /* Set order type */ + int sort_order = (!ignore_priority) && (int)handle->use_priority; + + /* Sort the array */ + qsort_r(node_list, found_slaves, sizeof(MONITOR_SERVERS *), compare_cluster_node_index, (void *)&sort_order); + + /* Select nodename from each server and append it to node_list */ + for (int k=0; k < found_slaves; k++) + { + MONITOR_SERVERS *ptr = node_list[k]; + + /* Get the Galera node name */ + if (mysql_query(ptr->con, "SHOW VARIABLES LIKE 'wsrep_node_name'") == 0 + && (result = mysql_store_result(ptr->con)) != NULL) + { + if (mysql_field_count(ptr->con) < 2) + { + mysql_free_result(result); + MXS_ERROR("Unexpected result for \"SHOW VARIABLES LIKE 'wsrep_node_name'\". " + "Expected 2 columns"); + return; + } + + while ((row = mysql_fetch_row(result))) + { + MXS_DEBUG("wsrep_node_name name for %s is [%s]", + ptr->server->unique_name, + row[1]); + + strncat(donor_list, row[1], DONOR_NODE_NAME_MAX_LEN); + strcat(donor_list, ","); + } + + mysql_free_result(result); + } + else + { + MXS_ERROR("Error while selecting 'wsrep_node_name' from node %s: %s", + ptr->server->unique_name, + mysql_error(ptr->con)); + } + } + int donor_list_size = strlen(donor_list); if (donor_list[donor_list_size - 1] == ',') { @@ -761,28 +800,109 @@ static void update_sst_donor_nodes(MONITOR *mon, int is_cluster) donor_list); /* Set now rep_sst_donor in each slave node */ - ptr = mon->databases; - while (ptr) + for (int k=0; k < found_slaves; k++) { - if (SERVER_IS_JOINED(ptr->server) && SERVER_IS_SLAVE(ptr->server)) + MONITOR_SERVERS *ptr = node_list[k]; + /* Set the Galera SST donor node list */ + if (mysql_query(ptr->con, donor_list) == 0) { - - /* Set the Galera SST donor node list */ - if (mysql_query(ptr->con, donor_list) == 0) - { - MXS_DEBUG("SET GLOBAL rep_sst_donor OK in node %s", - ptr->server->unique_name); - } - else - { - MXS_ERROR("SET GLOBAL rep_sst_donor error in node %s: %s", - ptr->server->unique_name, - mysql_error(ptr->con)); - } + MXS_DEBUG("SET GLOBAL rep_sst_donor OK in node %s", + ptr->server->unique_name); + } + else + { + MXS_ERROR("SET GLOBAL rep_sst_donor error in node %s: %s", + ptr->server->unique_name, + mysql_error(ptr->con)); } - - ptr = ptr->next; } MXS_FREE(donor_list); } + +/** + * Compare routine for slave nodes sorting + * + * The default order is DESC. + * + * Some special cases, i.e: no give priority, or 0 value + * are handled. + * + * Note: the master selection algorithm is: + * 1) node with lowest wsrep_local_index OR + * 2) lowest priority value and > 0 + * + * the sorting order DESC, will add master candidates + * at the end of the list. + * + * @param a Pointer to array value + * @param b Pointer to array value + * @param order Ordering by wsrep_local_index or node priority + * @return A number less than, threater than or equal to 0 + */ + +static int compare_cluster_node_index (const void *a, const void *b, void *order) +{ + + const MONITOR_SERVERS *s_a = *(MONITOR_SERVERS * const *)a; + const MONITOR_SERVERS *s_b = *(MONITOR_SERVERS * const *)b; + + int list_order = *(int *)order; + + if (list_order) + { + const char *pri_a = server_get_parameter(s_a->server, "priority"); + const char *pri_b = server_get_parameter(s_b->server, "priority"); + + /** + * Check priority parameter: + * + * Return a - b in case of issues + */ + if (!pri_a && pri_b) + { + MXS_DEBUG("Server %s has no given priority. It will be at the beginning of the list", + s_a->server->unique_name); + return -(INT_MAX - 1); + } + else if (pri_a && !pri_b) + { + MXS_DEBUG("Server %s has no given priority. It will be at the beginning of the list", + s_b->server->unique_name); + return INT_MAX - 1; + } + else if (!pri_a && !pri_b) + { + MXS_DEBUG("Servers %s and %s have no given priority. They be at the beginning of the list", + s_a->server->unique_name, + s_b->server->unique_name); + return 0; + } + + /* The given priority is valid */ + int pri_val_a = atoi(pri_a); + int pri_val_b = atoi(pri_b); + + /* Return a - b in case of issues */ + if ((pri_val_a < INT_MAX && pri_val_a > 0) && !(pri_val_b < INT_MAX && pri_val_b > 0)) + { + return pri_val_a; + } + else if (!(pri_val_a < INT_MAX && pri_val_a > 0) && (pri_val_b < INT_MAX && pri_val_b > 0)) + { + return -pri_val_b; + } + else if (!(pri_val_a < INT_MAX && pri_val_a > 0) && !(pri_val_b < INT_MAX && pri_val_b > 0)) + { + return 0; + } + + // The order is DESC: b -a + return pri_val_b - pri_val_a; + } + else + { + // Order is DESC: b - a + return s_b->server->node_id - s_a->server->node_id; + } +}