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} } };