Merge remote-tracking branch 'origin/develop' into MXS-122

This commit is contained in:
counterpoint 2015-06-09 13:51:55 +01:00
commit 152f9bbc4a
36 changed files with 2333 additions and 1279 deletions

View File

@ -72,7 +72,7 @@ endif()
IF(DEFINED OLEVEL )
if((OLEVEL GREATER -1) AND (OLEVEL LESS 4) )
set(FLAGS "${FLAGS} -O${OLEVEL}" CACHE STRING "Compilation flags")
set(FLAGS "${FLAGS} -O${OLEVEL}" CACHE STRING "Compilation flags" FORCE)
message(STATUS "Optimization level at: ${OLEVEL}")
else()
message(WARNING "Optimization level was set to a bad value, ignoring it. (Valid values are 0-3)")
@ -80,16 +80,17 @@ IF(DEFINED OLEVEL )
endif()
if(GCOV)
set(FLAGS "${FLAGS} -fprofile-arcs -ftest-coverage" CACHE STRING "Compilation flags")
set(FLAGS "${FLAGS} -fprofile-arcs -ftest-coverage" CACHE STRING "Compilation flags" FORCE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov")
endif()
if(FAKE_CODE)
set(FLAGS "${FLAGS} -DFAKE_CODE" CACHE STRING "Compilation flags")
set(FLAGS "${FLAGS} -DFAKE_CODE" CACHE STRING "Compilation flags" FORCE)
endif()
if(PROFILE)
set(FLAGS "${FLAGS} -pg " CACHE STRING "Compilation flags")
message(STATUS "Profiling executables")
set(FLAGS "${FLAGS} -pg " CACHE STRING "Compilation flags" FORCE)
endif()
set(CMAKE_C_FLAGS "${FLAGS}")

View File

@ -42,6 +42,12 @@
- [RabbitMQ Setup and MaxScale Integration Tutorial](Tutorials/RabbitMQ-Setup-And-MaxScale-Integration.md)
- [Nagios Plugins for MaxScale Tutorial](Tutorials/Nagios-Plugins.md)
## Routers
- [Read Write Split](routers/ReadWriteSplit.md)
- [Read Connnection Router](routers/ReadConnRoute.md)
- [Schemarouter](routers/SchemaRouter.md)
## Filters
Here are detailed documents about the filters MaxScale offers. They contain configuration guides and example use cases. Before reading these,you should have read the filter tutorial so that you know how they work and how to configure them.
@ -53,6 +59,12 @@ Here are detailed documents about the filters MaxScale offers. They contain conf
- [Database Firewall Filter](filters/Database-Firewall-Filter.md)
- [RabbitMQ Filter](filters/RabbitMQ-Filter.md)
## Monitors
- [MySQL Monitor](monitors/MySQL-Monitor.md)
- [Galera Monitor](monitors/Galera-Monitor.md)
- [Multi-Master Monitor](monitors/MM-Monitor.md)
- [MySQL Cluster Monitor](monitors/NDB-Cluster-Monitor.md)
## Utilities
- [RabbitMQ Consumer Client](filters/RabbitMQ-Consumer-Client.md)

View File

@ -56,7 +56,7 @@ There are a number bugs and known limitations within this version of MaxScale, t
* Binlog Router Plugin is compatible with MySQL 5.6
Binlog Router Plugin currently does not work for MariaDB 5.5 and MariaDB 10.0
* LONGBLOG are currently not supported.
* LONGBLOB are currently not supported.
* Galera Cluster variables, such as @@wsrep_node_name, are not resolved by the embedded MariaDB parser.
@ -78,14 +78,14 @@ Both RPM and Debian packages are available for MaxScale in addition to the tar b
* Ubuntu 12.04 LTS
* Ubuntu 13.10
* Ubuntu 14.04 LTS
* Fedora 19
* Fedora 20
* Fedora 21
* OpenSuSE 13
* SuSE Linux Enterprise 11

View File

@ -0,0 +1,120 @@
# Galera Monitor
## Overview
The Galera Monitor is a monitoring module for MaxScale that monitors a Galera cluster. It detects whether nodes are a part of the cluster and if they are in sync with the rest of the cluster. It can also assign master and slave roles inside MaxScale, allowing Galera clusters to be used with modules designed for traditional master-slave clusters.
## Configuration
A minimal configuration for a monitor requires a set of servers for monitoring and a username and a password to connect to these servers. The user requires the REPLICATION CLIENT privilege to successfully monitor the state of the servers.
```
[Galera Monitor]
type=monitor
module=galeramon
servers=server1,server2,server3
user=myuser
passwd=mypwd
```
## Optional parameters for all monitors
Here are optional parameters that are common for all the monitors.
### `monitor_interval`
This is the time the monitor waits between each cycle of monitoring. The default value of 10000 milliseconds (10 seconds) should be lowered if you want a faster response to changes in the server states. The value is defined in milliseconds and the smallest possible value is 100 milliseconds.
```
monitor_interval=2500
```
### `backend_connect_timeout`
This parameter controls the timeout for connecting to a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 3 seconds.
```
backend_connect_timeout=6
```
### `backend_write_timeout`
This parameter controls the timeout for writing to a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 2 seconds.
```
backend_write_timeout=4
```
### `backend_read_timeout`
This parameter controls the timeout for reading from a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 1 seconds.
```
backend_read_timeout=2
```
## Galera Monitor optional parameters
These are optional parameters specific to the Galera Monitor.
### `disable_master_failback`
If a node marked as master inside MaxScale happens to fail and the master status is assigned to another node MaxScale will normally return the master status to the original node after it comes back up. With this option enabled, if the master status is assigned to a new node it will not be reassigned to the original node for as long as the new master node is running.
```
disable_master_failback=true
```
### `available_when_donor`
This option only has an effect if there is a single Galera node being backed up an XtraBackup instance. This causes the initial node to go into Donor state which would normally prevent if from being marked as a valid server inside MaxScale. If this option is enabled, a single node in Donor state where the method is XtraBackup will be kept in Synced state.
```
available_when_donor=true
```
### `disable_master_role_setting`
This disables the assignment of master and slave roles to the Galera cluster nodes. If this option is enabled, Synced is the only status assigned by this monitor.
```
disable_master_role_setting=true
```
### `script`
This script will be executed when a server changes its state. The parameter should be an absolute path to the script or it should be in the executable path.
```
script=/home/user/script.sh
```
### `events`
A list of event names which cause the script to be executed. If this option is not defined, all events cause the script to be executed. The list must contain a comma separated list of event names.
```
events=master_down,slave_down
```
## Script events
Here is a table of all possible event types and their descriptions.
Event Name|Description
----------|----------
master_down|A Master server has gone down
master_up|A Master server has come up
slave_down|A Slave server has gone down
slave_up|A Slave server has come up
server_down|A server with no assigned role has done down
server_up|A server with no assigned role has come up
synced_down|A synced Galera node has come up
synced_up|A synced Galera node has gone down
lost_master|A server lost Master status
lost_slave|A server lost Slave status
lost_synced|A Galera node lost synced status
new_master|A new Master was detected
new_slave|A new Slave was detected
new_synced|A new synced Galera node was detected

View File

@ -0,0 +1,107 @@
# Multi-Master Monitor
## Overview
The Multi-Master Monitor is a monitoring module for MaxScale that monitors Master-Master replication. It assigns master and slave roles inside MaxScale based on whether the read_only parameter on a server is set to off or on.
## Configuration
A minimal configuration for a monitor requires a set of servers for monitoring and a username and a password to connect to these servers. The user requires the REPLICATION CLIENT privilege to successfully monitor the state of the servers.
```
[Multi-Master Monitor]
type=monitor
module=mmmon
servers=server1,server2,server3
user=myuser
passwd=mypwd
```
## Optional parameters for all monitors
Here are optional parameters that are common for all the monitors.
### `monitor_interval`
This is the time the monitor waits between each cycle of monitoring. The default value of 10000 milliseconds (10 seconds) should be lowered if you want a faster response to changes in the server states. The value is defined in milliseconds and the smallest possible value is 100 milliseconds.
```
monitor_interval=2500
```
### `backend_connect_timeout`
This parameter controls the timeout for connecting to a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 3 seconds.
```
backend_connect_timeout=6
```
### `backend_write_timeout`
This parameter controls the timeout for writing to a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 2 seconds.
```
backend_write_timeout=4
```
### `backend_read_timeout`
This parameter controls the timeout for reading from a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 1 seconds.
```
backend_read_timeout=2
```
## Multi-Master Monitor optional parameters
These are optional parameters specific to the Multi-Master Monitor.
### `detect_stale_master`
Allow previous master to be available even in case of stopped or misconfigured replication. This allows services that depend on master and slave roles to continue functioning as long as the master server is available.
This is a situation which can happen if all slave servers are unreachable or the replication breaks for some reason.
```
detect_stale_master=true
```
### `script`
This script will be executed when a server changes its state. The parameter should be an absolute path to the script or it should be in the executable path.
```
script=/home/user/script.sh
```
This script will be called with the following command line arguments.
```
<name of the script> --event=<event type> --initiator=<server whose state changed> --nodelist=<list of all servers>
```
### `events`
A list of event names which cause the script to be executed. If this option is not defined, all events cause the script to be executed. The list must contain a comma separated list of event names.
```
events=master_down,slave_down
```
## Script events
Here is a table of all possible event types and their descriptions.
Event Name|Description
----------|----------
master_down|A Master server has gone down
master_up|A Master server has come up
slave_down|A Slave server has gone down
slave_up|A Slave server has come up
server_down|A server with no assigned role has done down
server_up|A server with no assigned role has come up
lost_master|A server lost Master status
lost_slave|A server lost Slave status
new_master|A new Master was detected
new_slave|A new Slave was detected

View File

@ -0,0 +1,117 @@
# MySQL Monitor
## Overview
The MySQL Monitor is a monitoring module for MaxScale that monitors a Master-Slave replication cluster. It assigns master and slave roles inside MaxScale according to the actual replication tree in the cluster.
## Configuration
A minimal configuration for a monitor requires a set of servers for monitoring and a username and a password to connect to these servers. The user requires the REPLICATION CLIENT privilege to successfully monitor the state of the servers.
```
[MySQL Monitor]
type=monitor
module=mysqlmon
servers=server1,server2,server3
user=myuser
passwd=mypwd
```
## Optional parameters for all monitors
Here are optional parameters that are common for all the monitors.
### `monitor_interval`
This is the time the monitor waits between each cycle of monitoring. The default value of 10000 milliseconds (10 seconds) should be lowered if you want a faster response to changes in the server states. The value is defined in milliseconds and the smallest possible value is 100 milliseconds.
```
monitor_interval=2500
```
### `backend_connect_timeout`
This parameter controls the timeout for connecting to a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 3 seconds.
```
backend_connect_timeout=6
```
### `backend_write_timeout`
This parameter controls the timeout for writing to a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 2 seconds.
```
backend_write_timeout=4
```
### `backend_read_timeout`
This parameter controls the timeout for reading from a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 1 seconds.
```
backend_read_timeout=2
```
## MySQL Monitor optional parameters
These are optional parameters specific to the MySQL Monitor.
### `detect_replication_lag`
Detect replication lag between the master and the slaves. This allows the routers to route read queries to only slaves that are up to date.
```
detect_replication_lag=true
```
### `detect_stale_master`
Allow previous master to be available even in case of stopped or misconfigured
replication. This allows services that depend on master and slave roles to continue functioning as long as the master server is available.
This is a situation which can happen if all slave servers are unreachable or the replication breaks for some reason.
```
detect_stale_master=true
```
### `script`
This script will be executed when a server changes its state. The parameter should be an absolute path to the script or it should be in the executable path.
```
script=/home/user/script.sh
```
This script will be called with the following command line arguments.
```
<name of the script> --event=<event type> --initiator=<server whose state changed> --nodelist=<list of all servers>
```
### `events`
A list of event names which cause the script to be executed. If this option is not defined, all events cause the script to be executed. The list must contain a comma separated list of event names.
```
events=master_down,slave_down
```
## Script events
Here is a table of all possible event types and their descriptions.
Event Name|Description
----------|----------
master_down|A Master server has gone down
master_up|A Master server has come up
slave_down|A Slave server has gone down
slave_up|A Slave server has come up
server_down|A server with no assigned role has done down
server_up|A server with no assigned role has come up
lost_master|A server lost Master status
lost_slave|A server lost Slave status
new_master|A new Master was detected
new_slave|A new Slave was detected

View File

@ -0,0 +1,102 @@
# NDB Cluster Monitor
## Overview
The MySQL Cluster Monitor is a monitoring module for MaxScale that monitors a MySQL Cluster. It assigns a NDB status for the server if it is a part of a MySQL Cluster.
## Configuration
A minimal configuration for a monitor requires a set of servers for monitoring and a username and a password to connect to these servers. The user requires the REPLICATION CLIENT privilege to successfully monitor the state of the servers.
```
[MySQL Cluster Monitor]
type=monitor
module=ndbclustermon
servers=server1,server2,server3
user=myuser
passwd=mypwd
```
## Optional parameters for all monitors
Here are optional parameters that are common for all the monitors.
### `monitor_interval`
This is the time the monitor waits between each cycle of monitoring. The default value of 10000 milliseconds (10 seconds) should be lowered if you want a faster response to changes in the server states. The value is defined in milliseconds and the smallest possible value is 100 milliseconds.
```
monitor_interval=2500
```
### `backend_connect_timeout`
This parameter controls the timeout for connecting to a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 3 seconds.
```
backend_connect_timeout=6
```
### `backend_write_timeout`
This parameter controls the timeout for writing to a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 2 seconds.
```
backend_write_timeout=4
```
### `backend_read_timeout`
This parameter controls the timeout for reading from a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 1 seconds.
```
backend_read_timeout=2
```
## MySQL Cluster Monitor optional parameters
These are optional parameters specific to the MySQL Cluster Monitor.
### `script`
This script will be executed when a server changes its state. The parameter should be an absolute path to the script or it should be in the executable path.
```
script=/home/user/script.sh
```
This script will be called with the following command line arguments.
```
<name of the script> --event=<event type> --initiator=<server whose state changed> --nodelist=<list of all servers>
```
### `events`
A list of event names which cause the script to be executed. If this option is not defined, all events cause the script to be executed. The list must contain a comma separated list of event names.
```
events=master_down,slave_down
```
## Script events
Here is a table of all possible event types and their descriptions that the MySQL Cluster monitor can be called with.
Event Name|Description
----------|----------
master_down|A Master server has gone down
master_up|A Master server has come up
slave_down|A Slave server has gone down
slave_up|A Slave server has come up
server_down|A server with no assigned role has done down
server_up|A server with no assigned role has come up
ndb_down|A MySQL Cluster node has gone down
ndb_up|A MySQL Cluster node has come up
lost_master|A server lost Master status
lost_slave|A server lost Slave status
lost_ndb|A MySQL Cluster node lost node membership
new_master|A new Master was detected
new_slave|A new Slave was detected
new_ndb|A new MySQL Cluster node was found

View File

@ -0,0 +1,104 @@
# Readconnroute
This document provides anoverview of the **readconnroute** router module and its intended use case scenarios. It also displays all router configuration parameters with their descriptions.
## Overview
The readconnroute router provides simple and lightweight load balancing across a set of servers. The router can also be configured to balance connections based on a weighting parameter defined in the server's section.
## Configuration
Readconnroute router-specific settings are specified in the configuration file of MaxScale in its specific section. The section can be freely named but the name is used later as a reference from listener section.
The configuration consists of mandatory and optional parameters.
## Mandatory parameters
**`type`** specifies the type of service. For readconnroute module the type is `router`:
type=router
**`router`** specifies the router module to be used. For readconnroute the value is `readconnroute`:
router=readconnroute
**`servers`** provides a list of servers, which the router will connect to:
servers=server1,server2,server3
**NOTE: Each server on the list must have its own section in the configuration file where it is defined.**
**`user`** is the username the router session uses for accessing backends in order to load the content of the `mysql.user` table (and `mysql.db` and database names as well) and optionally for creating, and using `maxscale_schema.replication_heartbeat` table.
**`passwd`** specifies corresponding password for the user. Syntax for user and passwd is:
```
user=<username>
passwd=<password>
```
## Optional parameters
The **`weightby`** parameter defines the name of the value which is used to calculate the weights of the servers. Here is an example server configuration with the `serv_weight` parameter used as the weighting parameter.
```
[server1]
type=server
address=127.0.0.1
port=3000
protocol=MySQLBackend
serv_weight=3
[server2]
type=server
address=127.0.0.1
port=3001
protocol=MySQLBackend
serv_weight=1
[Read Service]
type=service
router=readconnroute
servers=server1,server2
weightby=serv_weight
```
With this configuration and a heavy query load, the server *server1* will get most of the connections and about a third of the remaining queries are routed to the second server. With server weights, you can assing secondary servers that are only used when the primary server is under heavy load.
Without the weightby parameter, each connection counts as a single connection. With a weighting parameter, a single connection received its weight from the server's own weighting parameter divided by the sum of all weighting parameters in all the configured servers.
If we use the previous configuration as an example, the sum of the `serv_weight` parameter is 4. Server1 would receive a weight of `3/4=75%` and server2 would get `1/4=25%`. This means that server1 would get 75% of the connections and server2 would get 25% of the connections.
**`router_options`** can contain a list of valid server roles. These roles are used as the valid types of servers the router will form connections to when new sessions are created.
```
router_options=slave
```
Here is a list of all possible values for the `router_options`.
Role|Description
------|---------
master|A server assigned as a master by one of MaxScale monitors. Depending on the monitor implementation, this could be a master server of a Master-Slave replication cluster or a Write-Master of a Galera cluster.
slave|A server assigned as a slave of a master.
synced| A Galera cluster node which is in a synced state with the cluster.
ndb|A MySQL Replication Cluster node
running|A server that is up and running. All servers that MaxScale can connect to are labeled as running.
If no `router_options` parameter is configured in the service definition, the router will use the default value of `running`. This means that it will load balance connections across all running servers defined in the `servers` parameter of the service.
## Examples
The most common use for the readconnroute is to provide either a read or write port for an application. This provides a more lightweight routing solution than the more complex readwritesplit router but requires the application to be able to use distinct write and read ports.
To configure a read-only service that tolerates master failures, we first need to add a new section in to the configuration file.
```
[Read Service]
type=service
router=readconnroute
servers=slave1,slave2,slave3
router_options=slave
```
Here the `router_options`designates slaves as the only valid server type. With this configuration, the queries are load balanced across the slave servers.
For more complex examples of the readconnroute router, take a look at the examples in the [Tutorials](../Tutorials) folder.

View File

@ -18,9 +18,9 @@ The configuration consists of mandatory and optional parameters.
type=router
**`service`** specifies the router module to be used. For **readwritesplit** the value is `readwritesplit`:
**`router`** specifies the router module to be used. For **readwritesplit** the value is `readwritesplit`:
service=readwritesplit
router=readwritesplit
**`servers`** provides a list of servers, which must include one master and available slaves:

View File

@ -77,6 +77,9 @@ macro(set_variables)
# Build extra tools
set(BUILD_TOOLS FALSE CACHE BOOL "Build extra utility tools")
# Profiling
set(PROFILE FALSE CACHE BOOL "Profiling (gprof)")
endmacro()
macro(check_deps)

View File

@ -1,5 +1,5 @@
if(BUILD_TESTS OR BUILD_TOOLS)
add_library(fullcore STATIC adminusers.c atomic.c config.c buffer.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.c modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c)
add_library(fullcore STATIC adminusers.c atomic.c config.c buffer.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.c modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c externcmd.c)
if(WITH_JEMALLOC)
target_link_libraries(fullcore ${JEMALLOC_LIBRARIES})
elseif(WITH_TCMALLOC)
@ -12,7 +12,7 @@ add_executable(maxscale atomic.c buffer.c spinlock.c gateway.c
gw_utils.c utils.c dcb.c load_utils.c session.c service.c server.c
poll.c config.c users.c hashtable.c dbusers.c thread.c gwbitmask.c
monitor.c adminusers.c secrets.c filter.c modutil.c hint.c
housekeeper.c memlog.c resultset.c)
housekeeper.c memlog.c resultset.c externcmd.c)
if(WITH_JEMALLOC)
target_link_libraries(maxscale ${JEMALLOC_LIBRARIES})

View File

@ -1728,6 +1728,9 @@ SERVER *server;
obj->element = server_alloc(address,
protocol,
atoi(port));
server_set_unique_name(obj->element, obj->object);
if (obj->element && monuser && monpw)
{
serverAddMonUser(obj->element,
@ -1936,6 +1939,8 @@ static char *monitor_params[] =
"servers",
"user",
"passwd",
"script",
"events",
"monitor_interval",
"detect_replication_lag",
"detect_stale_master",

View File

@ -1118,6 +1118,7 @@ getUsers(SERVICE *service, USERS *users)
MYSQL_DATABASE_MAXLEN;
int dbnames = 0;
int db_grants = 0;
char dbnm[MYSQL_DATABASE_MAXLEN+1];
if (serviceGetUser(service, &service_user, &service_passwd) == 0)
{
@ -1464,16 +1465,32 @@ getUsers(SERVICE *service, USERS *users)
*/
if (db_grants) {
/* we have dbgrants, store them */
bool havedb = false;
/* we have dbgrants, store them */
if(row[5]){
unsigned long *rowlen = mysql_fetch_lengths(result);
memcpy(dbnm,row[5],rowlen[5]);
memset(dbnm + rowlen[5],0,1);
havedb = true;
if(service->strip_db_esc) {
strip_escape_chars(dbnm);
LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG,
"[%s]: %s -> %s",
service->name,
row[5],
dbnm)));
}
}
if(service->optimize_wildcard && wildcard_db_grant(row[5]))
if(service->optimize_wildcard && havedb && wildcard_db_grant(row[5]))
{
rc = add_wildcard_users(users, row[0], row[1], password, row[4], row[5], service->resources);
rc = add_wildcard_users(users, row[0], row[1], password, row[4], dbnm, service->resources);
skygw_log_write(LOGFILE_DEBUG|LOGFILE_TRACE,"%s: Converted '%s' to %d individual database grants.",service->name,row[5],rc);
}
else
{
rc = add_mysql_users_with_host_ipv4(users, row[0], row[1], password, row[4], row[5]);
rc = add_mysql_users_with_host_ipv4(users, row[0], row[1], password, row[4], havedb ? dbnm : NULL);
}
} else {

169
server/core/externcmd.c Normal file
View File

@ -0,0 +1,169 @@
#include <externcmd.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
extern size_t log_ses_count[];
extern __thread log_info_t tls_log_info;
/**
* Tokenize a string into arguments suitable for a execvp call.
* @param args Argument string
* @param argv Array of char pointers to be filled with tokenized arguments
* @return 0 on success, -1 on error
*/
int tokenize_arguments(char* args, char** argv)
{
int i = 0;
bool quoted = false;
bool read = false;
bool escaped = false;
char *ptr,*start;
char qc;
start = args;
ptr = start;
while(*ptr != '\0' && i < MAXSCALE_EXTCMD_ARG_MAX)
{
if(escaped)
{
escaped = false;
}
else
{
if(*ptr == '\\')
{
escaped = true;
}
else if(quoted && !escaped && *ptr == qc) /** End of quoted string */
{
*ptr = '\0';
argv[i++] = strdup(start);
read = false;
quoted = false;
}
else if (!quoted)
{
if(isspace(*ptr))
{
*ptr = '\0';
if(read) /** New token */
{
argv[i++] = strdup(start);
read = false;
}
}
else if( *ptr == '\"' || *ptr == '\'')
{
/** New quoted token, strip quotes */
quoted = true;
qc = *ptr;
start = ptr + 1;
}
else if(!read)
{
start = ptr;
read = true;
}
}
}
ptr++;
}
if(read)
argv[i++] = strdup(start);
argv[i] = NULL;
return 0;
}
/**
* Allocate a new external command.
* The name and parameters are copied into the external command structure so
* the original memory can be freed if needed.
* @param command Command to execute with the parameters
* @return Pointer to new external command struct or NULL if an error occurred
*/
EXTERNCMD* externcmd_allocate(char* argstr)
{
EXTERNCMD* cmd;
if(argstr == NULL)
return NULL;
if((cmd = (EXTERNCMD*)malloc(sizeof(EXTERNCMD))) != NULL)
{
if(tokenize_arguments(argstr,cmd->parameters) == -1)
{
free(cmd);
return NULL;
}
if(access(cmd->parameters[0],F_OK) != 0)
{
skygw_log_write(LE,
"Error: Cannot find file: %s",
cmd->parameters[0]);
externcmd_free(cmd);
return NULL;
}
if(access(cmd->parameters[0],X_OK) != 0)
{
skygw_log_write(LE,
"Error: Cannot execute file: %s",
cmd->parameters[0]);
externcmd_free(cmd);
return NULL;
}
}
return cmd;
}
/**
* Free a previously allocated external command.
* @param cmd Command to free
*/
void externcmd_free(EXTERNCMD* cmd)
{
int i;
for(i = 0;cmd->parameters[i] != NULL;i++)
{
free(cmd->parameters[i]);
}
free(cmd);
}
/**
*Execute a command in a separate process.
*@param cmd Command to execute
*@return 0 on success, -1 on error.
*/
int externcmd_execute(EXTERNCMD* cmd)
{
int rval = 0;
pid_t pid;
pid = fork();
if(pid < 0)
{
skygw_log_write(LOGFILE_ERROR,"Error: Failed to execute command '%s', fork failed: [%d] %s",
cmd->parameters[0],errno,strerror(errno));
rval = -1;
}
else if(pid == 0)
{
/** Child process, execute command */
execvp(cmd->parameters[0],cmd->parameters);
_exit(1);
}
else
{
cmd->child = pid;
cmd->n_exec++;
LOGIF(LD,skygw_log_write(LD,"[monitor_exec_cmd] Forked child process %d : %s.",pid,cmd));
}
return rval;
}

View File

@ -258,7 +258,8 @@ char *
modutil_get_SQL(GWBUF *buf)
{
unsigned int len, length;
char *ptr, *dptr, *rval = NULL;
unsigned char *ptr;
char *dptr, *rval = NULL;
if (!modutil_is_SQL(buf) && !modutil_is_SQL_prepare(buf))
return rval;

View File

@ -28,6 +28,7 @@
* and monitor id
* 30/10/14 Massimiliano Pinto Addition of disable_master_failback parameter
* 07/11/14 Massimiliano Pinto Addition of monitor network timeouts
* 08/05/15 Markus Makela Moved common monitor variables to MONITOR struct
*
* @endverbatim
*/
@ -65,8 +66,6 @@ MONITOR *mon;
{
return NULL;
}
mon->state = MONITOR_STATE_ALLOC;
mon->name = strdup(name);
if ((mon->module = load_module(module, MODULE_MONITOR)) == NULL)
{
@ -74,13 +73,19 @@ MONITOR *mon;
LOGFILE_ERROR,
"Error : Unable to load monitor module '%s'.",
name)));
free(mon->name);
free(mon);
return NULL;
}
mon->state = MONITOR_STATE_ALLOC;
mon->name = strdup(name);
mon->handle = NULL;
mon->databases = NULL;
mon->password = NULL;
mon->read_timeout = DEFAULT_READ_TIMEOUT;
mon->write_timeout = DEFAULT_WRITE_TIMEOUT;
mon->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
mon->interval = MONITOR_INTERVAL;
spinlock_init(&mon->lock);
spinlock_acquire(&monLock);
mon->next = allMonitors;
allMonitors = mon;
@ -100,7 +105,7 @@ monitor_free(MONITOR *mon)
{
MONITOR *ptr;
mon->module->stopMonitor(mon->handle);
mon->module->stopMonitor(mon);
mon->state = MONITOR_STATE_FREED;
spinlock_acquire(&monLock);
if (allMonitors == mon)
@ -127,8 +132,10 @@ MONITOR *ptr;
void
monitorStart(MONITOR *monitor, void* params)
{
monitor->handle = (*monitor->module->startMonitor)(monitor->handle,params);
spinlock_acquire(&monitor->lock);
monitor->handle = (*monitor->module->startMonitor)(monitor,params);
monitor->state = MONITOR_STATE_RUNNING;
spinlock_release(&monitor->lock);
}
/**
@ -142,7 +149,7 @@ monitorStop(MONITOR *monitor)
if(monitor->state != MONITOR_STATE_STOPPED)
{
monitor->state = MONITOR_STATE_STOPPING;
monitor->module->stopMonitor(monitor->handle);
monitor->module->stopMonitor(monitor);
monitor->state = MONITOR_STATE_STOPPED;
}
}
@ -175,7 +182,31 @@ MONITOR *ptr;
void
monitorAddServer(MONITOR *mon, SERVER *server)
{
mon->module->registerServer(mon->handle, server);
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;
/** Server status is uninitialized */
db->mon_prev_status = -1;
/* pending status is updated by get_replication_tree */
db->pending_status = 0;
spinlock_acquire(&mon->lock);
if (mon->databases == NULL)
mon->databases = db;
else
{
ptr = mon->databases;
while (ptr->next != NULL)
ptr = ptr->next;
ptr->next = db;
}
spinlock_release(&mon->lock);
}
/**
@ -189,7 +220,8 @@ monitorAddServer(MONITOR *mon, SERVER *server)
void
monitorAddUser(MONITOR *mon, char *user, char *passwd)
{
mon->module->defaultUser(mon->handle, user, passwd);
mon->user = strdup(user);
mon->password = strdup(passwd);
}
/**
@ -209,7 +241,7 @@ MONITOR *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->module->diagnostics(dcb, ptr);
ptr = ptr->next;
}
spinlock_release(&monLock);
@ -227,7 +259,7 @@ 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);
monitor->module->diagnostics(dcb, monitor);
}
/**
@ -288,10 +320,7 @@ MONITOR *ptr;
void
monitorSetInterval (MONITOR *mon, unsigned long interval)
{
if (mon->module->setInterval != NULL) {
mon->interval = interval;
mon->module->setInterval(mon->handle, interval);
}
mon->interval = interval;
}
/**
@ -303,9 +332,55 @@ monitorSetInterval (MONITOR *mon, unsigned long interval)
*/
void
monitorSetNetworkTimeout(MONITOR *mon, int type, int value) {
if (mon->module->setNetworkTimeout != NULL) {
mon->module->setNetworkTimeout(mon->handle, type, value);
int max_timeout = (int)(mon->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(&mon->connect_timeout, &value, sizeof(int));
} else {
memcpy(&mon->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(&mon->read_timeout, &value, sizeof(int));
} else {
memcpy(&mon->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(&mon->write_timeout, &value, sizeof(int));
} else {
memcpy(&mon->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;
}
}
/**

View File

@ -66,12 +66,39 @@ int result, length, residual;
}
int
test2()
{
GWBUF *buffer;
char len = 128;
char query[129];
buffer = gwbuf_alloc(132);
ss_info_dassert((buffer != NULL),"Buffer should not be null");
memset(query,';',128);
memset(query+128,'\0',1);
*((unsigned char*)buffer->start) = len;
*((unsigned char*)buffer->start+1) = 0;
*((unsigned char*)buffer->start+2) = 0;
*((unsigned char*)buffer->start+3) = 1;
*((unsigned char*)buffer->start+4) = 0x03;
memcpy(buffer->start + 5,query,strlen(query));
char* result = modutil_get_SQL(buffer);
ss_dassert(strcmp(result,query) == 0);
gwbuf_free(buffer);
free(result);
ss_dfprintf(stderr, "\t..done\n");
return 0;
}
int main(int argc, char **argv)
{
int result = 0;
result += test1();
result += test2();
exit(result);
}

View File

@ -0,0 +1,20 @@
#ifndef _EXTERN_CMD_HG
#define _EXTERN_CMD_HG
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <skygw_utils.h>
#include <log_manager.h>
#define MAXSCALE_EXTCMD_ARG_MAX 256
typedef struct extern_cmd_t{
char* parameters[MAXSCALE_EXTCMD_ARG_MAX]; /*< Command arguments */
int n_exec; /*< Number of times executed */
pid_t child; /*< PID of the child process */
}EXTERNCMD;
EXTERNCMD* externcmd_allocate(char* argstr);
void externcmd_free(EXTERNCMD* cmd);
int externcmd_execute(EXTERNCMD* cmd);
#endif

View File

@ -17,6 +17,7 @@
*
* Copyright MariaDB Corporation Ab 2013-2014
*/
#include <mysql.h>
#include <server.h>
#include <dcb.h>
#include <resultset.h>
@ -69,19 +70,14 @@
typedef struct {
void *(*startMonitor)(void *, void*);
void (*stopMonitor)(void *);
void (*registerServer)(void *, SERVER *);
void (*unregisterServer)(void *, SERVER *);
void (*defaultUser)(void *, char *, char *);
void (*diagnostics)(DCB *, void *);
void (*setInterval)(void *, size_t);
void (*setNetworkTimeout)(void *, int, int);
} MONITOR_OBJECT;
/**
* The monitor API version number. Any change to the monitor module API
* must change these versions usign the rules defined in modinfo.h
*/
#define MONITOR_VERSION {2, 0, 0}
#define MONITOR_VERSION {3, 0, 0}
/** Monitor's poll frequency */
#define MON_BASE_INTERVAL_MS 100
@ -112,12 +108,46 @@ typedef enum
#define DEFAULT_READ_TIMEOUT 1
#define DEFAULT_WRITE_TIMEOUT 2
#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
/**
* The linked list of servers that are being monitored by the 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;
/**
* Representation of the running monitor.
*/
typedef struct monitor {
char *name; /**< The name of the monitor module */
char* user; /*< Monitor username */
char* password; /*< Monitor password */
SPINLOCK lock;
MONITOR_SERVERS* databases; /*< List of databases the monitor monitors */
monitor_state_t state; /**< The state of the 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.
*/
MONITOR_OBJECT *module; /**< The "monitor object" */
void *handle; /**< Handle returned from startMonitor */
size_t interval; /**< The monitor interval */

View File

@ -50,6 +50,7 @@
#include <sys/time.h>
#include <regex.h>
#include <string.h>
#include <atomic.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
@ -304,7 +305,7 @@ char *remote, *userName;
sprintf(my_session->filename, "%s.%d",
my_instance->filebase,
my_instance->sessions);
my_instance->sessions++;
atomic_add(&my_instance->sessions,1);
if (my_session->active)
{

View File

@ -23,7 +23,7 @@
#include <log_manager.h>
#include <string.h>
#include <regex.h>
#include <atomic.h>
#include "maxconfig.h"
/** Defined in log_manager.cc */
@ -97,6 +97,7 @@ typedef struct {
*/
typedef struct {
DOWNSTREAM down; /* The downstream filter */
SPINLOCK lock;
int no_change; /* No. of unchanged requests */
int replacements; /* No. of changed requests */
int active; /* Is filter active */
@ -356,13 +357,17 @@ char *sql, *newsql;
{
queue = modutil_replace_SQL(queue, newsql);
queue = gwbuf_make_contiguous(queue);
spinlock_acquire(&my_session->lock);
log_match(my_instance,my_instance->match,sql,newsql);
spinlock_release(&my_session->lock);
free(newsql);
my_session->replacements++;
}
else
{
spinlock_acquire(&my_session->lock);
log_nomatch(my_instance,my_instance->match,sql);
spinlock_release(&my_session->lock);
my_session->no_change++;
}
free(sql);

View File

@ -19,6 +19,7 @@
#include <filter.h>
#include <modinfo.h>
#include <modutil.h>
#include <atomic.h>
/**
* @file testfilter.c - a very simple test filter.
@ -145,7 +146,7 @@ TEST_SESSION *my_session;
if ((my_session = calloc(1, sizeof(TEST_SESSION))) != NULL)
{
my_instance->sessions++;
atomic_add(&my_instance->sessions,1);
my_session->count = 0;
}

View File

@ -47,6 +47,7 @@
#include <time.h>
#include <sys/time.h>
#include <regex.h>
#include <atomic.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
@ -296,7 +297,7 @@ char *remote, *user;
}
sprintf(my_session->filename, "%s.%d", my_instance->filebase,
my_instance->sessions);
my_instance->sessions++;
atomic_add(&my_instance->sessions,1);
my_session->top = (TOPNQ **)calloc(my_instance->topN + 1,
sizeof(TOPNQ *));
for (i = 0; i < my_instance->topN; i++)

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,404 @@
/*
* 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;
int slen = strlen(str);
while(ptr && slen < len)
{
if(!first)
{
strncat(str,",",len);
}
first = false;
strncat(str,ptr->server->unique_name,len);
ptr = ptr->next;
slen = strlen(str);
}
}
/**
* 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,67 @@ 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;
handle->script = NULL;
handle->master = NULL;
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 +179,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 +195,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 +213,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 +230,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 +260,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 +301,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 +313,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 +326,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 +356,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 +394,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 +421,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

View File

@ -287,7 +287,7 @@ int gw_read_backend_handshake(
pthread_self(),
conn->owner_dcb->fd,
pthread_self())));
while(head = gwbuf_consume(head, GWBUF_LENGTH(head)));
while((head = gwbuf_consume(head, GWBUF_LENGTH(head))));
return 1;
}

View File

@ -574,7 +574,7 @@ typedef enum skygw_chk_t {
#if defined(FAKE_CODE)
bool conn_open[10240];
static bool conn_open[10240];
#endif /* FAKE_CODE */
#endif /* SKYGW_DEBUG_H */