Add runtime schemarouter reconfiguration
The schemarouter now also uses versioned configurations implemented by shared pointers to configuration objects. Moved all the configuration management into the Config class. Removed router options from schemarouter.
This commit is contained in:
@ -13,9 +13,33 @@
|
|||||||
|
|
||||||
#include "schemarouter.hh"
|
#include "schemarouter.hh"
|
||||||
|
|
||||||
|
#include <maxscale/utils.hh>
|
||||||
|
|
||||||
namespace schemarouter
|
namespace schemarouter
|
||||||
{
|
{
|
||||||
|
|
||||||
|
Config::Config(MXS_CONFIG_PARAMETER* conf):
|
||||||
|
refresh_min_interval(config_get_integer(conf, "refresh_interval")),
|
||||||
|
refresh_databases(config_get_bool(conf, "refresh_databases")),
|
||||||
|
debug(config_get_bool(conf, "debug")),
|
||||||
|
ignore_regex(config_get_compiled_regex(conf, "ignore_databases_regex", 0, NULL)),
|
||||||
|
ignore_match_data(ignore_regex ? pcre2_match_data_create_from_pattern(ignore_regex, NULL) : NULL),
|
||||||
|
preferred_server(config_get_server(conf, "preferred_server"))
|
||||||
|
{
|
||||||
|
ignored_dbs.insert("mysql");
|
||||||
|
ignored_dbs.insert("information_schema");
|
||||||
|
ignored_dbs.insert("performance_schema");
|
||||||
|
|
||||||
|
// TODO: Don't process this in the router
|
||||||
|
if (MXS_CONFIG_PARAMETER* p = config_get_param(conf, "ignore_databases"))
|
||||||
|
{
|
||||||
|
for (auto&& a: mxs::strtok(p->value, ", \t"))
|
||||||
|
{
|
||||||
|
ignored_dbs.insert(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SRBackend::set_mapped(bool value)
|
void SRBackend::set_mapped(bool value)
|
||||||
{
|
{
|
||||||
m_mapped = value;
|
m_mapped = value;
|
||||||
|
@ -48,17 +48,17 @@ struct Config
|
|||||||
std::set<std::string> ignored_dbs; /**< Set of ignored databases */
|
std::set<std::string> ignored_dbs; /**< Set of ignored databases */
|
||||||
SERVER* preferred_server; /**< Server to prefer in conflict situations */
|
SERVER* preferred_server; /**< Server to prefer in conflict situations */
|
||||||
|
|
||||||
Config():
|
Config(MXS_CONFIG_PARAMETER* conf);
|
||||||
refresh_min_interval(0.0),
|
|
||||||
refresh_databases(false),
|
~Config()
|
||||||
debug(false),
|
|
||||||
ignore_regex(NULL),
|
|
||||||
ignore_match_data(NULL),
|
|
||||||
preferred_server(NULL)
|
|
||||||
{
|
{
|
||||||
|
pcre2_match_data_free(ignore_match_data);
|
||||||
|
pcre2_code_free(ignore_regex);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef std::shared_ptr<Config> SConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Router statistics
|
* Router statistics
|
||||||
*/
|
*/
|
||||||
|
@ -42,7 +42,7 @@ namespace schemarouter
|
|||||||
* @file schemarouter.c The entry points for the simple sharding router module.
|
* @file schemarouter.c The entry points for the simple sharding router module.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SchemaRouter::SchemaRouter(SERVICE *service, Config& config):
|
SchemaRouter::SchemaRouter(SERVICE *service, SConfig config):
|
||||||
mxs::Router<SchemaRouter, SchemaRouterSession>(service),
|
mxs::Router<SchemaRouter, SchemaRouterSession>(service),
|
||||||
m_config(config),
|
m_config(config),
|
||||||
m_service(service)
|
m_service(service)
|
||||||
@ -52,10 +52,6 @@ SchemaRouter::SchemaRouter(SERVICE *service, Config& config):
|
|||||||
|
|
||||||
SchemaRouter::~SchemaRouter()
|
SchemaRouter::~SchemaRouter()
|
||||||
{
|
{
|
||||||
if (m_config.ignore_regex)
|
|
||||||
{
|
|
||||||
pcre2_code_free(m_config.ignore_regex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SchemaRouter* SchemaRouter::create(SERVICE* pService, char** pzOptions)
|
SchemaRouter* SchemaRouter::create(SERVICE* pService, char** pzOptions)
|
||||||
@ -69,108 +65,15 @@ SchemaRouter* SchemaRouter::create(SERVICE* pService, char** pzOptions)
|
|||||||
pService->users_from_all = true;
|
pService->users_from_all = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Config config;
|
SConfig config(new Config(pService->svc_config_param));
|
||||||
MXS_CONFIG_PARAMETER* param;
|
return new SchemaRouter(pService, config);
|
||||||
|
}
|
||||||
|
|
||||||
config.refresh_databases = config_get_bool(conf, "refresh_databases");
|
bool SchemaRouter::configure(MXS_CONFIG_PARAMETER* params)
|
||||||
config.refresh_min_interval = config_get_integer(conf, "refresh_interval");
|
{
|
||||||
config.debug = config_get_bool(conf, "debug");
|
SConfig config(new Config(params));
|
||||||
config.preferred_server = config_get_server(conf, "preferred_server");
|
m_config = config;
|
||||||
|
return true;
|
||||||
/** Add default system databases to ignore */
|
|
||||||
config.ignored_dbs.insert("mysql");
|
|
||||||
config.ignored_dbs.insert("information_schema");
|
|
||||||
config.ignored_dbs.insert("performance_schema");
|
|
||||||
|
|
||||||
if ((param = config_get_param(conf, "ignore_databases_regex")))
|
|
||||||
{
|
|
||||||
int errcode;
|
|
||||||
PCRE2_SIZE erroffset;
|
|
||||||
pcre2_code* re = pcre2_compile((PCRE2_SPTR)param->value, PCRE2_ZERO_TERMINATED, 0,
|
|
||||||
&errcode, &erroffset, NULL);
|
|
||||||
|
|
||||||
if (re == NULL)
|
|
||||||
{
|
|
||||||
PCRE2_UCHAR errbuf[512];
|
|
||||||
pcre2_get_error_message(errcode, errbuf, sizeof(errbuf));
|
|
||||||
MXS_ERROR("Regex compilation failed at %d for regex '%s': %s",
|
|
||||||
(int)erroffset, param->value, errbuf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pcre2_match_data* match_data = pcre2_match_data_create_from_pattern(re, NULL);
|
|
||||||
|
|
||||||
if (match_data == NULL)
|
|
||||||
{
|
|
||||||
pcre2_code_free(re);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
config.ignore_regex = re;
|
|
||||||
config.ignore_match_data = match_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((param = config_get_param(conf, "ignore_databases")))
|
|
||||||
{
|
|
||||||
char val[strlen(param->value) + 1];
|
|
||||||
strcpy(val, param->value);
|
|
||||||
|
|
||||||
const char *sep = ", \t";
|
|
||||||
char *sptr;
|
|
||||||
char *tok = strtok_r(val, sep, &sptr);
|
|
||||||
|
|
||||||
while (tok)
|
|
||||||
{
|
|
||||||
config.ignored_dbs.insert(tok);
|
|
||||||
tok = strtok_r(NULL, sep, &sptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool success = true;
|
|
||||||
|
|
||||||
for (int i = 0; pzOptions && pzOptions[i]; i++)
|
|
||||||
{
|
|
||||||
char* value = strchr(pzOptions[i], '=');
|
|
||||||
|
|
||||||
if (value == NULL)
|
|
||||||
{
|
|
||||||
MXS_ERROR("Unknown router options for %s", pzOptions[i]);
|
|
||||||
success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
*value = '\0';
|
|
||||||
value++;
|
|
||||||
|
|
||||||
if (strcmp(pzOptions[i], "max_sescmd_history") == 0)
|
|
||||||
{
|
|
||||||
MXS_WARNING("Use of 'max_sescmd_history' is deprecated");
|
|
||||||
}
|
|
||||||
else if (strcmp(pzOptions[i], "disable_sescmd_history") == 0)
|
|
||||||
{
|
|
||||||
MXS_WARNING("Use of 'disable_sescmd_history' is deprecated");
|
|
||||||
}
|
|
||||||
else if (strcmp(pzOptions[i], "refresh_databases") == 0)
|
|
||||||
{
|
|
||||||
config.refresh_databases = config_truth_value(value);
|
|
||||||
}
|
|
||||||
else if (strcmp(pzOptions[i], "refresh_interval") == 0)
|
|
||||||
{
|
|
||||||
config.refresh_min_interval = atof(value);
|
|
||||||
}
|
|
||||||
else if (strcmp(pzOptions[i], "debug") == 0)
|
|
||||||
{
|
|
||||||
config.debug = config_truth_value(value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MXS_ERROR("Unknown router options for %s", pzOptions[i]);
|
|
||||||
success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success ? new SchemaRouter(pService, config) : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -364,7 +267,7 @@ json_t* SchemaRouter::diagnostics_json() const
|
|||||||
|
|
||||||
uint64_t SchemaRouter::getCapabilities()
|
uint64_t SchemaRouter::getCapabilities()
|
||||||
{
|
{
|
||||||
return RCAP_TYPE_NONE;
|
return RCAP_TYPE_CONTIGUOUS_INPUT | RCAP_TYPE_RUNTIME_CONFIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -386,7 +289,7 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
|
|||||||
MXS_ROUTER_VERSION,
|
MXS_ROUTER_VERSION,
|
||||||
"A database sharding router for simple sharding",
|
"A database sharding router for simple sharding",
|
||||||
"V1.0.0",
|
"V1.0.0",
|
||||||
RCAP_TYPE_CONTIGUOUS_INPUT,
|
RCAP_TYPE_CONTIGUOUS_INPUT | RCAP_TYPE_RUNTIME_CONFIG,
|
||||||
&schemarouter::SchemaRouter::s_object,
|
&schemarouter::SchemaRouter::s_object,
|
||||||
NULL, /* Process init. */
|
NULL, /* Process init. */
|
||||||
NULL, /* Process finish. */
|
NULL, /* Process finish. */
|
||||||
|
@ -39,15 +39,16 @@ public:
|
|||||||
void diagnostics(DCB* pDcb);
|
void diagnostics(DCB* pDcb);
|
||||||
json_t* diagnostics_json() const;
|
json_t* diagnostics_json() const;
|
||||||
uint64_t getCapabilities();
|
uint64_t getCapabilities();
|
||||||
|
bool configure(MXS_CONFIG_PARAMETER* param);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class SchemaRouterSession;
|
friend class SchemaRouterSession;
|
||||||
|
|
||||||
/** Internal functions */
|
/** Internal functions */
|
||||||
SchemaRouter(SERVICE *service, Config& config);
|
SchemaRouter(SERVICE *service, SConfig config);
|
||||||
|
|
||||||
/** Member variables */
|
/** Member variables */
|
||||||
Config m_config; /*< expanded config info from SERVICE */
|
SConfig m_config; /*< expanded config info from SERVICE */
|
||||||
ShardManager m_shard_manager; /*< Shard maps hashed by user name */
|
ShardManager m_shard_manager; /*< Shard maps hashed by user name */
|
||||||
SERVICE* m_service; /*< Pointer to service */
|
SERVICE* m_service; /*< Pointer to service */
|
||||||
SPINLOCK m_lock; /*< Lock for the instance data */
|
SPINLOCK m_lock; /*< Lock for the instance data */
|
||||||
|
@ -40,7 +40,7 @@ SchemaRouterSession::SchemaRouterSession(MXS_SESSION* session, SchemaRouter* rou
|
|||||||
m_client(session->client_dcb),
|
m_client(session->client_dcb),
|
||||||
m_mysql_session((MYSQL_session*)session->client_dcb->data),
|
m_mysql_session((MYSQL_session*)session->client_dcb->data),
|
||||||
m_backends(backends),
|
m_backends(backends),
|
||||||
m_config(&router->m_config),
|
m_config(router->m_config),
|
||||||
m_router(router),
|
m_router(router),
|
||||||
m_shard(m_router->m_shard_manager.get_shard(m_client->user, m_config->refresh_min_interval)),
|
m_shard(m_router->m_shard_manager.get_shard(m_client->user, m_config->refresh_min_interval)),
|
||||||
m_state(0),
|
m_state(0),
|
||||||
|
@ -153,7 +153,7 @@ private:
|
|||||||
DCB* m_client; /**< The client DCB */
|
DCB* m_client; /**< The client DCB */
|
||||||
MYSQL_session* m_mysql_session; /**< Session client data (username, password, SHA1). */
|
MYSQL_session* m_mysql_session; /**< Session client data (username, password, SHA1). */
|
||||||
SSRBackendList m_backends; /**< Backend references */
|
SSRBackendList m_backends; /**< Backend references */
|
||||||
Config* m_config; /**< Pointer to router config */
|
SConfig m_config; /**< Session specific configuration */
|
||||||
SchemaRouter* m_router; /**< The router instance */
|
SchemaRouter* m_router; /**< The router instance */
|
||||||
Shard m_shard; /**< Database to server mapping */
|
Shard m_shard; /**< Database to server mapping */
|
||||||
std::string m_connect_db; /**< Database the user was trying to connect to */
|
std::string m_connect_db; /**< Database the user was trying to connect to */
|
||||||
|
Reference in New Issue
Block a user