diff --git a/BUILD/install_build_deps.sh b/BUILD/install_build_deps.sh index 6f5f9bbde..0f1db8d03 100755 --- a/BUILD/install_build_deps.sh +++ b/BUILD/install_build_deps.sh @@ -163,7 +163,8 @@ avro_dir=`echo "$avro_filename" | sed "s/.tar.gz//"` tar -axf $avro_filename mkdir $avro_dir/build pushd $avro_dir/build -cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_C_FLAGS=-fPIC -DCMAKE_CXX_FLAGS=-fPIC +# The -DSNAPPY_FOUND=N is used to prevent the library from linking against libsnappy (MaxScale doesn't link against it) +cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_C_FLAGS=-fPIC -DCMAKE_CXX_FLAGS=-fPIC -DSNAPPY_FOUND=N make sudo make install popd diff --git a/include/maxscale/server.h b/include/maxscale/server.h index 89a0e2cfc..61718dbbe 100644 --- a/include/maxscale/server.h +++ b/include/maxscale/server.h @@ -356,7 +356,7 @@ extern void server_transfer_status(SERVER *dest_server, const SERVER *source_ser extern void server_add_mon_user(SERVER *server, const char *user, const char *passwd); extern const char *server_get_parameter(const SERVER *server, const char *name); extern void server_update_credentials(SERVER *server, const char *user, const char *passwd); -extern DCB *server_get_persistent(SERVER *server, const char *user, const char *protocol, int id); +extern DCB* server_get_persistent(SERVER *server, const char *user, const char* ip, const char *protocol, int id); extern void server_update_address(SERVER *server, const char *address); extern void server_update_port(SERVER *server, unsigned short port); extern uint64_t server_map_status(const char *str); diff --git a/maxscale-system-test/CMakeLists.txt b/maxscale-system-test/CMakeLists.txt index 207fa882a..9ef5f35a5 100644 --- a/maxscale-system-test/CMakeLists.txt +++ b/maxscale-system-test/CMakeLists.txt @@ -643,6 +643,10 @@ add_test_executable(mxs1713_lots_of_databases.cpp mxs1713_lots_of_databases mxs1 # https://jira.mariadb.org/browse/MXS-1731 add_test_executable(mxs1731_old_persisted_config.cpp mxs1731_old_persisted_config replication LABELS maxscale REPL_BACKEND) +# MXS-1743: Maxscale unable to enforce round-robin between read service for Slave +# https://jira.mariadb.org/browse/MXS-1743 +add_test_executable(mxs1743_rconn_bitmask.cpp mxs1743_rconn_bitmask mxs1743_rconn_bitmask LABELS REPL_BACKEND) + # MXS-1751: Maxscale crashes when certain config is in play (with nodes down) # https://jira.mariadb.org/browse/MXS-1751 add_test_executable(mxs1751_available_when_donor_crash.cpp mxs1751_available_when_donor_crash mxs1751_available_when_donor_crash LABELS galeramon GALERA_BACKEND) diff --git a/maxscale-system-test/cnf/maxscale.cnf.template.mxs1743_rconn_bitmask b/maxscale-system-test/cnf/maxscale.cnf.template.mxs1743_rconn_bitmask new file mode 100644 index 000000000..3cb1d090f --- /dev/null +++ b/maxscale-system-test/cnf/maxscale.cnf.template.mxs1743_rconn_bitmask @@ -0,0 +1,47 @@ +[maxscale] +threads=###threads### + +[MySQL Monitor] +type=monitor +module=mysqlmon +###repl51### +servers=server1,server2 +user=maxskysql +passwd=skysql +monitor_interval=1000 + +[Read Connection Router Master] +type=service +router=readconnroute +router_options=master,slave +servers=server1,server2 +user=maxskysql +passwd=skysql + +[Read Connection Listener Master] +type=listener +service=Read Connection Router Master +protocol=MySQLClient +port=4008 + +[CLI] +type=service +router=cli + +[CLI Listener] +type=listener +service=CLI +protocol=maxscaled +socket=default + +[server1] +type=server +address=###node_server_IP_1### +port=###node_server_port_1### +protocol=MySQLBackend + +[server2] +type=server +address=###node_server_IP_2### +port=###node_server_port_2### +protocol=MySQLBackend diff --git a/maxscale-system-test/different_size.cpp b/maxscale-system-test/different_size.cpp index 6715f03f3..171ab7b52 100644 --- a/maxscale-system-test/different_size.cpp +++ b/maxscale-system-test/different_size.cpp @@ -61,59 +61,43 @@ void set_max_packet(TestConnections* Test, bool binlog, char * cmd) void different_packet_size(TestConnections* Test, bool binlog) { - MYSQL * conn; Test->set_timeout(60); Test->tprintf("Set big max_allowed_packet\n"); set_max_packet(Test, binlog, (char *) "set global max_allowed_packet = 200000000;"); Test->set_timeout(40); Test->tprintf("Create table\n"); - conn = connect_to_serv(Test, binlog); - Test->try_query(conn, (char *) - "DROP TABLE IF EXISTS test.large_event;CREATE TABLE test.large_event(id INT, data LONGBLOB);"); + MYSQL* conn = connect_to_serv(Test, binlog); + Test->try_query(conn, "DROP TABLE IF EXISTS test.large_event;" + "CREATE TABLE test.large_event(id INT, data LONGBLOB);"); mysql_close(conn); - int ranges_num = 3; - unsigned int range_min[ranges_num]; - unsigned int range_max[ranges_num]; - unsigned int range = Test->smoke ? 2 : 50; + const int loops = 3; + const int range = 2; - range_min[0] = 0x0ffffff - range; - range_max[0] = 0x0ffffff + range; - range_min[1] = 0x0ffffff * 2 - range; - range_max[1] = 0x0ffffff * 2 + range; - range_min[2] = 0x0ffffff * 3 - range; - range_max[2] = 0x0ffffff * 3 + range; - - char * event; - int i; - unsigned long j; - - for (i = 0; i < ranges_num; i++) + for (int i = 1; i <= loops; i++) { - for (j = range_min[i]; j < range_max[i]; j++) + for (int j = -range; j <= range; j++) { + size_t size = 0x0ffffff * i + j; + Test->tprintf("Trying event app. %lu bytes", size); Test->set_timeout(240); - event = create_event_size(j); - Test->tprintf("Trying event app. %d bytes\t", j); - fflush(stdout); - conn = connect_to_serv(Test, binlog); - if (execute_query_silent(conn, event) == 0) - { - Test->tprintf("OK\n"); - } - else - { - Test->tprintf("FAIL\n"); - } + char* event = create_event_size(size); + conn = connect_to_serv(Test, binlog); + Test->assert(execute_query_silent(conn, event) == 0, "Query should succeed"); free(event); - execute_query_silent(conn, (char *) "DELETE FROM test.large_event WHERE id=1"); + execute_query_silent(conn, (char *) "DELETE FROM test.large_event"); mysql_close(conn); } } Test->set_timeout(40); - Test->tprintf("Restoring max_allowed_packet\n"); + Test->tprintf("Restoring max_allowed_packet"); set_max_packet(Test, binlog, (char *) "set global max_allowed_packet = 1048576;"); + + conn = connect_to_serv(Test, binlog); + Test->try_query(conn, "DROP TABLE test.large_event"); + mysql_close(conn); + } diff --git a/maxscale-system-test/mxs1743_rconn_bitmask.cpp b/maxscale-system-test/mxs1743_rconn_bitmask.cpp new file mode 100644 index 000000000..3d3bba969 --- /dev/null +++ b/maxscale-system-test/mxs1743_rconn_bitmask.cpp @@ -0,0 +1,36 @@ +/** + * MXS-1743: Maxscale unable to enforce round-robin between read service for Slave + * + * https://jira.mariadb.org/browse/MXS-1743 + */ +#include "testconnections.h" + +int main(int argc, char** argv) +{ + TestConnections test(argc, argv); + + + test.tprintf("Testing with both master and slave up"); + test.maxscales->connect(); + test.try_query(test.maxscales->conn_master[0], "SELECT 1"); + test.maxscales->disconnect(); + + test.tprintf("Testing with only the master"); + test.repl->block_node(0); + sleep(5); + test.maxscales->connect(); + test.try_query(test.maxscales->conn_master[0], "SELECT 1"); + test.maxscales->disconnect(); + test.repl->unblock_node(0); + sleep(5); + + test.tprintf("Testing with only the slave"); + test.repl->block_node(1); + sleep(5); + test.maxscales->connect(); + test.try_query(test.maxscales->conn_master[0], "SELECT 1"); + test.maxscales->disconnect(); + test.repl->unblock_node(1); + + return test.global_result; +} diff --git a/server/core/dcb.cc b/server/core/dcb.cc index 38ce9c7f8..1423a0bb8 100644 --- a/server/core/dcb.cc +++ b/server/core/dcb.cc @@ -391,7 +391,8 @@ dcb_connect(SERVER *server, MXS_SESSION *session, const char *protocol) if (user && strlen(user)) { MXS_DEBUG("Looking for persistent connection DCB user %s protocol %s", user, protocol); - dcb = server_get_persistent(server, user, protocol, session->client_dcb->poll.thread.id); + dcb = server_get_persistent(server, user, session->client_dcb->remote, + protocol, session->client_dcb->poll.thread.id); if (dcb) { /** @@ -428,6 +429,11 @@ dcb_connect(SERVER *server, MXS_SESSION *session, const char *protocol) memcpy(&(dcb->func), funcs, sizeof(MXS_PROTOCOL)); dcb->protoname = MXS_STRDUP_A(protocol); + if (session->client_dcb->remote) + { + dcb->remote = MXS_STRDUP_A(session->client_dcb->remote); + } + const char *authenticator = server->authenticator ? server->authenticator : dcb->func.auth_default ? dcb->func.auth_default() : "NullAuthDeny"; diff --git a/server/core/server.cc b/server/core/server.cc index 45336d6de..43fefe5c3 100644 --- a/server/core/server.cc +++ b/server/core/server.cc @@ -213,12 +213,15 @@ server_free(SERVER *tofreeserver) /** * Get a DCB from the persistent connection pool, if possible * - * @param server The server to set the name on - * @param user The name of the user needing the connection - * @param protocol The name of the protocol needed for the connection + * @param server The server to set the name on + * @param user The name of the user needing the connection + * @param ip Client IP address + * @param protocol The name of the protocol needed for the connection + * @param id Thread ID + * + * @return A DCB or NULL if no connection is found */ -DCB * -server_get_persistent(SERVER *server, const char *user, const char *protocol, int id) +DCB* server_get_persistent(SERVER *server, const char *user, const char* ip, const char *protocol, int id) { DCB *dcb, *previous = NULL; @@ -232,9 +235,12 @@ server_get_persistent(SERVER *server, const char *user, const char *protocol, in { if (dcb->user && dcb->protoname + && dcb->remote + && ip && !dcb-> dcb_errhandle_called && !(dcb->flags & DCBF_HUNG) && 0 == strcmp(dcb->user, user) + && 0 == strcmp(dcb->remote, ip) && 0 == strcmp(dcb->protoname, protocol)) { if (NULL == previous) diff --git a/server/modules/protocol/MySQL/mariadb_client.cc b/server/modules/protocol/MySQL/mariadb_client.cc index 61149f4e3..009c731a9 100644 --- a/server/modules/protocol/MySQL/mariadb_client.cc +++ b/server/modules/protocol/MySQL/mariadb_client.cc @@ -139,7 +139,7 @@ void LocalClient::process(uint32_t events) error(); } - if (m_queue.size() && m_state != VC_ERROR) + if (m_queue.size() && m_state != VC_ERROR && m_state != VC_WAITING_HANDSHAKE) { drain_queue(); } diff --git a/server/modules/protocol/MySQL/mariadbclient/mysql_client.cc b/server/modules/protocol/MySQL/mariadbclient/mysql_client.cc index f95e28367..69c1f26d8 100644 --- a/server/modules/protocol/MySQL/mariadbclient/mysql_client.cc +++ b/server/modules/protocol/MySQL/mariadbclient/mysql_client.cc @@ -336,8 +336,8 @@ int MySQLSendHandshake(DCB* dcb) mysql_server_capabilities_one[1] = (uint8_t)(GW_MYSQL_CAPABILITIES_SERVER >> 8); // Check that we match the old values - ss_dassert(mysql_server_capabilities_one[0] = 0xff); - ss_dassert(mysql_server_capabilities_one[1] = 0xf7); + ss_dassert(mysql_server_capabilities_one[0] == 0xff); + ss_dassert(mysql_server_capabilities_one[1] == 0xf7); if (is_maria) { @@ -1016,6 +1016,10 @@ gw_read_normal_data(DCB *dcb, GWBUF *read_buffer, int nbytes_read) return 0; } + // Update the current command, required by KILL command processing + MySQLProtocol *proto = (MySQLProtocol*)dcb->protocol; + proto->current_command = (mxs_mysql_cmd_t)mxs_mysql_get_command(read_buffer); + char* message = handle_variables(session, &read_buffer); if (message) diff --git a/server/modules/routing/readconnroute/readconnroute.c b/server/modules/routing/readconnroute/readconnroute.c index 286cd8d80..ed4244462 100644 --- a/server/modules/routing/readconnroute/readconnroute.c +++ b/server/modules/routing/readconnroute/readconnroute.c @@ -334,7 +334,7 @@ newSession(MXS_ROUTER *instance, MXS_SESSION *session) { if (master_host) { - if (ref == master_host && (inst->bitvalue & SERVER_SLAVE)) + if (ref == master_host && (inst->bitvalue & (SERVER_SLAVE | SERVER_MASTER)) == SERVER_SLAVE) { /* Skip root master here, as it could also be slave of an external server that * is not in the configuration. Intermediate masters (Relay Servers) are also @@ -353,16 +353,13 @@ newSession(MXS_ROUTER *instance, MXS_SESSION *session) break; } } - else + else if (inst->bitvalue == SERVER_MASTER) { /* Master_host is NULL, no master server. If requested router_option is 'master' - * candidate wll be NULL. + * candidate will be NULL. */ - if (inst->bitvalue & SERVER_MASTER) - { - candidate = NULL; - break; - } + candidate = NULL; + break; } /* If no candidate set, set first running server as our initial candidate server */ @@ -548,7 +545,7 @@ static inline bool connection_is_valid(ROUTER_INSTANCE* inst, ROUTER_CLIENT_SES* if (SERVER_IS_RUNNING(router_cli_ses->backend->server) && (router_cli_ses->backend->server->status & inst->bitmask & inst->bitvalue)) { - if ((inst->bitvalue & SERVER_MASTER) && router_cli_ses->backend->active) + if ((inst->bitvalue == SERVER_MASTER) && router_cli_ses->backend->active) { // If we're using an active master server, verify that it is still a master rval = router_cli_ses->backend == get_root_master(inst->service->dbref);