diff --git a/Documentation/Release-Notes/generate_release_notes.sh b/Documentation/Release-Notes/generate_release_notes.sh index a2b14160b..7c92ce782 100755 --- a/Documentation/Release-Notes/generate_release_notes.sh +++ b/Documentation/Release-Notes/generate_release_notes.sh @@ -31,7 +31,7 @@ For more information, please refer to the [Limitations](../About/Limitations.md) RPM and Debian packages are provided for supported the Linux distributions. -Packages can be downloaded [here](https://mariadb.com/downloads/mariadb-tx/maxscale). +Packages can be downloaded [here](https://mariadb.com/downloads/#mariadb_platform-mariadb_maxscale). ## Source Code diff --git a/include/maxscale/queryclassifier.hh b/include/maxscale/queryclassifier.hh index e25518121..d8b9f146e 100644 --- a/include/maxscale/queryclassifier.hh +++ b/include/maxscale/queryclassifier.hh @@ -415,5 +415,8 @@ private: RouteInfo m_route_info; bool m_trx_is_read_only; bool m_ps_continuation; + + uint32_t m_prev_ps_id = 0; /**< For direct PS execution, storest latest prepared PS ID. + * https://mariadb.com/kb/en/library/com_stmt_execute/#statement-id **/ }; } diff --git a/maxscale-system-test/CMakeLists.txt b/maxscale-system-test/CMakeLists.txt index bca607f34..0fa9afec3 100644 --- a/maxscale-system-test/CMakeLists.txt +++ b/maxscale-system-test/CMakeLists.txt @@ -994,6 +994,9 @@ add_test_executable(mxs2521_double_exec.cpp mxs2521_double_exec mxs2521_double_e # MXS-2572: Add smartrouter tests. add_test_executable(sr_basics.cpp sr_basics sr_basics LABELS REPL_BACKEND) +# MXS-2490: Direct execution doesn't work with MaxScale +add_test_executable(mxs2490_ps_execute_direct.cpp mxs2490_ps_execute_direct replication LABELS REPL_BACKEND readwritesplit) + ############################################ # BEGIN: binlogrouter and avrorouter tests # ############################################ diff --git a/maxscale-system-test/mxs2490_ps_execute_direct.cpp b/maxscale-system-test/mxs2490_ps_execute_direct.cpp new file mode 100644 index 000000000..6e5735ae5 --- /dev/null +++ b/maxscale-system-test/mxs2490_ps_execute_direct.cpp @@ -0,0 +1,26 @@ +/** + * MXS-2490: Unknown prepared statement handler (0) given to mysqld_stmt_execute + * + * See: + * + * https://mariadb.com/kb/en/library/mariadb_stmt_execute_direct/ + * https://mariadb.com/kb/en/library/com_stmt_execute/#statement-id + */ + +#include "testconnections.h" + +int main(int argc, char** argv) +{ + TestConnections test(argc, argv); + + test.set_timeout(30); + test.maxscales->connect(); + + MYSQL_STMT* stmt = mysql_stmt_init(test.maxscales->conn_rwsplit[0]); + std::string query = "SELECT user FROM mysql.user"; + test.expect(mariadb_stmt_execute_direct(stmt, query.c_str(), query.length()) == 0, + "execute_direct should work: %s", mysql_stmt_error(stmt)); + mysql_stmt_close(stmt); + + return test.global_result; +} diff --git a/maxutils/maxbase/src/stacktrace.cc b/maxutils/maxbase/src/stacktrace.cc index 28ce11380..b4aa8a49d 100644 --- a/maxutils/maxbase/src/stacktrace.cc +++ b/maxutils/maxbase/src/stacktrace.cc @@ -56,7 +56,7 @@ static void get_command_output(char* output, size_t size, const char* format, .. } } -static void extract_file_and_line(const char* symbols, char* cmd, size_t size) +static void extract_file_and_line(char* symbols, char* cmd, size_t size) { const char* filename_end = strchr(symbols, '('); const char* symname_end = strchr(symbols, ')'); @@ -116,6 +116,30 @@ static void extract_file_and_line(const char* symbols, char* cmd, size_t size) snprintf(symname, sizeof(symname), "%.*s", (int)(symname_end - symname_start), symname_start); get_command_output(cmd, size, "addr2line -e %s %s", filename, symname); } + + const char prefix[] = "MaxScale/"; + + // Remove common source prefix + if (char* str = strstr(cmd, prefix)) + { + str += sizeof(prefix) - 1; + memmove(cmd, str, strlen(cmd) - (str - cmd) + 1); + } + + // Strip the directory name from the symbols (could this be useful?) + if (char* str = strrchr(symbols, '/')) + { + ++str; + memmove(symbols, str, strlen(symbols) - (str - symbols) + 1); + } + + // Remove the address where the symbol is in memory (i.e. the [0xdeadbeef] that follows the + // (main+0xa1) part), we're only interested where it is in the library. + if (char* str = strchr(symbols, '[')) + { + str--; + *str = '\0'; + } } } } @@ -129,12 +153,21 @@ void dump_stacktrace(std::function handler) int count = backtrace(addrs, 128); char** symbols = backtrace_symbols(addrs, count); + int rc = system("/bin/test -f /bin/nm -a -f /bin/addr2line"); + bool do_extract = WIFEXITED(rc) && WEXITSTATUS(rc) == 0; + if (symbols) { - for (int n = 0; n < count; n++) + // Skip first five frames, they are inside the stacktrace printing function and signal handlers + for (int n = 4; n < count; n++) { - char cmd[PATH_MAX + 1024] = ""; - extract_file_and_line(symbols[n], cmd, sizeof(cmd)); + char cmd[PATH_MAX + 1024] = ""; + + if (do_extract) + { + extract_file_and_line(symbols[n], cmd, sizeof(cmd)); + } + handler(symbols[n], cmd); } free(symbols); diff --git a/server/core/dcb.cc b/server/core/dcb.cc index e940962d4..69da86ff9 100644 --- a/server/core/dcb.cc +++ b/server/core/dcb.cc @@ -958,6 +958,8 @@ static void dcb_log_write_failure(DCB* dcb, GWBUF* queue, int eno) */ int dcb_drain_writeq(DCB* dcb) { + mxb_assert(dcb->owner == RoutingWorker::get_current()); + if (dcb->ssl_read_want_write) { /** The SSL library needs to write more data */ diff --git a/server/core/queryclassifier.cc b/server/core/queryclassifier.cc index ab9d97b20..99ba0d561 100644 --- a/server/core/queryclassifier.cc +++ b/server/core/queryclassifier.cc @@ -644,6 +644,13 @@ uint32_t QueryClassifier::ps_id_internal_get(GWBUF* pBuffer) // All COM_STMT type statements store the ID in the same place uint32_t external_id = mysql_extract_ps_id(pBuffer); + + if (external_id == 0xffffffff) + { + // "Direct execution" that refers to the latest prepared statement + external_id = m_prev_ps_id; + } + auto it = m_ps_handles.find(external_id); if (it != m_ps_handles.end()) @@ -663,6 +670,7 @@ uint32_t QueryClassifier::ps_id_internal_get(GWBUF* pBuffer) void QueryClassifier::ps_store_response(uint32_t internal_id, GWBUF* buffer) { auto external_id = qc_mysql_extract_ps_id(buffer); + m_prev_ps_id = external_id; m_ps_handles[external_id] = internal_id; if (auto param_count = qc_extract_ps_param_count(buffer)) diff --git a/server/core/service.cc b/server/core/service.cc index 84703a247..794036b6d 100644 --- a/server/core/service.cc +++ b/server/core/service.cc @@ -1091,8 +1091,10 @@ bool Service::refresh_users() MXS_CONFIG* config = config_get_global_options(); - /* Check if refresh rate limit has been exceeded */ - if (now < m_rate_limits[self].last + config->users_refresh_time) + /* Check if refresh rate limit has been exceeded. Also check whether we are in the middle of starting up. + * If so, allow repeated reloading of users. */ + if (now > maxscale_started() + config->users_refresh_time + && now < m_rate_limits[self].last + config->users_refresh_time) { if (!m_rate_limits[self].warned) { diff --git a/server/modules/routing/readwritesplit/rwsplitsession.cc b/server/modules/routing/readwritesplit/rwsplitsession.cc index 39a00c0b5..66c9c62cd 100644 --- a/server/modules/routing/readwritesplit/rwsplitsession.cc +++ b/server/modules/routing/readwritesplit/rwsplitsession.cc @@ -147,20 +147,15 @@ int32_t RWSplitSession::routeQuery(GWBUF* querybuf) else { // Already busy executing a query, put the query in a queue and route it later - mxb_assert(m_expected_responses > 0 || !m_query_queue.empty()); MXS_INFO("Storing query (len: %d cmd: %0x), expecting %d replies to current command: %s", gwbuf_length(querybuf), GWBUF_DATA(querybuf)[4], m_expected_responses, mxs::extract_sql(querybuf, 1024).c_str()); + mxb_assert(m_expected_responses > 0 || !m_query_queue.empty()); m_query_queue.emplace_back(querybuf); querybuf = NULL; rval = 1; mxb_assert(m_expected_responses != 0); - - if (m_expected_responses == 0 && !route_stored_query()) - { - rval = 0; - } } if (querybuf != NULL) diff --git a/test/docker-compose.yml b/test/docker-compose.yml index da79ca1cf..bd2f4c92b 100644 --- a/test/docker-compose.yml +++ b/test/docker-compose.yml @@ -1,7 +1,7 @@ version: '2' services: server1: - image: mariadb:10.2 + image: mariadb:10.3 network_mode: "host" container_name: server1 environment: @@ -11,7 +11,7 @@ services: command: mysqld --log-bin=binlog --binlog-format=ROW --server-id=3000 --port=3000 --log-slave-updates server2: - image: mariadb:10.2 + image: mariadb:10.3 container_name: server2 network_mode: "host" environment: @@ -21,7 +21,7 @@ services: command: mysqld --log-bin=binlog --binlog-format=ROW --server-id=3001 --port=3001 --log-slave-updates server3: - image: mariadb:10.2 + image: mariadb:10.3 container_name: server3 network_mode: "host" environment: @@ -31,7 +31,7 @@ services: command: mysqld --log-bin=binlog --binlog-format=ROW --server-id=3002 --port=3002 --log-slave-updates server4: - image: mariadb:10.2 + image: mariadb:10.3 container_name: server4 network_mode: "host" environment: