diff --git a/Documentation/Changelog.md b/Documentation/Changelog.md index 9a08f24e6..4a5d6f8a2 100644 --- a/Documentation/Changelog.md +++ b/Documentation/Changelog.md @@ -21,6 +21,7 @@ * MaxScale now supports IPv6 For more details, please refer to: +* [MariaDB MaxScale 2.1.8 Release Notes](Release-Notes/MaxScale-2.1.8-Release-Notes.md) * [MariaDB MaxScale 2.1.7 Release Notes](Release-Notes/MaxScale-2.1.7-Release-Notes.md) * [MariaDB MaxScale 2.1.6 Release Notes](Release-Notes/MaxScale-2.1.6-Release-Notes.md) * [MariaDB MaxScale 2.1.5 Release Notes](Release-Notes/MaxScale-2.1.5-Release-Notes.md) diff --git a/Documentation/Release-Notes/MaxScale-2.1.8-Release-Notes.md b/Documentation/Release-Notes/MaxScale-2.1.8-Release-Notes.md new file mode 100644 index 000000000..167b0ec3e --- /dev/null +++ b/Documentation/Release-Notes/MaxScale-2.1.8-Release-Notes.md @@ -0,0 +1,48 @@ +# MariaDB MaxScale 2.1.8 Release Notes -- 2017-09-20 + +Release 2.1.8 is a GA release. + +This document describes the changes in release 2.1.8, when compared to +release [2.1.7](MaxScale-2.1.7-Release-Notes.md). + +If you are upgrading from release 2.0, please also read the following +release notes: +[2.1.7](./MaxScale-2.1.7-Release-Notes.md) +[2.1.6](./MaxScale-2.1.6-Release-Notes.md) +[2.1.5](./MaxScale-2.1.5-Release-Notes.md) +[2.1.4](./MaxScale-2.1.4-Release-Notes.md) +[2.1.3](./MaxScale-2.1.3-Release-Notes.md) +[2.1.2](./MaxScale-2.1.2-Release-Notes.md) +[2.1.1](./MaxScale-2.1.1-Release-Notes.md) +[2.1.0](./MaxScale-2.1.0-Release-Notes.md) + +For any problems you encounter, please consider submitting a bug +report at [Jira](https://jira.mariadb.org). + +## Bug fixes + +[Here is a list of bugs fixed in MaxScale 2.1.8.](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.1.8) + +* (MXS-1421)[https://jira.mariadb.org/browse/MXS-1421] Even though limit is reached, maxrows continues to buffer resultset. +* (MXS-1418)[https://jira.mariadb.org/browse/MXS-1418] remove server does not drain node +* (MXS-1414)[https://jira.mariadb.org/browse/MXS-1414] About Presistent Connection Mysql Gone away +* (MXS-1412)[https://jira.mariadb.org/browse/MXS-1412] Performance issue with MaxRows filter +* (MXS-1411)[https://jira.mariadb.org/browse/MXS-1411] error : (46) [maxrows] Received data from the backend although we were expecting nothing. +* (MXS-1409)[https://jira.mariadb.org/browse/MXS-1409] maxadmin socket with port results in help +* (MXS-1400)[https://jira.mariadb.org/browse/MXS-1400] Crash with OpenSSL 1.1 +* (MXS-1396)[https://jira.mariadb.org/browse/MXS-1396] Persistent connections hang with Percona Server 5.6.37-82.2-log + +## Packaging + +RPM and Debian packages are provided for the Linux distributions supported +by MariaDB Enterprise. + +Packages can be downloaded [here](https://mariadb.com/resources/downloads). + +## Source Code + +The source code of MaxScale is tagged at GitHub with a tag, which is identical +with the version of MaxScale. For instance, the tag of version X.Y.Z of MaxScale +is maxscale-X.Y.Z. + +The source code is available [here](https://github.com/mariadb-corporation/MaxScale). diff --git a/Documentation/Upgrading/Upgrading-To-MaxScale-2.1.md b/Documentation/Upgrading/Upgrading-To-MaxScale-2.1.md index 0b5665f1b..8bdbeedb3 100644 --- a/Documentation/Upgrading/Upgrading-To-MaxScale-2.1.md +++ b/Documentation/Upgrading/Upgrading-To-MaxScale-2.1.md @@ -7,6 +7,7 @@ For more information about MariaDB MaxScale 2.1, please refer to the [ChangeLog](../Changelog.md). For a complete list of changes in MaxScale 2.1, refer to the +[MaxScale 2.1.8 Release Notes](../Release-Notes/MaxScale-2.1.8-Release-Notes.md). [MaxScale 2.1.7 Release Notes](../Release-Notes/MaxScale-2.1.7-Release-Notes.md). [MaxScale 2.1.6 Release Notes](../Release-Notes/MaxScale-2.1.6-Release-Notes.md). [MaxScale 2.1.5 Release Notes](../Release-Notes/MaxScale-2.1.5-Release-Notes.md). diff --git a/Documentation/list_fixed_bugs.sh b/Documentation/list_fixed_bugs.sh index ac39dc1aa..8be27538f 100755 --- a/Documentation/list_fixed_bugs.sh +++ b/Documentation/list_fixed_bugs.sh @@ -8,4 +8,4 @@ then fi version=$1 -curl -s "https://jira.mariadb.org/sr/jira.issueviews:searchrequest-csv-current-fields/temp/SearchRequest.csv?jqlQuery=project+%3D+MXS+AND+issuetype+%3D+Bug+AND+status+%3D+Closed+AND+fixVersion+%3D+$version"|cut -f 1,2 -d ,|tail -n+2|sed 's/\(.*\),\(.*\)/* (\2)[https:\/\/jira.mariadb.org\/browse\/\2] \1/' +curl -s "https://jira.mariadb.org/sr/jira.issueviews:searchrequest-csv-current-fields/temp/SearchRequest.csv?jqlQuery=project+%3D+MXS+AND+issuetype+%3D+Bug+AND+status+%3D+Closed+AND+fixVersion+%3D+$version" | process.pl diff --git a/Documentation/list_fixed_issues.sh b/Documentation/list_fixed_issues.sh index e40aebf87..19707a3c4 100755 --- a/Documentation/list_fixed_issues.sh +++ b/Documentation/list_fixed_issues.sh @@ -8,4 +8,4 @@ then fi version=$1 -curl -s "https://jira.mariadb.org/sr/jira.issueviews:searchrequest-csv-current-fields/temp/SearchRequest.csv?jqlQuery=project+%3D+MXS+AND+issuetype+%21%3D+Bug+AND+status+%3D+Closed+AND+fixVersion+%3D+$version"|cut -f 1,2 -d ,|tail -n+2|sed 's/\(.*\),\(.*\)/* (\2)[https:\/\/jira.mariadb.org\/browse\/\2] \1/' +curl -s "https://jira.mariadb.org/sr/jira.issueviews:searchrequest-csv-current-fields/temp/SearchRequest.csv?jqlQuery=project+%3D+MXS+AND+issuetype+%21%3D+Bug+AND+status+%3D+Closed+AND+fixVersion+%3D+$version"|process.pl diff --git a/Documentation/process.pl b/Documentation/process.pl new file mode 100755 index 000000000..f325b96de --- /dev/null +++ b/Documentation/process.pl @@ -0,0 +1,20 @@ +#!/bin/perl + +# Discard the CSV headers +<>; + +while (<>) +{ + # Replace commas that are inside double quotes + s/("[^"]*),([^"]*")/$1$2/g; + + # Replace the double quotes themselves + s/"([^"]*)"/$1/g; + + # Split the line and grab the issue number and description + my @parts = split(/,/); + my $issue = @parts[1]; + my $desc = @parts[0]; + + print "* ($issue)[https://jira.mariadb.org/browse/$issue] $desc\n"; +} diff --git a/VERSION21.cmake b/VERSION21.cmake index 43a3b21b1..41a573525 100644 --- a/VERSION21.cmake +++ b/VERSION21.cmake @@ -5,7 +5,7 @@ set(MAXSCALE_VERSION_MAJOR "2" CACHE STRING "Major version") set(MAXSCALE_VERSION_MINOR "1" CACHE STRING "Minor version") -set(MAXSCALE_VERSION_PATCH "7" CACHE STRING "Patch version") +set(MAXSCALE_VERSION_PATCH "8" CACHE STRING "Patch version") # This should only be incremented if a package is rebuilt set(MAXSCALE_BUILD_NUMBER 1 CACHE STRING "Release number") diff --git a/client/maxadmin.c b/client/maxadmin.c index fe25af4ab..9ef3a33ce 100644 --- a/client/maxadmin.c +++ b/client/maxadmin.c @@ -182,6 +182,7 @@ main(int argc, char **argv) { // Both unix socket path and at least of the internet socket // options have been provided. + printf("\nError: Both socket and network options are provided\n\n"); DoUsage(argv[0]); exit(EXIT_FAILURE); } @@ -756,8 +757,8 @@ DoUsage(const char *progname) { PrintVersion(progname); printf("The MaxScale administrative and monitor client.\n\n"); - printf("Usage: %s [(-S socket)|([-u user] [-p password] [-h hostname] [-P port])]" - "[ | ]\n\n", progname); + printf("Usage: %s [-S socket] \n", progname); + printf(" %s [-u user] [-p password] [-h hostname] [-P port] \n\n", progname); printf(" -S|--socket=... The UNIX domain socket to connect to, The default is\n"); printf(" %s\n", MAXADMIN_DEFAULT_SOCKET); printf(" -u|--user=... The user name to use for the connection, default\n"); diff --git a/maxscale-system-test/CMakeLists.txt b/maxscale-system-test/CMakeLists.txt index 9dedbad9d..d6ba322a3 100644 --- a/maxscale-system-test/CMakeLists.txt +++ b/maxscale-system-test/CMakeLists.txt @@ -481,6 +481,10 @@ add_test_executable(mxs1123.cpp mxs1123 mxs1123 LABELS maxscale REPL_BACKEND) # https://jira.mariadb.org/browse/MXS-1319 add_test_executable(mxs1319.cpp mxs1319 replication LABELS MySQLAuth REPL_BACKEND) +# MXS-1418: Removing a server from a service breaks the connection +# https://jira.mariadb.org/browse/MXS-1418 +add_test_executable(mxs1418.cpp mxs1418 replication LABELS maxscale REPL_BACKEND) + # 'namedserverfilter' test add_test_executable(namedserverfilter.cpp namedserverfilter namedserverfilter LABELS namedserverfilter LIGHT REPL_BACKEND) diff --git a/maxscale-system-test/cnf/maxscale.cnf.template.mxs1323 b/maxscale-system-test/cnf/maxscale.cnf.template.mxs1323 index f5fff9976..031dbf9a1 100644 --- a/maxscale-system-test/cnf/maxscale.cnf.template.mxs1323 +++ b/maxscale-system-test/cnf/maxscale.cnf.template.mxs1323 @@ -1,6 +1,8 @@ [maxscale] threads=###threads### log_info=1 +auth_read_timeout=1 +auth_connect_timeout=1 [MySQL Monitor] type=monitor @@ -9,7 +11,9 @@ module=mysqlmon servers= server1,server2 user=maxskysql passwd= skysql -monitor_interval=500 +monitor_interval=1000 +backend_read_timeout=1 +backend_connect_timeout=1 [RW Split Router] type=service diff --git a/maxscale-system-test/mxs1323_retry_read.cpp b/maxscale-system-test/mxs1323_retry_read.cpp index 7d17f337f..3bd64f621 100644 --- a/maxscale-system-test/mxs1323_retry_read.cpp +++ b/maxscale-system-test/mxs1323_retry_read.cpp @@ -18,7 +18,7 @@ std::string do_query(TestConnections& test) { MYSQL* conn = test.open_rwsplit_connection(); - const char* query = "SELECT SLEEP(10), @@server_id"; + const char* query = "SELECT SLEEP(15), @@server_id"; char output[512] = ""; find_field(conn, query, "@@server_id", output); @@ -38,11 +38,13 @@ int main(int argc, char *argv[]) test.repl->close_connections(); test.set_timeout(60); - test.add_result(do_query(test) != slave, "The slave should respond to the first query"); + std::string res = do_query(test); + test.add_result(res != slave, "The slave should respond to the first query: %s", res.c_str()); pthread_t thr; pthread_create(&thr, NULL, async_block, &test); - test.add_result(do_query(test) != master, "The master should respond to the second query"); + res = do_query(test); + test.add_result(res != master, "The master should respond to the second query: %s", res.c_str()); pthread_join(thr, NULL); test.repl->unblock_node(1); diff --git a/maxscale-system-test/mxs1418.cpp b/maxscale-system-test/mxs1418.cpp new file mode 100644 index 000000000..9bd11efe6 --- /dev/null +++ b/maxscale-system-test/mxs1418.cpp @@ -0,0 +1,73 @@ +/** + * @file Check that removing a server from a service doesn't break active connections + */ + +#include "testconnections.h" + +static volatile bool running = true; + +void* thr(void* data) +{ + TestConnections* test = (TestConnections*)data; + + while (running && test->global_result == 0) + { + test->set_timeout(60); + if (test->try_query(test->conn_rwsplit, "SELECT 1")) + { + test->tprintf("Failed to select via readwritesplit"); + } + if (test->try_query(test->conn_master, "SELECT 1")) + { + test->tprintf("Failed to select via readconnroute master"); + } + if (test->try_query(test->conn_slave, "SELECT 1")) + { + test->tprintf("Failed to select via readconnroute slave"); + } + } + + test->stop_timeout(); + + return NULL; +} + +int main(int argc, char *argv[]) +{ + TestConnections test(argc, argv); + test.connect_maxscale(); + + test.tprintf("Connect to MaxScale and continuously execute queries"); + pthread_t thread; + pthread_create(&thread, NULL, thr, &test); + sleep(5); + + test.tprintf("Remove all servers from all services"); + + for (int i = 3; i > -1; i--) + { + test.ssh_maxscale(true, "maxadmin remove server server%d \"RW Split Router\"", i); + test.ssh_maxscale(true, "maxadmin remove server server%d \"Read Connection Router Slave\"", i); + test.ssh_maxscale(true, "maxadmin remove server server%d \"Read Connection Router Master\"", i); + } + + sleep(5); + + test.tprintf("Stop queries and close the connections"); + running = false; + pthread_join(thread, NULL); + test.close_maxscale_connections(); + + test.tprintf("Add all servers to all services"); + + for (int i = 3; i > -1; i--) + { + test.ssh_maxscale(true, "maxadmin add server server%d \"RW Split Router\"", i); + test.ssh_maxscale(true, "maxadmin add server server%d \"Read Connection Router Slave\"", i); + test.ssh_maxscale(true, "maxadmin add server server%d \"Read Connection Router Master\"", i); + } + + test.check_maxscale_alive(); + + return test.global_result; +} diff --git a/server/modules/filter/cache/cachefiltersession.cc b/server/modules/filter/cache/cachefiltersession.cc index f47d04138..d69fd6e5e 100644 --- a/server/modules/filter/cache/cachefiltersession.cc +++ b/server/modules/filter/cache/cachefiltersession.cc @@ -524,8 +524,28 @@ int CacheFilterSession::handle_expecting_nothing() { ss_dassert(m_state == CACHE_EXPECTING_NOTHING); ss_dassert(m_res.pData); - MXS_ERROR("Received data from the backend althoug we were expecting nothing."); - ss_dassert(!true); + unsigned long msg_size = gwbuf_length(m_res.pData); + + if ((int)MYSQL_GET_COMMAND(GWBUF_DATA(m_res.pData)) == 0xff) + { + /** + * Error text message is after: + * MYSQL_HEADER_LEN offset + status flag (1) + error code (2) + + * 6 bytes message status = MYSQL_HEADER_LEN + 9 + */ + MXS_INFO("Error packet received from backend " + "(possibly a server shut down ?): [%.*s].", + (int)msg_size - (MYSQL_HEADER_LEN + 9), + GWBUF_DATA(m_res.pData) + MYSQL_HEADER_LEN + 9); + } + else + { + MXS_WARNING("Received data from the backend although " + "filter is expecting nothing. " + "Packet size is %lu bytes long.", + msg_size); + ss_dassert(!true); + } return send_upstream(); } diff --git a/server/modules/filter/maxrows/maxrows.c b/server/modules/filter/maxrows/maxrows.c index 512e77376..270abdfe1 100644 --- a/server/modules/filter/maxrows/maxrows.c +++ b/server/modules/filter/maxrows/maxrows.c @@ -180,8 +180,8 @@ typedef struct maxrows_response_state size_t n_fields; /**< How many fields we have received, <= n_totalfields. */ size_t n_rows; /**< How many rows we have received. */ size_t offset; /**< Where we are in the response buffer. */ - size_t rows_offset; /**< Offset to first row in result set */ size_t length; /**< Buffer size. */ + GWBUF* column_defs; /**< Buffer with result set columns definitions */ } MAXROWS_RESPONSE_STATE; static void maxrows_response_state_reset(MAXROWS_RESPONSE_STATE *state); @@ -206,7 +206,7 @@ static void maxrows_session_data_free(MAXROWS_SESSION_DATA *data); static int handle_expecting_fields(MAXROWS_SESSION_DATA *csdata); static int handle_expecting_nothing(MAXROWS_SESSION_DATA *csdata); static int handle_expecting_response(MAXROWS_SESSION_DATA *csdata); -static int handle_rows(MAXROWS_SESSION_DATA *csdata); +static int handle_rows(MAXROWS_SESSION_DATA *csdata, GWBUF* buffer, size_t extra_offset); static int handle_ignoring_response(MAXROWS_SESSION_DATA *csdata); static bool process_params(char **options, MXS_CONFIG_PARAMETER *params, @@ -410,8 +410,19 @@ static int clientReply(MXS_FILTER *instance, if (csdata->res.data) { - gwbuf_append(csdata->res.data, data); - csdata->res.length += gwbuf_length(data); + if (csdata->discard_resultset && + csdata->state == MAXROWS_EXPECTING_ROWS) + { + gwbuf_free(csdata->res.data); + csdata->res.data = data; + csdata->res.length = gwbuf_length(data); + csdata->res.offset = 0; + } + else + { + gwbuf_append(csdata->res.data, data); + csdata->res.length += gwbuf_length(data); + } } else { @@ -453,7 +464,7 @@ static int clientReply(MXS_FILTER *instance, break; case MAXROWS_EXPECTING_ROWS: - rv = handle_rows(csdata); + rv = handle_rows(csdata, data, 0); break; case MAXROWS_IGNORING_RESPONSE: @@ -529,7 +540,7 @@ static void maxrows_response_state_reset(MAXROWS_RESPONSE_STATE *state) state->n_fields = 0; state->n_rows = 0; state->offset = 0; - state->rows_offset = 0; + state->column_defs = NULL; } /** @@ -608,16 +619,18 @@ static int handle_expecting_fields(MAXROWS_SESSION_DATA *csdata) case 0xfe: // EOF, the one after the fields. csdata->res.offset += packetlen; - /* Now set the offset to the first resultset - * this could be used for empty response handler + /** + * Set the buffer with column definitions. + * This will be used only by the empty response handler. */ - if (!csdata->res.rows_offset) + if (!csdata->res.column_defs && + csdata->instance->config.m_return == MAXROWS_RETURN_EMPTY) { - csdata->res.rows_offset = csdata->res.offset; + csdata->res.column_defs = gwbuf_clone(csdata->res.data); } csdata->state = MAXROWS_EXPECTING_ROWS; - rv = handle_rows(csdata); + rv = handle_rows(csdata, csdata->res.data, csdata->res.offset); break; default: // Field information. @@ -646,8 +659,28 @@ static int handle_expecting_nothing(MAXROWS_SESSION_DATA *csdata) { ss_dassert(csdata->state == MAXROWS_EXPECTING_NOTHING); ss_dassert(csdata->res.data); - MXS_ERROR("Received data from the backend although we were expecting nothing."); - ss_dassert(!true); + unsigned long msg_size = gwbuf_length(csdata->res.data); + + if ((int)MYSQL_GET_COMMAND(GWBUF_DATA(csdata->res.data)) == 0xff) + { + /** + * Error text message is after: + * MYSQL_HEADER_LEN offset + status flag (1) + error code (2) + + * 6 bytes message status = MYSQL_HEADER_LEN + 9 + */ + MXS_INFO("Error packet received from backend " + "(possibly a server shut down ?): [%.*s].", + (int)msg_size - (MYSQL_HEADER_LEN + 9), + GWBUF_DATA(csdata->res.data) + MYSQL_HEADER_LEN + 9); + } + else + { + MXS_WARNING("Received data from the backend although " + "filter is expecting nothing. " + "Packet size is %lu bytes long.", + msg_size); + ss_dassert(!true); + } return send_upstream(csdata); } @@ -772,32 +805,37 @@ static int handle_expecting_response(MAXROWS_SESSION_DATA *csdata) } /** - * Called when resultset rows are handled. + * Called when resultset rows are handled * - * @param csdata The maxrows session data. + * @param csdata The maxrows session data + * @param buffer The buffer containing the packet + * @param extra_offset Offset into @c buffer where the packet is stored + * + * @return The return value of the upstream component */ -static int handle_rows(MAXROWS_SESSION_DATA *csdata) +static int handle_rows(MAXROWS_SESSION_DATA *csdata, GWBUF* buffer, size_t extra_offset) { ss_dassert(csdata->state == MAXROWS_EXPECTING_ROWS); ss_dassert(csdata->res.data); int rv = 1; bool insufficient = false; - size_t buflen = csdata->res.length; + size_t offset = extra_offset; + size_t buflen = gwbuf_length(buffer); - while (!insufficient && (buflen - csdata->res.offset >= MYSQL_HEADER_LEN)) + while (!insufficient && (buflen - offset >= MYSQL_HEADER_LEN)) { bool pending_large_data = csdata->large_packet; // header array holds a full EOF packet uint8_t header[MYSQL_EOF_PACKET_LEN]; - gwbuf_copy_data(csdata->res.data, - csdata->res.offset, + gwbuf_copy_data(buffer, + offset, MYSQL_EOF_PACKET_LEN, header); size_t packetlen = MYSQL_HEADER_LEN + MYSQL_GET_PAYLOAD_LEN(header); - if (csdata->res.offset + packetlen <= buflen) + if (offset + packetlen <= buflen) { /* Check for large packet packet terminator: * min is 4 bytes "0x0 0x0 0x0 0xseq_no and @@ -809,10 +847,8 @@ static int handle_rows(MAXROWS_SESSION_DATA *csdata) packetlen < MYSQL_EOF_PACKET_LEN)) { // Update offset, number of rows and break - csdata->res.offset += packetlen; + offset += packetlen; csdata->res.n_rows++; - - ss_dassert(csdata->res.offset == buflen); break; } @@ -826,9 +862,7 @@ static int handle_rows(MAXROWS_SESSION_DATA *csdata) // Mark the beginning of a large packet receiving csdata->large_packet = true; // Just update offset and break - csdata->res.offset += packetlen; - - ss_dassert(csdata->res.offset == buflen); + offset += packetlen; break; } else @@ -843,8 +877,7 @@ static int handle_rows(MAXROWS_SESSION_DATA *csdata) switch (command) { case 0xff: // ERR packet after the rows. - csdata->res.offset += packetlen; - ss_dassert(csdata->res.offset == buflen); + offset += packetlen; // This is the end of resultset: set big packet var to false csdata->large_packet = false; @@ -883,8 +916,7 @@ static int handle_rows(MAXROWS_SESSION_DATA *csdata) * NOTE: not supported right now */ case 0xfe: // EOF, the one after the rows. - csdata->res.offset += packetlen; - ss_dassert(csdata->res.offset == buflen); + offset += packetlen; /* EOF could be the last packet in the transmission: * check first whether SERVER_MORE_RESULTS_EXIST flag is set. @@ -949,7 +981,7 @@ static int handle_rows(MAXROWS_SESSION_DATA *csdata) case 0xfb: // NULL default: // length-encoded-string - csdata->res.offset += packetlen; + offset += packetlen; // Increase res.n_rows counter while not receiving large packets if (!csdata->large_packet) { @@ -981,6 +1013,8 @@ static int handle_rows(MAXROWS_SESSION_DATA *csdata) } } + csdata->res.offset += offset - extra_offset; + return rv; } @@ -1009,12 +1043,20 @@ static int send_upstream(MAXROWS_SESSION_DATA *csdata) ss_dassert(csdata->res.data != NULL); /* Free a saved SQL not freed by send_error_upstream() */ - if (csdata->input_sql) + if (csdata->instance->config.m_return == MAXROWS_RETURN_ERR) { gwbuf_free(csdata->input_sql); csdata->input_sql = NULL; } + /* Free a saved columndefs not freed by send_eof_upstream() */ + if (csdata->instance->config.m_return == MAXROWS_RETURN_EMPTY) + { + gwbuf_free(csdata->res.column_defs); + csdata->res.column_defs = NULL; + } + + /* Send data to client */ int rv = csdata->up.clientReply(csdata->up.instance, csdata->up.session, csdata->res.data); @@ -1039,22 +1081,24 @@ static int send_eof_upstream(MAXROWS_SESSION_DATA *csdata) /* Sequence byte is #3 */ uint8_t eof[MYSQL_EOF_PACKET_LEN] = {05, 00, 00, 01, 0xfe, 00, 00, 02, 00}; GWBUF *new_pkt = NULL; + + ss_dassert(csdata->res.data != NULL); + ss_dassert(csdata->res.column_defs != NULL); + /** * The offset to server reply pointing to * next byte after column definitions EOF * of the first result set. */ - size_t offset = csdata->res.rows_offset; - - ss_dassert(csdata->res.data != NULL); + size_t offset = gwbuf_length(csdata->res.column_defs); /* Data to send + added EOF */ uint8_t *new_result = MXS_MALLOC(offset + MYSQL_EOF_PACKET_LEN); if (new_result) { - /* Get contiguous data from beginning to specified offset */ - gwbuf_copy_data(csdata->res.data, 0, offset, new_result); + /* Get contiguous data from saved columns defintions buffer */ + gwbuf_copy_data(csdata->res.column_defs, 0, offset, new_result); /* Increment sequence number for the EOF being added for empty resultset: * last one if found in EOF terminating column def @@ -1087,9 +1131,12 @@ static int send_eof_upstream(MAXROWS_SESSION_DATA *csdata) rv = 0; } - /* Free full input buffer */ + /* Free all data buffers */ gwbuf_free(csdata->res.data); + gwbuf_free(csdata->res.column_defs); + csdata->res.data = NULL; + csdata->res.column_defs = NULL; return rv; } @@ -1127,6 +1174,8 @@ static int send_ok_upstream(MAXROWS_SESSION_DATA *csdata) int rv = csdata->up.clientReply(csdata->up.instance, csdata->up.session, packet); + + /* Free server result buffer */ gwbuf_free(csdata->res.data); csdata->res.data = NULL; @@ -1208,10 +1257,10 @@ static int send_error_upstream(MAXROWS_SESSION_DATA *csdata) /* Free server result buffer */ gwbuf_free(csdata->res.data); + csdata->res.data = NULL; + /* Free input_sql buffer */ gwbuf_free(csdata->input_sql); - - csdata->res.data = NULL; csdata->input_sql = NULL; return rv; diff --git a/server/modules/routing/readconnroute/readconnroute.c b/server/modules/routing/readconnroute/readconnroute.c index 5e823376f..dc5690af5 100644 --- a/server/modules/routing/readconnroute/readconnroute.c +++ b/server/modules/routing/readconnroute/readconnroute.c @@ -519,10 +519,6 @@ static void log_closed_session(mxs_mysql_cmd_t mysql_command, bool is_closed, { sprintf(msg, "Server '%s' is down.", ref->server->unique_name); } - else if (!SERVER_REF_IS_ACTIVE(ref)) - { - sprintf(msg, "Server '%s' was removed from the service.", ref->server->unique_name); - } else if (SERVER_IN_MAINT(ref->server)) { sprintf(msg, "Server '%s' is in maintenance.", ref->server->unique_name); @@ -576,7 +572,6 @@ routeQuery(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *queu } if (rses_is_closed || backend_dcb == NULL || - !SERVER_REF_IS_ACTIVE(router_cli_ses->backend) || !SERVER_IS_RUNNING(router_cli_ses->backend->server)) { log_closed_session(mysql_command, rses_is_closed, router_cli_ses->backend); diff --git a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc index 2ce44c059..d3df7421e 100644 --- a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc +++ b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc @@ -424,7 +424,7 @@ SRWBackend get_target_backend(RWSplitSession *rses, backend_type_t btype, /** The server must be a valid slave, relay server, or master */ - if (backend->in_use() && backend->is_active() && + if (backend->in_use() && (strcasecmp(name, backend->name()) == 0) && (backend->is_slave() || backend->is_relay() || @@ -451,7 +451,7 @@ SRWBackend get_target_backend(RWSplitSession *rses, backend_type_t btype, * Unused backend or backend which is not master nor * slave can't be used */ - if (!backend->in_use() || !backend->is_active() || + if (!backend->in_use() || (!backend->is_master() && !backend->is_slave())) { continue; @@ -527,7 +527,7 @@ SRWBackend get_target_backend(RWSplitSession *rses, backend_type_t btype, */ else if (btype == BE_MASTER) { - if (master && master->is_active()) + if (master) { /** It is possible for the server status to change at any point in time * so copying it locally will make possible error messages