Initial implementation of the monitor modules and a simple mysql monitor to set

server up or down automatically.
This commit is contained in:
Mark Riddoch
2013-07-08 18:55:43 +02:00
parent 902e059342
commit 46f6d27b0b
15 changed files with 632 additions and 1 deletions

View File

@ -21,6 +21,7 @@
# targets
# 18/06/13 Mark Riddoch Addition of install target
# 21/06/13 Mark Riddoch Addition of inih
# 08/07/13 Mark Riddoch Addition of monitor modules
DEST=/usr/local/skysql
@ -29,17 +30,20 @@ all:
(cd core; make)
(cd modules/routing; make)
(cd modules/protocol; make)
(cd modules/monitor; make)
clean:
(cd Documentation; rm -rf html)
(cd core; make clean)
(cd modules/routing; make clean)
(cd modules/protocol; make clean)
(cd modules/monitor; make clean)
depend:
(cd core; make depend)
(cd modules/routing; make depend)
(cd modules/protocol; make depend)
(cd modules/monitor; make depend)
documentation:
doxygen doxygate
@ -48,3 +52,4 @@ install:
(cd core; make DEST=$(DEST) install)
(cd modules/routing; make DEST=$(DEST) install)
(cd modules/protocol; make DEST=$(DEST) install)
(cd modules/moinitor; make DEST=$(DEST) install)

View File

@ -55,7 +55,8 @@ LDFLAGS=-rdynamic -L$(LOGPATH) \
SRCS= atomic.c buffer.c spinlock.c gateway.c gateway_mysql_protocol.c \
gw_utils.c utils.c dcb.c load_utils.c session.c service.c server.c \
poll.c config.c users.c hashtable.c dbusers.c thread.c gwbitmask.c
poll.c config.c users.c hashtable.c dbusers.c thread.c gwbitmask.c \
monitor.c
HDRS= ../include/atomic.h ../include/buffer.h ../include/dcb.h \
../include/gateway_mysql.h ../include/gw.h ../include/mysql_protocol.h \

View File

@ -24,6 +24,7 @@
*
* Date Who Description
* 21/06/13 Mark Riddoch Initial implementation
* 08/07/13 mark Riddoch Addition on monitor module support
*
* @endverbatim
*/
@ -35,6 +36,7 @@
#include <service.h>
#include <server.h>
#include <users.h>
#include <monitor.h>
static int process_config_context(CONFIG_CONTEXT *);
static void free_config_context(CONFIG_CONTEXT *);
@ -155,8 +157,12 @@ CONFIG_CONTEXT *obj;
char *address = config_get_value(obj->parameters, "address");
char *port = config_get_value(obj->parameters, "port");
char *protocol = config_get_value(obj->parameters, "protocol");
char *monuser = config_get_value(obj->parameters, "monitoruser");
char *monpw = config_get_value(obj->parameters, "monitorpw");
if (address && port && protocol)
obj->element = server_alloc(address, protocol, atoi(port));
if (obj->element && monuser && monpw)
serverAddMonUser(obj->element, monuser, monpw);
}
obj = obj->next;
@ -215,6 +221,30 @@ CONFIG_CONTEXT *obj;
serviceAddProtocol(ptr->element, protocol, atoi(port));
}
}
else if (!strcmp(type, "monitor"))
{
char *module = config_get_value(obj->parameters, "module");
char *servers = config_get_value(obj->parameters, "servers");
if (module)
{
obj->element = monitor_alloc(obj->object, module);
if (servers && obj->element)
{
char *s = strtok(servers, ",");
while (s)
{
CONFIG_CONTEXT *obj1 = context;
while (obj1)
{
if (strcmp(s, obj1->object) == 0 && obj->element && obj1->element)
monitorAddServer(obj->element, obj1->element);
obj1 = obj1->next;
}
s = strtok(NULL, ",");
}
}
}
}
obj = obj->next;
}

116
core/monitor.c Normal file
View File

@ -0,0 +1,116 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file monitor.c - The monitor module management routines
*
* @verbatim
* Revision History
*
* Date Who Description
* 08/07/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <monitor.h>
#include <spinlock.h>
#include <modules.h>
static MONITOR *allMonitors = NULL;
static SPINLOCK monLock = SPINLOCK_INIT;
/**
* Allocate a new monitor, load the associated module for the monitor
* and start execution on the monitor.
*
* @param name The name of the monitor module to load
* @return The newly created monitor
*/
MONITOR *
monitor_alloc(char *name, char *module)
{
MONITOR *mon;
if ((mon = (MONITOR *)malloc(sizeof(MONITOR))) == NULL)
{
return NULL;
}
mon->name = strdup(name);
mon->module = strdup(module);
if ((mon->module = load_module(module, MODULE_MONITOR)) == NULL)
{
fprintf(stderr, "Unable to load monitor module '%s'\n", name);
free(mon->name);
free(mon);
return NULL;
}
mon->handle = (*mon->module->startMonitor)();
spinlock_acquire(&monLock);
mon->next = allMonitors;
allMonitors = mon;
spinlock_release(&monLock);
return mon;
}
/**
* Free a monitor, first stop the monitor and then remove the monitor from
* the chain of monitors and free the memory.
*
* @param mon The monitor to free
*/
void
monitor_free(MONITOR *mon)
{
MONITOR *ptr;
mon->module->stopMonitor(mon->handle);
spinlock_acquire(&monLock);
if (allMonitors == mon)
allMonitors = mon->next;
else
{
ptr = allMonitors;
while (ptr->next && ptr->next != mon)
ptr = ptr->next;
if (ptr->next)
ptr->next = mon->next;
}
spinlock_release(&monLock);
free(mon->name);
free(mon);
}
/**
* Add a server to a monitor. Simply register the server that needs to be
* monitored to the running monitor module.
*
* @param mon The Monitor instance
* @param server The Server to add to the monitoring
*/
void
monitorAddServer(MONITOR *mon, SERVER *server)
{
mon->module->registerServer(mon->handle, server);
}

View File

@ -238,3 +238,18 @@ server_clear_status(SERVER *server, int bit)
{
server->status &= ~bit;
}
/**
* Add a user name and password to use for monitoring the
* state of the server.
*
* @param server The server to update
* @param user The user name to use
* @param passwd The password of the user
*/
void
serverAddMonUser(SERVER *server, char *user, char *passwd)
{
server->monuser = strdup(user);
server->monpw = strdup(passwd);
}

View File

@ -61,3 +61,18 @@ void *rval;
pthread_join((pthread_t)thd, &rval);
}
/**
* Put the thread to sleep for a number of milliseconds
*
* @param ms Number of milliseconds to sleep
*/
void
thread_millisleep(int ms)
{
struct timespec req;
req.tv_sec = ms / 1000;
req.tv_nsec = (ms % 1000) * 1000000;
nanosleep(&req, NULL);
}

View File

@ -18,18 +18,24 @@ type=server
address=127.0.0.1
port=3306
protocol=MySQLBackend
monitoruser=massi
monitorpw=massi
[server2]
type=server
address=127.0.0.1
port=3307
protocol=MySQLBackend
monitoruser=massi
monitorpw=massi
[server3]
type=server
address=127.0.0.1
port=3308
protocol=MySQLBackend
monitoruser=massi
monitorpw=massi
[Debug Service]
type=service
@ -46,3 +52,8 @@ type=listener
service=Test Service
protocol=MySQLClient
port=4006
[MySQL Monitor]
type=monitor
module=mysqlmon
servers=server1,server2,server3

View File

@ -29,6 +29,7 @@
*
* Date Who Description
* 13/06/13 Mark Riddoch Initial implementation
* 08/07/13 Mark Riddoch Addition of monitor modules
* @endverbatim
*/
@ -47,6 +48,7 @@ typedef struct modules {
*/
#define MODULE_PROTOCOL "Protocol" /**< A protocol module type */
#define MODULE_ROUTER "Router" /**< A router module type */
#define MODULE_MONITOR "Monitor" /**< A database monitor module type */
extern void *load_module(const char *module, const char *type);

79
include/monitor.h Normal file
View File

@ -0,0 +1,79 @@
#ifndef _MONITOR_H
#define _MONITOR_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <server.h>
/**
* @file monitor.h The interface to the monitor module
*
* @verbatim
* Revision History
*
* Date Who Description
* 07/07/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
/**
* The "Module Object" for a monitor module.
*
* The monitor modules are designed to monitor the backend databases that the gateway
* connects to and provide information regarding the status of the databases that
* is used in the routing decisions.
*
* startMonitor is called to start the monitoring process, it is called on the main
* thread of the gateway and is responsible for creating a thread for the monitor
* itself to run on. This should use the entry points defined in the thread.h
* header file rather than make direct calls to the operating system thrading libraries.
* The return from startMonitor is a void * handle that will be passed to all other monitor
* API calls.
*
* stopMonitor is responsible for shuting down and destroying a monitor, it is called
* with the void * handle that was returned by startMonitor.
*
* registerServer is called to register a server that must be monitored with a running
* monitor. this will be called with the handle returned from the startMonitor call and
* the SERVER structure that the monitor must update and monitor. The SERVER structure
* contains the information required to connect to the monitored server.
*
* unregisterServer is called to remove a server from the set of servers that need to be
* monitored.
*/
typedef struct {
void *(*startMonitor)();
void (*stopMonitor)(void *);
void (*registerServer)(void *, SERVER *);
void (*unregisterServer)(void *, SERVER *);
} MONITOR_OBJECT;
/**
* Representation of the running monitor.
*/
typedef struct monitor {
char *name; /**< The name of the monitor module */
MONITOR_OBJECT *module; /**< The "monitor object" */
void *handle; /**< Handle returned from startMonitor */
struct monitor *next; /**< Next monitor in the linked list */
} MONITOR;
extern MONITOR *monitor_alloc(char *, char *);
extern void monitor_free(MONITOR *);
extern void monitorAddServer(MONITOR *, SERVER *);
#endif

View File

@ -54,6 +54,8 @@ typedef struct server {
unsigned short port; /**< Port to listen on */
char *protocol; /**< Protocol module to use */
unsigned int status; /**< Status flag bitmap for the server */
char *monuser; /**< User name to use to monitor the db */
char *monpw; /**< Password to use to monitor the db */
SERVER_STATS stats; /**< The server statistics */
struct server *next; /**< Next server */
struct server *nextdb; /**< Next server in list attached to a service */
@ -100,4 +102,5 @@ extern void dprintServer(DCB *, SERVER *);
extern char *server_status(SERVER *);
extern void server_set_status(SERVER *, int);
extern void server_clear_status(SERVER *, int);
extern void serverAddMonUser(SERVER *, char *, char *);
#endif

View File

@ -33,5 +33,6 @@
extern void *thread_start(void (*entry)(void *), void *arg);
extern void thread_wait(void *thd);
extern void thread_millisleep(int ms);
#endif

59
modules/monitor/Makefile Normal file
View File

@ -0,0 +1,59 @@
# This file is distributed as part of the SkySQL Gateway. It is free
# software: you can redistribute it and/or modify it under the terms of the
# GNU General Public License as published by the Free Software Foundation,
# version 2.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright SkySQL Ab 2013
#
# Revision History
# Date Who Description
# 08/07/13 Mark Riddoch Initial implementation
include ../../../build_gateway.inc
LOGPATH := $(ROOT_PATH)/log_manager
UTILSPATH := $(ROOT_PATH)/utils
CC=cc
CFLAGS=-c -fPIC -I. -I/usr/include -I../include -I../../include -I$(LOGPATH) \
-I$(UTILSPATH) -I/usr/include/mysql -Wall -g
LDFLAGS=-shared -L$(LOGPATH) -Wl,-rpath,$(LOGPATH) -Wl,-rpath,$(UTILSPATH)
MYSQLSRCS=mysql_mon.c
MYSQLOBJ=$(MYSQLSRCS:.c=.o)
SRCS=$(MYSQLSRCS)
OBJ=$(SRCS:.c=.o)
LIBS=$(UTILSPATH)/skygw_utils.o -llog_manager \
-L/packages/mariadb-5.5.25/libmysql -lmysqlclient
MODULES=libmysqlmon.so
all: $(MODULES)
libmysqlmon.so: $(MYSQLOBJ)
$(CC) $(LDFLAGS) $(MYSQLOBJ) $(LIBS) -o $@
.c.o:
$(CC) $(CFLAGS) $< -o $@
clean:
rm -f $(OBJ) $(MODULES)
tags:
ctags $(SRCS) $(HDRS)
depend:
@rm -f depend.mk
cc -M $(CFLAGS) $(SRCS) > depend.mk
install: $(MODULES)
install -D $< $(DEST)/gateway/modules
include depend.mk

16
modules/monitor/depend.mk Normal file
View File

@ -0,0 +1,16 @@
mysql_mon.o: mysql_mon.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 \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
../../include/monitor.h mysqlmon.h ../../include/server.h \
../../include/dcb.h ../../include/spinlock.h ../../include/thread.h \
/usr/include/pthread.h /usr/include/endian.h /usr/include/bits/endian.h \
/usr/include/bits/byteswap.h /usr/include/sched.h /usr/include/time.h \
/usr/include/bits/sched.h /usr/include/bits/time.h \
/usr/include/xlocale.h /usr/include/bits/pthreadtypes.h \
/usr/include/bits/setjmp.h ../../include/buffer.h \
../../include/gwbitmask.h

223
modules/monitor/mysql_mon.c Normal file
View File

@ -0,0 +1,223 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <stdio.h>
#include <stdlib.h>
#include <monitor.h>
#include <mysqlmon.h>
#include <thread.h>
static void monitorMain(void *);
static char *version_str = "V1.0.0";
static void *startMonitor();
static void stopMonitor(void *);
static void registerServer(void *, SERVER *);
static void unregisterServer(void *, SERVER *);
static MONITOR_OBJECT MyObject = { startMonitor, stopMonitor, registerServer, unregisterServer };
/**
* Implementation of the mandatory version entry point
*
* @return version string of the module
*/
char *
version()
{
return version_str;
}
/**
* The module initialisation routine, called when the module
* is first loaded.
*/
void
ModuleInit()
{
fprintf(stderr, "Initialise the MySQL Monitor module.\n");
}
/**
* The module entry point routine. It is this routine that
* must populate the structure that is referred to as the
* "module object", this is a structure with the set of
* external entry points for this module.
*
* @return The module object
*/
MONITOR_OBJECT *
GetModuleObject()
{
return &MyObject;
}
/**
* Start the instance of the monitor, returning a handle on the monitor.
*
* This function creates a thread to execute the actual monitoring.
*
* @return A handle to use when interacting with the monitor
*/
static void *
startMonitor()
{
MYSQL_MONITOR *handle;
if ((handle = (MYSQL_MONITOR *)malloc(sizeof(MYSQL_MONITOR))) == NULL)
return NULL;
handle->databases = NULL;
handle->shutdown = 0;
spinlock_init(&handle->lock);
thread_start(monitorMain, handle);
return handle;
}
/**
* Stop a running monitor
*
* @param handle Handle on thr running monior
*/
static void
stopMonitor(void *arg)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
handle->shutdown = 1;
}
/**
* Register a server that must be added to the monitored servers for
* a monitoring module.
*
* @param handle A handle on the running monitor module
* @param server The server to add
*/
static void
registerServer(void *arg, SERVER *server)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR_SERVERS *ptr, *db;
if ((db = (MONITOR_SERVERS *)malloc(sizeof(MONITOR_SERVERS))) == NULL)
return;
db->server = server;
db->con = NULL;
db->next = NULL;
spinlock_acquire(&handle->lock);
if (handle->databases == NULL)
handle->databases = db;
else
{
ptr = handle->databases;
while (ptr->next != NULL)
ptr = ptr->next;
ptr->next = db;
}
spinlock_release(&handle->lock);
}
/**
* Remove a server from those being monitored by a monitoring module
*
* @param handle A handle on the running monitor module
* @param server The server to remove
*/
static void
unregisterServer(void *arg, SERVER *server)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR_SERVERS *ptr, *lptr;
spinlock_acquire(&handle->lock);
if (handle->databases == NULL)
{
spinlock_release(&handle->lock);
return;
}
if (handle->databases->server == server)
{
ptr = handle->databases;
handle->databases = handle->databases->next;
free(ptr);
}
else
{
ptr = handle->databases;
while (ptr->next != NULL && ptr->next->server != server)
ptr = ptr->next;
if (ptr->next)
{
lptr = ptr->next;
ptr->next = ptr->next->next;
free(lptr);
}
}
spinlock_release(&handle->lock);
}
/**
* Monitor an individual server
*
* @param database The database to probe
*/
static void
monitorDatabase(MONITOR_SERVERS *database)
{
if (database->con == NULL || mysql_ping(database->con) != 0)
{
database->con = mysql_init(NULL);
if (mysql_real_connect(database->con, database->server->name,
database->server->monuser, database->server->monpw,
NULL, database->server->port, NULL, 0) == NULL)
{
server_clear_status(database->server, SERVER_RUNNING);
return;
}
}
// If we get this far then we have a workign connection
server_set_status(database->server, SERVER_RUNNING);
}
/**
* The entry point for the monitoring module thread
*
* @param arg The handle of the monitor
*/
static void
monitorMain(void *arg)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR_SERVERS *ptr;
while (1)
{
thread_millisleep(1000);
if (handle->shutdown)
return;
ptr = handle->databases;
while (ptr)
{
monitorDatabase(ptr);
ptr = ptr->next;
}
}
}

View File

@ -0,0 +1,55 @@
#ifndef _MYSQLMON_H
#define _MYSQLMON_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <server.h>
#include <spinlock.h>
#include <mysql.h>
/**
* @file mysqlmon.h - The MySQL monitor functionality within the gateway
*
* @verbatim
* Revision History
*
* Date Who Description
* 08/07/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
/**
* The linked list of servers that are being monitored by the MySQL
* Monitor module.
*/
typedef struct monitor_servers {
SERVER *server; /**< The server being monitored */
MYSQL *con; /**< The MySQL connection */
struct monitor_servers
*next; /**< The next server in the list */
} MONITOR_SERVERS;
/**
* The handle for an instance of a MySQL Monitor module
*/
typedef struct {
SPINLOCK lock; /**< The monitor spinlock */
int shutdown; /**< Flag to shutdown the monitor thread */
MONITOR_SERVERS *databases; /**< Linked list of servers to monitor */
} MYSQL_MONITOR;
#endif