247 lines
8.3 KiB
PHP
247 lines
8.3 KiB
PHP
################################################################################
|
|
# 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
|
|
# do --let $set_commit_parent_100=1 before this include file. So the two
|
|
# transactions can be paralleled on slave.
|
|
################################################################################
|
|
--echo #
|
|
--echo # Initialization the test
|
|
--echo #
|
|
|
|
# Create two database to support database MTS.
|
|
# For logical clock MTS the below DDLs and inserts should
|
|
# be run on slave in their original order.
|
|
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: MY-001756");
|
|
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
|
|
if ($set_commit_parent_100)
|
|
{
|
|
# Let the two inserts and later transactions run in parallel on slave.
|
|
SET DEBUG = "+d,set_commit_parent_100";
|
|
}
|
|
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(select count_transactions_retries from performance_schema.replication_applier_status, count_transactions_retries, 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_col_comparsion= >=
|
|
--let $status_col= count_transactions_retries
|
|
--let $table=replication_applier_status
|
|
--let $status_col_value= $retried_trans+2
|
|
--let $status_fail_query= SELECT GLOBAL.slave_retried_transactions
|
|
--source include/wait_for_rpl_pfs_status.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(select count_transactions_retries from performance_schema.replication_applier_status, count_transactions_retries, 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= count_transactions_retries should not increase
|
|
--let $assert_status_name= count_transactions_retries
|
|
--let $assert_status_value= $retried_trans
|
|
--source include/rpl_pfs_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
|
|
if ($set_commit_parent_100)
|
|
{
|
|
SET DEBUG = "-d,set_commit_parent_100";
|
|
}
|
|
DROP DATABASE db1;
|
|
DROP DATABASE db2;
|