Merge branch 'Z3' into log_manager_test
This commit is contained in:
commit
ae9d38025e
Binary file not shown.
@ -406,9 +406,9 @@ return_here:
|
||||
* restrictive, for example, QUERY_TYPE_READ is smaller than QUERY_TYPE_WRITE.
|
||||
*
|
||||
*/
|
||||
static u_int16_t set_query_type(
|
||||
u_int16_t* qtype,
|
||||
u_int16_t new_type)
|
||||
static u_int32_t set_query_type(
|
||||
u_int32_t* qtype,
|
||||
u_int32_t new_type)
|
||||
{
|
||||
*qtype = MAX(*qtype, new_type);
|
||||
return *qtype;
|
||||
@ -434,7 +434,7 @@ static skygw_query_type_t resolve_query_type(
|
||||
THD* thd)
|
||||
{
|
||||
skygw_query_type_t qtype = QUERY_TYPE_UNKNOWN;
|
||||
u_int16_t type = QUERY_TYPE_UNKNOWN;
|
||||
u_int32_t type = QUERY_TYPE_UNKNOWN;
|
||||
int set_autocommit_stmt = -1; /*< -1 no, 0 disable, 1 enable */
|
||||
LEX* lex;
|
||||
Item* item;
|
||||
@ -501,27 +501,51 @@ static skygw_query_type_t resolve_query_type(
|
||||
type |= QUERY_TYPE_DISABLE_AUTOCOMMIT;
|
||||
type |= QUERY_TYPE_BEGIN_TRX;
|
||||
}
|
||||
/**
|
||||
* REVOKE ALL, ASSIGN_TO_KEYCACHE,
|
||||
* PRELOAD_KEYS, FLUSH, RESET, CREATE|ALTER|DROP SERVER
|
||||
*/
|
||||
|
||||
if (lex->option_type == OPT_GLOBAL)
|
||||
{
|
||||
type |= QUERY_TYPE_GLOBAL_WRITE;
|
||||
goto return_qtype;
|
||||
/**
|
||||
* SHOW syntax http://dev.mysql.com/doc/refman/5.6/en/show.html
|
||||
*/
|
||||
if (lex->sql_command == SQLCOM_SHOW_VARIABLES)
|
||||
{
|
||||
type |= QUERY_TYPE_GSYSVAR_READ;
|
||||
}
|
||||
/**
|
||||
* SET syntax http://dev.mysql.com/doc/refman/5.6/en/set-statement.html
|
||||
*/
|
||||
else if (lex->sql_command == SQLCOM_SET_OPTION)
|
||||
{
|
||||
type |= QUERY_TYPE_GSYSVAR_WRITE;
|
||||
}
|
||||
/**
|
||||
* REVOKE ALL, ASSIGN_TO_KEYCACHE,
|
||||
* PRELOAD_KEYS, FLUSH, RESET, CREATE|ALTER|DROP SERVER
|
||||
*/
|
||||
else
|
||||
{
|
||||
type |= QUERY_TYPE_GSYSVAR_WRITE;
|
||||
}
|
||||
goto return_qtype;
|
||||
}
|
||||
else if (lex->option_type == OPT_SESSION)
|
||||
{
|
||||
/** SHOW commands are all reads to one backend */
|
||||
/**
|
||||
* SHOW syntax http://dev.mysql.com/doc/refman/5.6/en/show.html
|
||||
*/
|
||||
if (lex->sql_command == SQLCOM_SHOW_VARIABLES)
|
||||
{
|
||||
type |= QUERY_TYPE_SESSION_READ;
|
||||
type |= QUERY_TYPE_SYSVAR_READ;
|
||||
}
|
||||
else
|
||||
/**
|
||||
* SET syntax http://dev.mysql.com/doc/refman/5.6/en/set-statement.html
|
||||
*/
|
||||
else if (lex->sql_command == SQLCOM_SET_OPTION)
|
||||
{
|
||||
type |= QUERY_TYPE_SESSION_WRITE;
|
||||
/** Either user- or system variable write */
|
||||
type |= QUERY_TYPE_SESSION_WRITE;
|
||||
}
|
||||
goto return_qtype;
|
||||
goto return_qtype;
|
||||
}
|
||||
/**
|
||||
* 1:ALTER TABLE, TRUNCATE, REPAIR, OPTIMIZE, ANALYZE, CHECK.
|
||||
@ -538,31 +562,26 @@ static skygw_query_type_t resolve_query_type(
|
||||
if (thd->variables.sql_log_bin == 0 &&
|
||||
force_data_modify_op_replication)
|
||||
{
|
||||
/** Not replicated */
|
||||
type |= QUERY_TYPE_SESSION_WRITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
type |= QUERY_TYPE_WRITE;
|
||||
/** Written to binlog, that is, replicated except tmp tables */
|
||||
type |= QUERY_TYPE_WRITE; /*< to master */
|
||||
|
||||
if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE &&
|
||||
lex->sql_command == SQLCOM_CREATE_TABLE)
|
||||
{
|
||||
type |= QUERY_TYPE_CREATE_TMP_TABLE;
|
||||
}
|
||||
|
||||
type |= QUERY_TYPE_CREATE_TMP_TABLE; /*< remember in router */
|
||||
}
|
||||
}
|
||||
goto return_qtype;
|
||||
}
|
||||
|
||||
/** Try to catch session modifications here */
|
||||
switch (lex->sql_command) {
|
||||
case SQLCOM_SET_OPTION: /*< SET commands. */
|
||||
if (lex->option_type == OPT_GLOBAL)
|
||||
{
|
||||
type |= QUERY_TYPE_GLOBAL_WRITE;
|
||||
break;
|
||||
}
|
||||
/**<! fall through */
|
||||
/** fallthrough */
|
||||
case SQLCOM_CHANGE_DB:
|
||||
case SQLCOM_DEALLOCATE_PREPARE:
|
||||
type |= QUERY_TYPE_SESSION_WRITE;
|
||||
@ -599,15 +618,23 @@ static skygw_query_type_t resolve_query_type(
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (QTYPE_LESS_RESTRICTIVE_THAN_WRITE(type)) {
|
||||
#if defined(UPDATE_VAR_SUPPORT)
|
||||
if (QTYPE_LESS_RESTRICTIVE_THAN_WRITE(type))
|
||||
#endif
|
||||
if (QUERY_IS_TYPE(qtype, QUERY_TYPE_UNKNOWN) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_LOCAL_READ) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_READ) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_USERVAR_READ) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_SYSVAR_READ) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_GSYSVAR_READ))
|
||||
{
|
||||
/**
|
||||
* These values won't change qtype more restrictive than write.
|
||||
* UDFs and procedures could possibly cause session-wide write,
|
||||
* but unless their content is replicated this is a limitation
|
||||
* of this implementation.
|
||||
* In other words : UDFs and procedures are not allowed to
|
||||
* perform writes which are not replicated but nede to repeat
|
||||
* perform writes which are not replicated but need to repeat
|
||||
* in every node.
|
||||
* It is not sure if such statements exist. vraa 25.10.13
|
||||
*/
|
||||
@ -628,7 +655,9 @@ static skygw_query_type_t resolve_query_type(
|
||||
|
||||
if (itype == Item::SUBSELECT_ITEM) {
|
||||
continue;
|
||||
} else if (itype == Item::FUNC_ITEM) {
|
||||
}
|
||||
else if (itype == Item::FUNC_ITEM)
|
||||
{
|
||||
int func_qtype = QUERY_TYPE_UNKNOWN;
|
||||
/**
|
||||
* Item types:
|
||||
@ -710,23 +739,39 @@ static skygw_query_type_t resolve_query_type(
|
||||
break;
|
||||
/** System session variable */
|
||||
case Item_func::GSYSVAR_FUNC:
|
||||
/** User-defined variable read */
|
||||
case Item_func::GUSERVAR_FUNC:
|
||||
/** User-defined variable modification */
|
||||
case Item_func::SUSERVAR_FUNC:
|
||||
func_qtype |= QUERY_TYPE_SESSION_READ;
|
||||
func_qtype |= QUERY_TYPE_SYSVAR_READ;
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [resolve_query_type] "
|
||||
"functype SUSERVAR_FUNC, could be "
|
||||
"executed in MaxScale.",
|
||||
"functype GSYSVAR_FUNC, system "
|
||||
"variable read.",
|
||||
pthread_self())));
|
||||
break;
|
||||
/** User-defined variable read */
|
||||
case Item_func::GUSERVAR_FUNC:
|
||||
func_qtype |= QUERY_TYPE_USERVAR_READ;
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [resolve_query_type] "
|
||||
"functype GUSERVAR_FUNC, user "
|
||||
"variable read.",
|
||||
pthread_self())));
|
||||
break;
|
||||
/** User-defined variable modification */
|
||||
case Item_func::SUSERVAR_FUNC:
|
||||
func_qtype |= QUERY_TYPE_SESSION_WRITE;
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [resolve_query_type] "
|
||||
"functype SUSERVAR_FUNC, user "
|
||||
"variable write.",
|
||||
pthread_self())));
|
||||
break;
|
||||
case Item_func::UNKNOWN_FUNC:
|
||||
if (item->name != NULL &&
|
||||
strcmp(item->name, "last_insert_id()") == 0)
|
||||
{
|
||||
func_qtype |= QUERY_TYPE_SESSION_READ;
|
||||
func_qtype |= QUERY_TYPE_MASTER_READ;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -757,6 +802,7 @@ static skygw_query_type_t resolve_query_type(
|
||||
/**< Set new query type */
|
||||
type |= set_query_type(&type, func_qtype);
|
||||
}
|
||||
#if defined(UPDATE_VAR_SUPPORT)
|
||||
/**
|
||||
* Write is as restrictive as it gets due functions,
|
||||
* so break.
|
||||
@ -764,8 +810,9 @@ static skygw_query_type_t resolve_query_type(
|
||||
if ((type & QUERY_TYPE_WRITE) == QUERY_TYPE_WRITE) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
} /**< for */
|
||||
} /**< if */
|
||||
} /**< if */
|
||||
return_qtype:
|
||||
qtype = (skygw_query_type_t)type;
|
||||
return qtype;
|
||||
|
@ -31,23 +31,30 @@ EXTERN_C_BLOCK_BEGIN
|
||||
* is modified
|
||||
*/
|
||||
typedef enum {
|
||||
QUERY_TYPE_UNKNOWN = 0x0000, /*< Initial value, can't be tested bitwisely */
|
||||
QUERY_TYPE_LOCAL_READ = 0x0001, /*< Read non-database data, execute in MaxScale */
|
||||
QUERY_TYPE_READ = 0x0002, /*< No updates */
|
||||
QUERY_TYPE_WRITE = 0x0004, /*< Master data will be modified */
|
||||
QUERY_TYPE_SESSION_WRITE = 0x0008, /*< Session data will be modified */
|
||||
QUERY_TYPE_GLOBAL_WRITE = 0x0010, /*< Global system variable modification */
|
||||
QUERY_TYPE_BEGIN_TRX = 0x0020, /*< BEGIN or START TRANSACTION */
|
||||
QUERY_TYPE_ENABLE_AUTOCOMMIT = 0x0040, /*< SET autocommit=1 */
|
||||
QUERY_TYPE_DISABLE_AUTOCOMMIT = 0x0080, /*< SET autocommit=0 */
|
||||
QUERY_TYPE_ROLLBACK = 0x0100, /*< ROLLBACK */
|
||||
QUERY_TYPE_COMMIT = 0x0200, /*< COMMIT */
|
||||
QUERY_TYPE_PREPARE_NAMED_STMT = 0x0400, /*< Prepared stmt with name from user */
|
||||
QUERY_TYPE_PREPARE_STMT = 0x0800, /*< Prepared stmt with id provided by server */
|
||||
QUERY_TYPE_EXEC_STMT = 0x1000, /*< Execute prepared statement */
|
||||
QUERY_TYPE_SESSION_READ = 0x2000, /*< Read session data (from master 31.8.14) */
|
||||
QUERY_TYPE_CREATE_TMP_TABLE = 0x4000, /*< Create temporary table */
|
||||
QUERY_TYPE_READ_TMP_TABLE = 0x8000 /*< Read temporary table */
|
||||
QUERY_TYPE_UNKNOWN = 0x000000, /*< Initial value, can't be tested bitwisely */
|
||||
QUERY_TYPE_LOCAL_READ = 0x000001, /*< Read non-database data, execute in MaxScale:any */
|
||||
QUERY_TYPE_READ = 0x000002, /*< Read database data:any */
|
||||
QUERY_TYPE_WRITE = 0x000004, /*< Master data will be modified:master */
|
||||
QUERY_TYPE_MASTER_READ = 0x000008, /*< Read from the master:master */
|
||||
QUERY_TYPE_SESSION_WRITE = 0x000010, /*< Session data will be modified:master or all */
|
||||
/** Not implemented yet */
|
||||
// QUERY_TYPE_USERVAR_WRITE = 0x000020, /*< Write a user variable:master or all */
|
||||
QUERY_TYPE_USERVAR_READ = 0x000040, /*< Read a user variable:master or any */
|
||||
QUERY_TYPE_SYSVAR_READ = 0x000080, /*< Read a system variable:master or any */
|
||||
/** Not implemented yet */
|
||||
// QUERY_TYPE_SYSVAR_WRITE = 0x000100, /*< Write a system variable:master or all */
|
||||
QUERY_TYPE_GSYSVAR_READ = 0x000200, /*< Read global system variable:master or any */
|
||||
QUERY_TYPE_GSYSVAR_WRITE = 0x000400, /*< Write global system variable:master or all */
|
||||
QUERY_TYPE_BEGIN_TRX = 0x000800, /*< BEGIN or START TRANSACTION */
|
||||
QUERY_TYPE_ENABLE_AUTOCOMMIT = 0x001000, /*< SET autocommit=1 */
|
||||
QUERY_TYPE_DISABLE_AUTOCOMMIT = 0x002000, /*< SET autocommit=0 */
|
||||
QUERY_TYPE_ROLLBACK = 0x004000, /*< ROLLBACK */
|
||||
QUERY_TYPE_COMMIT = 0x008000, /*< COMMIT */
|
||||
QUERY_TYPE_PREPARE_NAMED_STMT = 0x010000, /*< Prepared stmt with name from user:all */
|
||||
QUERY_TYPE_PREPARE_STMT = 0x020000, /*< Prepared stmt with id provided by server:all */
|
||||
QUERY_TYPE_EXEC_STMT = 0x040000, /*< Execute prepared statement:master or any */
|
||||
QUERY_TYPE_CREATE_TMP_TABLE = 0x080000, /*< Create temporary table:master (could be all) */
|
||||
QUERY_TYPE_READ_TMP_TABLE = 0x100000 /*< Read temporary table:master (could be any) */
|
||||
} skygw_query_type_t;
|
||||
|
||||
|
||||
|
@ -51,7 +51,9 @@ passwd=maxpwd
|
||||
# enable_root_user=<0 or 1, default is 0>
|
||||
# version_string=<specific string for server handshake,
|
||||
# default is the MariaDB embedded library version>
|
||||
#
|
||||
#
|
||||
# read_ses_variables_from_slaves=<Y|N> Default is Yes
|
||||
# write_ses_variables_to_all=<Y|(N)> Default is No
|
||||
# router_options=<option[=value]>,<option[=value]>,...
|
||||
# where value=[master|slave|synced]
|
||||
#
|
||||
@ -70,6 +72,8 @@ router=readwritesplit
|
||||
servers=server1,server2,server3
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
read_ses_variables_from_slaves=No
|
||||
write_ses_variables_to_all=Yes
|
||||
max_slave_connections=50%
|
||||
max_slave_replication_lag=30
|
||||
router_options=slave_selection_criteria=LEAST_BEHIND_MASTER
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <ini.h>
|
||||
#include <config.h>
|
||||
#include <service.h>
|
||||
@ -247,18 +248,28 @@ int error_count = 0;
|
||||
{
|
||||
char* max_slave_conn_str;
|
||||
char* max_slave_rlag_str;
|
||||
char *user;
|
||||
char *auth;
|
||||
char *enable_root_user;
|
||||
char *weightby;
|
||||
char *version_string;
|
||||
bool is_rwsplit = false;
|
||||
|
||||
obj->element = service_alloc(obj->object, router);
|
||||
char *user =
|
||||
config_get_value(obj->parameters, "user");
|
||||
char *auth =
|
||||
config_get_value(obj->parameters, "passwd");
|
||||
char *enable_root_user =
|
||||
config_get_value(obj->parameters, "enable_root_user");
|
||||
char *weightby =
|
||||
config_get_value(obj->parameters, "weightby");
|
||||
user = config_get_value(obj->parameters, "user");
|
||||
auth = config_get_value(obj->parameters, "passwd");
|
||||
enable_root_user = config_get_value(
|
||||
obj->parameters,
|
||||
"enable_root_user");
|
||||
weightby = config_get_value(obj->parameters, "weightby");
|
||||
|
||||
char *version_string = config_get_value(obj->parameters, "version_string");
|
||||
version_string = config_get_value(obj->parameters,
|
||||
"version_string");
|
||||
/** flag for rwsplit-specific parameters */
|
||||
if (strncmp(router, "readwritesplit", strlen("readwritesplit")+1) == 0)
|
||||
{
|
||||
is_rwsplit = true;
|
||||
}
|
||||
|
||||
if (obj->element == NULL) /*< if module load failed */
|
||||
{
|
||||
@ -374,7 +385,71 @@ int error_count = 0;
|
||||
param->value)));
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Parameters for rwsplit router only */
|
||||
if (is_rwsplit)
|
||||
{
|
||||
CONFIG_PARAMETER* param;
|
||||
char* write_sesvars_to_all;
|
||||
char* read_sesvars_from_slaves;
|
||||
bool succp;
|
||||
|
||||
write_sesvars_to_all =
|
||||
config_get_value(obj->parameters,
|
||||
"write_ses_variables_to_all");
|
||||
|
||||
if (write_sesvars_to_all != NULL)
|
||||
{
|
||||
param = config_get_param(
|
||||
obj->parameters,
|
||||
"write_ses_variables_to_all");
|
||||
succp = service_set_param_value(obj->element,
|
||||
param,
|
||||
write_sesvars_to_all,
|
||||
COUNT_NONE,
|
||||
BOOL_TYPE);
|
||||
if (!succp)
|
||||
{
|
||||
LOGIF(LM, (skygw_log_write(
|
||||
LOGFILE_MESSAGE,
|
||||
"* Warning : invalid value type "
|
||||
"for parameter \'%s.%s = %s\'\n\tExpected "
|
||||
"type is <true/false> for write session "
|
||||
"variables to all backends.",
|
||||
((SERVICE*)obj->element)->name,
|
||||
param->name,
|
||||
param->value)));
|
||||
}
|
||||
}
|
||||
read_sesvars_from_slaves =
|
||||
config_get_value(
|
||||
obj->parameters,
|
||||
"read_ses_variables_from_slaves");
|
||||
|
||||
if (read_sesvars_from_slaves != NULL)
|
||||
{
|
||||
param = config_get_param(
|
||||
obj->parameters,
|
||||
"read_ses_variables_from_slaves");
|
||||
succp = service_set_param_value(obj->element,
|
||||
param,
|
||||
read_sesvars_from_slaves,
|
||||
COUNT_NONE,
|
||||
BOOL_TYPE);
|
||||
if (!succp)
|
||||
{
|
||||
LOGIF(LM, (skygw_log_write(
|
||||
LOGFILE_MESSAGE,
|
||||
"* Warning : invalid value type "
|
||||
"for parameter \'%s.%s = %s\'\n\tExpected "
|
||||
"type is <true/false> for write session "
|
||||
"variables to all backends.",
|
||||
((SERVICE*)obj->element)->name,
|
||||
param->name,
|
||||
param->value)));
|
||||
}
|
||||
}
|
||||
} /*< if (rw_split) */
|
||||
} /*< if (router) */
|
||||
else
|
||||
{
|
||||
obj->element = NULL;
|
||||
@ -813,12 +888,15 @@ config_param_type_t config_get_paramtype(
|
||||
return param->qfd_param_type;
|
||||
}
|
||||
|
||||
int config_get_valint(
|
||||
bool config_get_valint(
|
||||
int* val,
|
||||
CONFIG_PARAMETER* param,
|
||||
const char* name, /*< if NULL examine current param only */
|
||||
config_param_type_t ptype)
|
||||
{
|
||||
int val = -1; /*< -1 indicates failure */
|
||||
{
|
||||
bool succp = false;;
|
||||
|
||||
ss_dassert(ptype == COUNT_TYPE || ptype == PERCENT_TYPE);
|
||||
|
||||
while (param)
|
||||
{
|
||||
@ -826,29 +904,57 @@ int config_get_valint(
|
||||
{
|
||||
switch (ptype) {
|
||||
case COUNT_TYPE:
|
||||
val = param->qfd.valcount;
|
||||
goto return_val;
|
||||
*val = param->qfd.valcount;
|
||||
succp = true;
|
||||
goto return_succp;
|
||||
|
||||
case PERCENT_TYPE:
|
||||
val = param->qfd.valpercent;
|
||||
goto return_val;
|
||||
|
||||
case BOOL_TYPE:
|
||||
val = param->qfd.valbool;
|
||||
goto return_val;
|
||||
|
||||
default:
|
||||
goto return_val;
|
||||
*val = param->qfd.valpercent;
|
||||
succp =true;
|
||||
goto return_succp;
|
||||
|
||||
default:
|
||||
goto return_succp;
|
||||
}
|
||||
}
|
||||
else if (name == NULL)
|
||||
{
|
||||
goto return_val;
|
||||
}
|
||||
param = param->next;
|
||||
}
|
||||
return_val:
|
||||
return val;
|
||||
return_succp:
|
||||
return succp;
|
||||
}
|
||||
|
||||
|
||||
bool config_get_valbool(
|
||||
bool* val,
|
||||
CONFIG_PARAMETER* param,
|
||||
const char* name,
|
||||
config_param_type_t ptype)
|
||||
{
|
||||
bool succp;
|
||||
|
||||
ss_dassert(ptype == BOOL_TYPE);
|
||||
|
||||
if (ptype != BOOL_TYPE)
|
||||
{
|
||||
succp = false;
|
||||
goto return_succp;
|
||||
}
|
||||
|
||||
while (param)
|
||||
{
|
||||
if (name == NULL || !strncmp(param->name, name, MAX_PARAM_LEN))
|
||||
{
|
||||
*val = param->qfd.valbool;
|
||||
succp = true;
|
||||
goto return_succp;
|
||||
}
|
||||
param = param->next;
|
||||
}
|
||||
succp = false;
|
||||
|
||||
return_succp:
|
||||
return succp;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1320,6 +1426,8 @@ static char *service_params[] =
|
||||
"enable_root_user",
|
||||
"max_slave_connections",
|
||||
"max_slave_replication_lag",
|
||||
"write_ses_variables_to_all", /*< rwsplit only */
|
||||
"read_ses_variables_from_slaves", /*< rwsplit only */
|
||||
"version_string",
|
||||
"filters",
|
||||
NULL
|
||||
|
@ -52,12 +52,26 @@
|
||||
#include <poll.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
#include <../../../mariadb-5.5.30/include/ft_global.h>
|
||||
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
|
||||
/** To be used with configuration type checks */
|
||||
typedef struct typelib_st {
|
||||
int tl_nelems;
|
||||
const char* tl_name;
|
||||
const char** tl_p_elems;
|
||||
} typelib_t;
|
||||
|
||||
static const char* bool_strings[11]= {"FALSE", "TRUE", "OFF", "ON", "N", "Y", "0", "1", "NO", "YES", 0};
|
||||
typelib_t bool_type = {array_nelems(bool_strings)-1, "bool_type", bool_strings};
|
||||
|
||||
static SPINLOCK service_spin = SPINLOCK_INIT;
|
||||
static SERVICE *allServices = NULL;
|
||||
|
||||
static int find_type(typelib_t* tl, const char* needle, int maxlen);
|
||||
|
||||
static void service_add_qualified_param(
|
||||
SERVICE* svc,
|
||||
CONFIG_PARAMETER* param);
|
||||
@ -1009,76 +1023,143 @@ bool service_set_param_value (
|
||||
{
|
||||
char* p;
|
||||
int valint;
|
||||
bool succp = true;
|
||||
|
||||
/**
|
||||
* Find out whether the value is numeric and ends with '%' or '\0'
|
||||
*/
|
||||
p = valstr;
|
||||
|
||||
while(isdigit(*p)) p++;
|
||||
|
||||
errno = 0;
|
||||
|
||||
if (p == valstr || (*p != '%' && *p != '\0'))
|
||||
{
|
||||
succp = false;
|
||||
}
|
||||
else if (*p == '%')
|
||||
{
|
||||
if (*(p+1) == '\0')
|
||||
{
|
||||
*p = '\0';
|
||||
valint = (int) strtol(valstr, (char **)NULL, 10);
|
||||
|
||||
if (valint == 0 && errno != 0)
|
||||
{
|
||||
succp = false;
|
||||
}
|
||||
else if (PARAM_IS_TYPE(type,PERCENT_TYPE))
|
||||
{
|
||||
succp = true;
|
||||
config_set_qualified_param(param, (void *)&valint, PERCENT_TYPE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/** Log error */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
succp = false;
|
||||
}
|
||||
}
|
||||
else if (*p == '\0')
|
||||
{
|
||||
valint = (int) strtol(valstr, (char **)NULL, 10);
|
||||
bool valbool;
|
||||
bool succp = true;
|
||||
|
||||
if (valint == 0 && errno != 0)
|
||||
{
|
||||
succp = false;
|
||||
}
|
||||
else if (PARAM_IS_TYPE(type,COUNT_TYPE))
|
||||
{
|
||||
succp = true;
|
||||
config_set_qualified_param(param, (void *)&valint, COUNT_TYPE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/** Log error */
|
||||
}
|
||||
}
|
||||
|
||||
if (PARAM_IS_TYPE(type,PERCENT_TYPE) ||PARAM_IS_TYPE(type,COUNT_TYPE))
|
||||
{
|
||||
/**
|
||||
* Find out whether the value is numeric and ends with '%' or '\0'
|
||||
*/
|
||||
p = valstr;
|
||||
|
||||
while(isdigit(*p)) p++;
|
||||
|
||||
errno = 0;
|
||||
|
||||
if (p == valstr || (*p != '%' && *p != '\0'))
|
||||
{
|
||||
succp = false;
|
||||
}
|
||||
else if (*p == '%')
|
||||
{
|
||||
if (*(p+1) == '\0')
|
||||
{
|
||||
*p = '\0';
|
||||
valint = (int) strtol(valstr, (char **)NULL, 10);
|
||||
|
||||
if (valint == 0 && errno != 0)
|
||||
{
|
||||
succp = false;
|
||||
}
|
||||
else if (PARAM_IS_TYPE(type,PERCENT_TYPE))
|
||||
{
|
||||
succp = true;
|
||||
config_set_qualified_param(param, (void *)&valint, PERCENT_TYPE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/** Log error */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
succp = false;
|
||||
}
|
||||
}
|
||||
else if (*p == '\0')
|
||||
{
|
||||
valint = (int) strtol(valstr, (char **)NULL, 10);
|
||||
|
||||
if (valint == 0 && errno != 0)
|
||||
{
|
||||
succp = false;
|
||||
}
|
||||
else if (PARAM_IS_TYPE(type,COUNT_TYPE))
|
||||
{
|
||||
succp = true;
|
||||
config_set_qualified_param(param, (void *)&valint, COUNT_TYPE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/** Log error */
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == BOOL_TYPE)
|
||||
{
|
||||
unsigned int rc;
|
||||
|
||||
rc = find_type(&bool_type, valstr, strlen(valstr)+1);
|
||||
|
||||
if (rc > 0)
|
||||
{
|
||||
succp = true;
|
||||
if (rc%2 == 1)
|
||||
{
|
||||
valbool = false;
|
||||
}
|
||||
else if (rc%2 == 0)
|
||||
{
|
||||
valbool = true;
|
||||
}
|
||||
/** add param to config */
|
||||
config_set_qualified_param(param,
|
||||
(void *)&valbool,
|
||||
BOOL_TYPE);
|
||||
}
|
||||
else
|
||||
{
|
||||
succp = false;
|
||||
}
|
||||
}
|
||||
if (succp)
|
||||
{
|
||||
service_add_qualified_param(service, param); /*< add param to svc */
|
||||
service_add_qualified_param(service, param); /*< add param to svc */
|
||||
}
|
||||
return succp;
|
||||
}
|
||||
/*
|
||||
* Function to find a string in typelib_t
|
||||
* (similar to find_type() of mysys/typelib.c)
|
||||
*
|
||||
* SYNOPSIS
|
||||
* find_type()
|
||||
* lib typelib_t
|
||||
* find String to find
|
||||
* length Length of string to find
|
||||
* part_match Allow part matching of value
|
||||
*
|
||||
* RETURN
|
||||
* 0 error
|
||||
* > 0 position in TYPELIB->type_names +1
|
||||
*/
|
||||
|
||||
static int find_type(
|
||||
typelib_t* tl,
|
||||
const char* needle,
|
||||
int maxlen)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (tl == NULL || needle == NULL || maxlen <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=0; i<tl->tl_nelems; i++)
|
||||
{
|
||||
if (strncasecmp(tl->tl_p_elems[i], needle, maxlen) == 0)
|
||||
{
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add qualified config parameter to SERVICE struct.
|
||||
*/
|
||||
*/
|
||||
static void service_add_qualified_param(
|
||||
SERVICE* svc,
|
||||
CONFIG_PARAMETER* param)
|
||||
|
@ -13,7 +13,7 @@ TESTLOG := $(shell pwd)/testcore.log
|
||||
LOGPATH := $(ROOT_PATH)/log_manager
|
||||
UTILSPATH := $(ROOT_PATH)/utils
|
||||
|
||||
LDFLAGS=-rdynamic -L$(LOGPATH) \
|
||||
LDFLAGS=-rdynamic -L$(LOGPATH) -L$(EMBEDDED_LIB) \
|
||||
-Wl,-rpath,$(DEST)/lib \
|
||||
-Wl,-rpath,$(LOGPATH) -Wl,-rpath,$(UTILSPATH) \
|
||||
-Wl,-rpath,$(EMBEDDED_LIB)
|
||||
|
@ -99,9 +99,16 @@ bool config_set_qualified_param(
|
||||
config_param_type_t type);
|
||||
|
||||
|
||||
int config_get_valint(
|
||||
bool config_get_valint(
|
||||
int* val,
|
||||
CONFIG_PARAMETER* param,
|
||||
const char* name, /*< if NULL examine current param only */
|
||||
config_param_type_t ptype);
|
||||
|
||||
bool config_get_valbool(
|
||||
bool* val,
|
||||
CONFIG_PARAMETER* param,
|
||||
const char* name, /*< if NULL examine current param only */
|
||||
config_param_type_t ptype);
|
||||
|
||||
#endif
|
||||
|
@ -135,7 +135,7 @@ typedef struct service {
|
||||
struct service *next; /**< The next service in the linked list */
|
||||
} SERVICE;
|
||||
|
||||
typedef enum count_spec_t {COUNT_ATLEAST=0, COUNT_EXACT, COUNT_ATMOST} count_spec_t;
|
||||
typedef enum count_spec_t {COUNT_NONE=0, COUNT_ATLEAST, COUNT_EXACT, COUNT_ATMOST} count_spec_t;
|
||||
|
||||
#define SERVICE_STATE_ALLOC 1 /**< The service has been allocated */
|
||||
#define SERVICE_STATE_STARTED 2 /**< The service has been started */
|
||||
|
@ -30,7 +30,7 @@ CFLAGS=-c -fPIC -I/usr/include -I../include -I../../include -I$(LOGPATH) -I$(QCL
|
||||
|
||||
include ../../../makefile.inc
|
||||
|
||||
LDFLAGS=-shared -L$(LOGPATH) -L$(QCLASSPATH) -Wl,-rpath,$(DEST)/lib \
|
||||
LDFLAGS=-shared -L$(LOGPATH) -L$(EMBEDDED_LIB) -L$(QCLASSPATH) -Wl,-rpath,$(DEST)/lib \
|
||||
-Wl,-rpath,$(LOGPATH) -Wl,-rpath,$(UTILSPATH)
|
||||
|
||||
TESTSRCS=testfilter.c
|
||||
@ -48,7 +48,7 @@ MQOBJ=$(MQSRCS:.c=.o)
|
||||
SRCS=$(TESTSRCS) $(QLASRCS) $(REGEXSRCS) $(TOPNSRCS) $(TEESRCS)
|
||||
OBJ=$(SRCS:.c=.o)
|
||||
LIBS=$(UTILSPATH)/skygw_utils.o -lssl -llog_manager
|
||||
MODULES= libtestfilter.so libqlafilter.so libregexfilter.so libtopfilter.so libtee.so
|
||||
MODULES= libtestfilter.so libqlafilter.so libregexfilter.so libtopfilter.so libhintfilter.so libtee.so
|
||||
|
||||
ifndef BUILD_RABBITMQ
|
||||
BUILD_RABBITMQ=Y
|
||||
@ -80,8 +80,8 @@ libtopfilter.so: $(TOPNOBJ)
|
||||
libtee.so: $(TEEOBJ)
|
||||
$(CC) $(LDFLAGS) $(TEEOBJ) $(LIBS) -o $@
|
||||
|
||||
libhintfilter.so:
|
||||
# (cd hint; touch depend.mk ; make; cp $@ ..)
|
||||
libhintfilter.so:
|
||||
(cd hint; touch depend.mk ; make; cp $@ ..)
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $< -o $@
|
||||
@ -92,12 +92,12 @@ clean:
|
||||
|
||||
tags:
|
||||
ctags $(SRCS) $(HDRS)
|
||||
# (cd hint; touch depend.mk; make tags)
|
||||
(cd hint; touch depend.mk; make tags)
|
||||
|
||||
depend:
|
||||
@rm -f depend.mk
|
||||
cc -M $(CFLAGS) $(SRCS) > depend.mk
|
||||
# (cd hint; touch depend.mk; make depend)
|
||||
(cd hint; touch depend.mk; make depend)
|
||||
|
||||
install: $(MODULES)
|
||||
install -D $(MODULES) $(DEST)/modules
|
||||
|
@ -231,18 +231,9 @@ HINT_MODE mode = HM_EXECUTE;
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
/** This is not MaxScale hint because it doesn't start with 'maxscale' */
|
||||
if (tok->token != TOK_MAXSCALE)
|
||||
{
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Error : Invalid hint string '%s'. Hint should start "
|
||||
"with keyword 'maxscale'. Hint ignored.",
|
||||
token_get_keyword(tok))));
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Invalid hint string '%s'. Hint should start "
|
||||
"with keyword 'maxscale'. Hint ignored.",
|
||||
token_get_keyword(tok))));
|
||||
token_free(tok);
|
||||
goto retblock;
|
||||
}
|
||||
|
@ -118,6 +118,8 @@ typedef enum select_criteria {
|
||||
/** default values for rwsplit configuration parameters */
|
||||
#define CONFIG_MAX_SLAVE_CONN 1
|
||||
#define CONFIG_MAX_SLAVE_RLAG -1 /*< not used */
|
||||
#define CONFIG_READ_SESVARS_FROM_SLAVES false
|
||||
#define CONFIG_WRITE_SESVARS_TO_ALL true
|
||||
|
||||
#define GET_SELECT_CRITERIA(s) \
|
||||
(strncmp(s,"LEAST_GLOBAL_CONNECTIONS", strlen("LEAST_GLOBAL_CONNECTIONS")) == 0 ? \
|
||||
@ -232,6 +234,11 @@ typedef struct rwsplit_config_st {
|
||||
int rw_max_slave_conn_count;
|
||||
select_criteria_t rw_slave_select_criteria;
|
||||
int rw_max_slave_replication_lag;
|
||||
/** Route user- & system variable writes to all backends */
|
||||
bool rw_write_sesvars_to_all;
|
||||
/** Route queries including user- & system variables to slaves */
|
||||
bool rw_read_sesvars_from_slaves;
|
||||
|
||||
} rwsplit_config_t;
|
||||
|
||||
|
||||
|
@ -100,10 +100,11 @@ static backend_ref_t* get_bref_from_dcb(ROUTER_CLIENT_SES* rses, DCB* dcb);
|
||||
|
||||
static route_target_t get_route_target (
|
||||
skygw_query_type_t qtype,
|
||||
bool read_sesvars_from_slaves,
|
||||
bool write_sesvars_to_all,
|
||||
bool trx_active,
|
||||
HINT* hint);
|
||||
|
||||
|
||||
static uint8_t getCapabilities (ROUTER* inst, void* router_session);
|
||||
|
||||
#if defined(NOT_USED)
|
||||
@ -366,7 +367,8 @@ static void refreshInstance(
|
||||
{
|
||||
CONFIG_PARAMETER* param;
|
||||
bool refresh_single;
|
||||
|
||||
config_param_type_t paramtype;
|
||||
|
||||
if (singleparam != NULL)
|
||||
{
|
||||
param = singleparam;
|
||||
@ -377,39 +379,91 @@ static void refreshInstance(
|
||||
param = router->service->svc_config_param;
|
||||
refresh_single = false;
|
||||
}
|
||||
|
||||
paramtype = config_get_paramtype(param);
|
||||
|
||||
while (param != NULL)
|
||||
{
|
||||
config_param_type_t paramtype;
|
||||
|
||||
paramtype = config_get_paramtype(param);
|
||||
|
||||
if (paramtype == COUNT_TYPE)
|
||||
{
|
||||
if (strncmp(param->name, "max_slave_connections", MAX_PARAM_LEN) == 0)
|
||||
{
|
||||
int val;
|
||||
bool succp;
|
||||
|
||||
router->rwsplit_config.rw_max_slave_conn_percent = 0;
|
||||
router->rwsplit_config.rw_max_slave_conn_count =
|
||||
config_get_valint(param, NULL, paramtype);
|
||||
|
||||
succp = config_get_valint(&val, param, NULL, paramtype);
|
||||
|
||||
if (succp)
|
||||
{
|
||||
router->rwsplit_config.rw_max_slave_conn_count = val;
|
||||
}
|
||||
}
|
||||
else if (strncmp(param->name,
|
||||
"max_slave_replication_lag",
|
||||
MAX_PARAM_LEN) == 0)
|
||||
{
|
||||
router->rwsplit_config.rw_max_slave_replication_lag =
|
||||
config_get_valint(param, NULL, paramtype);
|
||||
}
|
||||
int val;
|
||||
bool succp;
|
||||
|
||||
succp = config_get_valint(&val, param, NULL, paramtype);
|
||||
|
||||
if (succp)
|
||||
{
|
||||
router->rwsplit_config.rw_max_slave_replication_lag = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (paramtype == PERCENT_TYPE)
|
||||
{
|
||||
if (strncmp(param->name, "max_slave_connections", MAX_PARAM_LEN) == 0)
|
||||
{
|
||||
int val;
|
||||
bool succp;
|
||||
|
||||
router->rwsplit_config.rw_max_slave_conn_count = 0;
|
||||
router->rwsplit_config.rw_max_slave_conn_percent =
|
||||
config_get_valint(param, NULL, paramtype);
|
||||
|
||||
succp = config_get_valint(&val, param, NULL, paramtype);
|
||||
|
||||
if (succp)
|
||||
{
|
||||
router->rwsplit_config.rw_max_slave_conn_percent = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (paramtype == BOOL_TYPE)
|
||||
{
|
||||
if (strncmp(param->name,
|
||||
"read_ses_variables_from_slaves",
|
||||
MAX_PARAM_LEN) == 0)
|
||||
{
|
||||
bool val;
|
||||
bool succp;
|
||||
|
||||
succp = config_get_valbool(&val, param, NULL, paramtype);
|
||||
|
||||
if (succp)
|
||||
{
|
||||
router->rwsplit_config.rw_read_sesvars_from_slaves = val;
|
||||
}
|
||||
}
|
||||
else if (strncmp(param->name,
|
||||
"write_ses_variables_to_all",
|
||||
MAX_PARAM_LEN) == 0)
|
||||
{
|
||||
bool val;
|
||||
bool succp;
|
||||
|
||||
succp = config_get_valbool(&val, param, NULL, paramtype);
|
||||
|
||||
if (succp)
|
||||
{
|
||||
router->rwsplit_config.rw_write_sesvars_to_all = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (refresh_single)
|
||||
{
|
||||
break;
|
||||
@ -459,6 +513,7 @@ static void refreshInstance(
|
||||
}
|
||||
}
|
||||
#endif /*< NOT_USED */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -637,6 +692,21 @@ createInstance(SERVICE *service, char **options)
|
||||
refreshInstance(router, param);
|
||||
}
|
||||
router->rwsplit_version = service->svc_config_version;
|
||||
/** Set default values */
|
||||
router->rwsplit_config.rw_read_sesvars_from_slaves = CONFIG_READ_SESVARS_FROM_SLAVES;
|
||||
router->rwsplit_config.rw_write_sesvars_to_all = CONFIG_WRITE_SESVARS_TO_ALL;
|
||||
param = config_get_param(service->svc_config_param, "read_ses_variables_from_slaves");
|
||||
|
||||
if (param != NULL)
|
||||
{
|
||||
refreshInstance(router, param);
|
||||
}
|
||||
param = config_get_param(service->svc_config_param, "write_ses_variables_to_all");
|
||||
|
||||
if (param != NULL)
|
||||
{
|
||||
refreshInstance(router, param);
|
||||
}
|
||||
/**
|
||||
* We have completed the creation of the router data, so now
|
||||
* insert this router into the linked list of routers
|
||||
@ -1115,106 +1185,148 @@ return_succp:
|
||||
static route_target_t get_route_target (
|
||||
skygw_query_type_t qtype,
|
||||
bool trx_active,
|
||||
bool read_ses_variables_from_slaves,
|
||||
bool write_ses_variables_to_all,
|
||||
HINT* hint)
|
||||
{
|
||||
route_target_t target;
|
||||
|
||||
if (QUERY_IS_TYPE(qtype, QUERY_TYPE_SESSION_WRITE) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_PREPARE_STMT) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_PREPARE_NAMED_STMT))
|
||||
{
|
||||
/** hints don't affect on routing */
|
||||
target = TARGET_ALL;
|
||||
}
|
||||
/**
|
||||
* Read-only statements to slave or to master can be re-routed after
|
||||
* the hints
|
||||
*/
|
||||
else if ((QUERY_IS_TYPE(qtype, QUERY_TYPE_READ) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_SESSION_READ)) &&
|
||||
!trx_active)
|
||||
{
|
||||
if (QUERY_IS_TYPE(qtype, QUERY_TYPE_READ))
|
||||
/**
|
||||
* These queries are not affected by hints
|
||||
*/
|
||||
if (!trx_active &&
|
||||
(QUERY_IS_TYPE(qtype, QUERY_TYPE_PREPARE_STMT) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_PREPARE_NAMED_STMT) ||
|
||||
/** Configured to allow writing variables to all nodes */
|
||||
(write_ses_variables_to_all &&
|
||||
(QUERY_IS_TYPE(qtype, QUERY_TYPE_SESSION_WRITE) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_GSYSVAR_WRITE)))))
|
||||
{
|
||||
/** hints don't affect on routing */
|
||||
target = TARGET_ALL;
|
||||
}
|
||||
/**
|
||||
* Hints may affect on routing of the following queries
|
||||
*/
|
||||
else if (!trx_active &&
|
||||
(QUERY_IS_TYPE(qtype, QUERY_TYPE_READ) || /*< any SELECT */
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_USERVAR_READ)|| /*< read user var */
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_SYSVAR_READ) || /*< read sys var */
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_EXEC_STMT) || /*< prepared stmt exec */
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_GSYSVAR_READ))) /*< read global sys var */
|
||||
{
|
||||
/** First set expected targets before evaluating hints */
|
||||
if (QUERY_IS_TYPE(qtype, QUERY_TYPE_READ) ||
|
||||
/** Configured to allow reading variables from slaves */
|
||||
(read_ses_variables_from_slaves &&
|
||||
(QUERY_IS_TYPE(qtype, QUERY_TYPE_USERVAR_READ) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_SYSVAR_READ) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_GSYSVAR_READ))))
|
||||
{
|
||||
target = TARGET_SLAVE;
|
||||
}
|
||||
else
|
||||
else if (QUERY_IS_TYPE(qtype, QUERY_TYPE_EXEC_STMT) ||
|
||||
/** Configured not to allow reading variables from slaves */
|
||||
(!read_ses_variables_from_slaves &&
|
||||
(QUERY_IS_TYPE(qtype, QUERY_TYPE_USERVAR_READ) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_SYSVAR_READ))))
|
||||
{
|
||||
target = TARGET_MASTER;
|
||||
}
|
||||
/** process routing hints */
|
||||
while (hint != NULL)
|
||||
{
|
||||
if (hint->type == HINT_ROUTE_TO_MASTER)
|
||||
{
|
||||
target = TARGET_MASTER; /*< override */
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Hint: route to master.")));
|
||||
break;
|
||||
}
|
||||
else if (hint->type == HINT_ROUTE_TO_NAMED_SERVER)
|
||||
{
|
||||
|
||||
/** process routing hints */
|
||||
while (hint != NULL)
|
||||
{
|
||||
if (hint->type == HINT_ROUTE_TO_MASTER)
|
||||
{
|
||||
target = TARGET_MASTER; /*< override */
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Hint: route to master.")));
|
||||
break;
|
||||
}
|
||||
else if (hint->type == HINT_ROUTE_TO_NAMED_SERVER)
|
||||
{
|
||||
/**
|
||||
* Searching for a named server. If it can't be
|
||||
* found, the oroginal target is chosen.
|
||||
*/
|
||||
target |= TARGET_NAMED_SERVER;
|
||||
target |= TARGET_NAMED_SERVER;
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Hint: route to named server : ")));
|
||||
"Hint: route to named server : ")));
|
||||
}
|
||||
else if (hint->type == HINT_ROUTE_TO_UPTODATE_SERVER)
|
||||
{
|
||||
/** not implemented */
|
||||
}
|
||||
else if (hint->type == HINT_ROUTE_TO_ALL)
|
||||
{
|
||||
/** not implemented */
|
||||
}
|
||||
else if (hint->type == HINT_PARAMETER)
|
||||
{
|
||||
if (strncasecmp(
|
||||
(char *)hint->data,
|
||||
"max_slave_replication_lag",
|
||||
strlen("max_slave_replication_lag")) == 0)
|
||||
{
|
||||
target |= TARGET_RLAG_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Error : Unknown hint parameter "
|
||||
"'%s' when 'max_slave_replication_lag' "
|
||||
"was expected.",
|
||||
(char *)hint->data)));
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Unknown hint parameter "
|
||||
"'%s' when 'max_slave_replication_lag' "
|
||||
"was expected.",
|
||||
(char *)hint->data)));
|
||||
}
|
||||
}
|
||||
else if (hint->type == HINT_ROUTE_TO_SLAVE)
|
||||
{
|
||||
else if (hint->type == HINT_ROUTE_TO_UPTODATE_SERVER)
|
||||
{
|
||||
/** not implemented */
|
||||
}
|
||||
else if (hint->type == HINT_ROUTE_TO_ALL)
|
||||
{
|
||||
/** not implemented */
|
||||
}
|
||||
else if (hint->type == HINT_PARAMETER)
|
||||
{
|
||||
if (strncasecmp(
|
||||
(char *)hint->data,
|
||||
"max_slave_replication_lag",
|
||||
strlen("max_slave_replication_lag")) == 0)
|
||||
{
|
||||
target |= TARGET_RLAG_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Error : Unknown hint parameter "
|
||||
"'%s' when 'max_slave_replication_lag' "
|
||||
"was expected.",
|
||||
(char *)hint->data)));
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Unknown hint parameter "
|
||||
"'%s' when 'max_slave_replication_lag' "
|
||||
"was expected.",
|
||||
(char *)hint->data)));
|
||||
}
|
||||
}
|
||||
else if (hint->type == HINT_ROUTE_TO_SLAVE)
|
||||
{
|
||||
target = TARGET_SLAVE;
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Hint: route to slave.")));
|
||||
}
|
||||
hint = hint->next;
|
||||
} /*< while (hint != NULL) */
|
||||
}
|
||||
else
|
||||
{
|
||||
/** hints don't affect on routing */
|
||||
target = TARGET_MASTER;
|
||||
}
|
||||
|
||||
return target;
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Hint: route to slave.")));
|
||||
}
|
||||
hint = hint->next;
|
||||
} /*< while (hint != NULL) */
|
||||
}
|
||||
else
|
||||
{
|
||||
/** hints don't affect on routing */
|
||||
ss_dassert(trx_active ||
|
||||
(QUERY_IS_TYPE(qtype, QUERY_TYPE_WRITE) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_MASTER_READ) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_SESSION_WRITE) ||
|
||||
(QUERY_IS_TYPE(qtype, QUERY_TYPE_USERVAR_READ) &&
|
||||
!write_ses_variables_to_all) ||
|
||||
(QUERY_IS_TYPE(qtype, QUERY_TYPE_SYSVAR_READ) &&
|
||||
!write_ses_variables_to_all) ||
|
||||
(QUERY_IS_TYPE(qtype, QUERY_TYPE_GSYSVAR_READ) &&
|
||||
!write_ses_variables_to_all) ||
|
||||
(QUERY_IS_TYPE(qtype, QUERY_TYPE_GSYSVAR_WRITE) &&
|
||||
!write_ses_variables_to_all) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_BEGIN_TRX) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_ENABLE_AUTOCOMMIT) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_DISABLE_AUTOCOMMIT) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_ROLLBACK) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_COMMIT) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_EXEC_STMT) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_CREATE_TMP_TABLE) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_READ_TMP_TABLE) ||
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_UNKNOWN)));
|
||||
target = TARGET_MASTER;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the query is a DROP TABLE... query and
|
||||
* if it targets a temporary table, remove it from the hashtable.
|
||||
@ -1550,8 +1662,7 @@ static int routeQuery(
|
||||
inst->stats.n_queries++;
|
||||
|
||||
master_dcb = router_cli_ses->rses_master_ref->bref_dcb;
|
||||
CHK_DCB(master_dcb);
|
||||
|
||||
CHK_DCB(master_dcb);
|
||||
|
||||
switch(packet_type) {
|
||||
case MYSQL_COM_QUIT: /*< 1 QUIT will close all sessions */
|
||||
@ -1597,11 +1708,9 @@ static int routeQuery(
|
||||
break;
|
||||
} /**< switch by packet type */
|
||||
|
||||
|
||||
/**
|
||||
* Check if the query has anything to do with temporary tables.
|
||||
*/
|
||||
|
||||
qtype = is_read_tmp_table(instance,router_session,querybuf,qtype);
|
||||
check_create_tmp_table(instance,router_session,querybuf,qtype);
|
||||
check_drop_tmp_table(instance,router_session,querybuf,qtype);
|
||||
@ -1620,7 +1729,7 @@ static int routeQuery(
|
||||
{
|
||||
router_cli_ses->rses_transaction_active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!router_cli_ses->rses_transaction_active &&
|
||||
QUERY_IS_TYPE(qtype, QUERY_TYPE_BEGIN_TRX))
|
||||
{
|
||||
@ -1641,8 +1750,7 @@ static int routeQuery(
|
||||
{
|
||||
router_cli_ses->rses_autocommit_enabled = true;
|
||||
router_cli_ses->rses_transaction_active = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out where to route the query. Result may not be clear; it is
|
||||
@ -1662,7 +1770,9 @@ static int routeQuery(
|
||||
* eventually to master
|
||||
*/
|
||||
route_target = get_route_target(qtype,
|
||||
router_cli_ses->rses_transaction_active,
|
||||
router_cli_ses->rses_transaction_active,
|
||||
router_cli_ses->rses_config.rw_read_sesvars_from_slaves,
|
||||
router_cli_ses->rses_config.rw_write_sesvars_to_all,
|
||||
querybuf->hint);
|
||||
|
||||
if (TARGET_IS_ALL(route_target))
|
||||
|
@ -51,15 +51,19 @@ type=service
|
||||
router=readwritesplit
|
||||
servers=server1,server2,server3,server4
|
||||
max_slave_connections=90%
|
||||
write_ses_variables_to_all=Yes
|
||||
read_ses_variables_from_slaves=Yes
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
|
||||
filters=Hint
|
||||
|
||||
[RW Split Hint Router]
|
||||
type=service
|
||||
router=readwritesplit
|
||||
servers=server1,server2,server3,server4
|
||||
max_slave_connections=90%
|
||||
write_ses_variables_to_all=Yes
|
||||
read_ses_variables_from_slaves=Yes
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
filters=Hint
|
||||
|
@ -45,5 +45,6 @@
|
||||
#endif
|
||||
|
||||
#define MAX_ERROR_MSG PATH_MAX
|
||||
#define array_nelems(a) ((uint)(sizeof(a)/sizeof(a[0])))
|
||||
|
||||
#endif /* SKYGW_TYPES_H */
|
||||
|
@ -83,6 +83,7 @@ typedef enum { THR_INIT, THR_RUNNING, THR_STOPPED, THR_DONE } skygw_thr_state_t;
|
||||
typedef enum { MES_RC_FAIL, MES_RC_SUCCESS, MES_RC_TIMEOUT } skygw_mes_rc_t;
|
||||
|
||||
EXTERN_C_BLOCK_BEGIN
|
||||
|
||||
slist_cursor_t* slist_init(void);
|
||||
void slist_done(slist_cursor_t* c);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user