From 34fdbdb34d14b05d96f61acc43d03521a61ed55d Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Tue, 25 Jun 2013 14:00:18 +0200 Subject: [PATCH] Addition for shutdown mechanism for the gateway Addition of stop and restart service Fix for telnetd in Makefile Fix for printing the server names in services --- core/depend.mk | 2 +- core/gateway.c | 28 ++++++++++++++---- core/poll.c | 26 +++++++++++++++-- core/service.c | 60 ++++++++++++++++++++++++++++++++++++-- core/session.c | 4 +++ core/thread.c | 3 +- include/poll.h | 2 ++ include/service.h | 2 ++ include/session.h | 7 +++-- modules/protocol/Makefile | 2 +- modules/routing/debugcmd.c | 47 +++++++++++++++++++++++++++++ 11 files changed, 167 insertions(+), 16 deletions(-) diff --git a/core/depend.mk b/core/depend.mk index dfdd042e1..7a660da19 100644 --- a/core/depend.mk +++ b/core/depend.mk @@ -336,7 +336,7 @@ service.o: service.c /usr/include/stdio.h /usr/include/features.h \ /usr/include/bits/setjmp.h ../include/dcb.h ../include/buffer.h \ ../include/server.h ../include/router.h ../include/modules.h \ ../include/users.h ../include/hashtable.h ../include/atomic.h \ - ../include/dbusers.h + ../include/dbusers.h ../include/poll.h server.o: server.c /usr/include/stdio.h /usr/include/features.h \ /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ diff --git a/core/gateway.c b/core/gateway.c index bce09e4c9..55218f76b 100644 --- a/core/gateway.c +++ b/core/gateway.c @@ -50,9 +50,10 @@ static void sighup_handler (int i) { } static void sigterm_handler (int i) { +extern void shutdown_gateway(); + fprintf(stderr, "Signal SIGTERM %i received ...Exiting!\n", i); - - exit(0); + shutdown_gateway(); } /* wrapper for sigaction */ @@ -170,7 +171,8 @@ main(int argc, char **argv) { int daemon_mode = 1; sigset_t sigset; -int n; +int n, n_threads; +void **threads; char buf[1024], *home, *cnf_file = NULL; if ((home = getenv("GATEWAY_HOME")) != NULL) @@ -250,8 +252,24 @@ char buf[1024], *home, *cnf_file = NULL; * Start the polling threads, note this is one less than is configured as the * main thread will also poll. */ - for (n = 0; n < config_threadcount() - 1; n++) - thread_start(poll_waitevents); + n_threads = config_threadcount(); + threads = (void **)calloc(n_threads, sizeof(void *)); + for (n = 0; n < n_threads - 1; n++) + threads[n] = thread_start(poll_waitevents); poll_waitevents(); + for (n = 0; n < n_threads - 1; n++) + thread_wait(threads[n]); + printf("Gateway shutdown\n"); + + return 0; } // End of main + +/** + * Shutdown the gateway + */ +void +shutdown_gateway() +{ + poll_shutdown(); +} diff --git a/core/poll.c b/core/poll.c index acb5114e0..77e04556c 100644 --- a/core/poll.c +++ b/core/poll.c @@ -37,6 +37,7 @@ */ static int epoll_fd = -1; /**< The epoll file descriptor */ +static int shutdown = 0; /**< Flag the shutdown of the poll subsystem */ /** * The polling statistics @@ -117,12 +118,18 @@ int i, nfds; while (1) { - atomic_add(&pollStats.n_polls, 1); - if ((nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1)) == -1) + if ((nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, 0)) == -1) { } - else + else if (nfds == 0) { + if ((nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, EPOLL_TIMEOUT)) == -1) + { + } + } + if (nfds > 0) + { + atomic_add(&pollStats.n_polls, 1); for (i = 0; i < nfds; i++) { DCB *dcb = (DCB *)events[i].data.ptr; @@ -158,9 +165,22 @@ int i, nfds; } } } + if (shutdown) + { + return; + } } } +/** + * Shutdown the polling loop + */ +void +poll_shutdown() +{ + shutdown = 1; +} + /** * Debug routine to print the polling statistics * diff --git a/core/service.c b/core/service.c index 42173a9e3..9829789fd 100644 --- a/core/service.c +++ b/core/service.c @@ -39,6 +39,7 @@ #include #include #include +#include static SPINLOCK service_spin = SPINLOCK_INIT; static SERVICE *allServices = NULL; @@ -160,6 +161,61 @@ int n = 0; return n; } +/** + * Stop a service + * + * This function stops the listener for the service + * + * @param service The Service that should be stopped + * @return Returns the number of listeners restarted + */ +int +serviceStop(SERVICE *service) +{ +SERV_PROTOCOL *port; +int listeners = 0; + + port = service->ports; + while (port) + { + poll_remove_dcb(port->listener); + port->listener->session->state = SESSION_STATE_LISTENER_STOPPED; + listeners++; + + port = port->next; + } + + return listeners; +} + +/** + * Restart a service + * + * This function stops the listener for the service + * + * @param service The Service that should be restarted + * @return Returns the number of listeners restarted + */ +int +serviceRestart(SERVICE *service) +{ +SERV_PROTOCOL *port; +int listeners = 0; + + port = service->ports; + while (port) + { + poll_add_dcb(port->listener); + port->listener->session->state = SESSION_STATE_LISTENER; + listeners++; + + port = port->next; + } + + return listeners; +} + + /** * Deallocate the specified service * @@ -306,7 +362,7 @@ SERVER *ptr = service->databases; while (ptr) { printf("\t\t%s:%d Protocol: %s\n", ptr->name, ptr->port, ptr->protocol); - ptr = ptr->next; + ptr = ptr->nextdb; } printf("\tTotal connections: %d\n", service->stats.n_sessions); printf("\tCurrently connected: %d\n", service->stats.n_current); @@ -360,7 +416,7 @@ SERVICE *ptr; { dcb_printf(dcb, "\t\t%s:%d Protocol: %s\n", server->name, server->port, server->protocol); - server = server->next; + server = server->nextdb; } dcb_printf(dcb, "\tTotal connections: %d\n", ptr->stats.n_sessions); dcb_printf(dcb, "\tCurrently connected: %d\n", ptr->stats.n_current); diff --git a/core/session.c b/core/session.c index 89009a473..d0f84e22b 100644 --- a/core/session.c +++ b/core/session.c @@ -130,6 +130,7 @@ void printSession(SESSION *session) { printf("Session %p\n", session); + printf("\tState: %s\n", session_state(session->state)); printf("\tService: %s (%p)\n", session->service->name, session->service); printf("\tClient DCB: %p\n", session->client); printf("\tConnected: %s", asctime(localtime(&session->stats.connect))); @@ -174,6 +175,7 @@ SESSION *ptr; while (ptr) { dcb_printf(dcb, "Session %p\n", ptr); + dcb_printf(dcb, "\tState: %s\n", session_state(ptr->state)); dcb_printf(dcb, "\tService: %s (%p)\n", ptr->service->name, ptr->service); dcb_printf(dcb, "\tClient DCB: %p\n", ptr->client); if (ptr->client && ptr->client->remote) @@ -222,6 +224,8 @@ session_state(int state) return "Session Ready"; case SESSION_STATE_LISTENER: return "Listener Session"; + case SESSION_STATE_LISTENER_STOPPED: + return "Stopped Listener Session"; default: return "Invalid State"; } diff --git a/core/thread.c b/core/thread.c index 715d4792e..addabc699 100644 --- a/core/thread.c +++ b/core/thread.c @@ -49,8 +49,9 @@ pthread_t thd; } /** - * Wait for all running threads to complete. + * Wait for a running threads to complete. * + * @param thd The thread handle */ void thread_wait(void *thd) diff --git a/include/poll.h b/include/poll.h index 61d890682..fa079cda0 100644 --- a/include/poll.h +++ b/include/poll.h @@ -31,10 +31,12 @@ * @endverbatim */ #define MAX_EVENTS 1000 +#define EPOLL_TIMEOUT 1000 /**< The epoll timeout we use (milliseconds) */ extern void poll_init(); extern int poll_add_dcb(DCB *); extern int poll_remove_dcb(DCB *); extern void poll_waitevents(); +extern void poll_shutdown(); extern void dprintPollStats(DCB *); #endif diff --git a/include/service.h b/include/service.h index f17e83d9f..8275ba055 100644 --- a/include/service.h +++ b/include/service.h @@ -112,6 +112,8 @@ extern int serviceAddProtocol(SERVICE *, char *, unsigned short); extern void serviceAddBackend(SERVICE *, SERVER *); extern int serviceStart(SERVICE *); extern int serviceStartAll(); +extern int serviceStop(SERVICE *); +extern int serviceRestart(SERVICE *); extern int serviceSetUser(SERVICE *, char *, char *); extern int serviceGetUser(SERVICE *, char **, char **); extern void printService(SERVICE *); diff --git a/include/session.h b/include/session.h index eaa443f32..62a74720b 100644 --- a/include/session.h +++ b/include/session.h @@ -60,9 +60,10 @@ typedef struct session { struct session *next; /**< Linked list of all sessions */ } SESSION; -#define SESSION_STATE_ALLOC 0 -#define SESSION_STATE_READY 1 -#define SESSION_STATE_LISTENER 2 +#define SESSION_STATE_ALLOC 0 /**< The session has been allocated */ +#define SESSION_STATE_READY 1 /**< The session is ready to route queries */ +#define SESSION_STATE_LISTENER 2 /**< The session is a running listener */ +#define SESSION_STATE_LISTENER_STOPPED 3 /**< The session listener is stopped */ #define SESSION_PROTOCOL(x, type) DCB_PROTOCOL((x)->client, type) diff --git a/modules/protocol/Makefile b/modules/protocol/Makefile index d7351258f..839af4326 100644 --- a/modules/protocol/Makefile +++ b/modules/protocol/Makefile @@ -28,7 +28,7 @@ MYSQLBACKENDSRCS=mysql_backend.c mysql_common.c MYSQLBACKENDOBJ=$(MYSQLBACKENDSRCS:.c=.o) TELNETDSRCS=telnetd.c TELNETDOBJ=$(TELNETDSRCS:.c=.o) -SRCS=$(MYSQLCLIENTSRCS) $(MYSQLBACKENDSRCS) +SRCS=$(MYSQLCLIENTSRCS) $(MYSQLBACKENDSRCS) $(TELNETDSRCS) OBJ=$(SRCS:.c=.o) LIBS= MODULES=libMySQLClient.so libMySQLBackend.so libtelnetd.so diff --git a/modules/routing/debugcmd.c b/modules/routing/debugcmd.c index f90cf0e00..e773d5675 100644 --- a/modules/routing/debugcmd.c +++ b/modules/routing/debugcmd.c @@ -80,6 +80,27 @@ struct subcommand showoptions[] = { { NULL, 0, NULL, NULL } }; +extern void shutdown_gateway(); +static void shutdown_service(DCB *dcb, SERVICE *service); + +/** + * The subcommands of the shutdown command + */ +struct subcommand shutdownoptions[] = { + { "gateway", 0, shutdown_gateway, "Shutdown the gateway" }, + { "service", 1, shutdown_service, "Shutdown a service, e.g. shutdown service 0x4838320" }, + { NULL, 0, NULL, NULL } +}; + +static void restart_service(DCB *dcb, SERVICE *service); +/** + * The subcommands of the restart command + */ +struct subcommand restartoptions[] = { + { "service", 1, restart_service, "Restart a service, e.g. restart service 0x4838320" }, + { NULL, 0, NULL, NULL } +}; + /** * The debug command table */ @@ -88,6 +109,8 @@ static struct { struct subcommand *options; } cmds[] = { { "show", showoptions }, + { "shutdown", shutdownoptions }, + { "restart", restartoptions }, { NULL, NULL } }; @@ -230,3 +253,27 @@ char *saveptr, *delim = " \t\r\n"; return 1; } + +/** + * Debug command to stop a service + * + * @param dcb The DCB to print any output to + * @param service The service to shutdown + */ +static void +shutdown_service(DCB *dcb, SERVICE *service) +{ + serviceStop(service); +} + +/** + * Debug command to restart a stopped service + * + * @param dcb The DCB to print any output to + * @param service The service to restart + */ +static void +restart_service(DCB *dcb, SERVICE *service) +{ + serviceRestart(service); +}