Merge branch 'MXS-121' into develop

This commit is contained in:
Markus Makela
2015-05-21 17:53:01 +03:00
22 changed files with 2138 additions and 1257 deletions

View File

@ -1,16 +1,16 @@
add_library(mysqlmon SHARED mysql_mon.c)
add_library(mysqlmon SHARED mysql_mon.c monitor_common.c)
target_link_libraries(mysqlmon log_manager utils)
install(TARGETS mysqlmon DESTINATION modules)
add_library(galeramon SHARED galera_mon.c)
add_library(galeramon SHARED galeramon.c monitor_common.c)
target_link_libraries(galeramon log_manager utils)
install(TARGETS galeramon DESTINATION modules)
add_library(ndbclustermon SHARED ndbcluster_mon.c)
add_library(ndbclustermon SHARED ndbclustermon.c monitor_common.c)
target_link_libraries(ndbclustermon log_manager utils)
install(TARGETS ndbclustermon DESTINATION modules)
if(BUILD_MMMON)
add_library(mmmon SHARED mm_mon.c)
add_library(mmmon SHARED mmmon.c monitor_common.c)
target_link_libraries(mmmon log_manager utils)
install(TARGETS mmmon DESTINATION modules)
endif()

View File

@ -34,24 +34,13 @@
* 10/11/14 Massimiliano Pinto Added setNetworkTimeout for connect,read,write
* 20/04/15 Guillaume Lefranc Added availableWhenDonor feature
* 22/04/15 Martin Brampton Addition of disableMasterRoleSetting
* 08/05/15 Markus Makela Addition of launchable scripts
*
* @endverbatim
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <monitor.h>
#include <mysqlmon.h>
#include <thread.h>
#include <mysql.h>
#include <mysqld_error.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <secrets.h>
#include <dcb.h>
#include <modinfo.h>
#include <maxconfig.h>
#include <galeramon.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
@ -60,7 +49,7 @@ extern __thread log_info_t tls_log_info;
static void monitorMain(void *);
static char *version_str = "V1.4.0";
static char *version_str = "V2.0.0";
MODULE_INFO info = {
MODULE_API_MONITOR,
@ -71,27 +60,16 @@ MODULE_INFO info = {
static void *startMonitor(void *,void*);
static void stopMonitor(void *);
static void registerServer(void *, SERVER *);
static void unregisterServer(void *, SERVER *);
static void defaultUsers(void *, char *, char *);
static void diagnostics(DCB *, void *);
static void setInterval(void *, size_t);
static MONITOR_SERVERS *get_candidate_master(MONITOR_SERVERS *);
static MONITOR_SERVERS *set_cluster_master(MONITOR_SERVERS *, MONITOR_SERVERS *, int);
static void disableMasterFailback(void *, int);
static void setNetworkTimeout(void *arg, int type, int value);
static bool mon_status_changed(MONITOR_SERVERS* mon_srv);
static bool mon_print_fail_status(MONITOR_SERVERS* mon_srv);
bool isGaleraEvent(monitor_event_t event);
static MONITOR_OBJECT MyObject = {
startMonitor,
stopMonitor,
registerServer,
unregisterServer,
defaultUsers,
diagnostics,
setInterval,
setNetworkTimeout
stopMonitor,
diagnostics
};
/**
@ -142,47 +120,80 @@ GetModuleObject()
static void *
startMonitor(void *arg,void* opt)
{
MYSQL_MONITOR *handle;
CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt;
if (arg != NULL)
{
handle = (MYSQL_MONITOR *)arg;
handle->shutdown = 0;
}
else
{
if ((handle = (MYSQL_MONITOR *)malloc(sizeof(MYSQL_MONITOR))) == NULL)
return NULL;
handle->databases = NULL;
handle->shutdown = 0;
handle->defaultUser = NULL;
handle->defaultPasswd = NULL;
handle->id = MONITOR_DEFAULT_ID;
handle->interval = MONITOR_INTERVAL;
handle->disableMasterFailback = 0;
handle->availableWhenDonor = 0;
handle->disableMasterRoleSetting = 0;
handle->master = NULL;
handle->connect_timeout=DEFAULT_CONNECT_TIMEOUT;
handle->read_timeout=DEFAULT_READ_TIMEOUT;
handle->write_timeout=DEFAULT_WRITE_TIMEOUT;
spinlock_init(&handle->lock);
}
MONITOR* mon = arg;
GALERA_MONITOR *handle = mon->handle;
CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt;
bool have_events = false;
if (handle != NULL)
{
handle->shutdown = 0;
}
else
{
if ((handle = (GALERA_MONITOR *)malloc(sizeof(GALERA_MONITOR))) == NULL)
return NULL;
handle->shutdown = 0;
handle->id = MONITOR_DEFAULT_ID;
handle->disableMasterFailback = 0;
handle->availableWhenDonor = 0;
handle->disableMasterRoleSetting = 0;
handle->master = NULL;
handle->script = NULL;
memset(handle->events,false,sizeof(handle->events));
spinlock_init(&handle->lock);
}
while(params)
while(params)
{
if(!strcmp(params->name,"disable_master_failback"))
handle->disableMasterFailback = config_truth_value(params->value);
else if(!strcmp(params->name,"available_when_donor"))
handle->availableWhenDonor = config_truth_value(params->value);
else if(!strcmp(params->name,"disable_master_role_setting"))
handle->disableMasterRoleSetting = config_truth_value(params->value);
else if(!strcmp(params->name,"script"))
{
if(!strcmp(params->name,"disable_master_failback"))
handle->disableMasterFailback = config_truth_value(params->value);
else if(!strcmp(params->name,"available_when_donor"))
handle->availableWhenDonor = config_truth_value(params->value);
else if(!strcmp(params->name,"disable_master_role_setting"))
handle->disableMasterRoleSetting = config_truth_value(params->value);
params = params->next;
}
if(handle->script)
free(handle->script);
handle->tid = (THREAD)thread_start(monitorMain, handle);
return handle;
if(access(params->value,X_OK) == 0)
{
handle->script = strdup(params->value);
}
else
{
if(access(params->value,F_OK) == 0)
{
skygw_log_write(LE,
"Error: The file cannot be executed: %s",
params->value);
}
else
{
skygw_log_write(LE,
"Error: The file cannot be found: %s",
params->value);
}
handle->script = NULL;
}
}
else if(!strcmp(params->name,"events"))
{
mon_parse_event_string((bool*)&handle->events,sizeof(handle->events),params->value);
have_events = true;
}
params = params->next;
}
/** If no specific events are given, enable them all */
if(!have_events)
{
memset(handle->events,true,sizeof(handle->events));
}
handle->tid = (THREAD)thread_start(monitorMain, mon);
return handle;
}
/**
@ -193,82 +204,13 @@ CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt;
static void
stopMonitor(void *arg)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR* mon = (MONITOR*)arg;
GALERA_MONITOR *handle = (GALERA_MONITOR *)mon->handle;
handle->shutdown = 1;
thread_wait((void *)handle->tid);
}
/**
* Register a server that must be added to the monitored servers for
* a monitoring module.
*
* @param arg 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 arg 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);
}
/**
* Diagnostic interface
*
@ -278,7 +220,8 @@ MONITOR_SERVERS *ptr, *lptr;
static void
diagnostics(DCB *dcb, void *arg)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR* mon = (MONITOR*)arg;
GALERA_MONITOR *handle = (GALERA_MONITOR *)mon->handle;
MONITOR_SERVERS *db;
char *sep;
@ -295,16 +238,16 @@ char *sep;
break;
}
dcb_printf(dcb,"\tSampling interval:\t%lu milliseconds\n", handle->interval);
dcb_printf(dcb,"\tSampling interval:\t%lu milliseconds\n", mon->interval);
dcb_printf(dcb,"\tMaster Failback:\t%s\n", (handle->disableMasterFailback == 1) ? "off" : "on");
dcb_printf(dcb,"\tAvailable when Donor:\t%s\n", (handle->availableWhenDonor == 1) ? "on" : "off");
dcb_printf(dcb,"\tMaster Role Setting Disabled:\t%s\n", (handle->disableMasterRoleSetting == 1) ? "on" : "off");
dcb_printf(dcb,"\tConnect Timeout:\t%i seconds\n", handle->connect_timeout);
dcb_printf(dcb,"\tRead Timeout:\t\t%i seconds\n", handle->read_timeout);
dcb_printf(dcb,"\tWrite Timeout:\t\t%i seconds\n", handle->write_timeout);
dcb_printf(dcb,"\tConnect Timeout:\t%i seconds\n", mon->connect_timeout);
dcb_printf(dcb,"\tRead Timeout:\t\t%i seconds\n", mon->read_timeout);
dcb_printf(dcb,"\tWrite Timeout:\t\t%i seconds\n", mon->write_timeout);
dcb_printf(dcb, "\tMonitored servers: ");
db = handle->databases;
db = mon->databases;
sep = "";
while (db)
{
@ -315,27 +258,6 @@ char *sep;
dcb_printf(dcb, "\n");
}
/**
* Set the default username and password to use to monitor if the server does not
* override this.
*
* @param arg The handle allocated by startMonitor
* @param uname The default user name
* @param passwd The default password
*/
static void
defaultUsers(void *arg, char *uname, char *passwd)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
if (handle->defaultUser)
free(handle->defaultUser);
if (handle->defaultPasswd)
free(handle->defaultPasswd);
handle->defaultUser = strdup(uname);
handle->defaultPasswd = strdup(passwd);
}
/**
* Monitor an individual server
*
@ -343,14 +265,14 @@ MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
* @param database The database to probe
*/
static void
monitorDatabase(MYSQL_MONITOR *handle, MONITOR_SERVERS *database)
monitorDatabase(MONITOR *mon, MONITOR_SERVERS *database)
{
GALERA_MONITOR* handle = (GALERA_MONITOR*)mon->handle;
MYSQL_ROW row;
MYSQL_RES *result;
int num_fields;
int isjoined = 0;
char *uname = handle->defaultUser;
char *passwd = handle->defaultPasswd;
char *uname = mon->user;
char *passwd = mon->password;
unsigned long int server_version = 0;
char *server_string;
@ -372,18 +294,17 @@ char *server_string;
if (database->con == NULL || mysql_ping(database->con) != 0)
{
char *dpwd = decryptPassword(passwd);
int rc;
int connect_timeout = handle->connect_timeout;
int read_timeout = handle->read_timeout;
int write_timeout = handle->write_timeout;
int connect_timeout = mon->connect_timeout;
int read_timeout = mon->read_timeout;
int write_timeout = mon->write_timeout;
if(database->con)
mysql_close(database->con);
database->con = mysql_init(NULL);
rc = mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&connect_timeout);
rc = mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout);
rc = mysql_options(database->con, MYSQL_OPT_WRITE_TIMEOUT, (void *)&write_timeout);
mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&connect_timeout);
mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout);
mysql_options(database->con, MYSQL_OPT_WRITE_TIMEOUT, (void *)&write_timeout);
if (mysql_real_connect(database->con, database->server->name,
uname, dpwd, NULL, database->server->port, NULL, 0) == NULL)
@ -428,9 +349,6 @@ char *server_string;
/* If we get this far then we have a working connection */
server_set_status(database->server, SERVER_RUNNING);
/* get server version from current server */
server_version = mysql_get_server_version(database->con);
/* get server version string */
server_string = (char *)mysql_get_server_info(database->con);
if (server_string) {
@ -443,7 +361,6 @@ char *server_string;
if (mysql_query(database->con, "SHOW STATUS LIKE 'wsrep_local_state'") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
if (strcmp(row[1], "4") == 0)
@ -454,7 +371,6 @@ char *server_string;
if (mysql_query(database->con, "SHOW VARIABLES LIKE 'wsrep_sst_method'") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
if (strncmp(row[1], "xtrabackup", 10) == 0)
@ -471,7 +387,6 @@ char *server_string;
&& (result = mysql_store_result(database->con)) != NULL)
{
long local_index = -1;
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
local_index = strtol(row[1], NULL, 10);
@ -499,14 +414,20 @@ char *server_string;
static void
monitorMain(void *arg)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR* mon = (MONITOR*)arg;
GALERA_MONITOR *handle;
MONITOR_SERVERS *ptr;
size_t nrounds = 0;
MONITOR_SERVERS *candidate_master = NULL;
int master_stickiness = handle->disableMasterFailback;
int master_stickiness;
int is_cluster=0;
int log_no_members = 1;
monitor_event_t evtype;
spinlock_acquire(&mon->lock);
handle = (GALERA_MONITOR *)mon->handle;
spinlock_release(&mon->lock);
master_stickiness = handle->disableMasterFailback;
if (mysql_thread_init())
{
LOGIF(LE, (skygw_log_write_flush(
@ -535,7 +456,7 @@ int log_no_members = 1;
* round.
*/
if (nrounds != 0 && ((nrounds*MON_BASE_INTERVAL_MS)%handle->interval) >= MON_BASE_INTERVAL_MS)
if (nrounds != 0 && ((nrounds*MON_BASE_INTERVAL_MS)%mon->interval) >= MON_BASE_INTERVAL_MS)
{
nrounds += 1;
continue;
@ -546,11 +467,13 @@ int log_no_members = 1;
/* reset cluster members counter */
is_cluster=0;
ptr = handle->databases;
ptr = mon->databases;
while (ptr)
{
monitorDatabase(handle, ptr);
ptr->mon_prev_status = ptr->server->status;
monitorDatabase(mon, ptr);
/* clear bits for non member nodes */
if ( ! SERVER_IN_MAINT(ptr->server) && (ptr->server->node_id < 0 || ! SERVER_IS_JOINED(ptr->server))) {
@ -586,6 +509,7 @@ int log_no_members = 1;
/** Increase this server'e error count */
dcb_call_foreach(ptr->server,DCB_REASON_NOT_RESPONDING);
ptr->mon_err_count += 1;
}
else
{
@ -604,7 +528,7 @@ int log_no_members = 1;
*/
/* get the candidate master, following MIN(node_id) rule */
candidate_master = get_candidate_master(handle->databases);
candidate_master = get_candidate_master(mon->databases);
/* Select the master, based on master_stickiness */
if (1 == handle->disableMasterRoleSetting) {
@ -614,7 +538,7 @@ int log_no_members = 1;
handle->master = set_cluster_master(handle->master, candidate_master, master_stickiness);
}
ptr = handle->databases;
ptr = mon->databases;
while (ptr) {
if (!SERVER_IS_JOINED(ptr->server) || SERVER_IN_MAINT(ptr->server)) {
@ -663,20 +587,32 @@ int log_no_members = 1;
log_no_members = 1;
}
}
}
}
/**
* Set the monitor sampling interval.
*
* @param arg The handle allocated by startMonitor
* @param interval The interval to set in monitor struct, in milliseconds
*/
static void
setInterval(void *arg, size_t interval)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
memcpy(&handle->interval, &interval, sizeof(unsigned long));
ptr = mon->databases;
while(ptr)
{
/** Execute monitor script if a server state has changed */
if(mon_status_changed(ptr))
{
evtype = mon_get_event_type(ptr);
if(isGaleraEvent(evtype))
{
skygw_log_write(LOGFILE_TRACE,"Server changed state: %s[%s:%u]: %s",
ptr->server->unique_name,
ptr->server->name,ptr->server->port,
mon_get_event_name(ptr));
if(handle->script && handle->events[evtype])
{
monitor_launch_script(mon,ptr,handle->script);
}
}
}
ptr = ptr->next;
}
}
}
/**
@ -761,7 +697,7 @@ static MONITOR_SERVERS *set_cluster_master(MONITOR_SERVERS *current_master, MONI
static void
disableMasterFailback(void *arg, int disable)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
GALERA_MONITOR *handle = (GALERA_MONITOR *)arg;
memcpy(&handle->disableMasterFailback, &disable, sizeof(int));
}
@ -777,115 +713,43 @@ MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
static void
availableWhenDonor(void *arg, int disable)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
GALERA_MONITOR *handle = (GALERA_MONITOR *)arg;
memcpy(&handle->availableWhenDonor, &disable, sizeof(int));
}
static monitor_event_t galera_events[] = {
MASTER_DOWN_EVENT,
MASTER_UP_EVENT,
SLAVE_DOWN_EVENT,
SLAVE_UP_EVENT,
SERVER_DOWN_EVENT,
SERVER_UP_EVENT,
SYNCED_DOWN_EVENT,
SYNCED_UP_EVENT,
DONOR_DOWN_EVENT,
DONOR_UP_EVENT,
LOST_MASTER_EVENT,
LOST_SLAVE_EVENT,
LOST_SYNCED_EVENT,
LOST_DONOR_EVENT,
NEW_MASTER_EVENT,
NEW_SLAVE_EVENT,
NEW_SYNCED_EVENT,
NEW_DONOR_EVENT,
MAX_MONITOR_EVENT
};
/**
* Set the timeouts to use in the monitor.
*
* @param arg The handle allocated by startMonitor
* @param type The connect timeout type
* @param value The timeout value to set
*/
static void
setNetworkTimeout(void *arg, int type, int value)
* Check if the Galera monitor is monitoring this event type.
* @param event Event to check
* @return True if the event is monitored, false if it is not
* */
bool isGaleraEvent(monitor_event_t event)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
int max_timeout = (int)(handle->interval/1000);
int new_timeout = max_timeout -1;
if (new_timeout <= 0)
new_timeout = DEFAULT_CONNECT_TIMEOUT;
switch(type) {
case MONITOR_CONNECT_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->connect_timeout, &value, sizeof(int));
} else {
memcpy(&handle->connect_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Connect Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
case MONITOR_READ_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->read_timeout, &value, sizeof(int));
} else {
memcpy(&handle->read_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Read Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
case MONITOR_WRITE_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->write_timeout, &value, sizeof(int));
} else {
memcpy(&handle->write_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Write Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
default:
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Monitor setNetworkTimeout received an unsupported action type %i", type)));
break;
}
}
/**
* Check if current monitored server status has changed
*
* @param mon_srv The monitored server
* @return true if status has changed or false
*/
static bool mon_status_changed(
MONITOR_SERVERS* mon_srv)
{
bool succp;
if (mon_srv->mon_prev_status != mon_srv->server->status)
{
succp = true;
}
else
{
succp = false;
}
return succp;
}
/**
* Check if current monitored server has a loggable failure status
*
* @param mon_srv The monitored server
* @return true if failed status can be logged or false
*/
static bool mon_print_fail_status(
MONITOR_SERVERS* mon_srv)
{
bool succp;
int errcount = mon_srv->mon_err_count;
uint8_t modval;
modval = 1<<(MIN(errcount/10, 7));
if (SERVER_IS_DOWN(mon_srv->server) && errcount == 0)
{
succp = true;
}
else
{
succp = false;
}
return succp;
}
int i;
for(i = 0;galera_events[i] != MAX_MONITOR_EVENT;i++)
{
if(event == galera_events[i])
return true;
}
return false;
}

View File

@ -0,0 +1,67 @@
#ifndef _GALERAMON_H
#define _GALERAMON_H
/*
* This file is distributed as part of the MariaDB Corporation MaxScale. 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 MariaDB Corporation Ab 2013-2014
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <monitor.h>
#include <monitor_common.h>
#include <spinlock.h>
#include <externcmd.h>
#include <thread.h>
#include <mysql.h>
#include <mysqld_error.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <secrets.h>
#include <dcb.h>
#include <modinfo.h>
#include <maxconfig.h>
/**
* @file galeramon.h - The Galera cluster monitor
*
* @verbatim
* Revision History
*
* Date Who Description
* 07/05/15 Markus Makela Initial Implementation of galeramon.h
* @endverbatim
*/
/**
* The handle for an instance of a MySQL Monitor module
*/
typedef struct {
SPINLOCK lock; /**< The monitor spinlock */
pthread_t tid; /**< id of monitor thread */
int shutdown; /**< Flag to shutdown the monitor thread */
int status; /**< Monitor status */
unsigned long id; /**< Monitor ID */
int disableMasterFailback; /**< Monitor flag for Galera Cluster Master failback */
int availableWhenDonor; /**< Monitor flag for Galera Cluster Donor availability */
int disableMasterRoleSetting; /**< Monitor flag to disable setting master role */
MONITOR_SERVERS *master; /**< Master server for MySQL Master/Slave replication */
char* script;
bool events[MAX_MONITOR_EVENT]; /*< enabled events */
} GALERA_MONITOR;
#endif

View File

@ -17,31 +17,21 @@
*/
/**
* @file mysql_mon.c - A MySQL Multi Muster cluster monitor
* @file mm_mon.c - A Multi-Master Multi Muster cluster monitor
*
* @verbatim
* Revision History
*
* Date Who Description
* 08/09/14 Massimiliano Pinto Initial implementation
* 08/05/15 Markus Makela Addition of launchable scripts
*
* @endverbatim
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <monitor.h>
#include <mysqlmon.h>
#include <thread.h>
#include <mysql.h>
#include <mysqld_error.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <secrets.h>
#include <dcb.h>
#include <modinfo.h>
#include <maxconfig.h>
#include <mmmon.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
extern size_t log_ses_count[];
@ -49,37 +39,26 @@ extern __thread log_info_t tls_log_info;
static void monitorMain(void *);
static char *version_str = "V1.0.1";
static char *version_str = "V1.1.1";
MODULE_INFO info = {
MODULE_API_MONITOR,
MODULE_BETA_RELEASE,
MONITOR_VERSION,
"A MySQL Multi Master monitor"
"A Multi-Master Multi Master monitor"
};
static void *startMonitor(void *,void*);
static void stopMonitor(void *);
static void registerServer(void *, SERVER *);
static void unregisterServer(void *, SERVER *);
static void defaultUser(void *, char *, char *);
static void diagnostics(DCB *, void *);
static void setInterval(void *, size_t);
static void detectStaleMaster(void *, int);
static bool mon_status_changed(MONITOR_SERVERS* mon_srv);
static bool mon_print_fail_status(MONITOR_SERVERS* mon_srv);
static MONITOR_SERVERS *get_current_master(MYSQL_MONITOR *);
static void monitor_set_pending_status(MONITOR_SERVERS *, int);
static void monitor_clear_pending_status(MONITOR_SERVERS *, int);
static MONITOR_SERVERS *get_current_master(MONITOR *);
bool isMySQLEvent(monitor_event_t event);
static MONITOR_OBJECT MyObject = {
startMonitor,
stopMonitor,
registerServer,
unregisterServer,
defaultUser,
diagnostics,
setInterval
diagnostics
};
/**
@ -102,7 +81,7 @@ ModuleInit()
{
LOGIF(LM, (skygw_log_write(
LOGFILE_MESSAGE,
"Initialise the MySQL Monitor module %s.",
"Initialise the Multi-Master Monitor module %s.",
version_str)));
}
@ -131,38 +110,73 @@ GetModuleObject()
static void *
startMonitor(void *arg,void* opt)
{
MYSQL_MONITOR *handle;
CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt;
if (arg)
{
handle = arg; /* Must be a restart */
handle->shutdown = 0;
}
else
{
if ((handle = (MYSQL_MONITOR *)malloc(sizeof(MYSQL_MONITOR))) == NULL)
return NULL;
handle->databases = NULL;
handle->shutdown = 0;
handle->defaultUser = NULL;
handle->defaultPasswd = NULL;
handle->id = MONITOR_DEFAULT_ID;
handle->interval = MONITOR_INTERVAL;
handle->replicationHeartbeat = 0;
handle->detectStaleMaster = 0;
handle->master = NULL;
spinlock_init(&handle->lock);
}
MONITOR* mon = (MONITOR*)arg;
MM_MONITOR *handle = mon->handle;
CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt;
bool have_events = false;
while(params)
if (handle)
{
handle->shutdown = 0;
}
else
{
if ((handle = (MM_MONITOR *)malloc(sizeof(MM_MONITOR))) == NULL)
return NULL;
handle->shutdown = 0;
handle->id = MONITOR_DEFAULT_ID;
handle->master = NULL;
memset(handle->events,false,sizeof(handle->events));
spinlock_init(&handle->lock);
}
while(params)
{
if(!strcmp(params->name,"detect_stale_master"))
{
if(!strcmp(params->name,"detect_stale_master"))
handle->detectStaleMaster = config_truth_value(params->value);
params = params->next;
handle->detectStaleMaster = config_truth_value(params->value);
}
handle->tid = (THREAD)thread_start(monitorMain, handle);
return handle;
else if(!strcmp(params->name,"script"))
{
if(handle->script)
{
free(handle->script);
}
if(access(params->value,X_OK) == 0)
{
handle->script = strdup(params->value);
}
else
{
if(access(params->value,F_OK) == 0)
{
skygw_log_write(LE,
"Error: The file cannot be executed: %s",
params->value);
}
else
{
skygw_log_write(LE,
"Error: The file cannot be found: %s",
params->value);
}
handle->script = NULL;
}
}
else if(!strcmp(params->name,"events"))
{
mon_parse_event_string((bool*)&handle->events,sizeof(handle->events),params->value);
have_events = true;
}
params = params->next;
}
/** If no specific events are given, enable them all */
if(!have_events)
{
memset(handle->events,true,sizeof(handle->events));
}
handle->tid = (THREAD)thread_start(monitorMain, mon);
return handle;
}
/**
@ -173,109 +187,12 @@ CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt;
static void
stopMonitor(void *arg)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MM_MONITOR *handle = (MM_MONITOR *)arg;
handle->shutdown = 1;
thread_wait((void *)handle->tid);
}
/**
* Register a server that must be added to the monitored servers for
* a monitoring module.
*
* @param arg 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;
db->mon_err_count = 0;
db->mon_prev_status = 0;
/* pending status is updated by monitorMain */
db->pending_status = 0;
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 arg 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);
}
/**
* Set the default username and password to use to monitor if the server does not
* override this.
*
* @param arg The handle allocated by startMonitor
* @param uname The default user name
* @param passwd The default password
*/
static void
defaultUser(void *arg, char *uname, char *passwd)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
if (handle->defaultUser)
free(handle->defaultUser);
if (handle->defaultPasswd)
free(handle->defaultPasswd);
handle->defaultUser = strdup(uname);
handle->defaultPasswd = strdup(passwd);
}
/**
* Daignostic interface
*
@ -284,7 +201,8 @@ MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
*/
static void diagnostics(DCB *dcb, void *arg)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR* mon = (MONITOR*)arg;
MM_MONITOR *handle = (MM_MONITOR *)mon->handle;
MONITOR_SERVERS *db;
char *sep;
@ -301,11 +219,11 @@ char *sep;
break;
}
dcb_printf(dcb,"\tSampling interval:\t%lu milliseconds\n", handle->interval);
dcb_printf(dcb,"\tSampling interval:\t%lu milliseconds\n", mon->interval);
dcb_printf(dcb,"\tDetect Stale Master:\t%s\n", (handle->detectStaleMaster == 1) ? "enabled" : "disabled");
dcb_printf(dcb, "\tMonitored servers: ");
db = handle->databases;
db = mon->databases;
sep = "";
while (db)
{
@ -327,15 +245,15 @@ char *sep;
* @param database The database to probe
*/
static void
monitorDatabase(MYSQL_MONITOR *handle, MONITOR_SERVERS *database)
monitorDatabase(MONITOR* mon, MONITOR_SERVERS *database)
{
MM_MONITOR *handle = mon->handle;
MYSQL_ROW row;
MYSQL_RES *result;
int num_fields;
int isslave = 0;
int ismaster = 0;
char *uname = handle->defaultUser;
char *passwd = handle->defaultPasswd;
char *uname = mon->user;
char *passwd = mon->password;
unsigned long int server_version = 0;
char *server_string;
@ -352,19 +270,18 @@ char *server_string;
if (SERVER_IN_MAINT(database->server))
return;
/** Store prevous status */
/** Store previous status */
database->mon_prev_status = database->server->status;
if (database->con == NULL || mysql_ping(database->con) != 0)
{
char *dpwd = decryptPassword(passwd);
int rc;
int read_timeout = 1;
if(database->con)
mysql_close(database->con);
database->con = mysql_init(NULL);
rc = mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout);
mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout);
if (mysql_real_connect(database->con,
database->server->name,
@ -438,7 +355,7 @@ char *server_string;
&& (result = mysql_store_result(database->con)) != NULL)
{
long server_id = -1;
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
server_id = strtol(row[0], NULL, 10);
@ -464,7 +381,7 @@ char *server_string;
{
int i = 0;
long master_id = -1;
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
/* get Slave_IO_Running and Slave_SQL_Running values*/
@ -503,7 +420,7 @@ char *server_string;
&& (result = mysql_store_result(database->con)) != NULL)
{
long master_id = -1;
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
/* get Slave_IO_Running and Slave_SQL_Running values*/
@ -535,7 +452,7 @@ char *server_string;
if (mysql_query(database->con, "SHOW GLOBAL VARIABLES LIKE 'read_only'") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
if (strncasecmp(row[1], "OFF", 3) == 0) {
@ -585,12 +502,18 @@ char *server_string;
static void
monitorMain(void *arg)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR* mon = (MONITOR*)arg;
MM_MONITOR *handle;
MONITOR_SERVERS *ptr;
int detect_stale_master = handle->detectStaleMaster;
int detect_stale_master;
MONITOR_SERVERS *root_master;
size_t nrounds = 0;
spinlock_acquire(&mon->lock);
handle = (MM_MONITOR *)mon->handle;
spinlock_release(&mon->lock);
detect_stale_master = handle->detectStaleMaster;
if (mysql_thread_init())
{
LOGIF(LE, (skygw_log_write_flush(
@ -620,7 +543,7 @@ size_t nrounds = 0;
* round.
*/
if (nrounds != 0 &&
((nrounds*MON_BASE_INTERVAL_MS)%handle->interval) >=
((nrounds*MON_BASE_INTERVAL_MS)%mon->interval) >=
MON_BASE_INTERVAL_MS)
{
nrounds += 1;
@ -629,7 +552,7 @@ size_t nrounds = 0;
nrounds += 1;
/* start from the first server in the list */
ptr = handle->databases;
ptr = mon->databases;
while (ptr)
{
@ -637,7 +560,7 @@ size_t nrounds = 0;
ptr->pending_status = ptr->server->status;
/* monitor current node */
monitorDatabase(handle, ptr);
monitorDatabase(mon, ptr);
if (mon_status_changed(ptr))
{
@ -669,11 +592,11 @@ size_t nrounds = 0;
}
/* Get Master server pointer */
root_master = get_current_master(handle);
root_master = get_current_master(mon);
/* Update server status from monitor pending status on that server*/
ptr = handle->databases;
ptr = mon->databases;
while (ptr)
{
if (! SERVER_IN_MAINT(ptr->server)) {
@ -690,21 +613,30 @@ size_t nrounds = 0;
}
ptr = ptr->next;
}
ptr = mon->databases;
monitor_event_t evtype;
while(ptr)
{
if(mon_status_changed(ptr))
{
evtype = mon_get_event_type(ptr);
if(isMySQLEvent(evtype))
{
skygw_log_write(LOGFILE_TRACE,"Server changed state: %s[%s:%u]: %s",
ptr->server->unique_name,
ptr->server->name,ptr->server->port,
mon_get_event_name(ptr));
if(handle->script && handle->events[evtype])
{
monitor_launch_script(mon,ptr,handle->script);
}
}
}
ptr = ptr->next;
}
}
}
/**
* Set the monitor sampling interval.
*
* @param arg The handle allocated by startMonitor
* @param interval The interval to set in monitor struct, in milliseconds
*/
static void
setInterval(void *arg, size_t interval)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
memcpy(&handle->interval, &interval, sizeof(unsigned long));
}
/**
* Enable/Disable the MySQL Replication Stale Master dectection, allowing a previouvsly detected master to still act as a Master.
@ -717,70 +649,11 @@ MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
static void
detectStaleMaster(void *arg, int enable)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR* mon = (MONITOR*)arg;
MM_MONITOR *handle = (MM_MONITOR *)mon->handle;
memcpy(&handle->detectStaleMaster, &enable, sizeof(int));
}
static bool mon_status_changed(
MONITOR_SERVERS* mon_srv)
{
bool succp;
if (mon_srv->mon_prev_status != mon_srv->server->status)
{
succp = true;
}
else
{
succp = false;
}
return succp;
}
static bool mon_print_fail_status(
MONITOR_SERVERS* mon_srv)
{
bool succp;
int errcount = mon_srv->mon_err_count;
uint8_t modval;
modval = 1<<(MIN(errcount/10, 7));
if (SERVER_IS_DOWN(mon_srv->server) && errcount%modval == 0)
{
succp = true;
}
else
{
succp = false;
}
return succp;
}
/**
* Set a pending status bit in the monior server
*
* @param server The server to update
* @param bit The bit to clear for the server
*/
static void
monitor_set_pending_status(MONITOR_SERVERS *ptr, int bit)
{
ptr->pending_status |= bit;
}
/**
* Clear a pending status bit in the monior server
*
* @param server The server to update
* @param bit The bit to clear for the server
*/
static void
monitor_clear_pending_status(MONITOR_SERVERS *ptr, int bit)
{
ptr->pending_status &= ~bit;
}
/*******
* This function returns the master server
* from a set of MySQL Multi Master monitored servers
@ -791,10 +664,11 @@ monitor_clear_pending_status(MONITOR_SERVERS *ptr, int bit)
* @return The server at root level with SERVER_MASTER bit
*/
static MONITOR_SERVERS *get_current_master(MYSQL_MONITOR *handle) {
static MONITOR_SERVERS *get_current_master(MONITOR *mon) {
MM_MONITOR* handle = mon->handle;
MONITOR_SERVERS *ptr;
ptr = handle->databases;
ptr = mon->databases;
while (ptr)
{
@ -831,3 +705,32 @@ MONITOR_SERVERS *ptr;
}
}
static monitor_event_t mysql_events[] = {
MASTER_DOWN_EVENT,
MASTER_UP_EVENT,
SLAVE_DOWN_EVENT,
SLAVE_UP_EVENT,
SERVER_DOWN_EVENT,
SERVER_UP_EVENT,
LOST_MASTER_EVENT,
LOST_SLAVE_EVENT,
NEW_MASTER_EVENT,
NEW_SLAVE_EVENT,
MAX_MONITOR_EVENT
};
/**
* Check if the MM monitor is monitoring this event type.
* @param event Event to check
* @return True if the event is monitored, false if it is not
* */
bool isMySQLEvent(monitor_event_t event)
{
int i;
for(i = 0;mysql_events[i] != MAX_MONITOR_EVENT;i++)
{
if(event == mysql_events[i])
return true;
}
return false;
}

View File

@ -0,0 +1,52 @@
#ifndef _MMMON_H
#define _MMMON_H
/*
* This file is distributed as part of the MariaDB Corporation MaxScale. 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 MariaDB Corporation Ab 2015
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <monitor.h>
#include <spinlock.h>
#include <thread.h>
#include <mysql.h>
#include <mysqld_error.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <secrets.h>
#include <dcb.h>
#include <modinfo.h>
#include <maxconfig.h>
#include <monitor_common.h>
#include <externcmd.h>
/**
* The handle for an instance of a Multi-Master Monitor module
*/
typedef struct {
SPINLOCK lock; /**< The monitor spinlock */
pthread_t tid; /**< id of monitor thread */
int shutdown; /**< Flag to shutdown the monitor thread */
int status; /**< Monitor status */
unsigned long id; /**< Monitor ID */
int detectStaleMaster; /**< Monitor flag for Stale Master detection */
MONITOR_SERVERS *master; /**< Master server for Master/Slave replication */
char* script; /*< Script to call when state changes occur on servers */
bool events[MAX_MONITOR_EVENT]; /*< enabled events */
} MM_MONITOR;
#endif

View File

@ -0,0 +1,402 @@
/*
* This file is distributed as part of the MariaDB Corporation MaxScale. 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 MariaDB Corporation Ab 2013-2015
*/
#include <monitor_common.h>
monitor_event_t mon_name_to_event(char* tok);
/**
* Set a pending status bit in the monitor server
*
* @param server The server to update
* @param bit The bit to clear for the server
*/
void monitor_set_pending_status(MONITOR_SERVERS *ptr, int bit)
{
ptr->pending_status |= bit;
}
/**
* Clear a pending status bit in the monitor server
*
* @param server The server to update
* @param bit The bit to clear for the server
*/
void monitor_clear_pending_status(MONITOR_SERVERS *ptr, int bit)
{
ptr->pending_status &= ~bit;
}
monitor_event_t mon_get_event_type(MONITOR_SERVERS* node)
{
unsigned int prev = node->mon_prev_status;
if((prev & (SERVER_MASTER|SERVER_RUNNING)) == (SERVER_MASTER|SERVER_RUNNING) &&
SERVER_IS_DOWN(node->server))
{
return MASTER_DOWN_EVENT;
}
if((prev & (SERVER_RUNNING)) == 0 &&
SERVER_IS_RUNNING(node->server) && SERVER_IS_MASTER(node->server))
{
return MASTER_UP_EVENT;
}
if((prev & (SERVER_SLAVE|SERVER_RUNNING)) == (SERVER_SLAVE|SERVER_RUNNING) &&
SERVER_IS_DOWN(node->server))
{
return SLAVE_DOWN_EVENT;
}
if((prev & (SERVER_RUNNING)) == 0 &&
SERVER_IS_RUNNING(node->server) && SERVER_IS_SLAVE(node->server))
{
return SLAVE_UP_EVENT;
}
/** Galera specific events */
if((prev & (SERVER_JOINED|SERVER_RUNNING)) == (SERVER_JOINED|SERVER_RUNNING) &&
SERVER_IS_DOWN(node->server))
{
return SYNCED_DOWN_EVENT;
}
if((prev & (SERVER_RUNNING)) == 0 &&
SERVER_IS_RUNNING(node->server) && SERVER_IS_JOINED(node->server))
{
return SYNCED_UP_EVENT;
}
/** NDB events*/
if((prev & (SERVER_NDB|SERVER_RUNNING)) == (SERVER_NDB|SERVER_RUNNING) &&
SERVER_IS_DOWN(node->server))
{
return NDB_DOWN_EVENT;
}
if((prev & (SERVER_RUNNING)) == 0 &&
SERVER_IS_RUNNING(node->server) && SERVER_IS_NDB(node->server))
{
return NDB_UP_EVENT;
}
if((prev & (SERVER_RUNNING)) == SERVER_RUNNING &&
SERVER_IS_RUNNING(node->server) && SERVER_IS_MASTER(node->server))
{
return NEW_MASTER_EVENT;
}
if((prev & (SERVER_RUNNING)) == SERVER_RUNNING &&
SERVER_IS_RUNNING(node->server) && SERVER_IS_SLAVE(node->server))
{
return NEW_SLAVE_EVENT;
}
/** Status loss events */
if((prev & (SERVER_RUNNING|SERVER_MASTER)) == (SERVER_RUNNING|SERVER_MASTER) &&
SERVER_IS_RUNNING(node->server) && !SERVER_IS_MASTER(node->server))
{
return LOST_MASTER_EVENT;
}
if((prev & (SERVER_RUNNING|SERVER_SLAVE)) == (SERVER_RUNNING|SERVER_SLAVE) &&
SERVER_IS_RUNNING(node->server) && !SERVER_IS_SLAVE(node->server))
{
return LOST_SLAVE_EVENT;
}
if((prev & (SERVER_RUNNING|SERVER_JOINED)) == (SERVER_RUNNING|SERVER_JOINED) &&
SERVER_IS_RUNNING(node->server) && !SERVER_IS_JOINED(node->server))
{
return LOST_SYNCED_EVENT;
}
if((prev & (SERVER_RUNNING|SERVER_NDB)) == (SERVER_RUNNING|SERVER_NDB) &&
SERVER_IS_RUNNING(node->server) && !SERVER_IS_NDB(node->server))
{
return LOST_NDB_EVENT;
}
/** Generic server failure */
if((prev & SERVER_RUNNING) == 0 &&
SERVER_IS_RUNNING(node->server))
{
return SERVER_UP_EVENT;
}
if((prev & SERVER_RUNNING) == SERVER_RUNNING &&
SERVER_IS_DOWN(node->server))
{
return SERVER_DOWN_EVENT;
}
/** Something else, most likely a state that does not matter.
* For example SERVER_DOWN -> SERVER_MASTER|SERVER_DOWN still results in a
* server state equal to not running.*/
return UNDEFINED_MONITOR_EVENT;
}
char* mon_get_event_name(MONITOR_SERVERS* node)
{
switch(mon_get_event_type(node))
{
case UNDEFINED_MONITOR_EVENT:
return "undefined";
case MASTER_DOWN_EVENT:
return "master_down";
case MASTER_UP_EVENT:
return "master_up";
case SLAVE_DOWN_EVENT:
return "slave_down";
case SLAVE_UP_EVENT:
return "slave_up";
case SERVER_DOWN_EVENT:
return "server_down";
case SERVER_UP_EVENT:
return "server_up";
case SYNCED_DOWN_EVENT:
return "synced_down";
case SYNCED_UP_EVENT:
return "synced_up";
case DONOR_DOWN_EVENT:
return "donor_down";
case DONOR_UP_EVENT:
return "donor_up";
case NDB_DOWN_EVENT:
return "ndb_down";
case NDB_UP_EVENT:
return "ndb_up";
case LOST_MASTER_EVENT:
return "lost_master";
case LOST_SLAVE_EVENT:
return "lost_slave";
case LOST_SYNCED_EVENT:
return "lost_synced";
case LOST_DONOR_EVENT:
return "lost_donor";
case LOST_NDB_EVENT:
return "lost_ndb";
case NEW_MASTER_EVENT:
return "new_master";
case NEW_SLAVE_EVENT:
return "new_slave";
case NEW_SYNCED_EVENT:
return "new_synced";
case NEW_DONOR_EVENT:
return "new_donor";
case NEW_NDB_EVENT:
return "new_ndb";
default:
return "MONITOR_EVENT_FAILURE";
}
}
void mon_append_node_names(MONITOR_SERVERS* start,char* str, int len)
{
MONITOR_SERVERS* ptr = start;
bool first = true;
while(ptr)
{
if(!first)
{
strncat(str,",",len);
}
first = false;
strncat(str,ptr->server->unique_name,len);
ptr = ptr->next;
}
}
/**
* Check if current monitored server status has changed
*
* @param mon_srv The monitored server
* @return true if status has changed or false
*/
bool mon_status_changed(
MONITOR_SERVERS* mon_srv)
{
bool succp;
/** This is the first time the server was set with a status*/
if (mon_srv->mon_prev_status == -1)
return false;
if (mon_srv->mon_prev_status != mon_srv->server->status)
{
succp = true;
}
else
{
succp = false;
}
return succp;
}
/**
* Check if current monitored server has a loggable failure status
*
* @param mon_srv The monitored server
* @return true if failed status can be logged or false
*/
bool mon_print_fail_status(
MONITOR_SERVERS* mon_srv)
{
bool succp;
int errcount = mon_srv->mon_err_count;
if (SERVER_IS_DOWN(mon_srv->server) && errcount == 0)
{
succp = true;
}
else
{
succp = false;
}
return succp;
}
void monitor_launch_script(MONITOR* mon,MONITOR_SERVERS* ptr, char* script)
{
char argstr[PATH_MAX + MON_ARG_MAX + 1];
EXTERNCMD* cmd;
snprintf(argstr,PATH_MAX + MON_ARG_MAX,
"%s --event=%s --initiator=%s --nodelist=",
script,
mon_get_event_name(ptr),
ptr->server->unique_name);
mon_append_node_names(mon->databases,argstr,PATH_MAX + MON_ARG_MAX + 1);
if((cmd = externcmd_allocate(argstr)) == NULL)
{
skygw_log_write(LE,"Failed to execute script: %s",script);
return;
}
if(externcmd_execute(cmd))
{
skygw_log_write(LOGFILE_ERROR,
"Error: Failed to execute script "
"'%s' on server state change event %s.",
script,mon_get_event_type(ptr));
}
externcmd_free(cmd);
}
/**
* Parse a string of event names to an array with enabled events.
* @param events Pointer to an array of boolean values
* @param count Size of the array
* @param string String to parse
* @return 0 on success. 1 when an error has occurred or an unexpected event was
* found.
*/
int mon_parse_event_string(bool* events, size_t count,char* string)
{
char *tok,*saved;
monitor_event_t event;
tok = strtok_r(string,",| ",&saved);
if(tok == NULL)
return -1;
while(tok)
{
event = mon_name_to_event(tok);
if(event == UNDEFINED_MONITOR_EVENT)
return -1;
events[event] = true;
tok = strtok_r(NULL,",| ",&saved);
}
return 0;
}
monitor_event_t mon_name_to_event(char* tok)
{
if(!strcasecmp("master_down",tok))
return MASTER_DOWN_EVENT;
else if(!strcasecmp("master_up",tok))
return MASTER_UP_EVENT;
else if(!strcasecmp("slave_down",tok))
return SLAVE_DOWN_EVENT;
else if(!strcasecmp("slave_up",tok))
return SLAVE_UP_EVENT;
else if(!strcasecmp("server_down",tok))
return SERVER_DOWN_EVENT;
else if(!strcasecmp("server_up",tok))
return SERVER_UP_EVENT;
else if(!strcasecmp("synced_down",tok))
return SYNCED_DOWN_EVENT;
else if(!strcasecmp("synced_up",tok))
return SYNCED_UP_EVENT;
else if(!strcasecmp("donor_down",tok))
return DONOR_DOWN_EVENT;
else if(!strcasecmp("donor_up",tok))
return DONOR_UP_EVENT;
else if(!strcasecmp("ndb_down",tok))
return NDB_DOWN_EVENT;
else if(!strcasecmp("ndb_up",tok))
return NDB_UP_EVENT;
else if(!strcasecmp("lost_master",tok))
return LOST_MASTER_EVENT;
else if(!strcasecmp("lost_slave",tok))
return LOST_SLAVE_EVENT;
else if(!strcasecmp("lost_synced",tok))
return LOST_SYNCED_EVENT;
else if(!strcasecmp("lost_donor",tok))
return LOST_DONOR_EVENT;
else if(!strcasecmp("lost_ndb",tok))
return LOST_NDB_EVENT;
else if(!strcasecmp("new_master",tok))
return NEW_MASTER_EVENT;
else if(!strcasecmp("new_slave",tok))
return NEW_SLAVE_EVENT;
else if(!strcasecmp("new_synced",tok))
return NEW_SYNCED_EVENT;
else if(!strcasecmp("new_donor",tok))
return NEW_DONOR_EVENT;
else if(!strcasecmp("new_ndb",tok))
return NEW_NDB_EVENT;
else
return UNDEFINED_MONITOR_EVENT;
}

View File

@ -0,0 +1,75 @@
#ifndef _MONITOR_COMMON_HG
#define _MONITOR_COMMON_HG
/*
* This file is distributed as part of the MariaDB Corporation MaxScale. 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 MariaDB Corporation Ab 2013-2015
*/
#include <server.h>
#include <mysql.h>
#include <monitor.h>
#include <log_manager.h>
#include <externcmd.h>
/**
* @file monitor_common.h - The generic monitor structures all monitors use
*
* Revision History
*
* Date Who Description
* 07/05/15 Markus Makela Initial Implementation
* @endverbatim
*/
#define MON_ARG_MAX 8192
/** Monitor events that are caused by servers moving from
* one state to another.*/
typedef enum {
UNDEFINED_MONITOR_EVENT,
MASTER_DOWN_EVENT,
MASTER_UP_EVENT,
SLAVE_DOWN_EVENT,
SLAVE_UP_EVENT,
SERVER_DOWN_EVENT,
SERVER_UP_EVENT,
SYNCED_DOWN_EVENT,
SYNCED_UP_EVENT,
DONOR_DOWN_EVENT,
DONOR_UP_EVENT,
NDB_DOWN_EVENT,
NDB_UP_EVENT,
LOST_MASTER_EVENT,
LOST_SLAVE_EVENT,
LOST_SYNCED_EVENT,
LOST_DONOR_EVENT,
LOST_NDB_EVENT,
NEW_MASTER_EVENT,
NEW_SLAVE_EVENT,
NEW_SYNCED_EVENT,
NEW_DONOR_EVENT,
NEW_NDB_EVENT,
MAX_MONITOR_EVENT
}monitor_event_t;
void mon_append_node_names(MONITOR_SERVERS* start,char* str, int len);
monitor_event_t mon_get_event_type(MONITOR_SERVERS* node);
char* mon_get_event_name(MONITOR_SERVERS* node);
void monitor_clear_pending_status(MONITOR_SERVERS *ptr, int bit);
void monitor_set_pending_status(MONITOR_SERVERS *ptr, int bit);
bool mon_status_changed(MONITOR_SERVERS* mon_srv);
bool mon_print_fail_status(MONITOR_SERVERS* mon_srv);
void monitor_launch_script(MONITOR* mon,MONITOR_SERVERS* ptr, char* script);
int mon_parse_event_string(bool* events, size_t count,char* string);
#endif

View File

@ -46,24 +46,13 @@
* 10/11/14 Massimiliano Pinto Addition of setNetworkTimeout for connect, read, write
* 18/11/14 Massimiliano Pinto One server only in configuration becomes master.
* servers=server1 must be present in mysql_mon and in router sections as well.
* 08/05/15 Markus Makela Added launchable scripts
*
* @endverbatim
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <monitor.h>
#include <mysqlmon.h>
#include <thread.h>
#include <mysql.h>
#include <mysqld_error.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <secrets.h>
#include <dcb.h>
#include <modinfo.h>
#include <maxconfig.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
@ -83,33 +72,19 @@ MODULE_INFO info = {
static void *startMonitor(void *,void*);
static void stopMonitor(void *);
static void registerServer(void *, SERVER *);
static void unregisterServer(void *, SERVER *);
static void defaultUser(void *, char *, char *);
static void diagnostics(DCB *, void *);
static void setInterval(void *, size_t);
static void defaultId(void *, unsigned long);
static void setNetworkTimeout(void *, int, int);
static bool mon_status_changed(MONITOR_SERVERS* mon_srv);
static bool mon_print_fail_status(MONITOR_SERVERS* mon_srv);
static MONITOR_SERVERS *getServerByNodeId(MONITOR_SERVERS *, long);
static MONITOR_SERVERS *getSlaveOfNodeId(MONITOR_SERVERS *, long);
static MONITOR_SERVERS *get_replication_tree(MYSQL_MONITOR *, int);
static MONITOR_SERVERS *get_replication_tree(MONITOR *, int);
static void set_master_heartbeat(MYSQL_MONITOR *, MONITOR_SERVERS *);
static void set_slave_heartbeat(MYSQL_MONITOR *, MONITOR_SERVERS *);
static void set_slave_heartbeat(MONITOR *, MONITOR_SERVERS *);
static int add_slave_to_master(long *, int, long);
static void monitor_set_pending_status(MONITOR_SERVERS *, int);
static void monitor_clear_pending_status(MONITOR_SERVERS *, int);
bool isMySQLEvent(monitor_event_t event);
static MONITOR_OBJECT MyObject = {
startMonitor,
stopMonitor,
registerServer,
unregisterServer,
defaultUser,
diagnostics,
setInterval,
setNetworkTimeout
diagnostics
};
/**
@ -156,48 +131,80 @@ GetModuleObject()
* This function creates a thread to execute the actual monitoring.
*
* @param arg The current handle - NULL if first start
* @param opt Configuration parameters
* @return A handle to use when interacting with the monitor
*/
static void *
startMonitor(void *arg, void* opt)
{
MYSQL_MONITOR *handle;
CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt;
if (arg)
{
handle = arg; /* Must be a restart */
handle->shutdown = 0;
}
else
{
if ((handle = (MYSQL_MONITOR *)malloc(sizeof(MYSQL_MONITOR))) == NULL)
return NULL;
handle->databases = NULL;
handle->shutdown = 0;
handle->defaultUser = NULL;
handle->defaultPasswd = NULL;
handle->id = config_get_gateway_id();
handle->interval = MONITOR_INTERVAL;
handle->replicationHeartbeat = 0;
handle->detectStaleMaster = 0;
handle->master = NULL;
handle->connect_timeout=DEFAULT_CONNECT_TIMEOUT;
handle->read_timeout=DEFAULT_READ_TIMEOUT;
handle->write_timeout=DEFAULT_WRITE_TIMEOUT;
spinlock_init(&handle->lock);
}
MONITOR* monitor = (MONITOR*)arg;
MYSQL_MONITOR *handle = (MYSQL_MONITOR*)monitor->handle;
CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt;
bool have_events = false;
while(params)
if (handle)
{
handle->shutdown = 0;
}
else
{
if ((handle = (MYSQL_MONITOR *)malloc(sizeof(MYSQL_MONITOR))) == NULL)
return NULL;
handle->shutdown = 0;
handle->id = config_get_gateway_id();
handle->replicationHeartbeat = 0;
handle->detectStaleMaster = 0;
handle->master = NULL;
handle->script = NULL;
memset(handle->events,false,sizeof(handle->events));
spinlock_init(&handle->lock);
}
while(params)
{
if(!strcmp(params->name,"detect_stale_master"))
handle->detectStaleMaster = config_truth_value(params->value);
else if(!strcmp(params->name,"detect_replication_lag"))
handle->replicationHeartbeat = config_truth_value(params->value);
else if(!strcmp(params->name,"script"))
{
if(!strcmp(params->name,"detect_stale_master"))
handle->detectStaleMaster = config_truth_value(params->value);
else if(!strcmp(params->name,"detect_replication_lag"))
handle->replicationHeartbeat = config_truth_value(params->value);
params = params->next;
if(handle->script)
free(handle->script);
if(access(params->value,X_OK) == 0)
{
handle->script = strdup(params->value);
}
else
{
if(access(params->value,F_OK) == 0)
{
skygw_log_write(LE,
"Error: The file cannot be executed: %s",
params->value);
}
else
{
skygw_log_write(LE,
"Error: The file cannot be found: %s",
params->value);
}
handle->script = NULL;
}
}
handle->tid = (THREAD)thread_start(monitorMain, handle);
return handle;
else if(!strcmp(params->name,"events"))
{
mon_parse_event_string(handle->events,sizeof(handle->events),params->value);
have_events = true;
}
params = params->next;
}
/** If no specific events are given, enable them all */
if(!have_events)
{
memset(handle->events,true,sizeof(handle->events));
}
handle->tid = (THREAD)thread_start(monitorMain, monitor);
return handle;
}
/**
@ -208,107 +215,11 @@ CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt;
static void
stopMonitor(void *arg)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR* mon = (MONITOR*)arg;
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)mon->handle;
handle->shutdown = 1;
thread_wait((void *)handle->tid);
}
/**
* Register a server that must be added to the monitored servers for
* a monitoring module.
*
* @param arg 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;
db->mon_err_count = 0;
db->mon_prev_status = 0;
/* pending status is updated by get_replication_tree */
db->pending_status = 0;
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 arg 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);
}
/**
* Set the default username and password to use to monitor if the server does not
* override this.
*
* @param arg The handle allocated by startMonitor
* @param uname The default user name
* @param passwd The default password
*/
static void
defaultUser(void *arg, char *uname, char *passwd)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
if (handle->defaultUser)
free(handle->defaultUser);
if (handle->defaultPasswd)
free(handle->defaultPasswd);
handle->defaultUser = strdup(uname);
handle->defaultPasswd = strdup(passwd);
handle->shutdown = 1;
thread_wait((void *)handle->tid);
}
/**
@ -319,45 +230,46 @@ MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
*/
static void diagnostics(DCB *dcb, void *arg)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR_SERVERS *db;
char *sep;
MONITOR* mon = (MONITOR*)arg;
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)mon->handle;
MONITOR_SERVERS *db;
char *sep;
switch (handle->status)
{
case MONITOR_RUNNING:
dcb_printf(dcb, "\tMonitor running\n");
break;
case MONITOR_STOPPING:
dcb_printf(dcb, "\tMonitor stopping\n");
break;
case MONITOR_STOPPED:
dcb_printf(dcb, "\tMonitor stopped\n");
break;
}
switch (handle->status)
{
case MONITOR_RUNNING:
dcb_printf(dcb, "\tMonitor running\n");
break;
case MONITOR_STOPPING:
dcb_printf(dcb, "\tMonitor stopping\n");
break;
case MONITOR_STOPPED:
dcb_printf(dcb, "\tMonitor stopped\n");
break;
}
dcb_printf(dcb,"\tSampling interval:\t%lu milliseconds\n", handle->interval);
dcb_printf(dcb,"\tMaxScale MonitorId:\t%lu\n", handle->id);
dcb_printf(dcb,"\tReplication lag:\t%s\n", (handle->replicationHeartbeat == 1) ? "enabled" : "disabled");
dcb_printf(dcb,"\tDetect Stale Master:\t%s\n", (handle->detectStaleMaster == 1) ? "enabled" : "disabled");
dcb_printf(dcb,"\tConnect Timeout:\t%i seconds\n", handle->connect_timeout);
dcb_printf(dcb,"\tRead Timeout:\t\t%i seconds\n", handle->read_timeout);
dcb_printf(dcb,"\tWrite Timeout:\t\t%i seconds\n", handle->write_timeout);
dcb_printf(dcb, "\tMonitored servers: ");
db = handle->databases;
sep = "";
while (db)
{
dcb_printf(dcb,
"%s%s:%d",
sep,
db->server->name,
db->server->port);
sep = ", ";
db = db->next;
}
dcb_printf(dcb, "\n");
dcb_printf(dcb,"\tSampling interval:\t%lu milliseconds\n", mon->interval);
dcb_printf(dcb,"\tMaxScale MonitorId:\t%lu\n", handle->id);
dcb_printf(dcb,"\tReplication lag:\t%s\n", (handle->replicationHeartbeat == 1) ? "enabled" : "disabled");
dcb_printf(dcb,"\tDetect Stale Master:\t%s\n", (handle->detectStaleMaster == 1) ? "enabled" : "disabled");
dcb_printf(dcb,"\tConnect Timeout:\t%i seconds\n", mon->connect_timeout);
dcb_printf(dcb,"\tRead Timeout:\t\t%i seconds\n", mon->read_timeout);
dcb_printf(dcb,"\tWrite Timeout:\t\t%i seconds\n", mon->write_timeout);
dcb_printf(dcb, "\tMonitored servers: ");
db = mon->databases;
sep = "";
while (db)
{
dcb_printf(dcb,
"%s%s:%d",
sep,
db->server->name,
db->server->port);
sep = ", ";
db = db->next;
}
dcb_printf(dcb, "\n");
}
/**
@ -367,14 +279,14 @@ char *sep;
* @param database The database to probe
*/
static void
monitorDatabase(MYSQL_MONITOR *handle, MONITOR_SERVERS *database)
monitorDatabase(MONITOR *mon, MONITOR_SERVERS *database)
{
MYSQL_MONITOR* handle = mon->handle;
MYSQL_ROW row;
MYSQL_RES *result;
int num_fields;
int isslave = 0;
char *uname = handle->defaultUser;
char *passwd = handle->defaultPasswd;
char *uname = mon->user;
char *passwd = mon->password;
unsigned long int server_version = 0;
char *server_string;
@ -397,17 +309,15 @@ char *server_string;
if (database->con == NULL || mysql_ping(database->con) != 0)
{
char *dpwd = decryptPassword(passwd);
int rc;
int connect_timeout = handle->connect_timeout;
int read_timeout = handle->read_timeout;
int write_timeout = handle->write_timeout;
if(database->con)
mysql_close(database->con);
int connect_timeout = mon->connect_timeout;
int read_timeout = mon->read_timeout;
int write_timeout = mon->write_timeout;
database->con = mysql_init(NULL);
rc = mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&connect_timeout);
rc = mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout);
rc = mysql_options(database->con, MYSQL_OPT_WRITE_TIMEOUT, (void *)&write_timeout);
mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&connect_timeout);
mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout);
mysql_options(database->con, MYSQL_OPT_WRITE_TIMEOUT, (void *)&write_timeout);
if (mysql_real_connect(database->con,
database->server->name,
@ -486,7 +396,6 @@ char *server_string;
&& (result = mysql_store_result(database->con)) != NULL)
{
long server_id = -1;
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
server_id = strtol(row[0], NULL, 10);
@ -512,7 +421,6 @@ char *server_string;
{
int i = 0;
long master_id = -1;
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
/* get Slave_IO_Running and Slave_SQL_Running values*/
@ -551,7 +459,6 @@ char *server_string;
&& (result = mysql_store_result(database->con)) != NULL)
{
long master_id = -1;
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
/* get Slave_IO_Running and Slave_SQL_Running values*/
@ -608,15 +515,22 @@ char *server_string;
static void
monitorMain(void *arg)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR* mon = (MONITOR*) arg;
MYSQL_MONITOR *handle;
MONITOR_SERVERS *ptr;
int replication_heartbeat = handle->replicationHeartbeat;
int detect_stale_master = handle->detectStaleMaster;
int replication_heartbeat;
int detect_stale_master;
int num_servers=0;
MONITOR_SERVERS *root_master = NULL;
size_t nrounds = 0;
int log_no_master = 1;
spinlock_acquire(&mon->lock);
handle = (MYSQL_MONITOR *)mon->handle;
spinlock_release(&mon->lock);
replication_heartbeat = handle->replicationHeartbeat;
detect_stale_master = handle->detectStaleMaster;
if (mysql_thread_init())
{
LOGIF(LE, (skygw_log_write_flush(
@ -645,7 +559,7 @@ int log_no_master = 1;
* round.
*/
if (nrounds != 0 &&
((nrounds*MON_BASE_INTERVAL_MS)%handle->interval) >=
((nrounds*MON_BASE_INTERVAL_MS)%mon->interval) >=
MON_BASE_INTERVAL_MS)
{
nrounds += 1;
@ -656,15 +570,17 @@ int log_no_master = 1;
num_servers = 0;
/* start from the first server in the list */
ptr = handle->databases;
ptr = mon->databases;
while (ptr)
{
ptr->mon_prev_status = ptr->server->status;
/* copy server status into monitor pending_status */
ptr->pending_status = ptr->server->status;
/* monitor current node */
monitorDatabase(handle, ptr);
monitorDatabase(mon, ptr);
/* reset the slave list of current node */
if (ptr->server->slaves) {
@ -697,7 +613,12 @@ int log_no_master = 1;
!(SERVER_IS_IN_CLUSTER(ptr->server)))
{
dcb_call_foreach(ptr->server,DCB_REASON_NOT_RESPONDING);
}
}
}
if (mon_status_changed(ptr))
@ -733,7 +654,7 @@ int log_no_master = 1;
ptr = ptr->next;
}
ptr = handle->databases;
ptr = mon->databases;
/* if only one server is configured, that's is Master */
if (num_servers == 1) {
if (SERVER_IS_RUNNING(ptr->server)) {
@ -750,12 +671,12 @@ int log_no_master = 1;
}
} else {
/* Compute the replication tree */
root_master = get_replication_tree(handle, num_servers);
root_master = get_replication_tree(mon, num_servers);
}
/* Update server status from monitor pending status on that server*/
ptr = handle->databases;
ptr = mon->databases;
while (ptr)
{
if (! SERVER_IN_MAINT(ptr->server)) {
@ -792,7 +713,30 @@ int log_no_master = 1;
ptr = ptr->next;
}
/* log master detection failure od first master becomes available after failure */
ptr = mon->databases;
monitor_event_t evtype;
while(ptr)
{
/** Execute monitor script if a server state has changed */
if(mon_status_changed(ptr))
{
evtype = mon_get_event_type(ptr);
if(isMySQLEvent(evtype))
{
skygw_log_write(LOGFILE_TRACE,"Server changed state: %s[%s:%u]: %s",
ptr->server->unique_name,
ptr->server->name,ptr->server->port,
mon_get_event_name(ptr));
if(handle->script && handle->events[evtype])
{
monitor_launch_script(mon,ptr,handle->script);
}
}
}
ptr = ptr->next;
}
/* log master detection failure of first master becomes available after failure */
if (root_master &&
mon_status_changed(root_master) &&
!(root_master->server->status & SERVER_STALE_STATUS))
@ -832,7 +776,7 @@ int log_no_master = 1;
SERVER_IS_RELAY_SERVER(root_master->server)))
{
set_master_heartbeat(handle, root_master);
ptr = handle->databases;
ptr = mon->databases;
while (ptr) {
if( (! SERVER_IN_MAINT(ptr->server)) && SERVER_IS_RUNNING(ptr->server))
@ -841,7 +785,7 @@ int log_no_master = 1;
(SERVER_IS_SLAVE(ptr->server) ||
SERVER_IS_RELAY_SERVER(ptr->server)))
{
set_slave_heartbeat(handle, ptr);
set_slave_heartbeat(mon, ptr);
}
}
ptr = ptr->next;
@ -863,19 +807,6 @@ MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
memcpy(&handle->id, &id, sizeof(unsigned long));
}
/**
* Set the monitor sampling interval.
*
* @param arg The handle allocated by startMonitor
* @param interval The interval to set in monitor struct, in milliseconds
*/
static void
setInterval(void *arg, size_t interval)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
memcpy(&handle->interval, &interval, sizeof(unsigned long));
}
/**
* Enable/Disable the MySQL Replication hearbeat, detecting slave lag behind master.
*
@ -904,54 +835,6 @@ MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
memcpy(&handle->detectStaleMaster, &enable, sizeof(int));
}
/**
* Check if current monitored server status has changed
*
* @param mon_srv The monitored server
* @return true if status has changed or false
*/
static bool mon_status_changed(
MONITOR_SERVERS* mon_srv)
{
bool succp;
if (mon_srv->mon_prev_status != mon_srv->server->status)
{
succp = true;
}
else
{
succp = false;
}
return succp;
}
/**
* Check if current monitored server has a loggable failure status
*
* @param mon_srv The monitored server
* @return true if failed status can be logged or false
*/
static bool mon_print_fail_status(
MONITOR_SERVERS* mon_srv)
{
bool succp;
int errcount = mon_srv->mon_err_count;
uint8_t modval;
modval = 1<<(MIN(errcount/10, 7));
if (SERVER_IS_DOWN(mon_srv->server) && errcount == 0)
{
succp = true;
}
else
{
succp = false;
}
return succp;
}
/**
* Fetch a MySQL node by node_id
*
@ -1113,13 +996,13 @@ static void set_master_heartbeat(MYSQL_MONITOR *handle, MONITOR_SERVERS *databas
* @param handle The monitor handle
* @param database The number database server
*/
static void set_slave_heartbeat(MYSQL_MONITOR *handle, MONITOR_SERVERS *database) {
static void set_slave_heartbeat(MONITOR* mon, MONITOR_SERVERS *database) {
MYSQL_MONITOR *handle = (MYSQL_MONITOR*)mon->handle;
unsigned long id = handle->id;
time_t heartbeat;
char select_heartbeat_query[256] = "";
MYSQL_ROW row;
MYSQL_RES *result;
int num_fields;
if (handle->master == NULL) {
LOGIF(LE, (skygw_log_write_flush(
@ -1139,7 +1022,6 @@ static void set_slave_heartbeat(MYSQL_MONITOR *handle, MONITOR_SERVERS *database
if (handle->master !=NULL && (mysql_query(database->con, select_heartbeat_query) == 0
&& (result = mysql_store_result(database->con)) != NULL)) {
int rows_found = 0;
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result))) {
int rlag = -1;
@ -1164,7 +1046,7 @@ static void set_slave_heartbeat(MYSQL_MONITOR *handle, MONITOR_SERVERS *database
if (rlag >= 0) {
/* store rlag only if greater than monitor sampling interval */
database->server->rlag = (rlag > (handle->interval / 1000)) ? rlag : 0;
database->server->rlag = (rlag > (mon->interval / 1000)) ? rlag : 0;
} else {
database->server->rlag = -1;
}
@ -1218,7 +1100,8 @@ static void set_slave_heartbeat(MYSQL_MONITOR *handle, MONITOR_SERVERS *database
* @return The server at root level with SERVER_MASTER bit
*/
static MONITOR_SERVERS *get_replication_tree(MYSQL_MONITOR *handle, int num_servers) {
static MONITOR_SERVERS *get_replication_tree(MONITOR *mon, int num_servers) {
MYSQL_MONITOR* handle = (MYSQL_MONITOR*)mon->handle;
MONITOR_SERVERS *ptr;
MONITOR_SERVERS *backend;
SERVER *current;
@ -1226,7 +1109,7 @@ static MONITOR_SERVERS *get_replication_tree(MYSQL_MONITOR *handle, int num_serv
long node_id;
int root_level;
ptr = handle->databases;
ptr = mon->databases;
root_level = num_servers;
while (ptr)
@ -1245,7 +1128,7 @@ static MONITOR_SERVERS *get_replication_tree(MYSQL_MONITOR *handle, int num_serv
node_id = current->master_id;
if (node_id < 1) {
MONITOR_SERVERS *find_slave;
find_slave = getSlaveOfNodeId(handle->databases, current->node_id);
find_slave = getSlaveOfNodeId(mon->databases, current->node_id);
if (find_slave == NULL) {
current->depth = -1;
@ -1265,7 +1148,7 @@ static MONITOR_SERVERS *get_replication_tree(MYSQL_MONITOR *handle, int num_serv
root_level = current->depth;
handle->master = ptr;
}
backend = getServerByNodeId(handle->databases, node_id);
backend = getServerByNodeId(mon->databases, node_id);
if (backend) {
node_id = backend->server->master_id;
@ -1281,7 +1164,7 @@ static MONITOR_SERVERS *get_replication_tree(MYSQL_MONITOR *handle, int num_serv
MONITOR_SERVERS *master;
current->depth = depth;
master = getServerByNodeId(handle->databases, current->master_id);
master = getServerByNodeId(mon->databases, current->master_id);
if (master && master->server && master->server->node_id > 0) {
add_slave_to_master(master->server->slaves, MONITOR_MAX_NUM_SLAVES, current->node_id);
master->server->depth = current->depth -1;
@ -1340,88 +1223,31 @@ static int add_slave_to_master(long *slaves_list, int list_size, long node_id) {
return 0;
}
static monitor_event_t mysql_events[] = {
MASTER_DOWN_EVENT,
MASTER_UP_EVENT,
SLAVE_DOWN_EVENT,
SLAVE_UP_EVENT,
SERVER_DOWN_EVENT,
SERVER_UP_EVENT,
LOST_MASTER_EVENT,
LOST_SLAVE_EVENT,
NEW_MASTER_EVENT,
NEW_SLAVE_EVENT,
MAX_MONITOR_EVENT
};
/**
* Set a pending status bit in the monior server
*
* @param server The server to update
* @param bit The bit to clear for the server
*/
static void
monitor_set_pending_status(MONITOR_SERVERS *ptr, int bit)
* Check if the MySQL monitor is monitoring this event type.
* @param event Event to check
* @return True if the event is monitored, false if it is not
* */
bool isMySQLEvent(monitor_event_t event)
{
ptr->pending_status |= bit;
}
/**
* Clear a pending status bit in the monior server
*
* @param server The server to update
* @param bit The bit to clear for the server
*/
static void
monitor_clear_pending_status(MONITOR_SERVERS *ptr, int bit)
{
ptr->pending_status &= ~bit;
}
/**
* Set the default id to use in the monitor.
*
* @param arg The handle allocated by startMonitor
* @param type The connect timeout type
* @param value The timeout value to set
*/
static void
setNetworkTimeout(void *arg, int type, int value)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
int max_timeout = (int)(handle->interval/1000);
int new_timeout = max_timeout -1;
if (new_timeout <= 0)
new_timeout = DEFAULT_CONNECT_TIMEOUT;
switch(type) {
case MONITOR_CONNECT_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->connect_timeout, &value, sizeof(int));
} else {
memcpy(&handle->connect_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Connect Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
case MONITOR_READ_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->read_timeout, &value, sizeof(int));
} else {
memcpy(&handle->read_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Read Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
case MONITOR_WRITE_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->write_timeout, &value, sizeof(int));
} else {
memcpy(&handle->write_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Write Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
default:
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Monitor setNetworkTimeout received an unsupported action type %i", type)));
break;
}
}
int i;
for(i = 0;mysql_events[i] != MAX_MONITOR_EVENT;i++)
{
if(event == mysql_events[i])
return true;
}
return false;
}

View File

@ -17,10 +17,22 @@
*
* Copyright MariaDB Corporation Ab 2013-2014
*/
#include <server.h>
#include <spinlock.h>
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <monitor.h>
#include <spinlock.h>
#include <thread.h>
#include <mysql.h>
#include <mysqld_error.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <secrets.h>
#include <dcb.h>
#include <modinfo.h>
#include <maxconfig.h>
#include <monitor_common.h>
#include <externcmd.h>
/**
* @file mysqlmon.h - The MySQL monitor functionality within the gateway
*
@ -37,24 +49,10 @@
* 07/11/14 Massimiliano Pinto Addition of NetworkTimeout: connect, read, write
* 20/04/15 Guillaume Lefranc Addition of availableWhenDonor
* 22/04/15 Martin Brampton Addition of disableMasterRoleSetting
*
* 07/05/15 Markus Makela Addition of command execution on Master server failure
* @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 */
int mon_err_count;
unsigned int mon_prev_status;
unsigned int pending_status; /**< Pending Status flag bitmap */
struct monitor_servers
*next; /**< The next server in the list */
} MONITOR_SERVERS;
/**
* The handle for an instance of a MySQL Monitor module
*/
@ -63,9 +61,6 @@ typedef struct {
pthread_t tid; /**< id of monitor thread */
int shutdown; /**< Flag to shutdown the monitor thread */
int status; /**< Monitor status */
char *defaultUser; /**< Default username for monitoring */
char *defaultPasswd; /**< Default password for monitoring */
unsigned long interval; /**< Monitor sampling interval */
unsigned long id; /**< Monitor ID */
int replicationHeartbeat; /**< Monitor flag for MySQL replication heartbeat */
int detectStaleMaster; /**< Monitor flag for MySQL replication Stale Master detection */
@ -73,22 +68,8 @@ typedef struct {
int availableWhenDonor; /**< Monitor flag for Galera Cluster Donor availability */
int disableMasterRoleSetting; /**< Monitor flag to disable setting master role */
MONITOR_SERVERS *master; /**< Master server for MySQL Master/Slave replication */
MONITOR_SERVERS *databases; /**< Linked list of servers to monitor */
int connect_timeout; /**< Connect timeout in seconds for mysql_real_connect */
int read_timeout; /**< Timeout in seconds to read from the server.
* There are retries and the total effective timeout value is three times the option value.
*/
int write_timeout; /**< Timeout in seconds for each attempt to write to the server.
* There are retries and the total effective timeout value is two times the option value.
*/
char* script; /*< Script to call when state changes occur on servers */
bool events[MAX_MONITOR_EVENT]; /*< enabled events */
} MYSQL_MONITOR;
#define MONITOR_RUNNING 1
#define MONITOR_STOPPING 2
#define MONITOR_STOPPED 3
#define MONITOR_INTERVAL 10000 // in milliseconds
#define MONITOR_DEFAULT_ID 1UL // unsigned long value
#define MONITOR_MAX_NUM_SLAVES 20 //number of MySQL slave servers associated to a MySQL master server
#endif

View File

@ -25,24 +25,14 @@
* Date Who Description
* 25/07/14 Massimiliano Pinto Initial implementation
* 10/11/14 Massimiliano Pinto Added setNetworkTimeout for connect,read,write
* 08/05/15 Markus Makela Addition of launchable scripts
*
* @endverbatim
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <monitor.h>
#include <mysqlmon.h>
#include <thread.h>
#include <mysql.h>
#include <mysqld_error.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <secrets.h>
#include <dcb.h>
#include <modinfo.h>
#include <maxconfig.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
extern size_t log_ses_count[];
@ -50,7 +40,7 @@ extern __thread log_info_t tls_log_info;
static void monitorMain(void *);
static char *version_str = "V1.1.0";
static char *version_str = "V2.1.0";
MODULE_INFO info = {
MODULE_API_MONITOR,
@ -61,22 +51,13 @@ MODULE_INFO info = {
static void *startMonitor(void *,void*);
static void stopMonitor(void *);
static void registerServer(void *, SERVER *);
static void unregisterServer(void *, SERVER *);
static void defaultUsers(void *, char *, char *);
static void diagnostics(DCB *, void *);
static void setInterval(void *, size_t);
static void setNetworkTimeout(void *arg, int type, int value);
bool isNdbEvent(monitor_event_t event);
static MONITOR_OBJECT MyObject = {
startMonitor,
stopMonitor,
registerServer,
unregisterServer,
defaultUsers,
diagnostics,
setInterval,
setNetworkTimeout
stopMonitor,
diagnostics
};
/**
@ -127,31 +108,65 @@ GetModuleObject()
static void *
startMonitor(void *arg,void* opt)
{
MYSQL_MONITOR *handle;
CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt;
if (arg != NULL)
{
handle = (MYSQL_MONITOR *)arg;
handle->shutdown = 0;
}
else
{
if ((handle = (MYSQL_MONITOR *)malloc(sizeof(MYSQL_MONITOR))) == NULL)
return NULL;
handle->databases = NULL;
handle->shutdown = 0;
handle->defaultUser = NULL;
handle->defaultPasswd = NULL;
handle->id = MONITOR_DEFAULT_ID;
handle->interval = MONITOR_INTERVAL;
handle->connect_timeout=DEFAULT_CONNECT_TIMEOUT;
handle->read_timeout=DEFAULT_READ_TIMEOUT;
handle->write_timeout=DEFAULT_WRITE_TIMEOUT;
spinlock_init(&handle->lock);
}
MONITOR* mon = (MONITOR*)arg;
MYSQL_MONITOR *handle = mon->handle;
CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt;
bool have_events = false;
handle->tid = (THREAD)thread_start(monitorMain, handle);
return handle;
if (handle != NULL)
{
handle->shutdown = 0;
}
else
{
if ((handle = (MYSQL_MONITOR *)malloc(sizeof(MYSQL_MONITOR))) == NULL)
return NULL;
handle->shutdown = 0;
handle->id = MONITOR_DEFAULT_ID;
memset(handle->events,false,sizeof(handle->events));
spinlock_init(&handle->lock);
}
while(params)
{
if(!strcmp(params->name,"script"))
{
if(handle->script)
free(handle->script);
if(access(params->value,X_OK) == 0)
{
handle->script = strdup(params->value);
}
else
{
if(access(params->value,F_OK) == 0)
{
skygw_log_write(LE,
"Error: The file cannot be executed: %s",
params->value);
}
else
{
skygw_log_write(LE,
"Error: The file cannot be found: %s",
params->value);
}
handle->script = NULL;
}
}
else if(!strcmp(params->name,"events"))
{
mon_parse_event_string(&handle->events,sizeof(handle->events),params->value);
have_events = true;
}
params = params->next;
}
/** If no specific events are given, enable them all */
if(!have_events)
{
memset(handle->events,true,sizeof(handle->events));
}
handle->tid = (THREAD)thread_start(monitorMain, mon);
return handle;
}
/**
@ -162,82 +177,13 @@ CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt;
static void
stopMonitor(void *arg)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR* mon = (MONITOR*)arg;
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)mon->handle;
handle->shutdown = 1;
thread_wait((void *)handle->tid);
}
/**
* Register a server that must be added to the monitored servers for
* a monitoring module.
*
* @param arg 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 arg 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);
}
/**
* Diagnostic interface
*
@ -247,7 +193,8 @@ MONITOR_SERVERS *ptr, *lptr;
static void
diagnostics(DCB *dcb, void *arg)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR* mon = arg;
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)mon->handle;
MONITOR_SERVERS *db;
char *sep;
@ -264,13 +211,13 @@ char *sep;
break;
}
dcb_printf(dcb,"\tSampling interval:\t%lu milliseconds\n", handle->interval);
dcb_printf(dcb,"\tConnect Timeout:\t%i seconds\n", handle->connect_timeout);
dcb_printf(dcb,"\tRead Timeout:\t\t%i seconds\n", handle->read_timeout);
dcb_printf(dcb,"\tWrite Timeout:\t\t%i seconds\n", handle->write_timeout);
dcb_printf(dcb,"\tSampling interval:\t%lu milliseconds\n", mon->interval);
dcb_printf(dcb,"\tConnect Timeout:\t%i seconds\n", mon->connect_timeout);
dcb_printf(dcb,"\tRead Timeout:\t\t%i seconds\n", mon->read_timeout);
dcb_printf(dcb,"\tWrite Timeout:\t\t%i seconds\n", mon->write_timeout);
dcb_printf(dcb, "\tMonitored servers: ");
db = handle->databases;
db = mon->databases;
sep = "";
while (db)
{
@ -281,41 +228,19 @@ char *sep;
dcb_printf(dcb, "\n");
}
/**
* Set the default username and password to use to monitor if the server does not
* override this.
*
* @param arg The handle allocated by startMonitor
* @param uname The default user name
* @param passwd The default password
*/
static void
defaultUsers(void *arg, char *uname, char *passwd)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
if (handle->defaultUser)
free(handle->defaultUser);
if (handle->defaultPasswd)
free(handle->defaultPasswd);
handle->defaultUser = strdup(uname);
handle->defaultPasswd = strdup(passwd);
}
/**
* Monitor an individual server
*
* @param database The database to probe
*/
static void
monitorDatabase(MONITOR_SERVERS *database, char *defaultUser, char *defaultPasswd, MYSQL_MONITOR *handle)
monitorDatabase(MONITOR_SERVERS *database, char *defaultUser, char *defaultPasswd, MONITOR *mon)
{
MYSQL_MONITOR* handle = mon->handle;
MYSQL_ROW row;
MYSQL_RES *result;
int num_fields;
int isjoined = 0;
char *uname = defaultUser, *passwd = defaultPasswd;
unsigned long int server_version = 0;
char *server_string;
if (database->server->monuser != NULL)
@ -333,18 +258,17 @@ char *server_string;
if (database->con == NULL || mysql_ping(database->con) != 0)
{
char *dpwd = decryptPassword(passwd);
int rc;
int connect_timeout = handle->connect_timeout;
int read_timeout = handle->read_timeout;
int write_timeout = handle->write_timeout;
int connect_timeout = mon->connect_timeout;
int read_timeout = mon->read_timeout;
int write_timeout = mon->write_timeout;
if(database->con)
mysql_close(database->con);
database->con = mysql_init(NULL);
rc = mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&connect_timeout);
rc = mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout);
rc = mysql_options(database->con, MYSQL_OPT_WRITE_TIMEOUT, (void *)&write_timeout);
mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&connect_timeout);
mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout);
mysql_options(database->con, MYSQL_OPT_WRITE_TIMEOUT, (void *)&write_timeout);
if (mysql_real_connect(database->con, database->server->name,
uname, dpwd, NULL, database->server->port, NULL, 0) == NULL)
@ -375,9 +299,6 @@ char *server_string;
/* If we get this far then we have a working connection */
server_set_status(database->server, SERVER_RUNNING);
/* get server version from current server */
server_version = mysql_get_server_version(database->con);
/* get server version string */
server_string = (char *)mysql_get_server_info(database->con);
if (server_string) {
@ -390,7 +311,6 @@ char *server_string;
if (mysql_query(database->con, "SHOW STATUS LIKE 'Ndb_number_of_ready_data_nodes'") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
if (atoi(row[1]) > 0)
@ -404,7 +324,6 @@ char *server_string;
&& (result = mysql_store_result(database->con)) != NULL)
{
long cluster_node_id = -1;
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
cluster_node_id = strtol(row[1], NULL, 10);
@ -435,11 +354,15 @@ char *server_string;
static void
monitorMain(void *arg)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
MONITOR* mon = arg;
MYSQL_MONITOR *handle;
MONITOR_SERVERS *ptr;
long master_id;
size_t nrounds = 0;
spinlock_acquire(&mon->lock);
handle = (MYSQL_MONITOR *)mon->handle;
spinlock_release(&mon->lock);
if (mysql_thread_init())
{
LOGIF(LE, (skygw_log_write_flush(
@ -469,22 +392,21 @@ size_t nrounds = 0;
* round.
*/
if (nrounds != 0 &&
((nrounds*MON_BASE_INTERVAL_MS)%handle->interval) >=
((nrounds*MON_BASE_INTERVAL_MS)%mon->interval) >=
MON_BASE_INTERVAL_MS)
{
nrounds += 1;
continue;
}
nrounds += 1;
master_id = -1;
ptr = handle->databases;
ptr = mon->databases;
while (ptr)
{
unsigned int prev_status = ptr->server->status;
monitorDatabase(ptr, handle->defaultUser, handle->defaultPasswd,handle);
ptr->mon_prev_status = ptr->server->status;
monitorDatabase(ptr, mon->user, mon->password,mon);
if (ptr->server->status != prev_status ||
if (ptr->server->status != ptr->mon_prev_status ||
SERVER_IS_DOWN(ptr->server))
{
LOGIF(LD, (skygw_log_write_flush(
@ -497,80 +419,64 @@ size_t nrounds = 0;
ptr = ptr->next;
}
ptr = mon->databases;
monitor_event_t evtype;
while(ptr)
{
/** Execute monitor script if a server state has changed */
if(mon_status_changed(ptr))
{
evtype = mon_get_event_type(ptr);
if(isNdbEvent(evtype))
{
skygw_log_write(LOGFILE_TRACE,"Server changed state: %s[%s:%u]: %s",
ptr->server->unique_name,
ptr->server->name,ptr->server->port,
mon_get_event_name(ptr));
if(handle->script && handle->events[evtype])
{
monitor_launch_script(mon,ptr,handle->script);
}
}
}
ptr = ptr->next;
}
}
}
/**
* Set the monitor sampling interval.
*
* @param arg The handle allocated by startMonitor
* @param interval The interval to set in monitor struct, in milliseconds
*/
static void
setInterval(void *arg, size_t interval)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
memcpy(&handle->interval, &interval, sizeof(unsigned long));
}
static monitor_event_t ndb_events[] = {
MASTER_DOWN_EVENT,
MASTER_UP_EVENT,
SLAVE_DOWN_EVENT,
SLAVE_UP_EVENT,
SERVER_DOWN_EVENT,
SERVER_UP_EVENT,
NDB_UP_EVENT,
NDB_DOWN_EVENT,
LOST_MASTER_EVENT,
LOST_SLAVE_EVENT,
LOST_NDB_EVENT,
NEW_MASTER_EVENT,
NEW_SLAVE_EVENT,
NEW_NDB_EVENT,
MAX_MONITOR_EVENT
};
/**
* Set the timeouts to use in the monitor.
*
* @param arg The handle allocated by startMonitor
* @param type The connect timeout type
* @param value The timeout value to set
* Check if the event type is one the ndbcustermonitor is interested in.
* @param event Event to check
* @return True if the event is monitored, false if it is not
*/
static void
setNetworkTimeout(void *arg, int type, int value)
bool isNdbEvent(monitor_event_t event)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
int max_timeout = (int)(handle->interval/1000);
int new_timeout = max_timeout -1;
if (new_timeout <= 0)
new_timeout = DEFAULT_CONNECT_TIMEOUT;
switch(type) {
case MONITOR_CONNECT_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->connect_timeout, &value, sizeof(int));
} else {
memcpy(&handle->connect_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Connect Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
case MONITOR_READ_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->read_timeout, &value, sizeof(int));
} else {
memcpy(&handle->read_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Read Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
case MONITOR_WRITE_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->write_timeout, &value, sizeof(int));
} else {
memcpy(&handle->write_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Write Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
default:
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Monitor setNetworkTimeout received an unsupported action type %i", type)));
break;
}
}
int i;
for(i = 0;ndb_events[i] != MAX_MONITOR_EVENT;i++)
{
if(event == ndb_events[i])
return true;
}
return false;
}

View File

@ -0,0 +1,56 @@
#ifndef _MYSQLMON_H
#define _MYSQLMON_H
/*
* This file is distributed as part of the MariaDB Corporation MaxScale. 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 MariaDB Corporation Ab 2013-2014
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <monitor.h>
#include <spinlock.h>
#include <thread.h>
#include <mysql.h>
#include <mysqld_error.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <secrets.h>
#include <dcb.h>
#include <modinfo.h>
#include <maxconfig.h>
#include <monitor_common.h>
#include <externcmd.h>
/**
* @file ndbclustermon.h - The NDB Cluster monitor
*
*/
/**
* The handle for an instance of a NDB Cluster Monitor module
*/
typedef struct {
SPINLOCK lock; /**< The monitor spinlock */
pthread_t tid; /**< id of monitor thread */
int shutdown; /**< Flag to shutdown the monitor thread */
int status; /**< Monitor status */
unsigned long id; /**< Monitor ID */
MONITOR_SERVERS *master; /**< Master server for MySQL Master/Slave replication */
char* script; /*< Script to call when state changes occur on servers */
bool events[MAX_MONITOR_EVENT]; /*< enabled events */
} MYSQL_MONITOR;
#endif