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:
@ -43,6 +43,7 @@ struct ROUTER_CLIENT_SES: MXS_ROUTER_SESSION
|
|||||||
SERVER_REF *backend; /*< Backend used by the client session */
|
SERVER_REF *backend; /*< Backend used by the client session */
|
||||||
DCB *backend_dcb; /*< DCB Connection to the backend */
|
DCB *backend_dcb; /*< DCB Connection to the backend */
|
||||||
DCB *client_dcb; /**< Client DCB */
|
DCB *client_dcb; /**< Client DCB */
|
||||||
|
uint32_t bitmask; /*< Bitmask to apply to server->status */
|
||||||
uint32_t bitvalue; /*< Session specific required value of 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 */
|
SERVICE *service; /*< Pointer to the service using this router */
|
||||||
SPINLOCK lock; /*< Spinlock for the instance data */
|
SPINLOCK lock; /*< Spinlock for the instance data */
|
||||||
uint32_t bitmask; /*< Bitmask to apply to server->status */
|
uint64_t bitmask_and_bitvalue; /*< Lower 32-bits for bitmask and upper for bitvalue */
|
||||||
uint32_t bitvalue; /*< Required value of server->status */
|
|
||||||
ROUTER_STATS stats; /*< Statistics for this router */
|
ROUTER_STATS stats; /*< Statistics for this router */
|
||||||
};
|
};
|
||||||
|
|||||||
@ -76,6 +76,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include <maxscale/alloc.h>
|
#include <maxscale/alloc.h>
|
||||||
#include <maxscale/server.h>
|
#include <maxscale/server.h>
|
||||||
#include <maxscale/router.h>
|
#include <maxscale/router.h>
|
||||||
@ -86,6 +88,7 @@
|
|||||||
#include <maxscale/log_manager.h>
|
#include <maxscale/log_manager.h>
|
||||||
#include <maxscale/protocol/mysql.h>
|
#include <maxscale/protocol/mysql.h>
|
||||||
#include <maxscale/modutil.h>
|
#include <maxscale/modutil.h>
|
||||||
|
#include <maxscale/utils.hh>
|
||||||
|
|
||||||
/* The router entry points */
|
/* The router entry points */
|
||||||
static MXS_ROUTER *createInstance(SERVICE *service, char **options);
|
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,
|
static void handleError(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *errbuf,
|
||||||
DCB *problem_dcb, mxs_error_action_t action, bool *succp);
|
DCB *problem_dcb, mxs_error_action_t action, bool *succp);
|
||||||
static uint64_t getCapabilities(MXS_ROUTER* instance);
|
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 bool rses_begin_locked_router_action(ROUTER_CLIENT_SES* rses);
|
||||||
static void rses_end_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);
|
static SERVER_REF *get_root_master(SERVER_REF *servers);
|
||||||
@ -128,7 +132,8 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
|
|||||||
clientReply,
|
clientReply,
|
||||||
handleError,
|
handleError,
|
||||||
getCapabilities,
|
getCapabilities,
|
||||||
NULL
|
NULL,
|
||||||
|
configureInstance
|
||||||
};
|
};
|
||||||
|
|
||||||
static MXS_MODULE info =
|
static MXS_MODULE info =
|
||||||
@ -137,8 +142,8 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
|
|||||||
MXS_MODULE_GA,
|
MXS_MODULE_GA,
|
||||||
MXS_ROUTER_VERSION,
|
MXS_ROUTER_VERSION,
|
||||||
"A connection based router to load balance based on connections",
|
"A connection based router to load balance based on connections",
|
||||||
"V1.1.0",
|
"V2.0.0",
|
||||||
MXS_NO_MODULE_CAPABILITIES,
|
RCAP_TYPE_RUNTIME_CONFIG,
|
||||||
&MyObject,
|
&MyObject,
|
||||||
NULL, /* Process init. */
|
NULL, /* Process init. */
|
||||||
NULL, /* Process finish. */
|
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
|
* Create an instance of the router for a particular service
|
||||||
* within the gateway.
|
* within the gateway.
|
||||||
@ -169,87 +247,25 @@ static inline void free_readconn_instance(ROUTER_INSTANCE *router)
|
|||||||
*
|
*
|
||||||
* @return The instance data for this new instance
|
* @return The instance data for this new instance
|
||||||
*/
|
*/
|
||||||
static MXS_ROUTER *
|
static MXS_ROUTER* createInstance(SERVICE *service, char **options)
|
||||||
createInstance(SERVICE *service, char **options)
|
|
||||||
{
|
{
|
||||||
ROUTER_INSTANCE *inst;
|
ROUTER_INSTANCE* inst = static_cast<ROUTER_INSTANCE*>(MXS_CALLOC(1, sizeof(ROUTER_INSTANCE)));
|
||||||
SERVER_REF *sref;
|
|
||||||
int i, n;
|
|
||||||
|
|
||||||
if ((inst = static_cast<ROUTER_INSTANCE*>(MXS_CALLOC(1, sizeof(ROUTER_INSTANCE)))) == NULL)
|
if (inst)
|
||||||
{
|
{
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
inst->service = service;
|
inst->service = service;
|
||||||
spinlock_init(&inst->lock);
|
spinlock_init(&inst->lock);
|
||||||
|
inst->bitmask_and_bitvalue = 0;
|
||||||
|
|
||||||
/*
|
if (!configureInstance((MXS_ROUTER*)inst, service->svc_config_param))
|
||||||
* Process the options
|
|
||||||
*/
|
|
||||||
bool error = false;
|
|
||||||
inst->bitmask = 0;
|
|
||||||
inst->bitvalue = 0;
|
|
||||||
if (options)
|
|
||||||
{
|
|
||||||
for (i = 0; options[i]; i++)
|
|
||||||
{
|
{
|
||||||
if (!strcasecmp(options[i], "master"))
|
free_readconn_instance(inst);
|
||||||
{
|
inst = nullptr;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error)
|
return (MXS_ROUTER*)inst;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -281,7 +297,10 @@ newSession(MXS_ROUTER *instance, MXS_SESSION *session)
|
|||||||
}
|
}
|
||||||
|
|
||||||
client_rses->client_dcb = session->client_dcb;
|
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
|
* 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 */
|
/* Check server status bits against bitvalue from router_options */
|
||||||
if (ref && SERVER_IS_RUNNING(ref->server) &&
|
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 (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
|
/* 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
|
* is not in the configuration. Intermediate masters (Relay Servers) are also
|
||||||
@ -328,7 +347,7 @@ newSession(MXS_ROUTER *instance, MXS_SESSION *session)
|
|||||||
|
|
||||||
continue;
|
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
|
/* If option is "master" return only the root Master as there could be
|
||||||
* intermediate masters (Relay Servers) and they must not be selected.
|
* intermediate masters (Relay Servers) and they must not be selected.
|
||||||
@ -338,7 +357,7 @@ newSession(MXS_ROUTER *instance, MXS_SESSION *session)
|
|||||||
break;
|
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'
|
/* Master_host is NULL, no master server. If requested router_option is 'master'
|
||||||
* candidate will be NULL.
|
* 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.
|
// the sole master available at session creation time.
|
||||||
|
|
||||||
if (SERVER_IS_RUNNING(router_cli_ses->backend->server) &&
|
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
|
// 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
|
// '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)
|
static uint64_t getCapabilities(MXS_ROUTER* instance)
|
||||||
{
|
{
|
||||||
return RCAP_TYPE_NONE;
|
return RCAP_TYPE_RUNTIME_CONFIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user