
Fix for broken replication has been added to mysql_monitor. Both Slave_IO and Slave_SQL threads must be running in order to assign the SERVER_SLAVE status but If only Slave_IO is running let’s assign the master_id to current server and continue building the replication tree; if no slaves at all the master will be still available. The “detect_stale_master” option has been added, its default is 0. If set to 1 the monitor will keep the last detected master even if the replication setup is completely not working, i.e. both Slave_IO and Slave_SQL threads are not running: this applies only to the server that was master before. After monitor or MaxScale are restarted and the replication is still stopped or not configured there will be no master because it’s not possible to compute the replication topology tree.
329 lines
7.1 KiB
C
329 lines
7.1 KiB
C
/*
|
|
* 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
|
|
* 23/05/14 Massimiliano Pinto Addition of monitor_interval parameter
|
|
* and monitor id
|
|
*
|
|
* @endverbatim
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <monitor.h>
|
|
#include <spinlock.h>
|
|
#include <modules.h>
|
|
#include <skygw_utils.h>
|
|
#include <log_manager.h>
|
|
|
|
extern int lm_enabled_logfiles_bitmask;
|
|
|
|
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
|
|
* @param module The 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);
|
|
if ((mon->module = load_module(module, MODULE_MONITOR)) == NULL)
|
|
{
|
|
LOGIF(LE, (skygw_log_write_flush(
|
|
LOGFILE_ERROR,
|
|
"Error : Unable to load monitor module '%s'.",
|
|
name)));
|
|
free(mon->name);
|
|
free(mon);
|
|
return NULL;
|
|
}
|
|
mon->handle = (*mon->module->startMonitor)(NULL);
|
|
mon->state |= MONITOR_STATE_RUNNING;
|
|
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);
|
|
mon->state &= ~MONITOR_STATE_RUNNING;
|
|
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);
|
|
}
|
|
|
|
|
|
/**
|
|
* Start an individual monitor that has previoulsy been stopped.
|
|
*
|
|
* @param monitor The Monitor that should be started
|
|
*/
|
|
void
|
|
monitorStart(MONITOR *monitor)
|
|
{
|
|
monitor->handle = (*monitor->module->startMonitor)(monitor->handle);
|
|
monitor->state |= MONITOR_STATE_RUNNING;
|
|
}
|
|
|
|
/**
|
|
* Stop a given monitor
|
|
*
|
|
* @param monitor The monitor to stop
|
|
*/
|
|
void
|
|
monitorStop(MONITOR *monitor)
|
|
{
|
|
monitor->module->stopMonitor(monitor->handle);
|
|
monitor->state &= ~MONITOR_STATE_RUNNING;
|
|
}
|
|
|
|
/**
|
|
* Shutdown all running monitors
|
|
*/
|
|
void
|
|
monitorStopAll()
|
|
{
|
|
MONITOR *ptr;
|
|
|
|
spinlock_acquire(&monLock);
|
|
ptr = allMonitors;
|
|
while (ptr)
|
|
{
|
|
monitorStop(ptr);
|
|
ptr = ptr->next;
|
|
}
|
|
spinlock_release(&monLock);
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
/**
|
|
* Add a default user to the monitor. This user is used to connect to the
|
|
* monitored databases but may be overriden on a per server basis.
|
|
*
|
|
* @param mon The monitor instance
|
|
* @param user The default username to use when connecting
|
|
* @param passwd The default password associated to the default user.
|
|
*/
|
|
void
|
|
monitorAddUser(MONITOR *mon, char *user, char *passwd)
|
|
{
|
|
mon->module->defaultUser(mon->handle, user, passwd);
|
|
}
|
|
|
|
/**
|
|
* Show all monitors
|
|
*
|
|
* @param dcb DCB for printing output
|
|
*/
|
|
void
|
|
monitorShowAll(DCB *dcb)
|
|
{
|
|
MONITOR *ptr;
|
|
|
|
spinlock_acquire(&monLock);
|
|
ptr = allMonitors;
|
|
while (ptr)
|
|
{
|
|
dcb_printf(dcb, "Monitor: %p\n", ptr);
|
|
dcb_printf(dcb, "\tName: %s\n", ptr->name);
|
|
if (ptr->module->diagnostics)
|
|
ptr->module->diagnostics(dcb, ptr->handle);
|
|
ptr = ptr->next;
|
|
}
|
|
spinlock_release(&monLock);
|
|
}
|
|
|
|
/**
|
|
* Show a single monitor
|
|
*
|
|
* @param dcb DCB for printing output
|
|
*/
|
|
void
|
|
monitorShow(DCB *dcb, MONITOR *monitor)
|
|
{
|
|
|
|
dcb_printf(dcb, "Monitor: %p\n", monitor);
|
|
dcb_printf(dcb, "\tName: %s\n", monitor->name);
|
|
if (monitor->module->diagnostics)
|
|
monitor->module->diagnostics(dcb, monitor->handle);
|
|
}
|
|
|
|
/**
|
|
* List all the monitors
|
|
*
|
|
* @param dcb DCB for printing output
|
|
*/
|
|
void
|
|
monitorList(DCB *dcb)
|
|
{
|
|
MONITOR *ptr;
|
|
|
|
spinlock_acquire(&monLock);
|
|
ptr = allMonitors;
|
|
dcb_printf(dcb, "+----------------------+---------------------\n");
|
|
dcb_printf(dcb, "| %-20s | Status\n", "Monitor");
|
|
dcb_printf(dcb, "+----------------------+---------------------\n");
|
|
while (ptr)
|
|
{
|
|
dcb_printf(dcb, "| %-20s | %s\n", ptr->name,
|
|
ptr->state & MONITOR_STATE_RUNNING
|
|
? "Running" : "Stopped");
|
|
ptr = ptr->next;
|
|
}
|
|
dcb_printf(dcb, "+----------------------+---------------------\n");
|
|
spinlock_release(&monLock);
|
|
}
|
|
|
|
/**
|
|
* Find a monitor by name
|
|
*
|
|
* @param name The name of the monitor
|
|
* @return Pointer to the monitor or NULL
|
|
*/
|
|
MONITOR *
|
|
monitor_find(char *name)
|
|
{
|
|
MONITOR *ptr;
|
|
|
|
spinlock_acquire(&monLock);
|
|
ptr = allMonitors;
|
|
while (ptr)
|
|
{
|
|
if (!strcmp(ptr->name, name))
|
|
break;
|
|
ptr = ptr->next;
|
|
}
|
|
spinlock_release(&monLock);
|
|
return ptr;
|
|
}
|
|
|
|
|
|
/**
|
|
* Set the id of the monitor.
|
|
*
|
|
* @param mon The monitor instance
|
|
* @param id The id for the monitor
|
|
*/
|
|
|
|
void
|
|
monitorSetId(MONITOR *mon, unsigned long id)
|
|
{
|
|
if (mon->module->defaultId != NULL) {
|
|
mon->module->defaultId(mon->handle, id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the monitor sampling interval.
|
|
*
|
|
* @param mon The monitor instance
|
|
* @param interval The sampling interval in milliseconds
|
|
*/
|
|
void
|
|
monitorSetInterval (MONITOR *mon, unsigned long interval)
|
|
{
|
|
if (mon->module->setInterval != NULL) {
|
|
mon->interval = interval;
|
|
mon->module->setInterval(mon->handle, interval);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enable Replication Heartbeat support in monitor.
|
|
*
|
|
* @param mon The monitor instance
|
|
* @param enable The enabling value is 1, 0 turns it off
|
|
*/
|
|
void
|
|
monitorSetReplicationHeartbeat(MONITOR *mon, int enable)
|
|
{
|
|
if (mon->module->replicationHeartbeat != NULL) {
|
|
mon->module->replicationHeartbeat(mon->handle, enable);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enable Stale Master assignement.
|
|
*
|
|
* @param mon The monitor instance
|
|
* @param enable The enabling value is 1, 0 turns it off
|
|
*/
|
|
void
|
|
monitorDetectStaleMaster(MONITOR *mon, int enable)
|
|
{
|
|
if (mon->module->detectStaleMaster != NULL) {
|
|
mon->module->detectStaleMaster(mon->handle, enable);
|
|
}
|
|
}
|