Merge branch '2.0' into develop

This commit is contained in:
Markus Mäkelä 2016-12-22 13:40:16 +02:00
commit 520d28b27d
13 changed files with 241 additions and 89 deletions

View File

@ -14,6 +14,7 @@
as JSON objects (beta level functionality).
For more details, please refer to:
* [MariaDB MaxScale 2.0.3 Release Notes](Release-Notes/MaxScale-2.0.3-Release-Notes.md)
* [MariaDB MaxScale 2.0.2 Release Notes](Release-Notes/MaxScale-2.0.2-Release-Notes.md)
* [MariaDB MaxScale 2.0.1 Release Notes](Release-Notes/MaxScale-2.0.1-Release-Notes.md)
* [MariaDB MaxScale 2.0.0 Release Notes](Release-Notes/MaxScale-2.0.0-Release-Notes.md)

View File

@ -622,6 +622,10 @@ serverB | 15 | 27%
serverC | 10 | 18%
serverD | 20 | 36%
_**Note**: If the value of the weighting parameter of an individual server is
zero or the relative weight rounds down to zero, no queries will be routed to
that server as long as a server with a positive weight is available._
Here is an excerpt from an example configuration with the `serv_weight` parameter
used as the weighting parameter.

View File

@ -6,8 +6,9 @@ This document describes the changes in release 2.0.3, when compared to
release [2.0.2](MaxScale-2.0.2-Release-Notes.md).
If you are upgrading from release 1.4.4, please also read the release
notes of release [2.0.0](./MaxScale-2.0.0-Release-Notes.md) and
release [2.0.1](./MaxScale-2.0.1-Release-Notes.md).
notes of release [2.0.0](./MaxScale-2.0.0-Release-Notes.md),
release [2.0.1](./MaxScale-2.0.1-Release-Notes.md) and
release [2.0.2](./MaxScale-2.0.2-Release-Notes.md).
For any problems you encounter, please submit a bug report at
[Jira](https://jira.mariadb.org).
@ -22,9 +23,18 @@ support systemd.
## Bug fixes
[Here](https://jira.mariadb.org/issues/?jql=project%20%3D%20MXS%20AND%20issuetype%20%3D%20Bug%20AND%20status%20%3D%20Closed%20AND%20fixVersion%20%3D%202.0.3)
is a list of bugs fixed since the release of MaxScale 2.0.1.
is a list of bugs fixed since the release of MaxScale 2.0.2.
* [MXS-1048](https://jira.mariadb.org/browse/MXS-1048): ShemaRouter can't handle backquoted database names
* [MXS-1047](https://jira.mariadb.org/browse/MXS-1047): Batch inserts through Maxscale with C/J stall
* [MXS-1045](https://jira.mariadb.org/browse/MXS-1045): Defunct processes after maxscale have executed script during failover
* [MXS-1044](https://jira.mariadb.org/browse/MXS-1044): Init-Script for SLES 11 displays error messages when called
* [MXS-1043](https://jira.mariadb.org/browse/MXS-1043): Reading last insert id from @@identity variable does not work with maxscale
* [MXS-1033](https://jira.mariadb.org/browse/MXS-1033): maxscale crushes on maxadmin request
* [MXS-1026](https://jira.mariadb.org/browse/MXS-1026): Crash with NullAuth authenticator
* [MXS-1009](https://jira.mariadb.org/browse/MXS-1009): maxinfo sigsegv in spinlock_release
* [MXS-964](https://jira.mariadb.org/browse/MXS-964): Fatal: MaxScale 2.0.1 received fatal signal 6
* [MXS-956](https://jira.mariadb.org/browse/MXS-956): Maxscale crash: Removing DCB 0x7fbf94016760 but was in state DCB_STATE_DISCONNECTED which is not legal for a call to dcb_close
## Known Issues and Limitations
@ -45,4 +55,3 @@ from the version of MaxScale. For instance, the tag of version `X.Y.Z` of MaxSca
is `maxscale-X.Y.Z`.
The source code is available [here](https://github.com/mariadb-corporation/MaxScale).

View File

@ -31,6 +31,8 @@ issues and communicate with the MaxScale community.
- Email: maxscale@googlegroups.com
- Forum: http://groups.google.com/forum/#!forum/maxscale
We're also on the #maria and #maxscale channels on FreeNode.
Please report all feature requests, improvements and bugs in the [MariaDB Jira](https://jira.mariadb.org/projects/MXS/issues).
# Documentation

View File

@ -5,7 +5,7 @@
set(MAXSCALE_VERSION_MAJOR "2" CACHE STRING "Major version")
set(MAXSCALE_VERSION_MINOR "0" CACHE STRING "Minor version")
set(MAXSCALE_VERSION_PATCH "2" CACHE STRING "Patch version")
set(MAXSCALE_VERSION_PATCH "3" CACHE STRING "Patch version")
# This should only be incremented if a package is rebuilt
set(MAXSCALE_BUILD_NUMBER 1 CACHE STRING "Release number")

View File

@ -1,24 +1,29 @@
# Check which init.d script to install
find_file(RPM_FNC functions PATHS /etc/rc.d/init.d)
find_file(DEB_FNC init-functions PATHS /lib/lsb)
find_file(SLES_FNC SuSE-release PATHS /etc)
if(${RPM_FNC} MATCHES "NOTFOUND" AND ${DEB_FNC} MATCHES "NOTFOUND")
message(FATAL_ERROR "Cannot find required init-functions in /lib/lsb/ or /etc/rc.d/init.d/, please confirm that your system files are OK.")
elseif(${RPM_FNC} MATCHES "NOTFOUND")
set(HAVE_LSB_FUNCTIONS TRUE CACHE BOOL "If init.d script uses /lib/lsb/init-functions instead of /etc/rc.d/init.d/functions.")
if(EXISTS ${RPM_FNC})
set(USE_RPM TRUE CACHE BOOL "If init.d script uses /lib/lsb/init-functions instead of /etc/rc.d/init.d/functions.")
elseif(EXISTS ${SLES_FNC})
set(USE_SLES TRUE CACHE BOOL "SLES11 has reduced /lib/lsb/init-functions and needs a special init-script")
elseif(EXISTS ${DEB_FNC})
set(USE_DEB TRUE CACHE BOOL "If init.d script uses /lib/lsb/init-functions instead of /etc/rc.d/init.d/functions.")
else()
set(HAVE_LSB_FUNCTIONS FALSE CACHE BOOL "If init.d script uses /lib/lsb/init-functions instead of /etc/rc.d/init.d/functions.")
message(FATAL_ERROR "Cannot find required init-functions in /lib/lsb/ or /etc/rc.d/init.d/, please confirm that your system files are OK.")
endif()
if(USE_DEB)
configure_file(${CMAKE_SOURCE_DIR}/etc/ubuntu/init.d/maxscale.in ${CMAKE_BINARY_DIR}/maxscale @ONLY)
elseif(USE_RPM)
configure_file(${CMAKE_SOURCE_DIR}/etc/init.d/maxscale.in ${CMAKE_BINARY_DIR}/maxscale @ONLY)
elseif(USE_SLES)
configure_file(${CMAKE_SOURCE_DIR}/etc/sles11/init.d/maxscale.in ${CMAKE_BINARY_DIR}/maxscale @ONLY)
endif()
configure_file(${CMAKE_SOURCE_DIR}/etc/maxscale.conf.in ${CMAKE_BINARY_DIR}/maxscale.conf @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/etc/maxscale.service.in ${CMAKE_BINARY_DIR}/maxscale.service @ONLY)
if(HAVE_LSB_FUNCTIONS)
configure_file(${CMAKE_SOURCE_DIR}/etc/ubuntu/init.d/maxscale.in ${CMAKE_BINARY_DIR}/maxscale @ONLY)
else()
configure_file(${CMAKE_SOURCE_DIR}/etc/init.d/maxscale.in ${CMAKE_BINARY_DIR}/maxscale @ONLY)
endif()
if(PACKAGE)
message(STATUS "maxscale.conf will unpack to: /etc/ld.so.conf.d")
message(STATUS "startup scripts will unpack to to: /etc/init.d")

164
etc/sles11/init.d/maxscale.in Executable file
View File

@ -0,0 +1,164 @@
#!/bin/bash
#
# maxscale: The MariaDB Corporation MaxScale database proxy
#
# description: MaxScale provides database specific proxy functionality
#
# processname: maxscale
#
### BEGIN INIT INFO
# Provides: maxscale
# Required-Start: $syslog $local_fs
# Required-Stop: $syslog $local_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: The maxscale database proxy
# Description: MaxScale is a database proxy server that can be used to front end
# database clusters offering different routing, filtering and protocol choices
### END INIT INFO
#############################################
# MaxScale HOME, PIDFILE, LIB
#############################################
export MAXSCALE_PIDFILE=@MAXSCALE_VARDIR@/run/maxscale/maxscale.pid
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:@CMAKE_INSTALL_PREFIX@/@MAXSCALE_LIBDIR@/maxscale
###############################
# LSB Exit codes (non-Status)
###############################
_RETVAL_GENERIC=1
_RETVAL_NOT_INSTALLED=5
_RETVAL_NOT_RUNNING=7
###############################
# LSB Status action Exit codes
###############################
_RETVAL_STATUS_OK=0
_RETVAL_STATUS_NOT_RUNNING=3
# Sanity checks.
[ -x @CMAKE_INSTALL_PREFIX@/@MAXSCALE_BINDIR@/maxscale ] || exit $_RETVAL_NOT_INSTALLED
# Source additional command line arguments.
[ -f /etc/default/maxscale ] && . /etc/default/maxscale
#################################
# stop/start/status related vars
#################################
NAME=maxscale
DAEMON=@CMAKE_INSTALL_PREFIX@/@MAXSCALE_BINDIR@/maxscale
DAEMON_OPTS="--user=maxscale $MAXSCALE_OPTIONS"
# Source function library.
. /lib/lsb/init-functions
# we can rearrange this easily
processname=maxscale
servicename=maxscale
RETVAL=0
start() {
if [ ! -d @MAXSCALE_VARDIR@/log/maxscale ]
then
mkdir -p @MAXSCALE_VARDIR@/log/maxscale
fi
if [ ! -d @MAXSCALE_VARDIR@/cache/maxscale ]
then
mkdir -p @MAXSCALE_VARDIR@/cache/maxscale
fi
if [ ! -d @MAXSCALE_VARDIR@/lib/maxscale ]
then
mkdir -p @MAXSCALE_VARDIR@/lib/maxscale
fi
if [ ! -d @MAXSCALE_VARDIR@/run/maxscale ]
then
mkdir -p @MAXSCALE_VARDIR@/run/maxscale
fi
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/log/maxscale
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/lib/maxscale
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/cache/maxscale
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/run/maxscale
chmod 0755 @MAXSCALE_VARDIR@/log/maxscale
chmod 0755 @MAXSCALE_VARDIR@/lib/maxscale
chmod 0755 @MAXSCALE_VARDIR@/cache/maxscale
chmod 0755 @MAXSCALE_VARDIR@/run/maxscale
ulimit -HSn 65535
echo -n "Starting MaxScale"
start_daemon -p "$MAXSCALE_PIDFILE" $DAEMON $DAEMON_OPTS 2> /dev/null > /dev/null
sleep 2
checkproc $DAEMON
rc_status -v
}
stop() {
echo -n "Stopping MaxScale"
maxscale_wait_stop
rc_status -v
}
reload() {
echo -n "Reloading MaxScale"
kill -HUP $(cat "$MAXSCALE_PIDFILE")
rc_status -v
}
maxscale_wait_stop() {
PIDTMP=$(pidofproc -p "$MAXSCALE_PIDFILE" "$DAEMON")
kill -TERM "${PIDTMP:-}" 2> /dev/null;
if [ -n "${PIDTMP:-}" ] && kill -0 "${PIDTMP:-}" 2> /dev/null; then
local i=0
while kill -0 "${PIDTMP:-}" 2> /dev/null; do
if [ $i = '60' ]; then
break
STATUS=2
fi
[ "$VERBOSE" != no ] && echo -n "."
sleep 1
i=$(($i+1))
done
return $STATUS
else
return $STATUS
fi
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
status)
# return 0 on success
# return 3 on any error
echo -n "Checking MaxScale"
checkproc $DAEMON
rc_status -v
;;
restart)
stop
start
;;
reload)
reload
RETVAL=$?
;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload}"
;;
esac
exit $RETVAL

View File

@ -12,7 +12,7 @@ respawn
# respawn limit 2 5
# Unlimited open files
limit nofile unlimited unlimited
limit nofile 65535 65535
# Make sure /var/run/maxscale exists
pre-start exec /usr/bin/install -d -o maxscale -g maxscale @MAXSCALE_VARDIR@/run/maxscale

View File

@ -1305,6 +1305,7 @@ static void handleError(ROUTER *instance, void *router_session,
if (!rses_begin_locked_router_action(rses))
{
/** Session is already closed */
problem_dcb->dcb_errhandle_called = true;
*succp = false;
return;
}
@ -1327,15 +1328,17 @@ static void handleError(ROUTER *instance, void *router_session,
}
session = problem_dcb->session;
bool close_dcb = true;
backend_ref_t *bref = get_bref_from_dcb(rses, problem_dcb);
if (session == NULL || rses == NULL)
if (session == NULL)
{
MXS_ERROR("Session of DCB %p is NULL, won't close the DCB.", problem_dcb);
ss_dassert(false);
*succp = false;
}
else if (DCB_ROLE_CLIENT_HANDLER == problem_dcb->dcb_role)
{
dcb_close(problem_dcb);
*succp = false;
}
else
@ -1383,6 +1386,9 @@ static void handleError(ROUTER *instance, void *router_session,
if (bref != NULL)
{
CHK_BACKEND_REF(bref);
RW_CHK_DCB(bref, problem_dcb);
dcb_close(problem_dcb);
RW_CLOSE_BREF(bref);
close_failed_bref(bref, true);
}
else
@ -1399,21 +1405,13 @@ static void handleError(ROUTER *instance, void *router_session,
*succp = handle_error_new_connection(inst, &rses, problem_dcb, errmsgbuf);
}
RW_CHK_DCB(bref, problem_dcb);
if (bref)
{
/** This is a valid DCB for a backend ref */
if (!BREF_IS_IN_USE(bref) || bref->bref_dcb != problem_dcb)
if (BREF_IS_IN_USE(bref) && bref->bref_dcb == problem_dcb)
{
/** The backend is closed or the reference was replaced */
dcb_close(problem_dcb);
RW_CLOSE_BREF(bref);
}
else
{
MXS_ERROR("Backend '%s' is still in use and points to the problem DCB. Not closing.",
ss_dassert(false);
MXS_ERROR("Backend '%s' is still in use and points to the problem DCB.",
bref->ref->server->unique_name);
}
}
@ -1425,29 +1423,13 @@ static void handleError(ROUTER *instance, void *router_session,
MXS_ERROR("DCB connected to '%s' is not in use by the router "
"session, not closing it. DCB is in state '%s'",
remote, STRDCBSTATE(problem_dcb->state));
MXS_ERROR("Backends currently in use:");
for (int i = 0; i < rses->rses_nbackends; i++)
{
dcb_state_t state = DCB_STATE_UNDEFINED;
if (BREF_IS_IN_USE(&rses->rses_backend_ref[i]))
{
state = rses->rses_backend_ref[i].bref_dcb->state;
}
MXS_ERROR("%p: %s - %p", &rses->rses_backend_ref[i], STRDCBSTATE(state),
rses->rses_backend_ref[i].bref_dcb);
}
}
close_dcb = false;
break;
}
case ERRACT_REPLY_CLIENT:
{
handle_error_reply_client(session, rses, problem_dcb, errmsgbuf);
close_dcb = false;
*succp = false; /*< no new backend servers were made available */
break;
}
@ -1459,12 +1441,6 @@ static void handleError(ROUTER *instance, void *router_session,
}
}
if (close_dcb)
{
RW_CHK_DCB(bref, problem_dcb);
dcb_close(problem_dcb);
RW_CLOSE_BREF(bref);
}
rses_end_locked_router_action(rses);
}
@ -1594,6 +1570,8 @@ static bool handle_error_new_connection(ROUTER_INSTANCE *inst,
/**
* If bref == NULL it has been replaced already with another one.
*
* NOTE: This can never happen.
*/
if ((bref = get_bref_from_dcb(myrses, backend_dcb)) == NULL)
{
@ -1626,25 +1604,10 @@ static bool handle_error_new_connection(ROUTER_INSTANCE *inst,
}
}
RW_CHK_DCB(bref, backend_dcb);
dcb_close(backend_dcb);
RW_CLOSE_BREF(bref);
close_failed_bref(bref, false);
/**
* Error handler is already called for this DCB because
* it's not polling anymore. It can be assumed that
* it succeed because rses isn't closed.
*/
if (backend_dcb->state != DCB_STATE_POLLING)
{
return true;
}
/**
* Remove callback because this DCB won't be used
* unless it is reconnected later, and then the callback
* is set again.
*/
dcb_remove_callback(backend_dcb, DCB_REASON_NOT_RESPONDING,
&router_handle_state_switch, (void *)bref);
max_nslaves = rses_get_max_slavecount(myrses, myrses->rses_nbackends);
max_slave_rlag = rses_get_max_replication_lag(myrses);
/**

View File

@ -31,15 +31,15 @@ MXS_BEGIN_DECLS
*/
#include <maxscale/protocol/mysql.h>
#define RW_CHK_DCB(bref, dcb) \
#define RW_CHK_DCB(b, d) \
do{ \
if(dcb->state == DCB_STATE_DISCONNECTED){ \
if(d->state == DCB_STATE_DISCONNECTED){ \
MXS_NOTICE("DCB was closed on line %d and another attempt to close it is made on line %d." , \
(bref) ? (bref)->closed_at : -1, __LINE__); \
(b) ? (b)->closed_at : -1, __LINE__); \
} \
}while (false)
#define RW_CLOSE_BREF(b) do{ if (bref){ bref->closed_at = __LINE__; } } while (false)
#define RW_CLOSE_BREF(b) do{ if (b){ (b)->closed_at = __LINE__; } } while (false)
/*
* The following are implemented in rwsplit_mysql.c

View File

@ -1175,6 +1175,14 @@ bool handle_master_is_target(ROUTER_INSTANCE *inst, ROUTER_CLIENT_SES *rses,
if (rses->rses_config.rw_master_failure_mode == RW_ERROR_ON_WRITE)
{
succp = send_readonly_error(rses->client_dcb);
if (rses->rses_master_ref && BREF_IS_IN_USE(rses->rses_master_ref))
{
close_failed_bref(rses->rses_master_ref, true);
RW_CHK_DCB(rses->rses_master_ref, rses->rses_master_ref->bref_dcb);
dcb_close(rses->rses_master_ref->bref_dcb);
RW_CLOSE_BREF(rses->rses_master_ref);
}
}
else
{

View File

@ -528,8 +528,9 @@ char* get_shard_target_name(ROUTER_INSTANCE* router,
query = modutil_get_SQL(buffer);
if ((tmp = strcasestr(query, "from")))
{
char *saved, *tok = strtok_r(tmp, " ;", &saved);
tok = strtok_r(NULL, " ;", &saved);
const char *delim = "` \n\t;";
char *saved, *tok = strtok_r(tmp, delim, &saved);
tok = strtok_r(NULL, delim, &saved);
ss_dassert(tok != NULL);
tmp = (char*) hashtable_fetch(ht, tok);

View File

@ -34,16 +34,20 @@ bool extract_database(GWBUF* buf, char* str)
/** Copy database name from MySQL packet to session */
if (qc_get_operation(buf) == QUERY_OP_CHANGE_DB)
{
const char *delim = "` \n\t;";
query = modutil_get_SQL(buf);
tok = strtok_r(query, " ;", &saved);
tok = strtok_r(query, delim, &saved);
if (tok == NULL || strcasecmp(tok, "use") != 0)
{
MXS_ERROR("extract_database: Malformed change database packet.");
MXS_ERROR("extract_database: Malformed chage database packet.");
succp = false;
goto retblock;
}
tok = strtok_r(NULL, " ;", &saved);
tok = strtok_r(NULL, delim, &saved);
if (tok == NULL)
{
MXS_ERROR("extract_database: Malformed change database packet.");
@ -51,16 +55,7 @@ bool extract_database(GWBUF* buf, char* str)
goto retblock;
}
size_t len = strlen(tok);
if (len > MYSQL_DATABASE_MAXLEN)
{
MXS_ERROR("extract_database: Malformed change database packet, "
"too long database name.");
succp = false;
goto retblock;
}
strcpy(str, tok);
strncpy(str, tok, MYSQL_DATABASE_MAXLEN);
}
else
{