diff --git a/Documentation/Release-Notes/MaxScale-2.2.3-Release-Notes.md b/Documentation/Release-Notes/MaxScale-2.2.3-Release-Notes.md index 90db0ff3c..1b0b18545 100644 --- a/Documentation/Release-Notes/MaxScale-2.2.3-Release-Notes.md +++ b/Documentation/Release-Notes/MaxScale-2.2.3-Release-Notes.md @@ -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. diff --git a/cmake/BuildMicroHttpd.cmake b/cmake/BuildMicroHttpd.cmake index 9de770a4d..4ae56cee3 100644 --- a/cmake/BuildMicroHttpd.cmake +++ b/cmake/BuildMicroHttpd.cmake @@ -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/ diff --git a/include/maxscale/service.h b/include/maxscale/service.h index 5d29f9bf0..799ef8e25 100644 --- a/include/maxscale/service.h +++ b/include/maxscale/service.h @@ -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 * diff --git a/server/core/config.cc b/server/core/config.cc index 9e1db34b2..8ff9be096 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -3500,62 +3500,85 @@ int create_new_listener(CONFIG_CONTEXT *obj) if (raw_service_name && protocol && (socket || port)) { - char service_name[strlen(raw_service_name) + 1]; - strcpy(service_name, raw_service_name); - fix_section_name(service_name); - - SERVICE *service = service_find(service_name); - if (service) + if (socket && port) { - SSL_LISTENER *ssl_info = make_ssl_structure(obj, true, &error_count); - if (socket) - { - if (serviceHasListener(service, obj->object, protocol, address, 0)) - { - MXS_ERROR("Listener '%s' for service '%s' already has a socket at '%s.", - obj->object, service_name, socket); - error_count++; - } - else - { - serviceCreateListener(service, obj->object, protocol, socket, 0, - authenticator, authenticator_options, ssl_info); - } - } - - if (port) - { - if (serviceHasListener(service, obj->object, protocol, address, atoi(port))) - { - MXS_ERROR("Listener '%s', for service '%s', already have port %s.", - obj->object, - service_name, - port); - error_count++; - } - else - { - serviceCreateListener(service, obj->object, protocol, address, atoi(port), - authenticator, authenticator_options, ssl_info); - } - } - - if (ssl_info && error_count) - { - free_ssl_structure(ssl_info); - } + 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 { - MXS_ERROR("Listener '%s', service '%s' not found.", obj->object, - service_name); - error_count++; + char service_name[strlen(raw_service_name) + 1]; + strcpy(service_name, raw_service_name); + fix_section_name(service_name); + + 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 (address) + { + 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 + { + serviceCreateListener(service, obj->object, protocol, socket, 0, + authenticator, authenticator_options, ssl_info); + } + } + + if (port) + { + listener = service_find_listener(service, NULL, address, atoi(port)); + + if (listener) + { + 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 + { + serviceCreateListener(service, obj->object, protocol, address, atoi(port), + authenticator, authenticator_options, ssl_info); + } + } + + if (ssl_info && error_count) + { + free_ssl_structure(ssl_info); + } + } + else + { + MXS_ERROR("Listener '%s', service '%s' not found.", obj->object, + service_name); + 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++; } diff --git a/server/core/messagequeue.cc b/server/core/messagequeue.cc index 2731394a0..8d52c798e 100644 --- a/server/core/messagequeue.cc +++ b/server/core/messagequeue.cc @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #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]; diff --git a/server/core/service.cc b/server/core/service.cc index 531736845..5cf41ea5a 100644 --- a/server/core/service.cc +++ b/server/core/service.cc @@ -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 * diff --git a/server/core/worker.cc b/server/core/worker.cc index f2f03d832..97fe7cab4 100644 --- a/server/core/worker.cc +++ b/server/core/worker.cc @@ -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(); } diff --git a/server/modules/monitor/mariadbmon/mariadbmon.cc b/server/modules/monitor/mariadbmon/mariadbmon.cc index 84e747db1..422b23b26 100644 --- a/server/modules/monitor/mariadbmon/mariadbmon.cc +++ b/server/modules/monitor/mariadbmon/mariadbmon.cc @@ -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]); diff --git a/server/modules/routing/readwritesplit/rwsplit_mysql.cc b/server/modules/routing/readwritesplit/rwsplit_mysql.cc index 6abd8fd24..22ab4c507 100644 --- a/server/modules/routing/readwritesplit/rwsplit_mysql.cc +++ b/server/modules/routing/readwritesplit/rwsplit_mysql.cc @@ -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);