################################################################################ # It verifys that transaction retry works well on MTS. It is designed to work # on both database and logical clock MTS. # # Test Scenarios: # 1. slave_transaction_retries = 0, coordinator and workers should stop without # retry when encountering a temporary error. # 2. coordinator and workers should stop after retrying a transaction # 'slave_transaction_retries' times. # 3. the worker can continue to finish the transaction correctly if retry does't # encounter any error and succeeds. # # Test Logic: # 1. Inserts some data into tables on master and sync the data to slave. # 2. Locks all rows on slave through SELECT ... FOR UPDATE # 3. Inserts some new data into tables on master. # Slave workers will encounter the temporary error 'Lock wait timeout # exceeded' when applying the events. # 4. check some status to make sure it acts as expected. # # In the test cases, we setup two slave workers. So it initializes two databases. # in each test case, it will use two transactions. They operate on different # databases. For databases MTS, it works. For logic clock MTS, the caller should # call below DEBUG instruction before this include file. So the two transactions # can be paralleled on slave. # SET DEBUG = "d,set_commit_parent_100"; ################################################################################ --echo # --echo # Initialization the test --echo # # Create two database to support mts of db parallel CREATE DATABASE db1; CREATE DATABASE db2; CREATE TABLE db1.t1(c1 INT PRIMARY KEY, c2 VARCHAR(4096)) ENGINE=InnoDB; CREATE TABLE db1.t2(c1 INT PRIMARY KEY, c2 VARCHAR(4096)) ENGINE=InnoDB; CREATE TABLE db2.t1(c1 INT PRIMARY KEY, c2 VARCHAR(4096)) ENGINE=InnoDB; INSERT INTO db1.t1 VALUES(1, NULL), (10, NULL), (100, NULL); INSERT INTO db1.t2 VALUES(1, NULL), (10, NULL), (100, NULL); INSERT INTO db2.t1 VALUES(1, NULL), (10, NULL), (100, NULL); --source include/sync_slave_sql_with_master.inc CALL mtr.add_suppression("Slave SQL for channel '':.*Lock wait timeout exceeded.*"); CALL mtr.add_suppression("Slave SQL for channel '': Worker . failed executing transaction.*"); CALL mtr.add_suppression("Slave SQL for channel '': .*Error_code: 1756"); CALL mtr.add_suppression("Slave SQL for channel '': worker thread retried transaction.*"); # Backup the original value of the variables SET @saved_innodb_lock_wait_timeout = @@GLOBAL.innodb_lock_wait_timeout; SET @saved_slave_parallel_workers = @@GLOBAL.slave_parallel_workers; SET @saved_slave_parallel_type = @@GLOBAL.slave_parallel_type; SET @saved_max_relay_log_size = @@GLOBAL.max_relay_log_size; SET @saved_slave_transaction_retries = @@GLOBAL.slave_transaction_retries; # Set a small wait timeout, so the test can run fast SET GLOBAL innodb_lock_wait_timeout = 1; SET GLOBAL slave_parallel_workers = 2; # Set a small relay log size, so the events of a transaction will be divided # into more than one relay logs. SET GLOBAL max_relay_log_size = 4096; --source include/stop_slave_sql.inc eval SET GLOBAL slave_parallel_type = $mts_parallel_type; --source include/start_slave_sql.inc --echo # --echo # Case 1: slave will stop if slave_transaction_retries is 0 --echo # SET GLOBAL slave_transaction_retries = 0; # Lock all rows of db1.t1 BEGIN; SELECT c1 FROM db1.t1 FOR UPDATE; --source include/rpl_connection_master.inc INSERT INTO db1.t1 VALUES(2, NULL); INSERT INTO db2.t1 VALUES(2, NULL); --source include/save_master_pos.inc --source include/rpl_connection_slave.inc # Lock wait timeout --let $slave_sql_errno= convert_error(ER_LOCK_WAIT_TIMEOUT) --source include/wait_for_slave_sql_error.inc --let $assert_text= Value 2 is not in db1.t1. --let $assert_cond= count(*) = 0 FROM db1.t1 WHERE c1 = 2 --source include/assert.inc # release the lock on db1.t1 ROLLBACK; --echo # --echo # Case 2: Slave will stop after retrying a transaction --echo # slave_transaction_retries times. --echo # SET GLOBAL slave_transaction_retries = 2; --source include/start_slave_sql.inc --source include/sync_slave_sql.inc # Lock all rows of db1.t2 BEGIN; SELECT c1 FROM db1.t2 FOR UPDATE; --source include/rpl_connection_master.inc BEGIN; INSERT INTO db1.t1 VALUES(20, NULL); INSERT INTO db1.t2 VALUES(20, NULL); COMMIT; INSERT INTO db2.t1 VALUES(20, NULL); --source include/save_master_pos.inc --source include/rpl_connection_slave.inc # Lock wait timeout --let $slave_sql_errno= convert_error(ER_LOCK_WAIT_TIMEOUT) --source include/wait_for_slave_sql_error.inc --let $assert_text= Value 20 is not in db1.t1. --let $assert_cond= count(*) = 0 FROM db1.t1 WHERE c1 = 20 --source include/assert.inc # release the lock on db1.t2 ROLLBACK; --echo # --echo # Case 3: Slave worker will not stop after retring a transaction --echo # sucessfully. --echo # --let $retried_trans= query_get_value(SHOW STATUS LIKE 'slave_retried_transactions', Value, 1) SET GLOBAL slave_transaction_retries = 10; --source include/start_slave_sql.inc --source include/sync_slave_sql.inc --source include/check_slave_no_error.inc # Lock all rows of db1.t2 BEGIN; SELECT c1 FROM db1.t2 FOR UPDATE; --source include/rpl_connection_master.inc --let $str= `SELECT repeat('a', 4096)` BEGIN; # It will make below INSERTs to be stored into different relay logs. --echo # INSERT INTO db1.t1 VALUES(30, 4096'a') --echo # INSERT INTO db1.t1 VALUES(31, 4096'a') --disable_query_log eval INSERT INTO db1.t1 VALUES(30, '$str'); eval INSERT INTO db1.t1 VALUES(31, '$str'); --enable_query_log # To Verify that Uservar_log_event works well SET @str= 'abc'; eval INSERT INTO db1.t2 VALUES(30, @str); COMMIT; INSERT INTO db2.t1 VALUES(30, NULL); --source include/save_master_pos.inc --source include/rpl_connection_slave.inc --let $status_var_comparsion= >= --let $status_type= GLOBAL --let $status_var= slave_retried_transactions --let $status_var_value= $retried_trans+2 --let $status_fail_query= SELECT GLOBAL.slave_retried_transactions --source include/wait_for_status_var.inc # # It is for verifying the fix of Bug#19282301 # To verify the temporary error is not reported through SHOW SLAVE STATUS --source include/check_slave_no_error.inc # Release the lock of db1.t2 ROLLBACK; --source include/sync_slave_sql.inc # It is for verifying the fix of Bug#19282301 --source include/check_slave_no_error.inc --let $rpl_diff_statement= SELECT * FROM db1.t1 --source include/rpl_diff.inc --let $rpl_diff_statement= SELECT * FROM db1.t2 --source include/rpl_diff.inc --let $rpl_diff_statement= SELECT * FROM db2.t1 --source include/rpl_diff.inc --source include/rpl_connection_master.inc INSERT INTO db1.t1 VALUES(40, NULL); INSERT INTO db2.t1 VALUES(40, NULL); --source include/sync_slave_sql_with_master.inc --echo # --echo # Case 4: Non-temporary error will stop slave workers without retrying --echo # --let $retried_trans= query_get_value(SHOW STATUS LIKE 'slave_retried_transactions', Value, 1) INSERT INTO db1.t1 VALUES(50, NULL); --source include/rpl_connection_master.inc INSERT INTO db1.t1 VALUES(50, NULL); --source include/save_master_pos.inc --source include/rpl_connection_slave.inc --let $slave_sql_errno= convert_error(ER_DUP_ENTRY) --source include/wait_for_slave_sql_error.inc --let $assert_text= slave_retried_transactions should not increase --let $assert_status_name= slave_retried_transactions --let $assert_status_value= $retried_trans --source include/assert_status.inc DELETE FROM db1.t1 WHERE c1 = 50; --source include/start_slave_sql.inc --source include/sync_slave_sql.inc --echo # --echo # Cleanup --echo # SET GLOBAL innodb_lock_wait_timeout = @saved_innodb_lock_wait_timeout; SET GLOBAL slave_parallel_workers = @saved_slave_parallel_workers; SET GLOBAL max_relay_log_size = @saved_max_relay_log_size; SET GLOBAL slave_transaction_retries = @saved_slave_transaction_retries; --source include/stop_slave_sql.inc SET GLOBAL slave_parallel_type= @saved_slave_parallel_type; --source include/start_slave_sql.inc --source include/rpl_connection_master.inc DROP DATABASE db1; DROP DATABASE db2;