Added error message generation for non-existent databases and backend status checks.
This commit is contained in:
@ -83,7 +83,7 @@ typedef enum {
|
|||||||
TARGET_RLAG_MAX = 0x10
|
TARGET_RLAG_MAX = 0x10
|
||||||
} route_target_t;
|
} route_target_t;
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
@ -249,6 +249,7 @@ struct router_client_session {
|
|||||||
SPINLOCK rses_lock; /*< protects rses_deleted */
|
SPINLOCK rses_lock; /*< protects rses_deleted */
|
||||||
int rses_versno; /*< even = no active update, else odd. not used 4/14 */
|
int rses_versno; /*< even = no active update, else odd. not used 4/14 */
|
||||||
bool rses_closed; /*< true when closeSession is called */
|
bool rses_closed; /*< true when closeSession is called */
|
||||||
|
DCB* rses_client_dcb;
|
||||||
MYSQL_session* rses_mysql_session;
|
MYSQL_session* rses_mysql_session;
|
||||||
/** Properties listed by their type */
|
/** Properties listed by their type */
|
||||||
rses_property_t* rses_properties[RSES_PROP_TYPE_COUNT];
|
rses_property_t* rses_properties[RSES_PROP_TYPE_COUNT];
|
||||||
@ -299,7 +300,6 @@ typedef struct router_instance {
|
|||||||
bool available_slaves; /*< The router has some slaves available */
|
bool available_slaves; /*< The router has some slaves available */
|
||||||
HASHTABLE* dbnames_hash; /** Hashtable containing the database names and where to find them */
|
HASHTABLE* dbnames_hash; /** Hashtable containing the database names and where to find them */
|
||||||
char** ignore_list;
|
char** ignore_list;
|
||||||
bool update_hash;
|
|
||||||
} ROUTER_INSTANCE;
|
} 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 : \
|
||||||
|
@ -473,6 +473,8 @@ bool update_dbnames_hash(BACKEND** backends, HASHTABLE* hashtable)
|
|||||||
dbnm)));
|
dbnm)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(srvname)
|
||||||
|
{
|
||||||
char* old_backend = (char*)hashtable_fetch(hashtable,dbnm);
|
char* old_backend = (char*)hashtable_fetch(hashtable,dbnm);
|
||||||
int j;
|
int j;
|
||||||
bool is_alive = false;
|
bool is_alive = false;
|
||||||
@ -484,8 +486,8 @@ bool update_dbnames_hash(BACKEND** backends, HASHTABLE* hashtable)
|
|||||||
* alive. If not then update
|
* alive. If not then update
|
||||||
* the hashtable with the current backend's name.
|
* the hashtable with the current backend's name.
|
||||||
*/
|
*/
|
||||||
if(strcmp(server->unique_name,old_backend) == 0 &&
|
if(strcmp(backends[j]->backend_server->unique_name,old_backend) == 0 &&
|
||||||
SERVER_IS_RUNNING(server))
|
SERVER_IS_RUNNING(backends[j]->backend_server))
|
||||||
{
|
{
|
||||||
is_alive = true;
|
is_alive = true;
|
||||||
break;
|
break;
|
||||||
@ -511,6 +513,7 @@ bool update_dbnames_hash(BACKEND** backends, HASHTABLE* hashtable)
|
|||||||
"Error: failed to insert values into hashtable.")));
|
"Error: failed to insert values into hashtable.")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} /*< hashtable_add failed */
|
} /*< hashtable_add failed */
|
||||||
} /*< while */
|
} /*< while */
|
||||||
|
|
||||||
@ -558,12 +561,13 @@ void* dbnames_hash_init(BACKEND** backends)
|
|||||||
return htbl;
|
return htbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool add_shard_info(GWBUF* buffer, char* target)
|
/**
|
||||||
{
|
* Check the hashtable for the right backend for this query.
|
||||||
HINT* hint = hint_create_route(NULL,HINT_ROUTE_TO_NAMED_SERVER,target);
|
* @param router Router instance
|
||||||
return (bool)gwbuf_add_hint(buffer,hint);
|
* @param client Client router session
|
||||||
}
|
* @param buffer Query to inspect
|
||||||
|
* @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){
|
||||||
HASHTABLE* ht = router->dbnames_hash;
|
HASHTABLE* ht = router->dbnames_hash;
|
||||||
int sz = 0,i,j;
|
int sz = 0,i,j;
|
||||||
@ -603,6 +607,36 @@ char* get_shard_target_name(ROUTER_INSTANCE* router, ROUTER_CLIENT_SES* client,
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the backend is still running. If the backend is not running the
|
||||||
|
* hashtable is updated with up-to-date values.
|
||||||
|
* @param router Router instance
|
||||||
|
* @param shard Shard to check
|
||||||
|
* @return True if the backend server is running
|
||||||
|
*/
|
||||||
|
bool check_shard_status(ROUTER_INSTANCE* router, char* shard)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
bool rval = false;
|
||||||
|
|
||||||
|
for(i = 0;router->servers[i];i++)
|
||||||
|
{
|
||||||
|
if(strcmp(router->servers[i]->backend_server->unique_name,shard) == 0)
|
||||||
|
{
|
||||||
|
if(SERVER_IS_RUNNING(router->servers[i]->backend_server))
|
||||||
|
{
|
||||||
|
rval = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
update_dbnames_hash(router->servers,router->dbnames_hash);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the mandatory version entry point
|
* Implementation of the mandatory version entry point
|
||||||
*
|
*
|
||||||
@ -930,6 +964,7 @@ static void* newSession(
|
|||||||
|
|
||||||
client_rses->router = router;
|
client_rses->router = router;
|
||||||
client_rses->rses_mysql_session = (MYSQL_session*)session->data;
|
client_rses->rses_mysql_session = (MYSQL_session*)session->data;
|
||||||
|
client_rses->rses_client_dcb = (DCB*)session->client;
|
||||||
/**
|
/**
|
||||||
* If service config has been changed, reload config from service to
|
* If service config has been changed, reload config from service to
|
||||||
* router instance first.
|
* router instance first.
|
||||||
@ -1348,15 +1383,16 @@ 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
|
/* else */
|
||||||
{
|
/* { */
|
||||||
target = TARGET_NAMED_SERVER;
|
/* target = TARGET_NAMED_SERVER; */
|
||||||
}
|
/* } */
|
||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
LOGIF(LT, (skygw_log_write(
|
LOGIF(LT, (skygw_log_write(
|
||||||
LOGFILE_TRACE,
|
LOGFILE_TRACE,
|
||||||
@ -1651,7 +1687,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;
|
||||||
route_target_t route_target;
|
route_target_t route_target = TARGET_UNDEFINED;
|
||||||
bool succp = false;
|
bool succp = false;
|
||||||
char* tname = NULL;
|
char* tname = NULL;
|
||||||
|
|
||||||
@ -1749,8 +1785,8 @@ static int routeQuery(
|
|||||||
LOGFILE_ERROR,
|
LOGFILE_ERROR,
|
||||||
"Error : Changing database failed.")));
|
"Error : Changing database failed.")));
|
||||||
}
|
}
|
||||||
ret = 1;
|
/* ret = 1; */
|
||||||
goto retblock;
|
/* goto retblock; */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1851,20 +1887,31 @@ static int routeQuery(
|
|||||||
* eventually to master
|
* eventually to master
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the hashtable
|
|
||||||
*/
|
|
||||||
|
|
||||||
if(inst->update_hash)
|
|
||||||
{
|
|
||||||
update_dbnames_hash(inst->servers,inst->dbnames_hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((tname = get_shard_target_name(inst,router_cli_ses,querybuf)) != NULL)
|
if((tname = get_shard_target_name(inst,router_cli_ses,querybuf)) != NULL)
|
||||||
|
{
|
||||||
|
bool shard_ok = check_shard_status(inst,tname);
|
||||||
|
|
||||||
|
if(shard_ok)
|
||||||
{
|
{
|
||||||
route_target = TARGET_NAMED_SERVER;
|
route_target = TARGET_NAMED_SERVER;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shard is not a viable target right now so we check
|
||||||
|
* for an alternate backend with the database. If this is not found
|
||||||
|
* 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 &&
|
||||||
|
check_shard_status(inst,tname))
|
||||||
|
{
|
||||||
|
route_target = TARGET_NAMED_SERVER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
route_target = get_shard_route_target(qtype,
|
route_target = get_shard_route_target(qtype,
|
||||||
@ -1873,6 +1920,45 @@ static int routeQuery(
|
|||||||
querybuf->hint);
|
querybuf->hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(TARGET_IS_UNDEFINED(route_target))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* No valid targets found for this query, return an error packet and update the hashtable. This also adds new databases to the hashtable.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char errstr[2048];
|
||||||
|
GWBUF *errbuff;
|
||||||
|
|
||||||
|
update_dbnames_hash(inst->servers,inst->dbnames_hash);
|
||||||
|
|
||||||
|
if(tname == NULL &&
|
||||||
|
router_cli_ses->rses_mysql_session->db[0] == '\0')
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* No current database or databases in query.
|
||||||
|
*/
|
||||||
|
|
||||||
|
errbuff = modutil_create_mysql_err_msg(1,0,1046,
|
||||||
|
"3D000",
|
||||||
|
"No database selected");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bad shard status
|
||||||
|
*/
|
||||||
|
sprintf(errstr,"Unknown database '%s'",
|
||||||
|
router_cli_ses->rses_mysql_session->db);
|
||||||
|
errbuff = modutil_create_mysql_err_msg(1,0,1049,
|
||||||
|
"42000",
|
||||||
|
errstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
router_cli_ses->rses_client_dcb->func.write(router_cli_ses->rses_client_dcb,errbuff);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (TARGET_IS_ALL(route_target))
|
if (TARGET_IS_ALL(route_target))
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -1992,6 +2078,7 @@ retblock:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
gwbuf_free(querybuf);
|
gwbuf_free(querybuf);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4176,6 +4263,9 @@ static bool change_current_db(
|
|||||||
* 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);
|
||||||
|
|
||||||
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)
|
||||||
|
Reference in New Issue
Block a user