Conflicts:
	server/modules/routing/dbshard/dbshard.c
This commit is contained in:
VilhoRaatikka
2014-12-15 15:24:56 +02:00
3 changed files with 415 additions and 69 deletions

View File

@ -450,6 +450,58 @@ int error_count = 0;
param->value))); param->value)));
} }
} }
if(is_dbshard)
{
CONFIG_PARAMETER* param = NULL;
char* ignore_databases;
bool succp;
ignore_databases =
config_get_value(obj->parameters,
"ignore_databases");
if (ignore_databases != NULL)
{
param = config_get_param(
obj->parameters,
"ignore_databases");
}
if (param == NULL)
{
succp = false;
}
else
{
param->qfd.valstr = strdup(param->value);
param->qfd_param_type = STRING_TYPE;
succp = service_set_param_value(obj->element,
param,
ignore_databases,
COUNT_NONE,
STRING_TYPE);
}
if (!succp)
{
if(param){
LOGIF(LM, (skygw_log_write(
LOGFILE_MESSAGE,
"* Warning : invalid value type "
"for parameter \'%s.%s = %s\'\n\tExpected "
"type is [master|all] for "
"use sql variables in.",
((SERVICE*)obj->element)->name,
param->name,
param->value)));
}else{
LOGIF(LE, (skygw_log_write(
LOGFILE_ERROR,
"Error : parameter was NULL")));
}
}
}
/** Parameters for rwsplit router only */ /** Parameters for rwsplit router only */
if (is_rwsplit) if (is_rwsplit)
{ {
@ -1685,6 +1737,7 @@ static char *service_params[] =
"max_slave_connections", "max_slave_connections",
"max_slave_replication_lag", "max_slave_replication_lag",
"use_sql_variables_in", /*< rwsplit only */ "use_sql_variables_in", /*< rwsplit only */
"ignore_databases",
"version_string", "version_string",
"filters", "filters",
"weightby", "weightby",

View File

@ -80,12 +80,14 @@ typedef enum {
TARGET_SLAVE = 0x02, TARGET_SLAVE = 0x02,
TARGET_NAMED_SERVER = 0x04, TARGET_NAMED_SERVER = 0x04,
TARGET_ALL = 0x08, TARGET_ALL = 0x08,
TARGET_RLAG_MAX = 0x10 TARGET_RLAG_MAX = 0x10,
TARGET_ANY = 0x20
} route_target_t; } route_target_t;
#define TARGET_IS_UNDEFINED(t) (t == TARGET_UNDEFINED) #define TARGET_IS_UNDEFINED(t) (t == TARGET_UNDEFINED)
#define TARGET_IS_NAMED_SERVER(t) (t & TARGET_NAMED_SERVER) #define TARGET_IS_NAMED_SERVER(t) (t & TARGET_NAMED_SERVER)
#define TARGET_IS_ALL(t) (t & TARGET_ALL) #define TARGET_IS_ALL(t) (t & TARGET_ALL)
#define TARGET_IS_ANY(t) (t & TARGET_ANY)
typedef struct rses_property_st rses_property_t; typedef struct rses_property_st rses_property_t;
typedef struct router_client_session ROUTER_CLIENT_SES; typedef struct router_client_session ROUTER_CLIENT_SES;
@ -305,7 +307,7 @@ typedef struct router_instance {
#define BACKEND_TYPE(b) (SERVER_IS_MASTER((b)->backend_server) ? BE_MASTER : \ #define BACKEND_TYPE(b) (SERVER_IS_MASTER((b)->backend_server) ? BE_MASTER : \
(SERVER_IS_SLAVE((b)->backend_server) ? BE_SLAVE : BE_UNDEFINED)); (SERVER_IS_SLAVE((b)->backend_server) ? BE_SLAVE : BE_UNDEFINED));
void* dbnames_hash_init(BACKEND** backends); void* dbnames_hash_init(ROUTER_INSTANCE* inst,BACKEND** backends);
bool update_dbnames_hash(BACKEND** backends, HASHTABLE* hashtable); bool update_dbnames_hash(ROUTER_INSTANCE* inst,BACKEND** backends, HASHTABLE* hashtable);
#endif /*< _DBSHARDROUTER_H */ #endif /*< _DBSHARDROUTER_H */

View File

@ -152,6 +152,9 @@ static bool get_shard_dcb(
DCB** dcb, DCB** dcb,
ROUTER_CLIENT_SES* rses, ROUTER_CLIENT_SES* rses,
char* name); char* name);
bool is_ignored_database(ROUTER_INSTANCE* inst, char* str);
#if 0 #if 0
static void rwsplit_process_router_options( static void rwsplit_process_router_options(
ROUTER_INSTANCE* router, ROUTER_INSTANCE* router,
@ -317,12 +320,13 @@ static void* hfree(void* fval)
/** /**
* Updates the hashtable with the database names and where to find them, adding * Updates the hashtable with the database names and where to find them, adding
* new and removing obsolete pairs. * new and removing obsolete pairs.
* @param inst Router instance
* @param backends Backends to query for database names * @param backends Backends to query for database names
* @param hashtable Hashtable to use * @param hashtable Hashtable to use
* @return True if all database and server names were successfully retrieved * @return True if all database and server names were successfully retrieved
* otherwise false * otherwise false
*/ */
bool update_dbnames_hash(BACKEND** backends, HASHTABLE* hashtable) bool update_dbnames_hash(ROUTER_INSTANCE* inst,BACKEND** backends, HASHTABLE* hashtable)
{ {
const unsigned int connect_timeout = 15; const unsigned int connect_timeout = 15;
const unsigned int read_timeout = 10; const unsigned int read_timeout = 10;
@ -434,20 +438,15 @@ bool update_dbnames_hash(BACKEND** backends, HASHTABLE* hashtable)
lengths = mysql_fetch_lengths(result); lengths = mysql_fetch_lengths(result);
/**
* Default databases to ignore, disable for now
*/
#ifdef NO_DEFAULT_DATABASES
if(strncmp(row[0],"information_schema",lengths[0]) == 0 ||
strncmp(row[0],"performance_schema",lengths[0]) == 0 ||
strncmp(row[0],"mysql",lengths[0]) == 0 ||
strncmp(row[0],"mysqlslap",lengths[0]) == 0 ||
strncmp(row[0],"test",lengths[0]) == 0){
continue;
}
#endif
dbnm = (char*)calloc(lengths[0] + 1,sizeof(char)); dbnm = (char*)calloc(lengths[0] + 1,sizeof(char));
memcpy(dbnm,row[0],lengths[0]); memcpy(dbnm,row[0],lengths[0]);
if(is_ignored_database(inst,dbnm))
{
free(dbnm);
continue;
}
servnm = strdup(server->unique_name); servnm = strdup(server->unique_name);
if(hashtable_add(hashtable,dbnm,servnm) == 0) if(hashtable_add(hashtable,dbnm,servnm) == 0)
@ -462,15 +461,16 @@ bool update_dbnames_hash(BACKEND** backends, HASHTABLE* hashtable)
} }
else else
{ {
LOGIF(LE, (skygw_log_write_flush( if(strcmp(srvname,server->unique_name) != 0)
LOGFILE_ERROR, {
"Warning : conflicting " LOGIF(LT, (skygw_log_write_flush(
"databases found. " LOGFILE_TRACE,
"Both \"%s\" and \"%s\" " "Both \"%s\" and \"%s\" "
"have a database \"%s\".", "have a database \"%s\".",
server->unique_name, srvname,
srvname, server->unique_name,
dbnm))); dbnm)));
}
} }
if(srvname) if(srvname)
@ -529,14 +529,37 @@ cleanup:
return rval; return rval;
} }
/**
* Check if the database is in the ignore list of the router instance
* @param inst Router instance
* @param str Null-terminated string with the database name to check
* @return True if the database is in the ignore list and false if it is not in it
*/
bool is_ignored_database(ROUTER_INSTANCE* inst, char* str)
{
if(inst->ignore_list)
{
int i;
for(i = 0;inst->ignore_list[i];i++)
{
if(strcmp(inst->ignore_list[i],str) == 0)
{
return true;
}
}
}
return false;
}
/** /**
* Allocates a new hashtable and inserts database names and where to find them * Allocates a new hashtable and inserts database names and where to find them
* into it. * into it.
* @param inst Router instance
* @param backends Backends to query for database names * @param backends Backends to query for database names
* @return Pointer to the newly allocated hashtable or NULL if an error occurred * @return Pointer to the newly allocated hashtable or NULL if an error occurred
*/ */
void* dbnames_hash_init(BACKEND** backends) void* dbnames_hash_init(ROUTER_INSTANCE* inst,BACKEND** backends)
{ {
HASHTABLE* htbl = hashtable_alloc(512,hashkeyfun,hashcmpfun); HASHTABLE* htbl = hashtable_alloc(512,hashkeyfun,hashcmpfun);
@ -548,13 +571,8 @@ void* dbnames_hash_init(BACKEND** backends)
return NULL; return NULL;
} }
/**Update the new hashtable with the key-value pairs*/ /**Update the new hashtable with the key-value pairs*/
if(!update_dbnames_hash(backends,htbl)) if(!update_dbnames_hash(inst,backends,htbl))
{ {
/*
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,"Errors encountered while querying databases.")));
hashtable_free(htbl);
return NULL;
*/
hashtable_free(htbl); hashtable_free(htbl);
htbl = NULL; htbl = NULL;
} }
@ -568,12 +586,11 @@ void* dbnames_hash_init(BACKEND** backends)
* @param buffer Query to inspect * @param buffer Query to inspect
* @return Name of the backend or NULL if the query contains no known databases. * @return Name of the backend or NULL if the query contains no known databases.
*/ */
char* get_shard_target_name(ROUTER_INSTANCE* router, ROUTER_CLIENT_SES* client, GWBUF* buffer){ char* get_shard_target_name(ROUTER_INSTANCE* router, ROUTER_CLIENT_SES* client, GWBUF* buffer,skygw_query_type_t qtype){
HASHTABLE* ht = router->dbnames_hash; HASHTABLE* ht = router->dbnames_hash;
int sz = 0,i,j; int sz = 0,i,j;
char** dbnms = NULL; char** dbnms = NULL;
char* rval = NULL; char* rval = NULL;
bool has_dbs = false; /**If the query targets any database other than the current one*/ bool has_dbs = false; /**If the query targets any database other than the current one*/
if(!query_is_parsed(buffer)){ if(!query_is_parsed(buffer)){
@ -600,7 +617,8 @@ char* get_shard_target_name(ROUTER_INSTANCE* router, ROUTER_CLIENT_SES* client,
* check if the session has an active database and if it is sharded. * check if the session has an active database and if it is sharded.
*/ */
if(rval == NULL && !has_dbs && client->rses_mysql_session->db[0] != '\0'){ if(QUERY_IS_TYPE(qtype, QUERY_TYPE_SHOW_TABLES) ||
(rval == NULL && !has_dbs && client->rses_mysql_session->db[0] != '\0')){
rval = (char*)hashtable_fetch(ht,client->rses_mysql_session->db); rval = (char*)hashtable_fetch(ht,client->rses_mysql_session->db);
} }
@ -629,7 +647,7 @@ bool check_shard_status(ROUTER_INSTANCE* router, char* shard)
} }
else else
{ {
update_dbnames_hash(router->servers,router->dbnames_hash); update_dbnames_hash(router,router->servers,router->dbnames_hash);
} }
break; break;
} }
@ -637,6 +655,43 @@ bool check_shard_status(ROUTER_INSTANCE* router, char* shard)
return rval; return rval;
} }
char** tokenize_string(char* str)
{
char *tok;
char **list = NULL;
int sz = 2, count = 0;
tok = strtok(str,", ");
if(tok == NULL)
return NULL;
list = (char**)malloc(sizeof(char*)*(sz));
while(tok)
{
if(count + 1 >= sz)
{
char** tmp = realloc(list,sizeof(char*)*(sz*2));
if(tmp == NULL)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : realloc returned NULL: %s.",strerror(errno))));
free(list);
return NULL;
}
list = tmp;
sz *= 2;
}
list[count] = strdup(tok);
count++;
tok = strtok(NULL,", ");
}
list[count] = NULL;
return list;
}
/** /**
* Implementation of the mandatory version entry point * Implementation of the mandatory version entry point
* *
@ -700,7 +755,8 @@ static void refreshInstance(
/** Catch unused parameter types */ /** Catch unused parameter types */
ss_dassert(paramtype == COUNT_TYPE || ss_dassert(paramtype == COUNT_TYPE ||
paramtype == PERCENT_TYPE || paramtype == PERCENT_TYPE ||
paramtype == SQLVAR_TARGET_TYPE); paramtype == SQLVAR_TARGET_TYPE ||
paramtype == STRING_TYPE);
if (paramtype == COUNT_TYPE) if (paramtype == COUNT_TYPE)
{ {
@ -708,6 +764,16 @@ static void refreshInstance(
else if (paramtype == PERCENT_TYPE) else if (paramtype == PERCENT_TYPE)
{ {
} }
else if (paramtype == STRING_TYPE)
{
if (strncmp(param->name,
"ignore_databases",
MAX_PARAM_LEN) == 0)
{
router->ignore_list = tokenize_string(param->qfd.valstr);
}
}
else if (paramtype == SQLVAR_TARGET_TYPE) else if (paramtype == SQLVAR_TARGET_TYPE)
{ {
if (strncmp(param->name, if (strncmp(param->name,
@ -792,8 +858,7 @@ createInstance(SERVICE *service, char **options)
{ {
ROUTER_INSTANCE* router; ROUTER_INSTANCE* router;
SERVER* server; SERVER* server;
//CONFIG_PARAMETER* conf; CONFIG_PARAMETER* conf;
//char* confval = NULL;
int nservers; int nservers;
int i; int i;
@ -862,21 +927,12 @@ createInstance(SERVICE *service, char **options)
router->bitvalue = 0; router->bitvalue = 0;
/* Ignored for now
conf = config_get_param(service->svc_config_param,"ignore_databases"); conf = config_get_param(service->svc_config_param,"ignore_databases");
if(conf) if(conf)
{ {
confval = conf->value; refreshInstance(router, conf);
} }
if(!parse_db_ignore_list(router,confval))
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Parsing of database ignore list failed. ")));
goto clean_up;
}
*/
/** /**
* Read config version number from service to inform what configuration * Read config version number from service to inform what configuration
@ -888,7 +944,7 @@ createInstance(SERVICE *service, char **options)
/** /**
* Get hashtable which includes dbname,backend pairs * Get hashtable which includes dbname,backend pairs
*/ */
router->dbnames_hash = (HASHTABLE*)dbnames_hash_init(router->servers); router->dbnames_hash = (HASHTABLE*)dbnames_hash_init(router,router->servers);
if (router->dbnames_hash == NULL) if (router->dbnames_hash == NULL)
{ {
@ -1383,12 +1439,17 @@ static route_target_t get_shard_route_target (
QUERY_IS_TYPE(qtype, QUERY_TYPE_GSYSVAR_WRITE)) || QUERY_IS_TYPE(qtype, QUERY_TYPE_GSYSVAR_WRITE)) ||
/** enable or disable autocommit are always routed to all */ /** enable or disable autocommit are always routed to all */
QUERY_IS_TYPE(qtype, QUERY_TYPE_ENABLE_AUTOCOMMIT) || QUERY_IS_TYPE(qtype, QUERY_TYPE_ENABLE_AUTOCOMMIT) ||
QUERY_IS_TYPE(qtype, QUERY_TYPE_DISABLE_AUTOCOMMIT) || QUERY_IS_TYPE(qtype, QUERY_TYPE_DISABLE_AUTOCOMMIT))
QUERY_IS_TYPE(qtype, QUERY_TYPE_SYSVAR_READ)) /** added for @@version comment, temporary*/
{ {
/** hints don't affect on routing */ /** hints don't affect on routing */
target = TARGET_ALL; target = TARGET_ALL;
} }
else if(QUERY_IS_TYPE(qtype, QUERY_TYPE_SYSVAR_READ) ||
(use_sql_variables_in == TYPE_ALL &&
QUERY_IS_TYPE(qtype, QUERY_TYPE_GSYSVAR_READ)))
{
target = TARGET_ANY;
}
#if defined(SS_DEBUG) #if defined(SS_DEBUG)
LOGIF(LT, (skygw_log_write( LOGIF(LT, (skygw_log_write(
LOGFILE_TRACE, LOGFILE_TRACE,
@ -1647,6 +1708,137 @@ void check_create_tmp_table(
} }
} }
GWBUF* gen_show_dbs_response(ROUTER_INSTANCE* router, ROUTER_CLIENT_SES* client)
{
GWBUF* rval = NULL;
HASHTABLE* ht = router->dbnames_hash;
HASHITERATOR* iter = hashtable_iterator(ht);
unsigned int coldef_len = 0;
char dbname[MYSQL_DATABASE_MAXLEN+1];
char *value;
unsigned char* ptr;
char catalog[4] = {0x03,'d','e','f'};
const char* schema = "information_schema";
const char* table = "SCHEMATA";
const char* org_table = "SCHEMATA";
const char* name = "Database";
const char* org_name = "SCHEMA_NAME";
char next_length = 0x0c;
char charset[2] = {0x21, 0x00};
char column_length[4] = { MYSQL_DATABASE_MAXLEN,
MYSQL_DATABASE_MAXLEN >> 8,
MYSQL_DATABASE_MAXLEN >> 16,
MYSQL_DATABASE_MAXLEN >> 24 };
char column_type = 0xfd;
char eof[9] = { 0x05,0x00,0x00,
0x03,0xfe,0x00,
0x00,0x22,0x00 };
char ok_packet[11] = { 0x07,0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,
0x00,0x00 };
coldef_len = sizeof(catalog) + strlen(schema) + 1 +
strlen(table) + 1 +
strlen(org_table) + 1 +
strlen(name) + 1 +
strlen(org_name) + 1 +
1 + 2 + 4 + 1 + 2 + 1 + 2;
rval = gwbuf_alloc(5 + 4 + coldef_len + sizeof(eof));
ptr = rval->start;
/**First packet*/
*ptr++ = 0x01;
*ptr++ = 0x00;
*ptr++ = 0x00;
*ptr++ = 0x01;
*ptr++ = 0x01;
/**Second packet containing the column definitions*/
*ptr++ = coldef_len;
*ptr++ = coldef_len >> 8;
*ptr++ = coldef_len >> 16;
*ptr++ = 0x02;
memcpy((void*)ptr,catalog,4);
ptr += 4;
*ptr++ = strlen(schema);
memcpy((void*)ptr,schema,strlen(schema));
ptr += strlen(schema);
*ptr++ = strlen(table);
memcpy((void*)ptr,table,strlen(table));
ptr += strlen(table);
*ptr++ = strlen(org_table);
memcpy((void*)ptr,org_table,strlen(org_table));
ptr += strlen(org_table);
*ptr++ = strlen(name);
memcpy((void*)ptr,name,strlen(name));
ptr += strlen(name);
*ptr++ = strlen(org_name);
memcpy((void*)ptr,org_name,strlen(org_name));
ptr += strlen(org_name);
*ptr++ = next_length;
*ptr++ = charset[0];
*ptr++ = charset[1];
*ptr++ = column_length[0];
*ptr++ = column_length[1];
*ptr++ = column_length[2];
*ptr++ = column_length[3];
*ptr++ = column_type;
*ptr++ = 0x01;
memset(ptr,0,4);
ptr += 4;
memcpy(ptr,eof,sizeof(eof));
unsigned int packet_num = 4;
while((value = (char*)hashtable_next(iter)))
{
GWBUF* temp;
int plen = strlen(value) + 1;
sprintf(dbname,"%s",value);
temp = gwbuf_alloc(plen + 4);
ptr = temp->start;
*ptr++ = plen;
*ptr++ = plen >> 8;
*ptr++ = plen >> 16;
*ptr++ = packet_num++;
*ptr++ = plen - 1;
memcpy(ptr,dbname,plen - 1);
/** Append the row*/
rval = gwbuf_append(rval,temp);
}
eof[3] = packet_num;
GWBUF* last_packet = gwbuf_alloc(sizeof(eof));
memcpy(last_packet->start,eof,sizeof(eof));
rval = gwbuf_append(rval,last_packet);
rval = gwbuf_make_contiguous(rval);
return rval;
}
/** /**
* The main routing entry, this is called with every packet that is * The main routing entry, this is called with every packet that is
* received and has to be forwarded to the backend database. * received and has to be forwarded to the backend database.
@ -1683,6 +1875,7 @@ static int routeQuery(
ROUTER_INSTANCE* inst = (ROUTER_INSTANCE *)instance; ROUTER_INSTANCE* inst = (ROUTER_INSTANCE *)instance;
ROUTER_CLIENT_SES* router_cli_ses = (ROUTER_CLIENT_SES *)router_session; ROUTER_CLIENT_SES* router_cli_ses = (ROUTER_CLIENT_SES *)router_session;
bool rses_is_closed = false; bool rses_is_closed = false;
bool change_successful = false;
route_target_t route_target = TARGET_UNDEFINED; route_target_t route_target = TARGET_UNDEFINED;
bool succp = false; bool succp = false;
char* tname = NULL; char* tname = NULL;
@ -1775,7 +1968,7 @@ static int routeQuery(
if (packet_type == MYSQL_COM_INIT_DB) if (packet_type == MYSQL_COM_INIT_DB)
{ {
if (!change_current_db(inst, router_cli_ses, querybuf)) if (!(change_successful = change_current_db(inst, router_cli_ses, querybuf)))
{ {
LOGIF(LE, (skygw_log_write_flush( LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR, LOGFILE_ERROR,
@ -1785,7 +1978,7 @@ static int routeQuery(
/* goto retblock; */ /* goto retblock; */
} }
/** /**
* !!! Temporary tablen tutkiminen voi olla turhaa. Poista tarvittaessa. * !!! Temporary tablen tutkiminen voi olla turhaa. Poista tarvittaessa.
*/ */
/** /**
@ -1865,6 +2058,42 @@ static int routeQuery(
* Find out whether the query should be routed to single server or to * Find out whether the query should be routed to single server or to
* all of them. * all of them.
*/ */
if(QUERY_IS_TYPE(qtype, QUERY_TYPE_SHOW_DATABASES))
{
/**
* Generate custom response that contains all the databases
* after updating the hashtable
*/
backend_ref_t* backend = NULL;
DCB* backend_dcb = NULL;
int i;
update_dbnames_hash(inst,inst->servers,inst->dbnames_hash);
for(i = 0;i < router_cli_ses->rses_nbackends;i++)
{
if(SERVER_IS_RUNNING(router_cli_ses->rses_backend_ref[i].bref_backend->backend_server))
{
backend = &router_cli_ses->rses_backend_ref[i];
backend_dcb = backend->bref_dcb;
break;
}
}
if(backend)
{
GWBUF* fake = gen_show_dbs_response(inst,router_cli_ses);
poll_add_epollin_event_to_dcb(backend_dcb,fake);
ret = 1;
}
else
{
ret = 0;
}
goto retblock;
}
if (packet_type == MYSQL_COM_INIT_DB) if (packet_type == MYSQL_COM_INIT_DB)
{ {
char dbname[MYSQL_DATABASE_MAXLEN+1]; char dbname[MYSQL_DATABASE_MAXLEN+1];
@ -1877,7 +2106,7 @@ static int routeQuery(
route_target = TARGET_NAMED_SERVER; route_target = TARGET_NAMED_SERVER;
} }
} }
else if((tname = get_shard_target_name(inst,router_cli_ses,querybuf)) != NULL) else if((tname = get_shard_target_name(inst,router_cli_ses,querybuf,qtype)) != NULL)
{ {
bool shard_ok = check_shard_status(inst,tname); bool shard_ok = check_shard_status(inst,tname);
@ -1894,7 +2123,9 @@ static int routeQuery(
* the target is undefined and an error will be returned to the client. * the target is undefined and an error will be returned to the client.
*/ */
if((tname = get_shard_target_name(inst,router_cli_ses,querybuf)) != NULL && update_dbnames_hash(inst,inst->servers,inst->dbnames_hash);
if((tname = get_shard_target_name(inst,router_cli_ses,querybuf,qtype)) != NULL &&
check_shard_status(inst,tname)) check_shard_status(inst,tname))
{ {
route_target = TARGET_NAMED_SERVER; route_target = TARGET_NAMED_SERVER;
@ -1904,6 +2135,11 @@ static int routeQuery(
else else
{ {
/**
* The query targets something else than a shard.
*/
route_target = get_shard_route_target(qtype, route_target = get_shard_route_target(qtype,
router_cli_ses->rses_transaction_active, router_cli_ses->rses_transaction_active,
router_cli_ses->rses_config.rw_use_sql_variables_in, router_cli_ses->rses_config.rw_use_sql_variables_in,
@ -1919,16 +2155,21 @@ static int routeQuery(
char errstr[2048]; char errstr[2048];
GWBUF *errbuff; GWBUF *errbuff;
update_dbnames_hash(inst->servers,inst->dbnames_hash); update_dbnames_hash(inst,inst->servers,inst->dbnames_hash);
tname = get_shard_target_name(inst,router_cli_ses,querybuf); tname = get_shard_target_name(inst,router_cli_ses,querybuf,qtype);
if(tname == NULL && if((tname == NULL &&
router_cli_ses->rses_mysql_session->db[0] == '\0') router_cli_ses->rses_mysql_session->db[0] == '\0') ||
(packet_type == MYSQL_COM_INIT_DB && change_successful) ||
packet_type == MYSQL_COM_FIELD_LIST ||
(router_cli_ses->rses_mysql_session->db[0] != '\0' &&
is_ignored_database(inst,router_cli_ses->rses_mysql_session->db)))
{ {
/** /**
* No current database or databases in query, route to all. * No current database and no databases in query or
* the database is ignored, route to first available backend.
*/ */
route_target = TARGET_ALL; route_target = TARGET_ANY;
} }
else else
@ -1979,6 +2220,32 @@ static int routeQuery(
ret = 0; ret = 0;
goto retblock; goto retblock;
} }
if (TARGET_IS_ANY(route_target))
{
int z;
for(z = 0;inst->servers[z];z++)
{
if(SERVER_IS_RUNNING(inst->servers[z]->backend_server))
{
tname = inst->servers[z]->backend_server->unique_name;
route_target = TARGET_NAMED_SERVER;
break;
}
}
if(TARGET_IS_ANY(route_target))
{
/**No valid backends alive*/
rses_end_locked_router_action(router_cli_ses);
ret = 0;
goto retblock;
}
}
/** /**
* Query is routed to one of the backends * Query is routed to one of the backends
*/ */
@ -4072,6 +4339,8 @@ static bool prep_stmt_drop(
} }
#endif /*< PREP_STMT_CACHING */ #endif /*< PREP_STMT_CACHING */
#if 0
/******************************** /********************************
* This routine returns the root master server from MySQL replication tree * This routine returns the root master server from MySQL replication tree
* Get the root Master rule: * Get the root Master rule:
@ -4116,7 +4385,10 @@ static BACKEND *get_root_master(
return master_host; return master_host;
} }
#endif
#if 0
/******************************** /********************************
* This routine returns the root master server from MySQL replication tree * This routine returns the root master server from MySQL replication tree
* Get the root Master rule: * Get the root Master rule:
@ -4167,6 +4439,7 @@ static backend_ref_t* get_root_master_bref(
return candidate_bref; return candidate_bref;
} }
#endif
static void dbshard_process_router_options( static void dbshard_process_router_options(
ROUTER_INSTANCE* router, ROUTER_INSTANCE* router,
@ -4239,27 +4512,45 @@ static bool change_current_db(
{ {
bool succp; bool succp;
uint8_t* packet; uint8_t* packet;
int message_len; unsigned int plen;
int message_len,i;
char* fail_str; char* fail_str;
if(GWBUF_LENGTH(buf) <= MYSQL_DATABASE_MAXLEN - 5) if(GWBUF_LENGTH(buf) <= MYSQL_DATABASE_MAXLEN - 5)
{ {
packet = GWBUF_DATA(buf); packet = GWBUF_DATA(buf);
plen = gw_mysql_get_byte3(packet) - 1;
/** Copy database name from MySQL packet to session */ /** Copy database name from MySQL packet to session */
strncpy(rses->rses_mysql_session->db,
(char*)(packet + 5), memcpy(rses->rses_mysql_session->db,
(int)(GWBUF_LENGTH(buf) - 5)); packet + 5,
plen);
memset(rses->rses_mysql_session->db + plen,0,1);
/** /**
* Update the session's active database only if it's in the hashtable. * Update the session's active database only if it's in the hashtable.
* If it isn't found, send a custom error packet to the client. * If it isn't found, send a custom error packet to the client.
*/ */
update_dbnames_hash(inst->servers,inst->dbnames_hash); update_dbnames_hash(inst,inst->servers,inst->dbnames_hash);
if(hashtable_fetch( if(hashtable_fetch(
inst->dbnames_hash, inst->dbnames_hash,
(char*)rses->rses_mysql_session->db) == NULL) (char*)rses->rses_mysql_session->db) == NULL)
{ {
if(inst->ignore_list)
{
for(i = 0;inst->ignore_list[i];i++)
{
if(strcmp(inst->ignore_list[i],rses->rses_mysql_session->db) == 0)
{
succp = true;
goto retblock;
}
}
}
/** Create error message */ /** Create error message */
message_len = 25 + MYSQL_DATABASE_MAXLEN; message_len = 25 + MYSQL_DATABASE_MAXLEN;
fail_str = calloc(1, message_len+1); fail_str = calloc(1, message_len+1);