1--source include/have_innodb.inc 2--source include/have_debug.inc 3--source include/master-slave.inc 4 5--connection slave 6--source include/stop_slave.inc 7# Since we inject an error updating mysql.gtid_slave_pos, we will get different 8# output depending on whether it is InnoDB or MyISAM (roll back or no roll 9# back). So fix it to make sure we are consistent, in case an earlier test case 10# left it as InnoDB. 11SET sql_log_bin=0; 12ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria; 13SET sql_log_bin=1; 14--source include/start_slave.inc 15 16--connection master 17CREATE TABLE t1 (i int) ENGINE=InnoDB; 18 19--sync_slave_with_master 20 21--echo *** MDEV-4484, incorrect error handling when entries in gtid_slave_pos not found. *** 22TRUNCATE TABLE mysql.gtid_slave_pos; 23 24--connection master 25INSERT INTO t1 VALUES (1); 26--sync_slave_with_master 27 28# Inject an artificial error deleting entries, and check that the error handling code works. 29--connection slave 30--source include/stop_slave.inc 31SET @old_gtid_cleanup_batch_size= @@GLOBAL.gtid_cleanup_batch_size; 32SET GLOBAL gtid_cleanup_batch_size= 2; 33SET @old_dbug= @@GLOBAL.debug_dbug; 34SET GLOBAL debug_dbug="+d,gtid_slave_pos_simulate_failed_delete"; 35SET sql_log_bin= 0; 36CALL mtr.add_suppression("<DEBUG> Error deleting old GTID row"); 37SET sql_log_bin= 1; 38--source include/start_slave.inc 39 40--connection master 41--disable_query_log 42let $i = 20; 43while ($i) { 44 eval INSERT INTO t1 VALUES ($i+10); 45 dec $i; 46} 47--enable_query_log 48--save_master_pos 49 50--connection slave 51--sync_with_master 52 53# Now wait for the slave background thread to try to delete old rows and 54# hit the error injection. 55--let _TEST_MYSQLD_ERROR_LOG=$MYSQLTEST_VARDIR/log/mysqld.2.err 56--perl 57 open F, '<', $ENV{'_TEST_MYSQLD_ERROR_LOG'} or die; 58 outer: while (1) { 59 inner: while (<F>) { 60 last outer if /<DEBUG> Error deleting old GTID row/; 61 } 62 # Easy way to do sub-second sleep without extra modules. 63 select(undef, undef, undef, 0.1); 64 } 65EOF 66 67# Since we injected error in the cleanup code, the rows should remain in 68# mysql.gtid_slave_pos. Check that we have at least 20 (more robust against 69# non-deterministic cleanup and future changes than checking for exact number). 70SELECT COUNT(*), MAX(seq_no) INTO @pre_count, @pre_max_seq_no 71 FROM mysql.gtid_slave_pos; 72SELECT IF(@pre_count >= 20, "OK", CONCAT("Error: too few rows seen while errors injected: ", @pre_count)); 73SET GLOBAL debug_dbug= @old_dbug; 74 75--connection master 76--disable_query_log 77let $i = 20; 78while ($i) { 79 eval INSERT INTO t1 VALUES ($i+40); 80 dec $i; 81} 82--enable_query_log 83--sync_slave_with_master 84 85--connection slave 86# Now check that 1) rows are being deleted again after removing error 87# injection, and 2) old rows are left that failed their delete while errors 88# where injected (again compensating for non-deterministic deletion). 89# Deletion is async and slightly non-deterministic, so we wait for at 90# least 10 of the 20 new rows to be deleted. 91let $wait_condition= 92 SELECT COUNT(*) <= 20-10 93 FROM mysql.gtid_slave_pos 94 WHERE seq_no > @pre_max_seq_no; 95--source include/wait_condition.inc 96SELECT IF(COUNT(*) >= 1, "OK", CONCAT("Error: too few rows seen after errors no longer injected: ", COUNT(*))) 97 FROM mysql.gtid_slave_pos 98 WHERE seq_no <= @pre_max_seq_no; 99 100# Clean up 101--connection master 102DROP TABLE t1; 103--connection slave 104SET GLOBAL gtid_cleanup_batch_size= @old_gtid_cleanup_batch_size; 105 106--source include/rpl_end.inc 107