From 7300e5878771558f17503f4225a2a72c120a9990 Mon Sep 17 00:00:00 2001 From: VilhoRaatikka Date: Tue, 16 Sep 2014 12:11:08 +0300 Subject: [PATCH] Fix to #547, http://bugs.skysql.com/show_bug.cgi?id=547 readwritesplit.c:get_dcb now searches for master if slave is not available --- .../routing/readwritesplit/readwritesplit.c | 170 +++++++++++++----- 1 file changed, 126 insertions(+), 44 deletions(-) diff --git a/server/modules/routing/readwritesplit/readwritesplit.c b/server/modules/routing/readwritesplit/readwritesplit.c index e239b72ab..3f3b8516f 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.c +++ b/server/modules/routing/readwritesplit/readwritesplit.c @@ -268,6 +268,8 @@ static bool handle_error_new_connection( GWBUF* errmsg); static bool handle_error_reply_client(SESSION* ses, GWBUF* errmsg); +static backend_ref_t* get_root_master_bref(ROUTER_CLIENT_SES* rses); + static BACKEND* get_root_master( backend_ref_t* servers, int router_nservers); @@ -1044,6 +1046,7 @@ static bool get_dcb( int max_rlag) { backend_ref_t* backend_ref; + backend_ref_t* master_bref; int smallest_nconn = -1; int i; bool succp = false; @@ -1059,16 +1062,19 @@ static bool get_dcb( backend_ref = rses->rses_backend_ref; /** get root master from available servers */ + master_bref = get_root_master_bref(rses); +#if defined(SS_DEBUG) + master_host = get_root_master(backend_ref, rses->rses_nbackends); - + ss_dassert(master_bref->bref_backend == master_host); +#endif if (name != NULL) /*< Choose backend by name from a hint */ { ss_dassert(btype != BE_MASTER); /*< Master dominates and no name should be passed with it */ for (i=0; irses_nbackends; i++) { - BACKEND* b = backend_ref[i].bref_backend; - + BACKEND* b = backend_ref[i].bref_backend; /** * To become chosen: * backend must be in use, name must match, @@ -1081,10 +1087,10 @@ static bool get_dcb( name, b->backend_server->unique_name, PATH_MAX) == 0) && - master_host != NULL && + master_bref->bref_backend != NULL && (SERVER_IS_SLAVE(b->backend_server) || - SERVER_IS_RELAY_SERVER(b->backend_server) || - SERVER_IS_MASTER(b->backend_server))) + SERVER_IS_RELAY_SERVER(b->backend_server) || + SERVER_IS_MASTER(b->backend_server))) { *p_dcb = backend_ref[i].bref_dcb; succp = true; @@ -1113,15 +1119,15 @@ static bool get_dcb( * at the moment. */ if (BREF_IS_IN_USE((&backend_ref[i])) && - master_host != NULL && - b->backend_server != master_host->backend_server && + master_bref->bref_backend != NULL && + b->backend_server != master_bref->bref_backend->backend_server && (max_rlag == MAX_RLAG_UNDEFINED || (b->backend_server->rlag != MAX_RLAG_NOT_AVAILABLE && - b->backend_server->rlag <= max_rlag)) && + b->backend_server->rlag <= max_rlag)) && (SERVER_IS_SLAVE(b->backend_server) || - SERVER_IS_RELAY_SERVER(b->backend_server)) && + SERVER_IS_RELAY_SERVER(b->backend_server)) && (smallest_nconn == -1 || - b->backend_conn_count < smallest_nconn)) + b->backend_conn_count < smallest_nconn)) { *p_dcb = backend_ref[i].bref_dcb; smallest_nconn = b->backend_conn_count; @@ -1132,40 +1138,54 @@ static bool get_dcb( if (!succp) /*< No valid slave was found, search master next */ { + if (rses->router->available_slaves) + { + rses->router->available_slaves = false; + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Warning : No slaves available " + "for the service %s.", + rses->router->service->name))); + } + + btype = BE_MASTER; - - if (BREF_IS_IN_USE(backend_ref)) + + + if (BREF_IS_IN_USE(master_bref)) { - *p_dcb = backend_ref->bref_dcb; + *p_dcb = master_bref->bref_dcb; succp = true; - ss_dassert(backend_ref->bref_dcb->state != DCB_STATE_ZOMBIE); + ss_dassert(master_bref->bref_dcb->state != DCB_STATE_ZOMBIE); ss_dassert( - (master_host && (backend_ref->bref_backend->backend_server == master_host->backend_server)) && + (master_bref->bref_backend && + (master_bref->bref_backend->backend_server == + master_bref->bref_backend->backend_server)) && smallest_nconn == -1); - - if (rses->router->available_slaves) - { - rses->router->available_slaves = false; - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "Warning : No slaves available " - "for the service %s. " - "Using master %s:%d " - "instead.", - rses->router->service->name, - backend_ref->bref_backend->backend_server->name, - backend_ref->bref_backend->backend_server->port))); - } + + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Using master %s:%d instead.", + master_bref->bref_backend->backend_server->name, + master_bref->bref_backend->backend_server->port))); } + else + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error : No master is availabe either. " + "Unable to find backend server for " + "routing."))); + } } else if (rses->router->available_slaves == false) { rses->router->available_slaves = true; LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, - "At least one slave has become avilable for " + "At least one slave has become available for " "the service %s.", rses->router->service->name))); } @@ -1179,7 +1199,9 @@ static bool get_dcb( BACKEND* b = backend_ref[i].bref_backend; if (BREF_IS_IN_USE((&backend_ref[i])) && - (master_host && (b->backend_server == master_host->backend_server))) + (master_bref->bref_backend && + (b->backend_server == + master_bref->bref_backend->backend_server))) { *p_dcb = backend_ref[i].bref_dcb; succp = true; @@ -2430,7 +2452,7 @@ static bool select_connect_backend_servers( const int min_nslaves = 0; /*< not configurable at the time */ bool is_synced_master; int (*p)(const void *, const void *); - BACKEND *master_host = NULL; + BACKEND* master_host = NULL; if (p_master_ref == NULL || backend_ref == NULL) { @@ -4305,22 +4327,82 @@ static bool prep_stmt_drop( * @return The Master found * */ -static BACKEND *get_root_master(backend_ref_t *servers, int router_nservers) { +static BACKEND *get_root_master( + backend_ref_t *servers, + int router_nservers) +{ int i = 0; BACKEND * master_host = NULL; - for (i = 0; i< router_nservers; i++) { - BACKEND* b = NULL; - b = servers[i].bref_backend; - if (b && (b->backend_server->status & (SERVER_MASTER|SERVER_MAINT)) == SERVER_MASTER) { - if (master_host && b->backend_server->depth < master_host->backend_server->depth) { - master_host = b; - } else { - if (master_host == NULL) { - master_host = b; - } + for (i = 0; i< router_nservers; i++) + { + BACKEND* b; + + if (servers[i].bref_backend == NULL) + { + continue; + } + + b = servers[i].bref_backend; + + if ((b->backend_server->status & + (SERVER_MASTER|SERVER_MAINT)) == SERVER_MASTER) + { + if (master_host == NULL || + (b->backend_server->depth < master_host->backend_server->depth)) + { + master_host = b; } } } return master_host; } + + +/******************************** + * This routine returns the root master server from MySQL replication tree + * Get the root Master rule: + * + * find server with the lowest replication depth level + * and the SERVER_MASTER bitval + * Servers are checked even if they are in 'maintenance' + * + * @param rses pointer to router session + * @return pointer to backend reference of the root master + * + */ +static backend_ref_t* get_root_master_bref( + ROUTER_CLIENT_SES* rses) +{ + backend_ref_t* bref; + backend_ref_t* candidate_bref = NULL; + int i = 0; + + bref = rses->rses_backend_ref; + + while (irses_nbackends) + { + if (SERVER_IS_MASTER(bref->bref_backend->backend_server)) + { + if (candidate_bref == NULL || + (bref->bref_backend->backend_server->depth < + candidate_bref->bref_backend->backend_server->depth)) + { + candidate_bref = bref; + } + } + bref++; + i += 1; + } + return candidate_bref; +} + + + + + + + + + +