diff --git a/Documentation/MaxScale Configuration And Usage Scenarios-Z3.pdf b/Documentation/MaxScale Configuration And Usage Scenarios-Z3.pdf index 58c915371..b297e427c 100644 Binary files a/Documentation/MaxScale Configuration And Usage Scenarios-Z3.pdf and b/Documentation/MaxScale Configuration And Usage Scenarios-Z3.pdf differ diff --git a/server/MaxScale_template.cnf b/server/MaxScale_template.cnf index 7fcbed4d9..c322fec8f 100644 --- a/server/MaxScale_template.cnf +++ b/server/MaxScale_template.cnf @@ -51,9 +51,8 @@ passwd=maxpwd # enable_root_user=<0 or 1, default is 0> # version_string= -# -# read_ses_variables_from_slaves= Default is Yes -# write_ses_variables_to_all= Default is No +# +# use_sql_variables_in=[master|all] (default all) # router_options=,,... # where value=[master|slave|synced] # @@ -72,8 +71,7 @@ router=readwritesplit servers=server1,server2,server3 user=maxuser passwd=maxpwd -read_ses_variables_from_slaves=No -write_ses_variables_to_all=Yes +use_sql_variables_in=all max_slave_connections=50% max_slave_replication_lag=30 router_options=slave_selection_criteria=LEAST_BEHIND_MASTER diff --git a/server/core/config.c b/server/core/config.c index 47426eaf0..37764a14c 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -333,13 +333,20 @@ int error_count = 0; param = config_get_param(obj->parameters, "max_slave_connections"); - succp = service_set_param_value( - obj->element, - param, - max_slave_conn_str, - COUNT_ATMOST, - (COUNT_TYPE|PERCENT_TYPE)); - + if (param == NULL) + { + succp = false; + } + else + { + succp = service_set_param_value( + obj->element, + param, + max_slave_conn_str, + COUNT_ATMOST, + (COUNT_TYPE|PERCENT_TYPE)); + } + if (!succp) { LOGIF(LM, (skygw_log_write( @@ -365,13 +372,20 @@ int error_count = 0; obj->parameters, "max_slave_replication_lag"); - succp = service_set_param_value( - obj->element, - param, - max_slave_rlag_str, - COUNT_ATMOST, - COUNT_TYPE); - + if (param == NULL) + { + succp = false; + } + else + { + succp = service_set_param_value( + obj->element, + param, + max_slave_rlag_str, + COUNT_ATMOST, + COUNT_TYPE); + } + if (!succp) { LOGIF(LM, (skygw_log_write( @@ -389,60 +403,40 @@ int error_count = 0; if (is_rwsplit) { CONFIG_PARAMETER* param; - char* write_sesvars_to_all; - char* read_sesvars_from_slaves; + char* use_sql_variables_in; bool succp; - write_sesvars_to_all = + use_sql_variables_in = config_get_value(obj->parameters, - "write_ses_variables_to_all"); + "use_sql_variables_in"); - if (write_sesvars_to_all != NULL) + if (use_sql_variables_in != 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) + "use_sql_variables_in"); + + if (param == NULL) { - LOGIF(LM, (skygw_log_write( - LOGFILE_MESSAGE, - "* Warning : invalid value type " - "for parameter \'%s.%s = %s\'\n\tExpected " - "type is for write session " - "variables to all backends.", - ((SERVICE*)obj->element)->name, - param->name, - param->value))); + succp = false; } - } - 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); + else + { + succp = service_set_param_value(obj->element, + param, + use_sql_variables_in, + COUNT_NONE, + SQLVAR_TARGET_TYPE); + } + if (!succp) { LOGIF(LM, (skygw_log_write( LOGFILE_MESSAGE, "* Warning : invalid value type " "for parameter \'%s.%s = %s\'\n\tExpected " - "type is for write session " - "variables to all backends.", + "type is [master|all] for " + "use sql variables in.", ((SERVICE*)obj->element)->name, param->name, param->value))); @@ -896,7 +890,7 @@ bool config_get_valint( { bool succp = false;; - ss_dassert(ptype == COUNT_TYPE || ptype == PERCENT_TYPE); + ss_dassert((ptype == COUNT_TYPE || ptype == PERCENT_TYPE) && param != NULL); while (param) { @@ -933,8 +927,9 @@ bool config_get_valbool( bool succp; ss_dassert(ptype == BOOL_TYPE); + ss_dassert(param != NULL); - if (ptype != BOOL_TYPE) + if (ptype != BOOL_TYPE || param == NULL) { succp = false; goto return_succp; @@ -958,6 +953,40 @@ return_succp: } +bool config_get_valtarget( + target_t* val, + CONFIG_PARAMETER* param, + const char* name, + config_param_type_t ptype) +{ + bool succp; + + ss_dassert(ptype == SQLVAR_TARGET_TYPE); + ss_dassert(param != NULL); + + if (ptype != SQLVAR_TARGET_TYPE || param == NULL) + { + succp = false; + goto return_succp; + } + + while (param) + { + if (name == NULL || !strncmp(param->name, name, MAX_PARAM_LEN)) + { + *val = param->qfd.valtarget; + succp = true; + goto return_succp; + } + param = param->next; + } + succp = false; + +return_succp: + return succp; + +} + CONFIG_PARAMETER* config_clone_param( CONFIG_PARAMETER* param) { @@ -1135,13 +1164,20 @@ SERVER *server; param = config_get_param(obj->parameters, "max_slave_connections"); - succp = service_set_param_value( - service, - param, - max_slave_conn_str, - COUNT_ATMOST, - (PERCENT_TYPE|COUNT_TYPE)); - + if (param == NULL) + { + succp = false; + } + else + { + succp = service_set_param_value( + service, + param, + max_slave_conn_str, + COUNT_ATMOST, + (PERCENT_TYPE|COUNT_TYPE)); + } + if (!succp) { LOGIF(LM, (skygw_log_write( @@ -1171,13 +1207,20 @@ SERVER *server; obj->parameters, "max_slave_replication_lag"); - succp = service_set_param_value( - service, - param, - max_slave_rlag_str, - COUNT_ATMOST, - COUNT_TYPE); - + if (param == NULL) + { + succp = false; + } + else + { + succp = service_set_param_value( + service, + param, + max_slave_rlag_str, + COUNT_ATMOST, + COUNT_TYPE); + } + if (!succp) { LOGIF(LM, (skygw_log_write( @@ -1426,8 +1469,7 @@ 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 */ + "use_sql_variables_in", /*< rwsplit only */ "version_string", "filters", NULL @@ -1551,7 +1593,11 @@ bool config_set_qualified_param( param->qfd.valbool = *(bool *)val; succp = true; break; - + + case SQLVAR_TARGET_TYPE: + param->qfd.valtarget = *(target_t *)val; + succp = true; + break; default: succp = false; break; diff --git a/server/core/service.c b/server/core/service.c index d84e2464e..69b446b09 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -52,8 +52,6 @@ #include #include #include -#include <../../../mariadb-5.5.30/include/ft_global.h> - extern int lm_enabled_logfiles_bitmask; @@ -63,9 +61,17 @@ typedef struct typelib_st { const char* tl_name; const char** tl_p_elems; } typelib_t; +/** Set of subsequent false,true pairs */ +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 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}; +/** List of valid values */ +static const char* sqlvar_target_strings[4] = {"MASTER", "ALL", 0}; +typelib_t sqlvar_target_type = { + array_nelems(sqlvar_target_strings)-1, + "sqlvar_target_type", + sqlvar_target_strings +}; static SPINLOCK service_spin = SPINLOCK_INIT; static SERVICE *allServices = NULL; @@ -1021,10 +1027,11 @@ bool service_set_param_value ( count_spec_t count_spec, config_param_type_t type) { - char* p; - int valint; - bool valbool; - bool succp = true; + char* p; + int valint; + bool valbool; + target_t valtarget; + bool succp = true; if (PARAM_IS_TYPE(type,PERCENT_TYPE) ||PARAM_IS_TYPE(type,COUNT_TYPE)) { @@ -1113,6 +1120,34 @@ bool service_set_param_value ( succp = false; } } + else if (type == SQLVAR_TARGET_TYPE) + { + unsigned int rc; + + rc = find_type(&sqlvar_target_type, valstr, strlen(valstr)+1); + + if (rc > 0 && rc < 3) + { + succp = true; + if (rc == 1) + { + valtarget = TYPE_MASTER; + } + else if (rc == 2) + { + valtarget = TYPE_ALL; + } + /** add param to config */ + config_set_qualified_param(param, + (void *)&valtarget, + SQLVAR_TARGET_TYPE); + } + else + { + succp = false; + } + } + if (succp) { service_add_qualified_param(service, param); /*< add param to svc */ diff --git a/server/include/config.h b/server/include/config.h index 8dcb77c85..659fb6378 100644 --- a/server/include/config.h +++ b/server/include/config.h @@ -39,13 +39,20 @@ enum {MAX_PARAM_LEN=256}; typedef enum { - UNDEFINED_TYPE = 0x00, - STRING_TYPE = 0x01, - COUNT_TYPE = 0x02, - PERCENT_TYPE = 0x04, - BOOL_TYPE = 0x08 + UNDEFINED_TYPE = 0x00, + STRING_TYPE = 0x01, + COUNT_TYPE = 0x02, + PERCENT_TYPE = 0x04, + BOOL_TYPE = 0x08, + SQLVAR_TARGET_TYPE = 0x10 } config_param_type_t; +typedef enum { + TYPE_UNDEFINED = 0, + TYPE_MASTER, + TYPE_ALL +} target_t; + enum {MAX_RLAG_NOT_AVAILABLE=-1, MAX_RLAG_UNDEFINED=-2}; #define PARAM_IS_TYPE(p,t) ((p) & (t)) @@ -61,6 +68,7 @@ typedef struct config_parameter { int valcount; /*< int */ int valpercent; /*< int */ bool valbool; /*< bool */ + target_t valtarget; /*< sql variable route target */ } qfd; config_param_type_t qfd_param_type; struct config_parameter *next; /**< Next pointer in the linked list */ @@ -111,4 +119,9 @@ bool config_get_valbool( const char* name, /*< if NULL examine current param only */ config_param_type_t ptype); +bool config_get_valtarget( + target_t* val, + CONFIG_PARAMETER* param, + const char* name, /*< if NULL examine current param only */ + config_param_type_t ptype); #endif diff --git a/server/modules/include/readwritesplit.h b/server/modules/include/readwritesplit.h index d56e25a85..5956b3648 100644 --- a/server/modules/include/readwritesplit.h +++ b/server/modules/include/readwritesplit.h @@ -118,8 +118,7 @@ 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 CONFIG_SQL_VARIABLES_IN TYPE_ALL #define GET_SELECT_CRITERIA(s) \ (strncmp(s,"LEAST_GLOBAL_CONNECTIONS", strlen("LEAST_GLOBAL_CONNECTIONS")) == 0 ? \ @@ -234,9 +233,7 @@ 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 */ + target_t rw_use_sql_variables_in; bool rw_read_sesvars_from_slaves; } rwsplit_config_t; diff --git a/server/modules/protocol/mysql_client.c b/server/modules/protocol/mysql_client.c index 8454516e2..40aff1e27 100644 --- a/server/modules/protocol/mysql_client.c +++ b/server/modules/protocol/mysql_client.c @@ -34,6 +34,7 @@ * 28/02/2014 Massimiliano Pinto Added: client IPv4 in dcb->ipv4 and inet_ntop for string representation * 11/03/2014 Massimiliano Pinto Added: Unix socket support * 07/05/2014 Massimiliano Pinto Added: specific version string in server handshake + * 09/09/2014 Massimiliano Pinto Added: 777 permission for socket path * */ #include @@ -985,6 +986,16 @@ int gw_MySQLListener( return 0; } + + /* set permission for all users */ + if (chmod(config_bind, 0777) < 0) { + fprintf(stderr, + "\n* chmod failed for %s due error %i, %s.\n\n", + config_bind, + errno, + strerror(errno)); + } + break; case AF_INET: diff --git a/server/modules/routing/readwritesplit/readwritesplit.c b/server/modules/routing/readwritesplit/readwritesplit.c index 8ac5f6117..193c1e283 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.c +++ b/server/modules/routing/readwritesplit/readwritesplit.c @@ -99,11 +99,10 @@ static int rses_get_max_replication_lag(ROUTER_CLIENT_SES* rses); 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); + skygw_query_type_t qtype, + bool trx_active, + target_t use_sql_variables_in, + HINT* hint); static uint8_t getCapabilities (ROUTER* inst, void* router_session); @@ -383,6 +382,11 @@ static void refreshInstance( while (param != NULL) { + /** Catch unused parameter types */ + ss_dassert(paramtype == COUNT_TYPE || + paramtype == PERCENT_TYPE || + paramtype == SQLVAR_TARGET_TYPE); + if (paramtype == COUNT_TYPE) { if (strncmp(param->name, "max_slave_connections", MAX_PARAM_LEN) == 0) @@ -431,35 +435,20 @@ static void refreshInstance( } } } - - if (paramtype == BOOL_TYPE) + else if (paramtype == SQLVAR_TARGET_TYPE) { if (strncmp(param->name, - "read_ses_variables_from_slaves", + "use_sql_variables_in", MAX_PARAM_LEN) == 0) { - bool val; + target_t valtarget; bool succp; - succp = config_get_valbool(&val, param, NULL, paramtype); + succp = config_get_valtarget(&valtarget, 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; + router->rwsplit_config.rw_use_sql_variables_in = valtarget; } } } @@ -693,16 +682,9 @@ createInstance(SERVICE *service, char **options) } 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"); - + router->rwsplit_config.rw_use_sql_variables_in = CONFIG_SQL_VARIABLES_IN; + param = config_get_param(service->svc_config_param, "use_sql_variable_in"); + if (param != NULL) { refreshInstance(router, param); @@ -1185,8 +1167,7 @@ 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, + target_t use_sql_variables_in, HINT* hint) { route_target_t target; @@ -1197,7 +1178,7 @@ static route_target_t get_route_target ( (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 && + (use_sql_variables_in == TYPE_ALL && (QUERY_IS_TYPE(qtype, QUERY_TYPE_SESSION_WRITE) || QUERY_IS_TYPE(qtype, QUERY_TYPE_GSYSVAR_WRITE))))) { @@ -1217,7 +1198,7 @@ static route_target_t get_route_target ( /** 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 && + (use_sql_variables_in == TYPE_ALL && (QUERY_IS_TYPE(qtype, QUERY_TYPE_USERVAR_READ) || QUERY_IS_TYPE(qtype, QUERY_TYPE_SYSVAR_READ) || QUERY_IS_TYPE(qtype, QUERY_TYPE_GSYSVAR_READ)))) @@ -1226,13 +1207,12 @@ static route_target_t get_route_target ( } else if (QUERY_IS_TYPE(qtype, QUERY_TYPE_EXEC_STMT) || /** Configured not to allow reading variables from slaves */ - (!read_ses_variables_from_slaves && + (use_sql_variables_in == TYPE_MASTER && (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) { @@ -1306,13 +1286,13 @@ static route_target_t get_route_target ( 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) || + use_sql_variables_in == TYPE_MASTER) || (QUERY_IS_TYPE(qtype, QUERY_TYPE_SYSVAR_READ) && - !write_ses_variables_to_all) || + use_sql_variables_in == TYPE_MASTER) || (QUERY_IS_TYPE(qtype, QUERY_TYPE_GSYSVAR_READ) && - !write_ses_variables_to_all) || + use_sql_variables_in == TYPE_MASTER) || (QUERY_IS_TYPE(qtype, QUERY_TYPE_GSYSVAR_WRITE) && - !write_ses_variables_to_all) || + use_sql_variables_in == TYPE_MASTER) || QUERY_IS_TYPE(qtype, QUERY_TYPE_BEGIN_TRX) || QUERY_IS_TYPE(qtype, QUERY_TYPE_ENABLE_AUTOCOMMIT) || QUERY_IS_TYPE(qtype, QUERY_TYPE_DISABLE_AUTOCOMMIT) || @@ -1422,7 +1402,11 @@ skygw_query_type_t is_read_tmp_table( data = (MYSQL_session*)master_dcb->session->data; dbname = (char*)data->db; - if (QUERY_IS_TYPE(qtype, QUERY_TYPE_READ)) + if (QUERY_IS_TYPE(qtype, QUERY_TYPE_READ) || + QUERY_IS_TYPE(qtype, QUERY_TYPE_LOCAL_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)) { tbl = skygw_get_table_names(querybuf,&tsize,false); @@ -1771,8 +1755,7 @@ static int routeQuery( */ route_target = get_route_target(qtype, 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, + router_cli_ses->rses_config.rw_use_sql_variables_in, querybuf->hint); if (TARGET_IS_ALL(route_target)) diff --git a/server/modules/routing/readwritesplit/test/rwsplit.sh b/server/modules/routing/readwritesplit/test/rwsplit.sh index 63d7998b7..6fefd8801 100755 --- a/server/modules/routing/readwritesplit/test/rwsplit.sh +++ b/server/modules/routing/readwritesplit/test/rwsplit.sh @@ -279,9 +279,9 @@ do printf "." fi b=`$RUNCMD < $TINPUT 2>&1` - if [[ "`echo "$b"|grep -i 'null|error'`" != "" ]] + if [[ "`echo "$b"|grep -i 'null\|error'`" != "" ]] then - err=`echo "$b" | grep -i 'null\|error'` + err=`echo "$b" | grep -i null\|error` break fi done