mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 02:46:29 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			137 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			137 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| # ==== Purpose ====
 | |
| #
 | |
| # This test will generate two XA transactions on the master in a way that
 | |
| # they will block each other on the slave if the transaction isolation level
 | |
| # used by the slave applier is more restrictive than the READ COMMITTED one.
 | |
| #
 | |
| # Consider:
 | |
| #   E=execute, P=prepare, C=commit;
 | |
| #   1=first transaction, 2=second transaction;
 | |
| #
 | |
| # Master does: E1, E2, P2, P1, C1, C2
 | |
| # Slave does:  E2, P2, E1, P1, C1, C2
 | |
| #
 | |
| # The transactions are designed so that, if the applier transaction isolation
 | |
| # level is more restrictive than the READ COMMITTED, E1 will be blocked on
 | |
| # the slave waiting for gap locks to be released.
 | |
| #
 | |
| # Step 1
 | |
| #
 | |
| # The test will verify that the transactions don't block each other because
 | |
| # the applier thread automatically changed the isolation level.
 | |
| #
 | |
| # Step 2
 | |
| #
 | |
| # The test will verify that applying master's binary log dump in slave doesn't
 | |
| # block because mysqlbinlog is informing the isolation level to be used.
 | |
| #
 | |
| # ==== Related Bugs and Worklogs ====
 | |
| #
 | |
| # BUG#25040331: INTERLEAVED XA TRANSACTIONS MAY DEADLOCK SLAVE APPLIER WITH
 | |
| #               REPEATABLE READ
 | |
| #
 | |
| --source include/have_debug.inc
 | |
| --source include/have_innodb.inc
 | |
| # The test case only make sense for RBR
 | |
| --source include/have_binlog_format_row.inc
 | |
| --source include/master-slave.inc
 | |
| 
 | |
| --connection slave
 | |
| # To hit the issue, we need to split the data in two pages.
 | |
| # This global variable will help us.
 | |
| SET @saved_innodb_limit_optimistic_insert_debug = @@GLOBAL.innodb_limit_optimistic_insert_debug;
 | |
| SET @@GLOBAL.innodb_limit_optimistic_insert_debug = 2;
 | |
| 
 | |
| #
 | |
| # Step 1 - Using async replication
 | |
| #
 | |
| 
 | |
| # Let's generate the workload on the master
 | |
| --connection master
 | |
| CREATE TABLE t1 (
 | |
|   c1 INT NOT NULL,
 | |
|   KEY(c1)
 | |
| ) ENGINE=InnoDB;
 | |
| 
 | |
| CREATE TABLE t2 (
 | |
|   c1 INT NOT NULL,
 | |
|   FOREIGN KEY(c1) REFERENCES t1(c1)
 | |
| ) ENGINE=InnoDB;
 | |
| 
 | |
| INSERT INTO t1 VALUES (1), (3), (4);
 | |
| 
 | |
| --connection master1
 | |
| XA START 'XA1';
 | |
| INSERT INTO t1 values(2);
 | |
| XA END 'XA1';
 | |
| 
 | |
| # This transaction will reference the gap where XA1
 | |
| # was inserted, and will be prepared and committed
 | |
| # before XA1, so the slave will prepare it (but will
 | |
| # not commit it) before preparing XA1.
 | |
| --connection master
 | |
| XA START 'XA2';
 | |
| INSERT INTO t2 values(3);
 | |
| XA END 'XA2';
 | |
| 
 | |
| # The XA2 prepare should be binary logged first
 | |
| XA PREPARE 'XA2';
 | |
| 
 | |
| # The XA1 prepare should be binary logged
 | |
| # after XA2 prepare and before XA2 commit.
 | |
| --connection master1
 | |
| XA PREPARE 'XA1';
 | |
| 
 | |
| # The commit order doesn't matter much for the issue being tested.
 | |
| XA COMMIT 'XA1';
 | |
| --connection master
 | |
| XA COMMIT 'XA2';
 | |
| 
 | |
| # Everything is fine if the slave can sync with the master.
 | |
| --source include/sync_slave_sql_with_master.inc
 | |
| 
 | |
| #
 | |
| # Step 2 - Using mysqlbinlog dump to restore the slave
 | |
| #
 | |
| --source include/stop_slave.inc
 | |
| DROP TABLE t2, t1;
 | |
| RESET SLAVE;
 | |
| RESET MASTER;
 | |
| 
 | |
| --connection master
 | |
| --let $master_data_dir= `SELECT @@datadir`
 | |
| --let $master_log_file= query_get_value(SHOW MASTER STATUS, File, 1)
 | |
| --let $mysql_server= $MYSQL --defaults-group-suffix=.2
 | |
| --echo Restore binary log from the master into the slave
 | |
| --exec $MYSQL_BINLOG --force-if-open $master_data_dir/$master_log_file | $mysql_server
 | |
| 
 | |
| --let $diff_tables= master:test.t1, slave:test.t1
 | |
| --source include/diff_tables.inc
 | |
| --let $diff_tables= master:test.t2, slave:test.t2
 | |
| --source include/diff_tables.inc
 | |
| 
 | |
| #
 | |
| # Cleanup
 | |
| #
 | |
| --let $master_file= query_get_value(SHOW MASTER STATUS, File, 1)
 | |
| --let $master_pos= query_get_value(SHOW MASTER STATUS, Position, 1)
 | |
| DROP TABLE t2, t1;
 | |
| 
 | |
| ## When GTID_MODE=OFF, we need to skip already applied transactions
 | |
| --connection slave
 | |
| #--let $gtid_mode= `SELECT @@GTID_MODE`
 | |
| #if ($gtid_mode == OFF)
 | |
| #{
 | |
| #  --disable_query_log
 | |
| #  --disable_result_log
 | |
| #  --eval CHANGE MASTER TO MASTER_LOG_FILE='$master_file', MASTER_LOG_POS=$master_pos
 | |
| #  --enable_result_log
 | |
| #  --enable_query_log
 | |
| #}
 | |
| --replace_result $master_file LOG_FILE $master_pos LOG_POS
 | |
| --eval CHANGE MASTER TO MASTER_LOG_FILE='$master_file', MASTER_LOG_POS=$master_pos, MASTER_USE_GTID=NO
 | |
|  
 | |
| SET @@GLOBAL.innodb_limit_optimistic_insert_debug = @saved_innodb_limit_optimistic_insert_debug;
 | |
| --source include/start_slave.inc
 | |
| 
 | |
| --source include/rpl_end.inc
 | 
