Merge branch '2.2' into develop

This commit is contained in:
Johan Wikman
2018-03-09 21:00:16 +02:00
9 changed files with 186 additions and 122 deletions

View File

@ -1,4 +1,4 @@
# MariaDB MaxScale 2.2.3 Release Notes
# MariaDB MaxScale 2.2.3 Release Notes -- 2018-03-09
Release 2.2.3 is a GA release.

View File

@ -1,5 +1,8 @@
set(LIBMICROHTTPD_URL "http://ftpmirror.gnu.org/libmicrohttpd/libmicrohttpd-0.9.54.tar.gz"
CACHE STRING "GNU libmicrochttpd source code")
ExternalProject_Add(libmicrohttpd
URL http://ftpmirror.gnu.org/libmicrohttpd/libmicrohttpd-0.9.54.tar.gz
URL ${LIBMICROHTTPD_URL}
SOURCE_DIR ${CMAKE_BINARY_DIR}/libmicrohttpd/
CONFIGURE_COMMAND ${CMAKE_BINARY_DIR}/libmicrohttpd//configure --prefix=${CMAKE_BINARY_DIR}/libmicrohttpd/ --enable-shared --with-pic --libdir=${CMAKE_BINARY_DIR}/libmicrohttpd/lib/
BINARY_DIR ${CMAKE_BINARY_DIR}/libmicrohttpd/

View File

@ -237,6 +237,24 @@ bool serviceAddBackend(SERVICE *service, SERVER *server);
*/
bool serviceHasBackend(SERVICE *service, SERVER *server);
/**
* @brief Find listener with specified properties.
*
* @param service Service to check
* @param socket Listener socket path
* @param address Listener address
* @param port Listener port number
*
* @note Either socket should be NULL and port non-zero or socket
* non-NULL and port zero.
*
* @return True if service has the listener
*/
SERV_LISTENER* service_find_listener(SERVICE* service,
const char* socket,
const char* address,
unsigned short port);
/**
* @brief Check if a service has a listener
*

View File

@ -3499,6 +3499,15 @@ int create_new_listener(CONFIG_CONTEXT *obj)
char *authenticator_options = config_get_value(obj->parameters, CN_AUTHENTICATOR_OPTIONS);
if (raw_service_name && protocol && (socket || port))
{
if (socket && port)
{
MXS_ERROR("Creation of listener '%s' for service '%s' failed, because "
"both 'socket' and 'port' are defined. Only either one is allowed.",
obj->object, raw_service_name);
error_count++;
}
else
{
char service_name[strlen(raw_service_name) + 1];
strcpy(service_name, raw_service_name);
@ -3507,13 +3516,25 @@ int create_new_listener(CONFIG_CONTEXT *obj)
SERVICE *service = service_find(service_name);
if (service)
{
SERV_LISTENER *listener;
SSL_LISTENER *ssl_info = make_ssl_structure(obj, true, &error_count);
if (socket)
{
if (serviceHasListener(service, obj->object, protocol, address, 0))
if (address)
{
MXS_ERROR("Listener '%s' for service '%s' already has a socket at '%s.",
obj->object, service_name, socket);
MXS_WARNING("In the definition of the listener `%s', the value of "
"'address' lacks meaning as the listener listens on a "
"domain socket ('%s') and not on a port.",
obj->object, socket);
}
listener = service_find_listener(service, socket, NULL, 0);
if (listener)
{
MXS_ERROR("Creation of listener '%s' for service '%s' failed, because "
"listener '%s' already listens on the socket '%s'.",
obj->object, raw_service_name, listener->name, socket);
error_count++;
}
else
@ -3525,12 +3546,13 @@ int create_new_listener(CONFIG_CONTEXT *obj)
if (port)
{
if (serviceHasListener(service, obj->object, protocol, address, atoi(port)))
listener = service_find_listener(service, NULL, address, atoi(port));
if (listener)
{
MXS_ERROR("Listener '%s', for service '%s', already have port %s.",
obj->object,
service_name,
port);
MXS_ERROR("Creation of listener '%s' for service '%s' failed, because "
"listener '%s' already listens on the port %s.",
obj->object, raw_service_name, listener->name, port);
error_count++;
}
else
@ -3552,10 +3574,11 @@ int create_new_listener(CONFIG_CONTEXT *obj)
error_count++;
}
}
}
else
{
MXS_ERROR("Listener '%s' is missing a required parameter. A Listener "
"must have a service, port and protocol defined.", obj->object);
"must have a service, protocol and port (or socket) defined.", obj->object);
error_count++;
}

View File

@ -16,7 +16,6 @@
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <maxscale/debug.h>
#include <maxscale/log_manager.h>
#include "internal/worker.hh"
@ -27,11 +26,9 @@ namespace
static struct
{
bool initialized;
int pipe_flags;
} this_unit =
{
false,
O_NONBLOCK | O_CLOEXEC
false
};
}
@ -67,63 +64,6 @@ bool MessageQueue::init()
{
ss_dassert(!this_unit.initialized);
/* From "man 7 pipe"
* ----
*
* O_NONBLOCK enabled, n <= PIPE_BUF
* If there is room to write n bytes to the pipe, then write(2)
* succeeds immediately, writing all n bytes; otherwise write(2)
* fails, with errno set to EAGAIN.
*
* ... (On Linux, PIPE_BUF is 4096 bytes.)
*
* ----
*
* As O_NONBLOCK is set and the messages are less than 4096 bytes,
* O_DIRECT should not be needed and we should be safe without it.
*
* However, to be in the safe side, if we run on kernel version >= 3.4
* we use it.
*/
utsname u;
if (uname(&u) == 0)
{
char* p;
char* zMajor = strtok_r(u.release, ".", &p);
char* zMinor = strtok_r(NULL, ".", &p);
if (zMajor && zMinor)
{
int major = atoi(zMajor);
int minor = atoi(zMinor);
if (major >= 3 && minor >= 4)
{
// O_DIRECT for pipes is supported from kernel 3.4 onwards.
this_unit.pipe_flags |= O_DIRECT;
}
else
{
MXS_NOTICE("O_DIRECT is not supported for pipes on Linux kernel %s "
"(supported from version 3.4 onwards), NOT using it.",
u.release);
}
}
else
{
MXS_WARNING("Syntax used in utsname.release seems to have changed, "
"not able to figure out current kernel version. Assuming "
"O_DIRECT is not supported for pipes.");
}
}
else
{
MXS_WARNING("uname() failed, assuming O_DIRECT is not supported for pipes: %s",
mxs_strerror(errno));
}
this_unit.initialized = true;
return this_unit.initialized;
@ -141,10 +81,45 @@ MessageQueue* MessageQueue::create(Handler* pHandler)
{
ss_dassert(this_unit.initialized);
/* From "man 7 pipe"
* ----
*
* O_NONBLOCK enabled, n <= PIPE_BUF
* If there is room to write n bytes to the pipe, then write(2)
* succeeds immediately, writing all n bytes; otherwise write(2)
* fails, with errno set to EAGAIN.
*
* ... (On Linux, PIPE_BUF is 4096 bytes.)
*
* ----
*
* As O_NONBLOCK is set and the messages are less than 4096 bytes,
* O_DIRECT should not be needed and we should be safe without it.
*
* However, to be in the safe side, we first try whether it is supported,
* and if not, we create the pipe without O_DIRECT.
*/
MessageQueue* pThis = NULL;
int fds[2];
if (pipe2(fds, this_unit.pipe_flags) == 0)
int rv = pipe2(fds, O_NONBLOCK | O_CLOEXEC | O_DIRECT);
if ((rv != 0) && (errno == EINVAL))
{
// Ok, apparently the kernel does not support O_DIRECT. Let's try without.
rv = pipe2(fds, O_NONBLOCK | O_CLOEXEC);
if (rv == 0)
{
// Succeeded, so apparently it was the missing support for O_DIRECT.
MXS_WARNING("Platform does not support O_DIRECT in conjunction with pipes, "
"using without.");
}
}
if (rv == 0)
{
int read_fd = fds[0];
int write_fd = fds[1];

View File

@ -806,6 +806,46 @@ SERV_LISTENER* serviceCreateListener(SERVICE *service, const char *name, const c
return proto;
}
SERV_LISTENER* service_find_listener(SERVICE* service,
const char* socket,
const char* address, unsigned short port)
{
LISTENER_ITERATOR iter;
for (SERV_LISTENER *listener = listener_iterator_init(service, &iter);
listener; listener = listener_iterator_next(&iter))
{
if (listener_is_active(listener))
{
bool is_same_port = false;
if (port && (port == listener->port) &&
((address && listener->address && strcmp(listener->address, address) == 0) ||
(address == NULL && listener->address == NULL)))
{
is_same_port = true;
}
bool is_same_socket = false;
if (!is_same_port)
{
if (socket && listener->address && strcmp(listener->address, socket) == 0)
{
is_same_socket = true;
}
}
if (is_same_port || is_same_socket)
{
return listener;
}
}
}
return NULL;
}
/**
* Check if a protocol/port pair is part of the service
*

View File

@ -228,7 +228,6 @@ bool Worker::init()
{
ss_dassert(!this_unit.initialized);
this_unit.n_workers = config_threadcount();
this_unit.number_poll_spins = config_nbpolls();
this_unit.max_poll_sleep = config_pollsleep();
@ -236,33 +235,37 @@ bool Worker::init()
if (this_unit.epoll_listener_fd != -1)
{
this_unit.ppWorkers = new (std::nothrow) Worker* [this_unit.n_workers] (); // Zero initialized array
int n_workers = config_threadcount();
Worker** ppWorkers = new (std::nothrow) Worker* [n_workers] (); // Zero initialized array
if (this_unit.ppWorkers)
if (ppWorkers)
{
for (int i = 0; i < this_unit.n_workers; ++i)
for (int i = 0; i < n_workers; ++i)
{
Worker* pWorker = Worker::create(i, this_unit.epoll_listener_fd);
if (pWorker)
{
this_unit.ppWorkers[i] = pWorker;
ppWorkers[i] = pWorker;
}
else
{
for (int j = i - 1; j >= 0; --j)
{
delete this_unit.ppWorkers[j];
delete ppWorkers[j];
}
delete this_unit.ppWorkers;
this_unit.ppWorkers = NULL;
delete [] ppWorkers;
ppWorkers = NULL;
break;
}
}
if (this_unit.ppWorkers)
if (ppWorkers)
{
this_unit.ppWorkers = ppWorkers;
this_unit.n_workers = n_workers;
this_unit.initialized = true;
}
}
@ -977,10 +980,12 @@ void Worker::shutdown()
void Worker::shutdown_all()
{
// NOTE: No logging here, this function must be signal safe.
ss_dassert((this_unit.n_workers == 0) || (this_unit.ppWorkers != NULL));
for (int i = 0; i < this_unit.n_workers; ++i)
{
Worker* pWorker = this_unit.ppWorkers[i];
ss_dassert(pWorker);
pWorker->shutdown();
}

View File

@ -1173,7 +1173,7 @@ bool do_show_slave_status(MariaDBMonitor* mon,
* root master server.
* Please note, there could be no slaves at all if Slave_SQL_Running == 'No'
*/
if (server_version != MYSQL_SERVER_VERSION_51)
if (serv_info->slave_status.slave_io_running && server_version != MYSQL_SERVER_VERSION_51)
{
/* Get Master_Server_Id */
master_server_id = scan_server_id(row[i_master_server_id]);

View File

@ -179,7 +179,7 @@ log_transaction_status(RWSplitSession *rses, GWBUF *querybuf, uint32_t qtype)
const char *hint = querybuf->hint == NULL ? "" : ", Hint:";
const char *hint_type = querybuf->hint == NULL ? "" : STRHINTTYPE(querybuf->hint->type);
MXS_INFO("> Autocommit: %s, trx is %s, cmd: (0x%02x) %s, plen: %u, type: %s, pastmt: %.*s%s %s",
MXS_INFO("> Autocommit: %s, trx is %s, cmd: (0x%02x) %s, plen: %u, type: %s, stmt: %.*s%s %s",
autocommit, transaction, command, STRPACKETTYPE(command), plen,
querytype, len, sql, hint, hint_type);