diff --git a/server/modules/routing/binlog/blr.c b/server/modules/routing/binlog/blr.c index cd0de2fa0..5c0489a2d 100644 --- a/server/modules/routing/binlog/blr.c +++ b/server/modules/routing/binlog/blr.c @@ -288,6 +288,8 @@ char task_name[BLRM_TASK_NAME_LEN+1] = ""; inst->set_master_uuid = NULL; inst->set_master_server_id = NULL; + inst->serverid = 0; + my_uuid_init((ulong)rand()*12345,12345); if ((defuuid = (unsigned char *)malloc(20)) != NULL) { @@ -332,9 +334,28 @@ char task_name[BLRM_TASK_NAME_LEN+1] = ""; { inst->uuid = strdup(value); } - else if (strcmp(options[i], "server-id") == 0) + else if ( (strcmp(options[i], "server_id") == 0) || (strcmp(options[i], "server-id") == 0) ) { inst->serverid = atoi(value); + if (strcmp(options[i], "server-id") == 0) { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "WARNING: Configuration setting '%s' in router_options is deprecated" + " and will be removed in a later version of MaxScale. " + "Please use the new setting '%s' instead.", + "server-id", "server_id"))); + } + + if (inst->serverid <= 0) { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error : Service %s, invalid server-id '%s'. " + "Please configure it with a unique positive integer value (1..2^32-1)", + service->name, value))); + + free(inst); + return NULL; + } } else if (strcmp(options[i], "user") == 0) { @@ -348,13 +369,21 @@ char task_name[BLRM_TASK_NAME_LEN+1] = ""; { inst->password = strdup(value); } - else if (strcmp(options[i], "master-id") == 0) + else if ( (strcmp(options[i], "master_id") == 0) || (strcmp(options[i], "master-id") == 0) ) { int master_id = atoi(value); if (master_id > 0) { inst->masterid = master_id; inst->set_master_server_id = strdup(value); } + if (strcmp(options[i], "master-id") == 0) { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "WARNING: Configuration setting '%s' in router_options is deprecated" + " and will be removed in a later version of MaxScale. " + "Please use the new setting '%s' instead.", + "master-id", "master_id"))); + } } else if (strcmp(options[i], "master_uuid") == 0) { @@ -485,6 +514,14 @@ char task_name[BLRM_TASK_NAME_LEN+1] = ""; return NULL; } + if (inst->serverid <= 0) { + skygw_log_write_flush(LOGFILE_ERROR, + "Error : Service %s, server-id is not configured. Please configure it with a unique positive integer value (1..2^32-1)", + service->name, inst->serverid); + free(inst); + return NULL; + } + /** * If binlogdir is not found create it * On failure don't start the instance diff --git a/server/modules/routing/binlog/blr_master.c b/server/modules/routing/binlog/blr_master.c index c87d3ee31..a214ffd0c 100644 --- a/server/modules/routing/binlog/blr_master.c +++ b/server/modules/routing/binlog/blr_master.c @@ -98,6 +98,7 @@ GWBUF *blr_read_events_from_pos(ROUTER_INSTANCE *router, unsigned long long pos, static void blr_check_last_master_event(void *inst); extern int blr_check_heartbeat(ROUTER_INSTANCE *router); extern char * blr_last_event_description(ROUTER_INSTANCE *router); +static void blr_log_identity(ROUTER_INSTANCE *router); static int keepalive = 1; @@ -662,6 +663,9 @@ char task_name[BLRM_TASK_NAME_LEN + 1] = ""; snprintf(task_name, BLRM_TASK_NAME_LEN, "%s heartbeat", router->service->name); hktask_add(task_name, blr_check_last_master_event, router, router->heartbeat); + /* Log binlog router identity */ + blr_log_identity(router); + break; } @@ -2078,3 +2082,52 @@ char *event_desc = NULL; return 1; } +static void blr_log_identity(ROUTER_INSTANCE *router) { + + char *master_uuid; + char *master_hostname; + char *master_version; + + if (router->set_master_version) + master_version = router->set_master_version; + else { + master_version = blr_extract_column(router->saved_master.selectver, 1); + } + if (router->set_master_hostname) + master_hostname = router->set_master_hostname; + else { + master_hostname = blr_extract_column(router->saved_master.selecthostname, 1); + } + if (router->set_master_uuid) + master_uuid = router->master_uuid; + else { + master_uuid = blr_extract_column(router->saved_master.uuid, 2); + } + + LOGIF(LT, (skygw_log_write_flush( + LOGFILE_TRACE, + "%s: identity seen by the master: " + "server-id: %d, uuid: %s", + router->service->name, + router->serverid, (router->uuid == NULL ? "not available" : router->uuid)))); + + /* MariaDB 5.5 and MariaDB don't have the MASTER_UUID var */ + if (master_uuid == NULL) { + LOGIF(LT, (skygw_log_write_flush( + LOGFILE_TRACE, + "%s: identity seen by the slaves: " + "server-id: %d, hostname: %s, MySQL version: %s", + router->service->name, + router->masterid, (master_hostname == NULL ? "not available" : master_hostname), + (master_version == NULL ? "not available" : master_version)))); + } else { + LOGIF(LT, (skygw_log_write_flush( + LOGFILE_TRACE, + "%s: identity seen by the slaves: " + "server-id: %d, uuid: %s, hostname: %s, MySQL version: %s", + router->service->name, + router->masterid, master_uuid, + (master_hostname == NULL ? "not available" : master_hostname), + (master_version == NULL ? "not available" : master_version)))); + } +} diff --git a/server/modules/routing/binlog/blr_slave.c b/server/modules/routing/binlog/blr_slave.c index e5e2e8010..911e78d88 100644 --- a/server/modules/routing/binlog/blr_slave.c +++ b/server/modules/routing/binlog/blr_slave.c @@ -142,6 +142,8 @@ static int blr_slave_handle_variables(ROUTER_INSTANCE *router, ROUTER_SLAVE *sla static int blr_slave_send_warning_message(ROUTER_INSTANCE* router, ROUTER_SLAVE* slave, char *message); static int blr_slave_show_warnings(ROUTER_INSTANCE* router, ROUTER_SLAVE* slave); extern int MaxScaleUptime(); +static int blr_slave_send_status_variable(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, char *variable, char *value, int column_type); +static int blr_slave_handle_status_variables(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, char *stmt); void poll_fake_write_event(DCB *dcb); @@ -493,7 +495,7 @@ extern char *strcasestr(); else if (strcasecmp(word, "STATUS") == 0) { free(query_text); - return blr_slave_handle_variables(router, slave, brkb); + return blr_slave_handle_status_variables(router, slave, brkb); } } else if (strcasecmp(word, "VARIABLES") == 0) @@ -569,7 +571,7 @@ extern char *strcasestr(); else if (strcasecmp(word, "STATUS") == 0) { free(query_text); - return blr_slave_handle_variables(router, slave, brkb); + return blr_slave_handle_status_variables(router, slave, brkb); } } else if (strcasecmp(query_text, "SET") == 0) @@ -4053,3 +4055,101 @@ int level_len = 0; } } +/** + * Handle the response to the SQL command "SHOW [GLOBAL] STATUS LIKE or SHOW STATUS LIKE + * + * @param router The binlog router instance + * @param slave The slave server to which we are sending the response + * @param stmt The SQL statement + * @return Non-zero if the variable is handled, 0 if variable is unknown, -1 for syntax error + */ +static int +blr_slave_handle_status_variables(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, char *stmt) { +char *brkb; +char *word; +/* SPACE,TAB,= */ +char *sep = " ,="; + + if ((word = strtok_r(stmt, sep, &brkb)) == NULL) { + return 0; + } else if (strcasecmp(word, "LIKE") == 0) { + if ((word = strtok_r(NULL, sep, &brkb)) == NULL) { + LOGIF(LE, (skygw_log_write(LOGFILE_ERROR, + "%s: Missing LIKE clause in SHOW [GLOBAL] VARIABLES.", + router->service->name))); + return 0; + } else if (strcasecmp(word, "'Uptime'") == 0) { + char uptime[41]=""; + snprintf(uptime, 40, "%d", MaxScaleUptime()); + return blr_slave_send_status_variable(router, slave, "Uptime", uptime, BLR_TYPE_INT); + } else + return 0; + } else + return -1; +} + + +/** + * Send the response to the SQL command "SHOW [GLOBAL] STATUS LIKE 'xxx' + * + * @param router The binlog router instance + * @param slave The slave server to which we are sending the response + * @param variable The variable name + * @param value The variable value + * @param column_type The variable value type (string or int) + * @return Non-zero if data was sent + */ +static int +blr_slave_send_status_variable(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, char *variable, char *value, int column_type) +{ +GWBUF *pkt; +uint8_t *ptr; +int len, vers_len, seqno = 2; +char *p = strdup(variable); +int var_len; +char *old_ptr = p; + + /* Remove heading and trailing "'" */ + if(*p == '\'') + p++; + if (p[strlen(p)-1] == '\'') + p[strlen(p)-1] = '\0'; + + var_len = strlen(p); + + /* force lowercase */ + for(int i = 0; i< var_len; i++) { + p[i] = tolower(p[i]); + } + + /* First char is uppercase */ + p[0]=toupper(p[0]); + + blr_slave_send_fieldcount(router, slave, 2); + + blr_slave_send_columndef_with_info_schema(router, slave, "Variable_name", BLR_TYPE_STRING, 40, seqno++); + blr_slave_send_columndef_with_info_schema(router, slave, "Value", column_type, 40, seqno++); + + blr_slave_send_eof(router, slave, seqno++); + + vers_len = strlen(value); + len = 5 + vers_len + var_len + 1; + if ((pkt = gwbuf_alloc(len)) == NULL) + return 0; + ptr = GWBUF_DATA(pkt); + encode_value(ptr, vers_len + 2 + var_len, 24); // Add length of data packet + ptr += 3; + *ptr++ = seqno++; // Sequence number in response + *ptr++ = var_len; // Length of result string + strncpy((char *)ptr, p, var_len); // Result string with var name + ptr += var_len; + *ptr++ = vers_len; // Length of result string + strncpy((char *)ptr, value, vers_len); // Result string with var value + ptr += vers_len; + slave->dcb->func.write(slave->dcb, pkt); + + free(old_ptr); + + return blr_slave_send_eof(router, slave, seqno++); +} +