diff --git a/mysql-test/suite/rpl/r/rpl_parallel_retry.result b/mysql-test/suite/rpl/r/rpl_parallel_retry.result index 2cc4044a2cd..4c7effd737a 100644 --- a/mysql-test/suite/rpl/r/rpl_parallel_retry.result +++ b/mysql-test/suite/rpl/r/rpl_parallel_retry.result @@ -339,6 +339,28 @@ connection server_1; DROP TABLE t1, t2, t3, t4; DROP function foo; connection server_2; +connection server_2; +include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=4; +connection server_1; +CREATE TABLE t1 (a INT, b VARCHAR(123)) ENGINE=InnoDB; +INSERT INTO t1 VALUES(1, 'asdf'); +UPDATE t1 SET b='zxf1' WHERE a=1; +UPDATE t1 SET b='\n' WHERE a=1; +connection server_2; +SET @old_dbug=@@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,write_row_inject_sleep_before_ha_write_row"; +include/start_slave.inc +connection server_1; +connection server_2; +connection server_1; +DROP TABLE t1; +connection server_2; +include/stop_slave.inc +SET GLOBAL debug_dbug=@old_dbug; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +include/start_slave.inc connection server_1; CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; INSERT INTO t1 VALUES(100, 100); diff --git a/mysql-test/suite/rpl/t/rpl_parallel_retry.test b/mysql-test/suite/rpl/t/rpl_parallel_retry.test index fe6f40d2c85..1e87c85cd6c 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel_retry.test +++ b/mysql-test/suite/rpl/t/rpl_parallel_retry.test @@ -410,6 +410,44 @@ DROP function foo; --sync_slave_with_master server_2 +# +# MDEV-33303: slave_parallel_mode=optimistic should not report the mode's +# specific temporary errors. +# + +--connection server_2 +--source include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=4; + +--connection server_1 +# The problem occurred in the code path for row-based updates in tables +# with no primary/unique key, where a scan is needed. +CREATE TABLE t1 (a INT, b VARCHAR(123)) ENGINE=InnoDB; +INSERT INTO t1 VALUES(1, 'asdf'); +UPDATE t1 SET b='zxf1' WHERE a=1; +UPDATE t1 SET b='\n' WHERE a=1; + +--connection server_2 +# Inject a small sleep in the code that makes the race easier to hit. +SET @old_dbug=@@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,write_row_inject_sleep_before_ha_write_row"; +--source include/start_slave.inc + +--connection server_1 +# Here, we would get errors in the slave's error log: +# [ERROR] mariadbd: Can't find record in 't1' +--sync_slave_with_master server_2 + +--connection server_1 +DROP TABLE t1; +--sync_slave_with_master server_2 +--source include/stop_slave.inc +SET GLOBAL debug_dbug=@old_dbug; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + + # # MDEV-12746 rpl.rpl_parallel_optimistic_nobinlog fails committing out of order at retry # diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index cafac67a51d..77856cde6f1 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -7401,6 +7401,8 @@ Rows_log_event::write_row(rpl_group_info *rgi, TODO: Add safety measures against infinite looping. */ + DBUG_EXECUTE_IF("write_row_inject_sleep_before_ha_write_row", + my_sleep(20000);); if (table->s->sequence) error= update_sequence(); else while (unlikely(error= table->file->ha_write_row(table->record[0]))) @@ -7898,6 +7900,12 @@ static int row_not_found_error(rpl_group_info *rgi) ? HA_ERR_KEY_NOT_FOUND : HA_ERR_RECORD_CHANGED; } +static int end_of_file_error(rpl_group_info *rgi) +{ + return rgi->speculation != rpl_group_info::SPECULATE_OPTIMISTIC + ? HA_ERR_END_OF_FILE : HA_ERR_RECORD_CHANGED; +} + /** Locate the current row in event's table. @@ -8145,6 +8153,8 @@ int Rows_log_event::find_row(rpl_group_info *rgi) while ((error= table->file->ha_index_next(table->record[0]))) { DBUG_PRINT("info",("no record matching the given row found")); + if (error == HA_ERR_END_OF_FILE) + error= end_of_file_error(rgi); table->file->print_error(error, MYF(0)); table->file->ha_index_end(); goto end; @@ -8181,6 +8191,7 @@ int Rows_log_event::find_row(rpl_group_info *rgi) break; case HA_ERR_END_OF_FILE: + error= end_of_file_error(rgi); DBUG_PRINT("info", ("Record not found")); table->file->ha_rnd_end(); goto end;