From 92889ad216151999b9152a7072564e21f6c2c44c Mon Sep 17 00:00:00 2001 From: VilhoRaatikka Date: Sun, 7 Sep 2014 23:48:16 +0300 Subject: [PATCH] config.c: Added configuration parameter processing for read_ses_variables_from_slaves and for write_ses_variables_to_all . The values are read from config file, qualified and stored to service. Values are loaded when instance is created. This is limitation in current implementation and will change so that configuration is dynamically changeable. --- server/core/config.c | 96 ++++++++- server/core/service.c | 201 ++++++++++++------ server/include/service.h | 2 +- server/modules/include/readwritesplit.h | 7 + .../routing/readwritesplit/readwritesplit.c | 15 ++ 5 files changed, 249 insertions(+), 72 deletions(-) diff --git a/server/core/config.c b/server/core/config.c index 06eabd414..f151cab97 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -247,18 +247,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 +384,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 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 for write session " + "variables to all backends.", + ((SERVICE*)obj->element)->name, + param->name, + param->value))); + } + } + } /*< if (rw_split) */ + } /*< if (router) */ else { obj->element = NULL; @@ -1320,6 +1394,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 diff --git a/server/core/service.c b/server/core/service.c index 2068c4757..bd2dee7c6 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -52,12 +52,26 @@ #include #include #include +#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[9]= {"FALSE", "TRUE", "OFF", "ON", "N", "Y", "0", "1", "NO", "YES", 0}; +typelib_t bool_typelib = {array_nelems(bool_strings)-1, "bool_typelib", 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,141 @@ 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 (type == PERCENT_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_typelib, valstr, strlen(valstr)+1); + + if (rc > 0) + { + succp = true; + if (rc%2 == 1) + { + valbool = false; + } + else if (rc%2 == 0) + { + valbool = true; + } + } + else + { + succp = false; + } + } if (succp) { - service_add_qualified_param(service, param); /*< add param to svc */ + config_set_qualified_param(param, (void *)&valbool, BOOL_TYPE); /*< add param to config */ } 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; itl_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) diff --git a/server/include/service.h b/server/include/service.h index cd13d411b..abedaec7c 100644 --- a/server/include/service.h +++ b/server/include/service.h @@ -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 */ diff --git a/server/modules/include/readwritesplit.h b/server/modules/include/readwritesplit.h index 07254f37f..b2d3d7244 100644 --- a/server/modules/include/readwritesplit.h +++ b/server/modules/include/readwritesplit.h @@ -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 false #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; diff --git a/server/modules/routing/readwritesplit/readwritesplit.c b/server/modules/routing/readwritesplit/readwritesplit.c index b6e06cdbb..c043f4711 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.c +++ b/server/modules/routing/readwritesplit/readwritesplit.c @@ -637,6 +637,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