From a5e384fd29ac2ffe6e4d186474a957be5fd35fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Thu, 5 Jul 2018 15:37:00 +0300 Subject: [PATCH] Add reconfiguration to router API Added a new router API entry point that allows configuration changes after the instance has been created. This makes alterations to most service parameters at runtime possible. An option to reconfiguration would have been the creation of a new service and the eventual destruction of the old one. This would be a more complicated and costly method but from an architectural point of view it is interesting. The actual implementation of the configuration change is left to the router. Currently, only readwritesplit performs reconfiguration as implementing it with versioned configurations is very easy. Versioned configurations can be considered an adequate first step but it is not an optimal solution as it causes a bottleneck in the reference counting of the shared configuration. Thread-specific configuration definitions would make for a more efficient solution but the implementation is more complex. --- include/maxscale/router.h | 31 ++++++++++++++++--- include/maxscale/router.hh | 16 ++++++++++ .../routing/readwritesplit/readwritesplit.cc | 12 +++++-- .../routing/readwritesplit/readwritesplit.hh | 1 + 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/include/maxscale/router.h b/include/maxscale/router.h index 675de6019..144034f4c 100644 --- a/include/maxscale/router.h +++ b/include/maxscale/router.h @@ -211,6 +211,28 @@ typedef struct mxs_router_object * @param instance Router instance */ void (*destroyInstance)(MXS_ROUTER *instance); + + /** + * @brief Configure router instance at runtime + * + * This function is guaranteed to be called by only one thread at a time. + * The router must declare the RCAP_TYPE_RUNTIME_CONFIG in its capabilities + * in order for this function to be called. + * + * Modifications to the router should be made in an atomic manner so that + * existing sessions do not read a partial configuration. One way to do this + * is to use shared pointers for storing configurations. + * + * @param instance Router instance + * @param params Updated parameters for the service. The parameters are + * validated before this function is called. + * + * @return True if reconfiguration was successful, false if reconfiguration + * failed. If reconfiguration failed, the state of the router + * instance should not be modified. + */ + bool (*configureInstance)(MXS_ROUTER *instance, MXS_CONFIG_PARAMETER* params); + } MXS_ROUTER_OBJECT; /** @@ -218,7 +240,7 @@ typedef struct mxs_router_object * must update these versions numbers in accordance with the rules in * modinfo.h. */ -#define MXS_ROUTER_VERSION { 3, 0, 0 } +#define MXS_ROUTER_VERSION { 3, 1, 0 } /** * Specifies capabilities specific for routers. Common capabilities @@ -231,10 +253,11 @@ typedef struct mxs_router_object */ typedef enum router_capability { - RCAP_TYPE_NO_RSESSION = 0x00010000, /**< Router does not use router sessions */ - RCAP_TYPE_NO_USERS_INIT = 0x00020000, /**< Prevent the loading of authenticator + RCAP_TYPE_NO_RSESSION = 0x00010000, /**< Router does not use router sessions */ + RCAP_TYPE_NO_USERS_INIT = 0x00020000, /**< Prevent the loading of authenticator users when the service is started */ - RCAP_TYPE_NO_AUTH = 0x00040000, /**< No `user` or `password` parameter required */ + RCAP_TYPE_NO_AUTH = 0x00040000, /**< No `user` or `password` parameter required */ + RCAP_TYPE_RUNTIME_CONFIG = 0x00080000, /**< Router supports runtime cofiguration */ } mxs_router_capability_t; typedef enum diff --git a/include/maxscale/router.hh b/include/maxscale/router.hh index 7f6a15d91..0b7507462 100644 --- a/include/maxscale/router.hh +++ b/include/maxscale/router.hh @@ -130,6 +130,13 @@ template class Router : public MXS_ROUTER { public: + + // The default configure entry point, does nothing and always fails + bool configure(MXS_CONFIG_PARAMETER* param) + { + return false; + } + static MXS_ROUTER* createInstance(SERVICE* pService, char** pzOptions) { RouterType* pRouter = NULL; @@ -228,6 +235,14 @@ public: MXS_EXCEPTION_GUARD(delete pRouter); } + static bool configure(MXS_ROUTER* pInstance, MXS_CONFIG_PARAMETER* param) + { + RouterType* pRouter = static_cast(pInstance); + bool rval = false; + MXS_EXCEPTION_GUARD(rval = pRouter->configure(param)); + return rval; + } + static MXS_ROUTER_OBJECT s_object; protected: @@ -254,6 +269,7 @@ MXS_ROUTER_OBJECT Router::s_object = &Router::handleError, &Router::getCapabilities, &Router::destroyInstance, + &Router::configure, }; diff --git a/server/modules/routing/readwritesplit/readwritesplit.cc b/server/modules/routing/readwritesplit/readwritesplit.cc index ed72306ec..c02c70738 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.cc +++ b/server/modules/routing/readwritesplit/readwritesplit.cc @@ -429,7 +429,14 @@ json_t* RWSplit::diagnostics_json() const uint64_t RWSplit::getCapabilities() { return RCAP_TYPE_STMT_INPUT | RCAP_TYPE_TRANSACTION_TRACKING | - RCAP_TYPE_PACKET_OUTPUT | RCAP_TYPE_SESSION_STATE_TRACKING; + RCAP_TYPE_PACKET_OUTPUT | RCAP_TYPE_SESSION_STATE_TRACKING | + RCAP_TYPE_RUNTIME_CONFIG; +} + +bool RWSplit::configure(MXS_CONFIG_PARAMETER* params) +{ + m_config.reset(new Config(params)); + return true; } /** @@ -445,7 +452,8 @@ extern "C" MXS_MODULE *MXS_CREATE_MODULE() "A Read/Write splitting router for enhancement read scalability", "V1.1.0", RCAP_TYPE_STMT_INPUT | RCAP_TYPE_TRANSACTION_TRACKING | - RCAP_TYPE_PACKET_OUTPUT | RCAP_TYPE_SESSION_STATE_TRACKING, + RCAP_TYPE_PACKET_OUTPUT | RCAP_TYPE_SESSION_STATE_TRACKING | + RCAP_TYPE_RUNTIME_CONFIG, &RWSplit::s_object, NULL, /* Process init. */ NULL, /* Process finish. */ diff --git a/server/modules/routing/readwritesplit/readwritesplit.hh b/server/modules/routing/readwritesplit/readwritesplit.hh index 6985d8ee5..a86e78c0d 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.hh +++ b/server/modules/routing/readwritesplit/readwritesplit.hh @@ -298,6 +298,7 @@ public: */ uint64_t getCapabilities(); + bool configure(MXS_CONFIG_PARAMETER* params); private: SERVICE* m_service; /**< Service where the router belongs*/ SConfig m_config;