Add readconnroute runtime reconfiguration

Readconnroute can now be configured at runtime. The changes to
configuration processing allow the removal of router_options now that the
parameters are parsed inside the router.
This commit is contained in:
Markus Mäkelä
2018-07-09 09:18:40 +03:00
parent 5604023b26
commit c4be3f75c0
2 changed files with 103 additions and 84 deletions

View File

@ -43,6 +43,7 @@ struct ROUTER_CLIENT_SES: MXS_ROUTER_SESSION
SERVER_REF *backend; /*< Backend used by the client session */
DCB *backend_dcb; /*< DCB Connection to the backend */
DCB *client_dcb; /**< Client DCB */
uint32_t bitmask; /*< Bitmask to apply to server->status */
uint32_t bitvalue; /*< Session specific required value of server->status */
};
@ -62,7 +63,6 @@ struct ROUTER_INSTANCE: public MXS_ROUTER
{
SERVICE *service; /*< Pointer to the service using this router */
SPINLOCK lock; /*< Spinlock for the instance data */
uint32_t bitmask; /*< Bitmask to apply to server->status */
uint32_t bitvalue; /*< Required value of server->status */
uint64_t bitmask_and_bitvalue; /*< Lower 32-bits for bitmask and upper for bitvalue */
ROUTER_STATS stats; /*< Statistics for this router */
};

View File

@ -76,6 +76,8 @@
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <string>
#include <vector>
#include <maxscale/alloc.h>
#include <maxscale/server.h>
#include <maxscale/router.h>
@ -86,6 +88,7 @@
#include <maxscale/log_manager.h>
#include <maxscale/protocol/mysql.h>
#include <maxscale/modutil.h>
#include <maxscale/utils.hh>
/* The router entry points */
static MXS_ROUTER *createInstance(SERVICE *service, char **options);
@ -100,6 +103,7 @@ static void clientReply(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session
static void handleError(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *errbuf,
DCB *problem_dcb, mxs_error_action_t action, bool *succp);
static uint64_t getCapabilities(MXS_ROUTER* instance);
static bool configureInstance(MXS_ROUTER* instance, MXS_CONFIG_PARAMETER* params);
static bool rses_begin_locked_router_action(ROUTER_CLIENT_SES* rses);
static void rses_end_locked_router_action(ROUTER_CLIENT_SES* rses);
static SERVER_REF *get_root_master(SERVER_REF *servers);
@ -128,7 +132,8 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
clientReply,
handleError,
getCapabilities,
NULL
NULL,
configureInstance
};
static MXS_MODULE info =
@ -137,8 +142,8 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
MXS_MODULE_GA,
MXS_ROUTER_VERSION,
"A connection based router to load balance based on connections",
"V1.1.0",
MXS_NO_MODULE_CAPABILITIES,
"V2.0.0",
RCAP_TYPE_RUNTIME_CONFIG,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
@ -160,6 +165,79 @@ static inline void free_readconn_instance(ROUTER_INSTANCE *router)
}
}
static bool configureInstance(MXS_ROUTER* instance, MXS_CONFIG_PARAMETER* params)
{
ROUTER_INSTANCE* inst = static_cast<ROUTER_INSTANCE*>(instance);
uint64_t bitmask = 0;
uint64_t bitvalue = 0;
bool ok = true;
std::string optstr = config_get_string(params, "router_options");
std::vector<std::string> options;
while (!optstr.empty())
{
size_t pos = optstr.find(',');
options.push_back(mxs::trimmed_copy(optstr.substr(0, pos)));
optstr.erase(0, pos);
if (pos != optstr.npos)
{
optstr.erase(0, 1);
}
}
for (auto&& opt: options)
{
if (!strcasecmp(opt.c_str(), "master"))
{
bitmask |= (SERVER_MASTER | SERVER_SLAVE);
bitvalue |= SERVER_MASTER;
}
else if (!strcasecmp(opt.c_str(), "slave"))
{
bitmask |= (SERVER_MASTER | SERVER_SLAVE);
bitvalue |= SERVER_SLAVE;
}
else if (!strcasecmp(opt.c_str(), "running"))
{
bitmask |= (SERVER_RUNNING);
bitvalue |= SERVER_RUNNING;
}
else if (!strcasecmp(opt.c_str(), "synced"))
{
bitmask |= (SERVER_JOINED);
bitvalue |= SERVER_JOINED;
}
else if (!strcasecmp(opt.c_str(), "ndb"))
{
bitmask |= (SERVER_NDB);
bitvalue |= SERVER_NDB;
}
else
{
MXS_ERROR("Unsupported router option \'%s\' for readconnroute. "
"Expected router options are [slave|master|synced|ndb|running]",
opt.c_str());
ok = false;
}
}
if (bitmask == 0 && bitvalue == 0)
{
/** No parameters given, use RUNNING as a valid server */
bitmask |= (SERVER_RUNNING);
bitvalue |= SERVER_RUNNING;
}
if (ok)
{
uint64_t mask = bitmask | (bitvalue << 32);
atomic_store_uint64(&inst->bitmask_and_bitvalue, mask);
}
return ok;
}
/**
* Create an instance of the router for a particular service
* within the gateway.
@ -169,87 +247,25 @@ static inline void free_readconn_instance(ROUTER_INSTANCE *router)
*
* @return The instance data for this new instance
*/
static MXS_ROUTER *
createInstance(SERVICE *service, char **options)
static MXS_ROUTER* createInstance(SERVICE *service, char **options)
{
ROUTER_INSTANCE *inst;
SERVER_REF *sref;
int i, n;
ROUTER_INSTANCE* inst = static_cast<ROUTER_INSTANCE*>(MXS_CALLOC(1, sizeof(ROUTER_INSTANCE)));
if ((inst = static_cast<ROUTER_INSTANCE*>(MXS_CALLOC(1, sizeof(ROUTER_INSTANCE)))) == NULL)
if (inst)
{
return NULL;
}
inst->service = service;
spinlock_init(&inst->lock);
inst->service = service;
spinlock_init(&inst->lock);
inst->bitmask_and_bitvalue = 0;
/*
* Process the options
*/
bool error = false;
inst->bitmask = 0;
inst->bitvalue = 0;
if (options)
{
for (i = 0; options[i]; i++)
if (!configureInstance((MXS_ROUTER*)inst, service->svc_config_param))
{
if (!strcasecmp(options[i], "master"))
{
inst->bitmask |= (SERVER_MASTER | SERVER_SLAVE);
inst->bitvalue |= SERVER_MASTER;
}
else if (!strcasecmp(options[i], "slave"))
{
inst->bitmask |= (SERVER_MASTER | SERVER_SLAVE);
inst->bitvalue |= SERVER_SLAVE;
}
else if (!strcasecmp(options[i], "running"))
{
inst->bitmask |= (SERVER_RUNNING);
inst->bitvalue |= SERVER_RUNNING;
}
else if (!strcasecmp(options[i], "synced"))
{
inst->bitmask |= (SERVER_JOINED);
inst->bitvalue |= SERVER_JOINED;
}
else if (!strcasecmp(options[i], "ndb"))
{
inst->bitmask |= (SERVER_NDB);
inst->bitvalue |= SERVER_NDB;
}
else
{
MXS_WARNING("Unsupported router "
"option \'%s\' for readconnroute. "
"Expected router options are "
"[slave|master|synced|ndb|running]",
options[i]);
error = true;
}
free_readconn_instance(inst);
inst = nullptr;
}
}
if (error)
{
free_readconn_instance(inst);
return NULL;
}
if (inst->bitmask == 0 && inst->bitvalue == 0)
{
/** No parameters given, use RUNNING as a valid server */
inst->bitmask |= (SERVER_RUNNING);
inst->bitvalue |= SERVER_RUNNING;
}
/*
* We have completed the creation of the instance data, so now
* insert this router instance into the linked list of routers
* that have been created with this module.
*/
return (MXS_ROUTER *) inst;
return (MXS_ROUTER*)inst;
}
/**
@ -281,7 +297,10 @@ newSession(MXS_ROUTER *instance, MXS_SESSION *session)
}
client_rses->client_dcb = session->client_dcb;
client_rses->bitvalue = inst->bitvalue;
uint64_t mask = atomic_load_uint64(&inst->bitmask_and_bitvalue);
client_rses->bitmask = mask;
client_rses->bitvalue = mask >> 32;
/**
* Find the Master host from available servers
@ -315,11 +334,11 @@ newSession(MXS_ROUTER *instance, MXS_SESSION *session)
/* Check server status bits against bitvalue from router_options */
if (ref && SERVER_IS_RUNNING(ref->server) &&
(ref->server->status & inst->bitmask & inst->bitvalue))
(ref->server->status & client_rses->bitmask & client_rses->bitvalue))
{
if (master_host)
{
if (ref == master_host && (inst->bitvalue & (SERVER_SLAVE | SERVER_MASTER)) == SERVER_SLAVE)
if (ref == master_host && (client_rses->bitvalue & (SERVER_SLAVE | SERVER_MASTER)) == SERVER_SLAVE)
{
/* Skip root master here, as it could also be slave of an external server that
* is not in the configuration. Intermediate masters (Relay Servers) are also
@ -328,7 +347,7 @@ newSession(MXS_ROUTER *instance, MXS_SESSION *session)
continue;
}
if (ref == master_host && inst->bitvalue == SERVER_MASTER)
if (ref == master_host && client_rses->bitvalue == SERVER_MASTER)
{
/* If option is "master" return only the root Master as there could be
* intermediate masters (Relay Servers) and they must not be selected.
@ -338,7 +357,7 @@ newSession(MXS_ROUTER *instance, MXS_SESSION *session)
break;
}
}
else if (inst->bitvalue == SERVER_MASTER)
else if (client_rses->bitvalue == SERVER_MASTER)
{
/* Master_host is NULL, no master server. If requested router_option is 'master'
* candidate will be NULL.
@ -540,7 +559,7 @@ static inline bool connection_is_valid(ROUTER_INSTANCE* inst, ROUTER_CLIENT_SES*
// the sole master available at session creation time.
if (SERVER_IS_RUNNING(router_cli_ses->backend->server) &&
(router_cli_ses->backend->server->status & inst->bitmask & router_cli_ses->bitvalue))
(router_cli_ses->backend->server->status & router_cli_ses->bitmask & router_cli_ses->bitvalue))
{
// Note the use of '==' and not '|'. We must use the former to exclude a
// 'router_options=slave' that uses the master due to no slave having been
@ -831,7 +850,7 @@ static void rses_end_locked_router_action(ROUTER_CLIENT_SES* rses)
static uint64_t getCapabilities(MXS_ROUTER* instance)
{
return RCAP_TYPE_NONE;
return RCAP_TYPE_RUNTIME_CONFIG;
}
/*