diff --git a/maxscale-system-test/CMakeLists.txt b/maxscale-system-test/CMakeLists.txt index 93aab271e..cb66968c5 100644 --- a/maxscale-system-test/CMakeLists.txt +++ b/maxscale-system-test/CMakeLists.txt @@ -306,6 +306,10 @@ add_test_executable(mxs1507_migrate_trx.cpp mxs1507_migrate_trx mxs1507_trx_repl # https://jira.mariadb.org/browse/MXS-1507 add_test_executable(mxs1507_trx_stress.cpp mxs1507_trx_stress mxs1507_trx_stress LABELS readwritesplit REPL_BACKEND) +# MXS-2187: Multiple transaction replays +# https://jira.mariadb.org/browse/MXS-1507 +add_test_executable(mxs2187_multi_replay.cpp mxs2187_multi_replay mxs2187_multi_replay LABELS readwritesplit REPL_BACKEND) + # MXS-1778: Use GTID from OK packets for consistent reads # https://jira.mariadb.org/browse/MXS-1776 add_test_executable(mxs1778_causal_reads.cpp mxs1778_causal_reads mxs1778_causal_reads LABELS readwritesplit REPL_BACKEND) diff --git a/maxscale-system-test/cnf/maxscale.cnf.template.mxs2187_multi_replay b/maxscale-system-test/cnf/maxscale.cnf.template.mxs2187_multi_replay new file mode 100644 index 000000000..1c8ef41ee --- /dev/null +++ b/maxscale-system-test/cnf/maxscale.cnf.template.mxs2187_multi_replay @@ -0,0 +1,54 @@ +[maxscale] +threads=###threads### +log_info=1 + +[MySQL Monitor] +type=monitor +module=mysqlmon +servers=server1,server2,server3,server4 +user=maxskysql +password=skysql +monitor_interval=1000 +auto_failover=true +auto_rejoin=true +failcount=1 +master_failure_timeout=1 + +[RW Split Router] +type=service +router=readwritesplit +servers=server1,server2,server3,server4 +user=maxskysql +password=skysql +transaction_replay=true +delayed_retry_timeout=30 + +[RW Split Listener] +type=listener +service=RW Split Router +protocol=MySQLClient +port=4006 + +[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 + +[server3] +type=server +address=###node_server_IP_3### +port=###node_server_port_3### +protocol=MySQLBackend + +[server4] +type=server +address=###node_server_IP_4### +port=###node_server_port_4### +protocol=MySQLBackend diff --git a/maxscale-system-test/mxs2187_multi_replay.cpp b/maxscale-system-test/mxs2187_multi_replay.cpp new file mode 100644 index 000000000..b3f9eb31b --- /dev/null +++ b/maxscale-system-test/mxs2187_multi_replay.cpp @@ -0,0 +1,96 @@ +/** + * MXS-1507: Test inconsistent result detection + * + * https://jira.mariadb.org/browse/MXS-1507 + */ +#include "testconnections.h" +#include +#include +#include + +using namespace std; + +int main(int argc, char** argv) +{ + Mariadb_nodes::require_gtid(true); + TestConnections test(argc, argv); + + auto query = [&](string q) { + return execute_query_silent(test.maxscales->conn_rwsplit[0], q.c_str()) == 0; + }; + + auto ok = [&](string q) { + test.expect(query(q), + "Query '%s' should work: %s", + q.c_str(), + mysql_error(test.maxscales->conn_rwsplit[0])); + }; + + auto kill_master = [&]() { + test.repl->connect(); + int master = test.repl->find_master(); + test.repl->disconnect(); + test.repl->block_node(master); + test.maxscales->wait_for_monitor(3); + test.repl->unblock_node(master); + test.maxscales->wait_for_monitor(3); + }; + + // Create a table + test.maxscales->connect(); + ok("CREATE OR REPLACE TABLE test.t1 (id INT)"); + test.maxscales->disconnect(); + + // Make sure it's replicated to all slaves before starting the transaction + test.repl->connect(); + test.repl->sync_slaves(); + test.repl->disconnect(); + + // Try to do a transaction across multiple master failures + test.maxscales->connect(); + + cout << "Start transaction, insert a value and read it" << endl; + ok("START TRANSACTION"); + ok("INSERT INTO test.t1 VALUES (1)"); + ok("SELECT * FROM test.t1 WHERE id = 1"); + + cout << "Killing master" << endl; + kill_master(); + + cout << "Insert value and read it" << endl; + ok("INSERT INTO test.t1 VALUES (2)"); + ok("SELECT * FROM test.t1 WHERE id = 2"); + + cout << "Killing second master" << endl; + kill_master(); + + cout << "Inserting value 3" << endl; + ok("INSERT INTO test.t1 VALUES (3)"); + ok("SELECT * FROM test.t1 WHERE id = 3"); + + cout << "Killing third master" << endl; + kill_master(); + + cout << "Selecting final result" << endl; + ok("SELECT SUM(id) FROM test.t1"); + + cout << "Killing fourth master" << endl; + kill_master(); + + cout << "Committing transaction" << endl; + ok("COMMIT"); + test.maxscales->disconnect(); + + test.maxscales->connect(); + cout << "Checking results" << endl; + Row r = get_row(test.maxscales->conn_rwsplit[0], "SELECT SUM(id), @@last_insert_id FROM t1"); + test.expect(!r.empty() && r[0] == "6", "All rows were not inserted: %s", + r.empty() ? "No rows" : r[0].c_str()); + test.maxscales->disconnect(); + + test.maxscales->connect(); + ok("DROP TABLE test.t1"); + test.maxscales->disconnect(); + + return test.global_result; +}