From 8982ee3db2738c14787a536ec906a1b9cdaa44bc Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Thu, 3 Nov 2016 15:50:43 +0200 Subject: [PATCH] Allow servers to be added and removed from services Servers can now be added and removed from services which allows routers to use them with new sessions. The routers don't fully use the new functionality in the server references which prevents new servers from being taken into use. --- include/maxscale/service.h | 3 + server/core/service.c | 58 +++++++++++++++++-- server/modules/routing/debugcli/debugcmd.c | 67 +++++++++++++++++----- 3 files changed, 107 insertions(+), 21 deletions(-) diff --git a/include/maxscale/service.h b/include/maxscale/service.h index b6d7940d5..273528f68 100644 --- a/include/maxscale/service.h +++ b/include/maxscale/service.h @@ -101,6 +101,7 @@ typedef struct server_ref_t SERVER* server; /**< The actual server */ int weight; /**< Weight of this server */ int connections; /**< Number of connections created through this reference */ + bool active; /**< Whether this reference is valid and in use*/ } SERVER_REF; #define SERVICE_MAX_RETRY_INTERVAL 3600 /*< The maximum interval between service start retries */ @@ -146,6 +147,7 @@ typedef struct service void *router_instance; /**< The router instance for this service */ char *version_string; /** version string for this service listeners */ SERVER_REF *dbref; /** server references */ + int n_dbref; /** Number of server references */ SERVICE_USER credentials; /**< The cedentials of the service user */ SPINLOCK spin; /**< The service spinlock */ SERVICE_STATS stats; /**< The service statistics */ @@ -194,6 +196,7 @@ extern int serviceAddProtocol(SERVICE *service, char *name, char *protocol, extern int serviceHasProtocol(SERVICE *service, const char *protocol, const char* address, unsigned short port); extern void serviceAddBackend(SERVICE *, SERVER *); +extern void serviceRemoveBackend(SERVICE *, const SERVER *); extern int serviceHasBackend(SERVICE *, SERVER *); extern void serviceAddRouterOption(SERVICE *, char *); extern void serviceClearRouterOptions(SERVICE *); diff --git a/server/core/service.c b/server/core/service.c index f8f2a77a7..aef3b022d 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -149,6 +149,7 @@ service_alloc(const char *servname, const char *router) service->capabilities = service->router->getCapabilities(); service->client_count = 0; + service->n_dbref = 0; service->name = (char*)servname; service->routerModule = (char*)router; service->users_from_all = false; @@ -742,7 +743,7 @@ int serviceHasProtocol(SERVICE *service, const char *protocol, * @param server Server to refer to * @return Server reference or NULL on error */ -static SERVER_REF* server_ref_alloc(SERVER *server) +static SERVER_REF* server_ref_create(SERVER *server) { SERVER_REF *sref = MXS_MALLOC(sizeof(SERVER_REF)); @@ -752,6 +753,7 @@ static SERVER_REF* server_ref_alloc(SERVER *server) sref->server = server; sref->weight = SERVICE_BASE_SERVER_WEIGHT; sref->connections = 0; + sref->active = true; } return sref; @@ -766,28 +768,72 @@ static SERVER_REF* server_ref_alloc(SERVER *server) void serviceAddBackend(SERVICE *service, SERVER *server) { - SERVER_REF *sref = server_ref_alloc(server); + SERVER_REF *new_ref = server_ref_create(server); - if (sref) + if (new_ref) { spinlock_acquire(&service->spin); + + service->n_dbref++; + if (service->dbref) { SERVER_REF *ref = service->dbref; - while (ref->next) + SERVER_REF *prev = ref; + + while (ref) { + if (ref->server == server) + { + ref->active = true; + break; + } + prev = ref; ref = ref->next; } - ref->next = sref; + + if (ref == NULL) + { + /** A new server that hasn't been used by this service */ + atomic_synchronize(); + prev->next = new_ref; + } } else { - service->dbref = sref; + atomic_synchronize(); + service->dbref = new_ref; } spinlock_release(&service->spin); } } +/** + * @brief Remove a server from a service + * + * This function sets the server reference into an inactive state. This does not + * remove the server from the list or free any of the memory. + * + * @param service Service to modify + * @param server Server to remove + */ +void serviceRemoveBackend(SERVICE *service, const SERVER *server) +{ + spinlock_acquire(&service->spin); + + service->n_dbref--; + + for (SERVER_REF *ref = service->dbref; ref; ref = ref->next) + { + if (ref->server == server) + { + ref->active = false; + break; + } + } + + spinlock_release(&service->spin); +} /** * Test if a server is part of a service * diff --git a/server/modules/routing/debugcli/debugcmd.c b/server/modules/routing/debugcli/debugcmd.c index 3e828bc77..9d072c600 100644 --- a/server/modules/routing/debugcli/debugcmd.c +++ b/server/modules/routing/debugcli/debugcmd.c @@ -715,39 +715,76 @@ struct subcommand failoptions[] = { static void telnetdAddUser(DCB *, char *user, char *password); +static void cmd_serviceAddBackend(DCB *dcb, void *a, void *b) +{ + SERVICE *service = (SERVICE*)a; + SERVER *server = (SERVER*)b; + + serviceAddBackend(service, server); + + MXS_NOTICE("Added server '%s' to service '%s'", server->unique_name, service->name); + dcb_printf(dcb, "Added server '%s' to service '%s'\n", server->unique_name, service->name); +} + /** * The subcommands of the add command */ struct subcommand addoptions[] = { - { "user", 2, telnetdAddUser, - "Add insecure account for using maxadmin over the network. E.g.:\n" - " MaxScale> add user bob somepass", - "Add insecure account for using maxadmin over the network. E.g.:\n" - " MaxScale> add user bob somepass", - {ARG_TYPE_STRING, ARG_TYPE_STRING, 0} }, + { + "user", 2, telnetdAddUser, + "Add insecure account for using maxadmin over the network. E.g.:\n" + " MaxScale> add user bob somepass", + "Add insecure account for using maxadmin over the network. E.g.:\n" + " MaxScale> add user bob somepass", + {ARG_TYPE_STRING, ARG_TYPE_STRING, 0} + }, + { + "server", 2, cmd_serviceAddBackend, + "Add a new server to a service", + "Add a new server to a service. The server must exist in the configuration file.", + {ARG_TYPE_SERVICE, ARG_TYPE_SERVER, 0} + }, { NULL, 0, NULL, NULL, NULL, - {0, 0, 0} } + {0, 0, 0}} }; static void telnetdRemoveUser(DCB *, char *user, char *password); +static void cmd_serviceRemoveBackend(DCB *dcb, void *a, void *b) +{ + SERVICE *service = (SERVICE*)a; + SERVER *server = (SERVER*)b; + + serviceRemoveBackend(service, server); + + MXS_NOTICE("Removed server '%s' from service '%s'", server->unique_name, service->name); + dcb_printf(dcb, "Removed server '%s' from service '%s'\n", server->unique_name, service->name); +} + /** * The subcommands of the remove command */ struct subcommand removeoptions[] = { { - "user", - 2, - telnetdRemoveUser, - "Remove account for using maxadmin over the network. E.g.:\n" - " MaxAdmin> remove user bob somepass", - "Remove account for using maxadmin over the network. E.g.:\n" - " MaxAdmin> remove user bob somepass", + "user", + 2, + telnetdRemoveUser, + "Remove account for using maxadmin over the network. E.g.:\n" + " MaxAdmin> remove user bob somepass", + "Remove account for using maxadmin over the network. E.g.:\n" + " MaxAdmin> remove user bob somepass", {ARG_TYPE_STRING, ARG_TYPE_STRING, 0} }, { - NULL, 0, NULL, NULL, NULL, {0, 0, 0} + "server", 2, cmd_serviceRemoveBackend, + "Remove a server from a service", + "Remove a server from a service. The server must exist in the configuration file.", + {ARG_TYPE_SERVICE, ARG_TYPE_SERVER, 0} + }, + { + NULL, 0, NULL, NULL, NULL, + {0, 0, 0} } };