From b0b60f249807b6c2d423313350d9ad66693c2d1e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 May 2014 14:20:18 +0200 Subject: [PATCH 01/13] MDEV-5262: Missing retry after temp error in parallel replication Start implementing that an event group can be re-tried in parallel replication if it fails with a temporary error (like deadlock). Patch is very incomplete, just some very basic retry works. Stuff still missing (not complete list): - Handle moving to the next relay log file, if event group to be retried spans multiple relay log files. - Handle refcounting of relay log files, to ensure that we do not purge a relay log file and then later attempt to re-execute events out of it. - Handle description_event_for_exec - we need to save this somehow for the possible retry - and use the correct one in case it differs between relay logs. - Do another retry attempt in case the first retry also fails. - Limit the max number of retries. - Lots of testing will be needed for the various edge cases. --- .../suite/rpl/r/rpl_parallel_retry.result | 62 +++++++ .../suite/rpl/t/rpl_parallel_retry.test | 91 ++++++++++ sql/rpl_parallel.cc | 163 ++++++++++++++++-- sql/rpl_parallel.h | 6 +- sql/rpl_rli.cc | 39 ++++- sql/rpl_rli.h | 36 ++++ sql/slave.cc | 14 +- sql/slave.h | 1 + 8 files changed, 394 insertions(+), 18 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_parallel_retry.result create mode 100644 mysql-test/suite/rpl/t/rpl_parallel_retry.test diff --git a/mysql-test/suite/rpl/r/rpl_parallel_retry.result b/mysql-test/suite/rpl/r/rpl_parallel_retry.result new file mode 100644 index 00000000000..352285a91bf --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_parallel_retry.result @@ -0,0 +1,62 @@ +include/rpl_init.inc [topology=1->2] +*** Test retry of transactions that fail to replicate due to deadlock or similar temporary error. *** +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,1); +SET sql_log_bin=0; +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) +RETURNS INT DETERMINISTIC +BEGIN +RETURN x; +END +|| +SET sql_log_bin=1; +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +include/stop_slave.inc +SET GLOBAL slave_parallel_threads=5; +include/start_slave.inc +SET sql_log_bin=0; +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) +RETURNS INT DETERMINISTIC +BEGIN +IF d1 != '' THEN +SET debug_sync = d1; +END IF; +IF d2 != '' THEN +SET debug_sync = d2; +END IF; +RETURN x; +END +|| +include/stop_slave.inc +SET @old_format= @@SESSION.binlog_format; +SET binlog_format='statement'; +SET gtid_seq_no = 100; +BEGIN; +INSERT INTO t1 VALUES (2,1); +UPDATE t1 SET b=b+1 WHERE a=1; +INSERT INTO t1 VALUES (3,1); +COMMIT; +SET binlog_format=@old_format; +SELECT * FROM t1 ORDER BY a; +a b +1 2 +2 1 +3 1 +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_1_100"; +include/start_slave.inc +SET GLOBAL debug_dbug=@old_dbug; +retries +1 +SELECT * FROM t1 ORDER BY a; +a b +1 2 +2 1 +3 1 +include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +include/start_slave.inc +DROP TABLE t1; +DROP function foo; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_retry.test b/mysql-test/suite/rpl/t/rpl_parallel_retry.test new file mode 100644 index 00000000000..edf00269737 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_retry.test @@ -0,0 +1,91 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--echo *** Test retry of transactions that fail to replicate due to deadlock or similar temporary error. *** + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,1); +--save_master_pos + +# Use a stored function to inject a debug_sync into the appropriate THD. +# The function does nothing on the master, and on the slave it injects the +# desired debug_sync action(s). +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=5; +--source include/start_slave.inc +--sync_with_master +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + IF d1 != '' THEN + SET debug_sync = d1; + END IF; + IF d2 != '' THEN + SET debug_sync = d2; + END IF; + RETURN x; + END +|| +--delimiter ; +--source include/stop_slave.inc + +--connection server_1 +SET @old_format= @@SESSION.binlog_format; +SET binlog_format='statement'; +SET gtid_seq_no = 100; +BEGIN; +INSERT INTO t1 VALUES (2,1); +UPDATE t1 SET b=b+1 WHERE a=1; +#INSERT INTO t1 VALUES (3,foo(1, +# "ha_write_row_end SIGNAL q1_ready WAIT_FOR q1_cont", +# "")); +INSERT INTO t1 VALUES (3,1); +COMMIT; +SET binlog_format=@old_format; +SELECT * FROM t1 ORDER BY a; +--save_master_pos + +--connection server_2 +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_1_100"; +let $old_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +--source include/start_slave.inc +--sync_with_master +SET GLOBAL debug_dbug=@old_dbug; +let $new_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +--disable_query_log +eval SELECT $new_retry - $old_retry AS retries; +--enable_query_log + +SELECT * FROM t1 ORDER BY a; + +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1; +DROP function foo; + +--source include/rpl_end.inc diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 53769107661..f0147527957 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -7,15 +7,6 @@ /* Code for optional parallel execution of replicated events on the slave. - - ToDo list: - - - Retry of failed transactions is not yet implemented for the parallel case. - - - All the waits (eg. in struct wait_for_commit and in - rpl_parallel_thread_pool::get_thread()) need to be killable. And on kill, - everything needs to be correctly rolled back and stopped in all threads, - to ensure a consistent slave replication state. */ struct rpl_parallel_thread_pool global_rpl_thread_pool; @@ -197,6 +188,105 @@ unlock_or_exit_cond(THD *thd, mysql_mutex_t *lock, bool *did_enter_cond, } +static int +retry_handle_relay_log_rotate(Log_event *ev, IO_CACHE *rlog) +{ + /* ToDo */ + return 0; +} + + +static int +retry_event_group(rpl_group_info *rgi, rpl_parallel_thread *rpt, + rpl_parallel_thread::queued_event *orig_qev) +{ + IO_CACHE rlog; + File fd; + const char *errmsg= NULL; + inuse_relaylog *ir= rgi->relay_log; + uint64 event_count= 0; + uint64 events_to_execute= rgi->retry_event_count; + Relay_log_info *rli= rgi->rli; + int err= 0; + ulonglong cur_offset, old_offset; + char log_name[FN_REFLEN]; + THD *thd= rgi->thd; + +do_retry: + rgi->cleanup_context(thd, 1); + + mysql_mutex_lock(&rli->data_lock); + ++rli->retried_trans; + statistic_increment(slave_retried_transactions, LOCK_status); + mysql_mutex_unlock(&rli->data_lock); + + strcpy(log_name, ir->name); + if ((fd= open_binlog(&rlog, log_name, &errmsg)) <0) + return 1; + cur_offset= rgi->retry_start_offset; + my_b_seek(&rlog, cur_offset); + + do + { + Log_event_type event_type; + Log_event *ev; + + old_offset= cur_offset; + ev= Log_event::read_log_event(&rlog, 0, + rli->relay_log.description_event_for_exec /* ToDo: this needs fixing */, + opt_slave_sql_verify_checksum); + cur_offset= my_b_tell(&rlog); + + if (!ev) + { + err= 1; + goto err; + } + ev->thd= thd; + event_type= ev->get_type_code(); + if (Log_event::is_group_event(event_type)) + { + rpl_parallel_thread::queued_event *qev; + + mysql_mutex_lock(&rpt->LOCK_rpl_thread); + qev= rpt->retry_get_qev(ev, orig_qev, log_name, cur_offset, + cur_offset - old_offset); + mysql_mutex_unlock(&rpt->LOCK_rpl_thread); + if (!qev) + { + delete ev; + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + err= 1; + goto err; + } + err= rpt_handle_event(qev, rpt); + ++event_count; + mysql_mutex_lock(&rpt->LOCK_rpl_thread); + rpt->free_qev(qev); + mysql_mutex_unlock(&rpt->LOCK_rpl_thread); + } + else + err= retry_handle_relay_log_rotate(ev, &rlog); + delete_or_keep_event_post_apply(rgi, event_type, ev); + + if (err) + { + /* ToDo: Need to here also handle second retry. */ + goto err; + } + + // ToDo: handle too many retries. + + } while (event_count < events_to_execute); + +err: + + end_io_cache(&rlog); + mysql_file_close(fd, MYF(MY_WME)); + return err; +} + + pthread_handler_t handle_rpl_parallel_thread(void *arg) { @@ -499,7 +589,23 @@ handle_rpl_parallel_thread(void *arg) everything is stopped and cleaned up correctly. */ if (likely(!rgi->worker_error) && !skip_event_group) + { + ++rgi->retry_event_count; err= rpt_handle_event(events, rpt); + DBUG_EXECUTE_IF("rpl_parallel_simulate_temp_err_gtid_0_1_100", + if (rgi->current_gtid.domain_id == 0 && + rgi->current_gtid.server_id == 1 && + rgi->current_gtid.seq_no == 100 && + rgi->retry_event_count == 4) + { + thd->clear_error(); + thd->get_stmt_da()->reset_diagnostics_area(); + my_error(ER_LOCK_DEADLOCK, MYF(0)); + err= 1; + };); + if (err && has_temporary_error(thd)) + err= retry_event_group(rgi, rpt, events); + } else err= thd->wait_for_prior_commit(); @@ -802,8 +908,7 @@ err: rpl_parallel_thread::queued_event * -rpl_parallel_thread::get_qev(Log_event *ev, ulonglong event_size, - Relay_log_info *rli) +rpl_parallel_thread::get_qev_common(Log_event *ev, ulonglong event_size) { queued_event *qev; mysql_mutex_assert_owner(&LOCK_rpl_thread); @@ -817,6 +922,17 @@ rpl_parallel_thread::get_qev(Log_event *ev, ulonglong event_size, qev->ev= ev; qev->event_size= event_size; qev->next= NULL; + return qev; +} + + +rpl_parallel_thread::queued_event * +rpl_parallel_thread::get_qev(Log_event *ev, ulonglong event_size, + Relay_log_info *rli) +{ + queued_event *qev= get_qev_common(ev, event_size); + if (!qev) + return NULL; strcpy(qev->event_relay_log_name, rli->event_relay_log_name); qev->event_relay_log_pos= rli->event_relay_log_pos; qev->future_event_relay_log_pos= rli->future_event_relay_log_pos; @@ -825,6 +941,24 @@ rpl_parallel_thread::get_qev(Log_event *ev, ulonglong event_size, } +rpl_parallel_thread::queued_event * +rpl_parallel_thread::retry_get_qev(Log_event *ev, queued_event *orig_qev, + const char *relay_log_name, + ulonglong event_pos, ulonglong event_size) +{ + queued_event *qev= get_qev_common(ev, event_size); + if (!qev) + return NULL; + qev->rgi= orig_qev->rgi; + strcpy(qev->event_relay_log_name, relay_log_name); + qev->event_relay_log_pos= event_pos; + qev->future_event_relay_log_pos= event_pos+event_size; + strcpy(qev->future_event_master_log_name, + orig_qev->future_event_master_log_name); + return qev; +} + + void rpl_parallel_thread::free_qev(rpl_parallel_thread::queued_event *qev) { @@ -836,7 +970,7 @@ rpl_parallel_thread::free_qev(rpl_parallel_thread::queued_event *qev) rpl_group_info* rpl_parallel_thread::get_rgi(Relay_log_info *rli, Gtid_log_event *gtid_ev, - rpl_parallel_entry *e) + rpl_parallel_entry *e, ulonglong event_size) { rpl_group_info *rgi; mysql_mutex_assert_owner(&LOCK_rpl_thread); @@ -864,6 +998,9 @@ rpl_parallel_thread::get_rgi(Relay_log_info *rli, Gtid_log_event *gtid_ev, return NULL; } rgi->parallel_entry= e; + rgi->relay_log= rli->last_inuse_relaylog; + rgi->retry_start_offset= rli->future_event_relay_log_pos-event_size; + rgi->retry_event_count= 0; return rgi; } @@ -1439,7 +1576,7 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, { Gtid_log_event *gtid_ev= static_cast(ev); - if (!(rgi= cur_thread->get_rgi(rli, gtid_ev, e))) + if (!(rgi= cur_thread->get_rgi(rli, gtid_ev, e, event_size))) { cur_thread->free_qev(qev); abandon_worker_thread(rli->sql_driver_thd, cur_thread, diff --git a/sql/rpl_parallel.h b/sql/rpl_parallel.h index 1808efd0926..3b6641523f6 100644 --- a/sql/rpl_parallel.h +++ b/sql/rpl_parallel.h @@ -106,11 +106,15 @@ struct rpl_parallel_thread { queued_size-= dequeue_size; } + queued_event *get_qev_common(Log_event *ev, ulonglong event_size); queued_event *get_qev(Log_event *ev, ulonglong event_size, Relay_log_info *rli); + queued_event *retry_get_qev(Log_event *ev, queued_event *orig_qev, + const char *relay_log_name, + ulonglong event_pos, ulonglong event_size); void free_qev(queued_event *qev); rpl_group_info *get_rgi(Relay_log_info *rli, Gtid_log_event *gtid_ev, - rpl_parallel_entry *e); + rpl_parallel_entry *e, ulonglong event_size); void free_rgi(rpl_group_info *rgi); group_commit_orderer *get_gco(uint64 wait_count, group_commit_orderer *prev); void free_gco(group_commit_orderer *gco); diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index cc543f7c377..3a3e22f970a 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -52,6 +52,7 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery) info_fd(-1), cur_log_fd(-1), relay_log(&sync_relaylog_period), sync_counter(0), is_relay_log_recovery(is_slave_recovery), save_temporary_tables(0), mi(0), + inuse_relaylog_list(0), last_inuse_relaylog(0), cur_log_old_open_count(0), group_relay_log_pos(0), event_relay_log_pos(0), #if HAVE_valgrind @@ -98,8 +99,17 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery) Relay_log_info::~Relay_log_info() { + inuse_relaylog *cur; DBUG_ENTER("Relay_log_info::~Relay_log_info"); + cur= inuse_relaylog_list; + while (cur) + { + DBUG_ASSERT(cur->queued_count == cur->dequeued_count); + inuse_relaylog *next= cur->next; + my_free(cur); + cur= next; + } mysql_mutex_destroy(&run_lock); mysql_mutex_destroy(&data_lock); mysql_mutex_destroy(&log_space_lock); @@ -1339,6 +1349,29 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos, DBUG_VOID_RETURN; } + +int +Relay_log_info::alloc_inuse_relaylog(const char *name) +{ + inuse_relaylog *ir; + + if (!(ir= (inuse_relaylog *)my_malloc(sizeof(*ir), MYF(MY_WME|MY_ZEROFILL)))) + { + my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*ir)); + return 1; + } + strcpy(ir->name, name); + + if (!inuse_relaylog_list) + inuse_relaylog_list= ir; + else + last_inuse_relaylog->next= ir; + last_inuse_relaylog= ir; + + return 0; +} + + #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) int rpl_load_gtid_slave_state(THD *thd) @@ -1623,7 +1656,7 @@ delete_or_keep_event_post_apply(rpl_group_info *rgi, void rpl_group_info::cleanup_context(THD *thd, bool error) { - DBUG_ENTER("Relay_log_info::cleanup_context"); + DBUG_ENTER("rpl_group_info::cleanup_context"); DBUG_PRINT("enter", ("error: %d", (int) error)); DBUG_ASSERT(this->thd == thd); @@ -1689,7 +1722,7 @@ void rpl_group_info::cleanup_context(THD *thd, bool error) void rpl_group_info::clear_tables_to_lock() { - DBUG_ENTER("Relay_log_info::clear_tables_to_lock()"); + DBUG_ENTER("rpl_group_info::clear_tables_to_lock()"); #ifndef DBUG_OFF /** When replicating in RBR and MyISAM Merge tables are involved @@ -1736,7 +1769,7 @@ void rpl_group_info::clear_tables_to_lock() void rpl_group_info::slave_close_thread_tables(THD *thd) { - DBUG_ENTER("Relay_log_info::slave_close_thread_tables(THD *thd)"); + DBUG_ENTER("rpl_group_info::slave_close_thread_tables(THD *thd)"); thd->get_stmt_da()->set_overwrite_status(true); thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); thd->get_stmt_da()->set_overwrite_status(false); diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 00d16f52488..c2cdbcdc573 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -61,6 +61,7 @@ enum { *****************************************************************************/ struct rpl_group_info; +struct inuse_relaylog; class Relay_log_info : public Slave_reporting_capability { @@ -163,6 +164,13 @@ public: /* parent Master_info structure */ Master_info *mi; + /* + List of active relay log files. + (This can be more than one in case of parallel replication). + */ + inuse_relaylog *inuse_relaylog_list; + inuse_relaylog *last_inuse_relaylog; + /* Needed to deal properly with cur_log getting closed and re-opened with a different log under our feet @@ -398,6 +406,7 @@ public: void stmt_done(my_off_t event_log_pos, time_t event_creation_time, THD *thd, rpl_group_info *rgi); + int alloc_inuse_relaylog(const char *name); /** Is the replication inside a group? @@ -463,6 +472,25 @@ private: }; +/* + In parallel replication, if we need to re-try a transaction due to a + deadlock or other temporary error, we may need to go back and re-read events + out of an earlier relay log. + + This structure keeps track of the relaylogs that are potentially in use. + Each rpl_group_info has a pointer to one of those, corresponding to the + first GTID event. + + A reference count keeps track of how long a relay log is potentially in use. +*/ +struct inuse_relaylog { + inuse_relaylog *next; + uint64 queued_count; + uint64 dequeued_count; + char name[FN_REFLEN]; +}; + + /* This is data for various state needed to be kept for the processing of one event group (transaction) during replication. @@ -596,6 +624,14 @@ struct rpl_group_info /* Needs room for "Gtid D-S-N\x00". */ char gtid_info_buf[5+10+1+10+1+20+1]; + /* + Information to be able to re-try an event group in case of a deadlock or + other temporary error. + */ + inuse_relaylog *relay_log; + uint64 retry_start_offset; + uint64 retry_event_count; + rpl_group_info(Relay_log_info *rli_); ~rpl_group_info(); void reinit(Relay_log_info *rli); diff --git a/sql/slave.cc b/sql/slave.cc index f755cb63558..ab505a4011f 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3094,7 +3094,8 @@ static ulong read_event(MYSQL* mysql, Master_info *mi, bool* suppress_warnings) that the error is temporary by pushing a warning with the error code ER_GET_TEMPORARY_ERRMSG, if the originating error is temporary. */ -static int has_temporary_error(THD *thd) +int +has_temporary_error(THD *thd) { DBUG_ENTER("has_temporary_error"); @@ -4478,6 +4479,9 @@ pthread_handler_t handle_slave_sql(void *arg) "Error initializing relay log position: %s", errmsg); goto err; } + if (rli->alloc_inuse_relaylog(rli->group_relay_log_name)) + goto err; + strcpy(rli->future_event_master_log_name, rli->group_master_log_name); THD_CHECK_SENTRY(thd); #ifndef DBUG_OFF @@ -6521,6 +6525,12 @@ static Log_event* next_event(rpl_group_info *rgi, ulonglong *event_size) mysql_mutex_unlock(log_lock); goto err; } + if (rli->alloc_inuse_relaylog(rli->linfo.log_file_name)) + { + if (!hot_log) + mysql_mutex_unlock(log_lock); + goto err; + } if (!hot_log) mysql_mutex_unlock(log_lock); continue; @@ -6536,6 +6546,8 @@ static Log_event* next_event(rpl_group_info *rgi, ulonglong *event_size) if ((rli->cur_log_fd=open_binlog(cur_log,rli->linfo.log_file_name, &errmsg)) <0) goto err; + if (rli->alloc_inuse_relaylog(rli->linfo.log_file_name)) + goto err; } else { diff --git a/sql/slave.h b/sql/slave.h index 7352ac0274b..4b5bc1686fb 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -229,6 +229,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset, void set_slave_thread_options(THD* thd); void set_slave_thread_default_charset(THD *thd, rpl_group_info *rgi); int rotate_relay_log(Master_info* mi); +int has_temporary_error(THD *thd); int apply_event_and_update_pos(Log_event* ev, THD* thd, struct rpl_group_info *rgi, rpl_parallel_thread *rpt); From d60915692cd02cc70b7eb8245c9ac6eab5df3d0c Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 13 May 2014 13:42:06 +0200 Subject: [PATCH 02/13] MDEV-5262: Missing retry after temp error in parallel replication Implement that if first retry fails, we can do another attempt. Add testcases to test multi-retry that succeeds in second attempt, and multi-retry that eventually fails due to exceeding slave_trans_retries. --- .../suite/rpl/r/rpl_parallel_retry.result | 95 ++++++++++++++++++- .../suite/rpl/t/rpl_parallel_retry.test | 85 +++++++++++++++-- sql/rpl_parallel.cc | 73 +++++++++----- 3 files changed, 217 insertions(+), 36 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_parallel_retry.result b/mysql-test/suite/rpl/r/rpl_parallel_retry.result index 352285a91bf..1badf084440 100644 --- a/mysql-test/suite/rpl/r/rpl_parallel_retry.result +++ b/mysql-test/suite/rpl/r/rpl_parallel_retry.result @@ -28,23 +28,21 @@ END IF; RETURN x; END || +SET sql_log_bin=1; include/stop_slave.inc -SET @old_format= @@SESSION.binlog_format; -SET binlog_format='statement'; SET gtid_seq_no = 100; BEGIN; INSERT INTO t1 VALUES (2,1); UPDATE t1 SET b=b+1 WHERE a=1; INSERT INTO t1 VALUES (3,1); COMMIT; -SET binlog_format=@old_format; SELECT * FROM t1 ORDER BY a; a b 1 2 2 1 3 1 SET @old_dbug= @@GLOBAL.debug_dbug; -SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_1_100"; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_x_100"; include/start_slave.inc SET GLOBAL debug_dbug=@old_dbug; retries @@ -54,6 +52,95 @@ a b 1 2 2 1 3 1 +*** Test that double retry works when the first retry also fails with temp error *** +include/stop_slave.inc +SET gtid_seq_no = 100; +SET @old_server_id = @@server_id; +SET server_id = 10; +BEGIN; +INSERT INTO t1 VALUES (4,1); +UPDATE t1 SET b=b+1 WHERE a=1; +INSERT INTO t1 VALUES (5,1); +INSERT INTO t1 VALUES (6,1); +COMMIT; +SET server_id = @old_server_id; +SELECT * FROM t1 ORDER BY a; +a b +1 3 +2 1 +3 1 +4 1 +5 1 +6 1 +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_x_100,rpl_parallel_simulate_double_temp_err_gtid_0_x_100"; +include/start_slave.inc +SET GLOBAL debug_dbug=@old_dbug; +retries +2 +SELECT * FROM t1 ORDER BY a; +a b +1 3 +2 1 +3 1 +4 1 +5 1 +6 1 +*** Test too many retries, eventually causing failure. *** +include/stop_slave.inc +SET gtid_seq_no = 100; +SET @old_server_id = @@server_id; +SET server_id = 11; +BEGIN; +INSERT INTO t1 VALUES (7,1); +UPDATE t1 SET b=b+1 WHERE a=1; +INSERT INTO t1 VALUES (8,1); +INSERT INTO t1 VALUES (9,1); +COMMIT; +SET server_id = @old_server_id; +SELECT * FROM t1 ORDER BY a; +a b +1 4 +2 1 +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 +9 1 +SET sql_log_bin=0; +CALL mtr.add_suppression("Slave worker thread retried transaction 10 time\\(s\\) in vain, giving up"); +CALL mtr.add_suppression("Slave: Deadlock found when trying to get lock; try restarting transaction"); +SET sql_log_bin=1; +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_x_100,rpl_parallel_simulate_infinite_temp_err_gtid_0_x_100"; +START SLAVE; +include/wait_for_slave_sql_error.inc [errno=1213] +SET GLOBAL debug_dbug=@old_dbug; +retries +10 +SELECT * FROM t1 ORDER BY a; +a b +1 3 +2 1 +3 1 +4 1 +5 1 +6 1 +STOP SLAVE IO_THREAD; +include/start_slave.inc +SELECT * FROM t1 ORDER BY a; +a b +1 4 +2 1 +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 +9 1 include/stop_slave.inc SET GLOBAL slave_parallel_threads=@old_parallel_threads; include/start_slave.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_retry.test b/mysql-test/suite/rpl/t/rpl_parallel_retry.test index edf00269737..a2ccce45f0c 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel_retry.test +++ b/mysql-test/suite/rpl/t/rpl_parallel_retry.test @@ -47,27 +47,22 @@ CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) END || --delimiter ; +SET sql_log_bin=1; --source include/stop_slave.inc --connection server_1 -SET @old_format= @@SESSION.binlog_format; -SET binlog_format='statement'; SET gtid_seq_no = 100; BEGIN; INSERT INTO t1 VALUES (2,1); UPDATE t1 SET b=b+1 WHERE a=1; -#INSERT INTO t1 VALUES (3,foo(1, -# "ha_write_row_end SIGNAL q1_ready WAIT_FOR q1_cont", -# "")); INSERT INTO t1 VALUES (3,1); COMMIT; -SET binlog_format=@old_format; SELECT * FROM t1 ORDER BY a; --save_master_pos --connection server_2 SET @old_dbug= @@GLOBAL.debug_dbug; -SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_1_100"; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_x_100"; let $old_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); --source include/start_slave.inc --sync_with_master @@ -79,6 +74,82 @@ eval SELECT $new_retry - $old_retry AS retries; SELECT * FROM t1 ORDER BY a; + +--echo *** Test that double retry works when the first retry also fails with temp error *** +--source include/stop_slave.inc + +--connection server_1 +SET gtid_seq_no = 100; +SET @old_server_id = @@server_id; +SET server_id = 10; +BEGIN; +INSERT INTO t1 VALUES (4,1); +UPDATE t1 SET b=b+1 WHERE a=1; +INSERT INTO t1 VALUES (5,1); +INSERT INTO t1 VALUES (6,1); +COMMIT; +SET server_id = @old_server_id; +SELECT * FROM t1 ORDER BY a; +--save_master_pos + +--connection server_2 +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_x_100,rpl_parallel_simulate_double_temp_err_gtid_0_x_100"; +let $old_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +--source include/start_slave.inc +--sync_with_master +SET GLOBAL debug_dbug=@old_dbug; +let $new_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +--disable_query_log +eval SELECT $new_retry - $old_retry AS retries; +--enable_query_log + +SELECT * FROM t1 ORDER BY a; + + +--echo *** Test too many retries, eventually causing failure. *** +--source include/stop_slave.inc + +--connection server_1 +SET gtid_seq_no = 100; +SET @old_server_id = @@server_id; +SET server_id = 11; +BEGIN; +INSERT INTO t1 VALUES (7,1); +UPDATE t1 SET b=b+1 WHERE a=1; +INSERT INTO t1 VALUES (8,1); +INSERT INTO t1 VALUES (9,1); +COMMIT; +SET server_id = @old_server_id; +SELECT * FROM t1 ORDER BY a; +--save_master_pos + +--connection server_2 +SET sql_log_bin=0; +CALL mtr.add_suppression("Slave worker thread retried transaction 10 time\\(s\\) in vain, giving up"); +CALL mtr.add_suppression("Slave: Deadlock found when trying to get lock; try restarting transaction"); +SET sql_log_bin=1; + +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_x_100,rpl_parallel_simulate_infinite_temp_err_gtid_0_x_100"; +let $old_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +START SLAVE; +--let $slave_sql_errno= 1213 +--let $slave_timeout= 10 +--source include/wait_for_slave_sql_error.inc +SET GLOBAL debug_dbug=@old_dbug; +let $new_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +--disable_query_log +eval SELECT $new_retry - $old_retry AS retries; +--enable_query_log + +SELECT * FROM t1 ORDER BY a; +STOP SLAVE IO_THREAD; +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; + + --connection server_2 --source include/stop_slave.inc SET GLOBAL slave_parallel_threads=@old_parallel_threads; diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index f0147527957..0b35e3c9fdc 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -188,6 +188,22 @@ unlock_or_exit_cond(THD *thd, mysql_mutex_t *lock, bool *did_enter_cond, } +#ifndef DBUG_OFF +static int +dbug_simulate_tmp_error(rpl_group_info *rgi, THD *thd) +{ + if (rgi->current_gtid.domain_id == 0 && rgi->current_gtid.seq_no == 100 && + rgi->retry_event_count == 4) + { + thd->clear_error(); + thd->get_stmt_da()->reset_diagnostics_area(); + my_error(ER_LOCK_DEADLOCK, MYF(0)); + return 1; + } + return 0; +} +#endif + static int retry_handle_relay_log_rotate(Log_event *ev, IO_CACHE *rlog) { @@ -204,15 +220,18 @@ retry_event_group(rpl_group_info *rgi, rpl_parallel_thread *rpt, File fd; const char *errmsg= NULL; inuse_relaylog *ir= rgi->relay_log; - uint64 event_count= 0; + uint64 event_count; uint64 events_to_execute= rgi->retry_event_count; Relay_log_info *rli= rgi->rli; - int err= 0; + int err; ulonglong cur_offset, old_offset; char log_name[FN_REFLEN]; THD *thd= rgi->thd; + ulong retries= 0; do_retry: + event_count= 0; + err= 0; rgi->cleanup_context(thd, 1); mysql_mutex_lock(&rli->data_lock); @@ -268,10 +287,26 @@ do_retry: else err= retry_handle_relay_log_rotate(ev, &rlog); delete_or_keep_event_post_apply(rgi, event_type, ev); - + DBUG_EXECUTE_IF("rpl_parallel_simulate_double_temp_err_gtid_0_x_100", + if (retries == 0) err= dbug_simulate_tmp_error(rgi, thd);); + DBUG_EXECUTE_IF("rpl_parallel_simulate_infinite_temp_err_gtid_0_x_100", + err= dbug_simulate_tmp_error(rgi, thd);); if (err) { - /* ToDo: Need to here also handle second retry. */ + if (has_temporary_error(thd)) + { + ++retries; + if (retries < slave_trans_retries) + { + end_io_cache(&rlog); + mysql_file_close(fd, MYF(MY_WME)); + goto do_retry; + } + sql_print_error("Slave worker thread retried transaction %lu time(s) " + "in vain, giving up. Consider raising the value of " + "the slave_transaction_retries variable.", + slave_trans_retries); + } goto err; } @@ -592,29 +627,23 @@ handle_rpl_parallel_thread(void *arg) { ++rgi->retry_event_count; err= rpt_handle_event(events, rpt); - DBUG_EXECUTE_IF("rpl_parallel_simulate_temp_err_gtid_0_1_100", - if (rgi->current_gtid.domain_id == 0 && - rgi->current_gtid.server_id == 1 && - rgi->current_gtid.seq_no == 100 && - rgi->retry_event_count == 4) - { - thd->clear_error(); - thd->get_stmt_da()->reset_diagnostics_area(); - my_error(ER_LOCK_DEADLOCK, MYF(0)); - err= 1; - };); + delete_or_keep_event_post_apply(rgi, event_type, events->ev); + DBUG_EXECUTE_IF("rpl_parallel_simulate_temp_err_gtid_0_x_100", + err= dbug_simulate_tmp_error(rgi, thd);); if (err && has_temporary_error(thd)) err= retry_event_group(rgi, rpt, events); } else + { + delete events->ev; err= thd->wait_for_prior_commit(); + } end_of_group= in_event_group && ((group_standalone && !Log_event::is_part_of_group(event_type)) || group_ending); - delete_or_keep_event_post_apply(rgi, event_type, events->ev); events->next= qevs_to_free; qevs_to_free= events; @@ -1528,15 +1557,9 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, if (typ == GTID_EVENT) { - uint32 domain_id; - if (likely(typ == GTID_EVENT)) - { - Gtid_log_event *gtid_ev= static_cast(ev); - domain_id= (rli->mi->using_gtid == Master_info::USE_GTID_NO ? - 0 : gtid_ev->domain_id); - } - else - domain_id= 0; + Gtid_log_event *gtid_ev= static_cast(ev); + uint32 domain_id= (rli->mi->using_gtid == Master_info::USE_GTID_NO ? + 0 : gtid_ev->domain_id); if (!(e= find(domain_id))) { my_error(ER_OUT_OF_RESOURCES, MYF(MY_WME)); From 787c470cef54574e744eb5dfd9153d837fe67e45 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 15 May 2014 15:52:08 +0200 Subject: [PATCH 03/13] MDEV-5262: Missing retry after temp error in parallel replication Handle retry of event groups that span multiple relay log files. - If retry reaches the end of one relay log file, move on to the next. - Handle refcounting of relay log files, and avoid purging relay log files until all event groups have completed that might have needed them for transaction retry. --- .../suite/rpl/r/rpl_parallel_retry.result | 49 +++++- .../suite/rpl/t/rpl_parallel_retry.test | 60 ++++++- sql/log.cc | 26 ++- sql/rpl_parallel.cc | 154 +++++++++++++----- sql/rpl_parallel.h | 2 + sql/rpl_rli.cc | 5 + sql/rpl_rli.h | 21 ++- sql/slave.cc | 1 + 8 files changed, 269 insertions(+), 49 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_parallel_retry.result b/mysql-test/suite/rpl/r/rpl_parallel_retry.result index 1badf084440..cd12d92430b 100644 --- a/mysql-test/suite/rpl/r/rpl_parallel_retry.result +++ b/mysql-test/suite/rpl/r/rpl_parallel_retry.result @@ -141,9 +141,56 @@ a b 7 1 8 1 9 1 +*** Test retry of event group that spans multiple relay log files. *** +CREATE TABLE t2 (a int PRIMARY KEY, b BLOB) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1,"Hulubullu"); +include/stop_slave.inc +SET @old_max= @@GLOBAL.max_relay_log_size; +SET GLOBAL max_relay_log_size=4096; +SET gtid_seq_no = 100; +SET @old_server_id = @@server_id; +SET server_id = 12; +BEGIN; +INSERT INTO t1 VALUES (10, 4); +COMMIT; +SET server_id = @old_server_id; +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; +a b +10 4 +SELECT a, LENGTH(b) FROM t2 ORDER BY a; +a LENGTH(b) +1 9 +2 5006 +3 5012 +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_x_100"; +include/start_slave.inc +SET GLOBAL debug_dbug=@old_dbug; +retries +1 +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; +a b +10 4 +SELECT a, LENGTH(b) FROM t2 ORDER BY a; +a LENGTH(b) +1 9 +2 5006 +3 5012 +INSERT INTO t1 VALUES (11,11); +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; +a b +10 4 +11 11 +SELECT a, LENGTH(b) FROM t2 ORDER BY a; +a LENGTH(b) +1 9 +2 5006 +3 5012 +4 5000 +SET GLOBAL max_relay_log_size=@old_max; include/stop_slave.inc SET GLOBAL slave_parallel_threads=@old_parallel_threads; include/start_slave.inc -DROP TABLE t1; +DROP TABLE t1, t2; DROP function foo; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_retry.test b/mysql-test/suite/rpl/t/rpl_parallel_retry.test index a2ccce45f0c..d3be6262cb0 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel_retry.test +++ b/mysql-test/suite/rpl/t/rpl_parallel_retry.test @@ -149,6 +149,64 @@ STOP SLAVE IO_THREAD; --sync_with_master SELECT * FROM t1 ORDER BY a; +--echo *** Test retry of event group that spans multiple relay log files. *** + +--connection server_1 +CREATE TABLE t2 (a int PRIMARY KEY, b BLOB) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1,"Hulubullu"); +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc +SET @old_max= @@GLOBAL.max_relay_log_size; +SET GLOBAL max_relay_log_size=4096; + +--connection server_1 +--let $big= `SELECT REPEAT("*", 5000)` +SET gtid_seq_no = 100; +SET @old_server_id = @@server_id; +SET server_id = 12; +BEGIN; +--disable_query_log +eval INSERT INTO t2 VALUES (2, CONCAT("Hello ", "$big")); +eval INSERT INTO t2 VALUES (3, CONCAT("Long data: ", "$big")); +--enable_query_log +INSERT INTO t1 VALUES (10, 4); +COMMIT; +SET server_id = @old_server_id; +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; +SELECT a, LENGTH(b) FROM t2 ORDER BY a; +--save_master_pos + +--connection server_2 +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_x_100"; +let $old_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +--source include/start_slave.inc +--sync_with_master +SET GLOBAL debug_dbug=@old_dbug; +let $new_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +--disable_query_log +eval SELECT $new_retry - $old_retry AS retries; +--enable_query_log + +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; +SELECT a, LENGTH(b) FROM t2 ORDER BY a; + +--connection server_1 +INSERT INTO t1 VALUES (11,11); +--disable_query_log +eval INSERT INTO t2 VALUES (4, "$big"); +--enable_query_log +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; +SELECT a, LENGTH(b) FROM t2 ORDER BY a; +SET GLOBAL max_relay_log_size=@old_max; + --connection server_2 --source include/stop_slave.inc @@ -156,7 +214,7 @@ SET GLOBAL slave_parallel_threads=@old_parallel_threads; --source include/start_slave.inc --connection server_1 -DROP TABLE t1; +DROP TABLE t1, t2; DROP function foo; --source include/rpl_end.inc diff --git a/sql/log.cc b/sql/log.cc index 4f9a1f2b746..116ac6aed52 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -4097,6 +4097,7 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included) { int error; char *to_purge_if_included= NULL; + inuse_relaylog *ir; DBUG_ENTER("purge_first_log"); DBUG_ASSERT(is_open()); @@ -4104,7 +4105,30 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included) DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name)); mysql_mutex_lock(&LOCK_index); - to_purge_if_included= my_strdup(rli->group_relay_log_name, MYF(0)); + + ir= rli->inuse_relaylog_list; + while (ir) + { + inuse_relaylog *next= ir->next; + if (!ir->completed || ir->dequeued_count < ir->queued_count) + { + included= false; + break; + } + if (!included && 0 == strcmp(ir->name, rli->group_relay_log_name)) + break; + if (!next) + { + rli->last_inuse_relaylog= NULL; + included= 1; + to_purge_if_included= my_strdup(ir->name, MYF(0)); + } + my_free(ir); + ir= next; + } + rli->inuse_relaylog_list= ir; + if (ir) + to_purge_if_included= my_strdup(ir->name, MYF(0)); /* Read the next log file name from the index file and pass it back to diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 0b35e3c9fdc..67d61b7cf11 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -204,20 +204,14 @@ dbug_simulate_tmp_error(rpl_group_info *rgi, THD *thd) } #endif -static int -retry_handle_relay_log_rotate(Log_event *ev, IO_CACHE *rlog) -{ - /* ToDo */ - return 0; -} - static int retry_event_group(rpl_group_info *rgi, rpl_parallel_thread *rpt, rpl_parallel_thread::queued_event *orig_qev) { IO_CACHE rlog; - File fd; + LOG_INFO linfo; + File fd= (File)-1; const char *errmsg= NULL; inuse_relaylog *ir= rgi->relay_log; uint64 event_count; @@ -241,7 +235,10 @@ do_retry: strcpy(log_name, ir->name); if ((fd= open_binlog(&rlog, log_name, &errmsg)) <0) - return 1; + { + err= 1; + goto err; + } cur_offset= rgi->retry_start_offset; my_b_seek(&rlog, cur_offset); @@ -249,43 +246,85 @@ do_retry: { Log_event_type event_type; Log_event *ev; + rpl_parallel_thread::queued_event *qev; - old_offset= cur_offset; - ev= Log_event::read_log_event(&rlog, 0, - rli->relay_log.description_event_for_exec /* ToDo: this needs fixing */, - opt_slave_sql_verify_checksum); - cur_offset= my_b_tell(&rlog); - - if (!ev) + /* The loop is here so we can try again the next relay log file on EOF. */ + for (;;) { - err= 1; - goto err; - } - ev->thd= thd; - event_type= ev->get_type_code(); - if (Log_event::is_group_event(event_type)) - { - rpl_parallel_thread::queued_event *qev; + old_offset= cur_offset; + ev= Log_event::read_log_event(&rlog, 0, + rli->relay_log.description_event_for_exec /* ToDo: this needs fixing */, + opt_slave_sql_verify_checksum); + cur_offset= my_b_tell(&rlog); - mysql_mutex_lock(&rpt->LOCK_rpl_thread); - qev= rpt->retry_get_qev(ev, orig_qev, log_name, cur_offset, - cur_offset - old_offset); - mysql_mutex_unlock(&rpt->LOCK_rpl_thread); - if (!qev) + if (ev) + break; + if (rlog.error < 0) { - delete ev; - my_error(ER_OUT_OF_RESOURCES, MYF(0)); + errmsg= "slave SQL thread aborted because of I/O error"; err= 1; goto err; } - err= rpt_handle_event(qev, rpt); - ++event_count; - mysql_mutex_lock(&rpt->LOCK_rpl_thread); - rpt->free_qev(qev); - mysql_mutex_unlock(&rpt->LOCK_rpl_thread); + if (rlog.error > 0) + { + sql_print_error("Slave SQL thread: I/O error reading " + "event(errno: %d cur_log->error: %d)", + my_errno, rlog.error); + errmsg= "Aborting slave SQL thread because of partial event read"; + err= 1; + goto err; + } + /* EOF. Move to the next relay log. */ + end_io_cache(&rlog); + mysql_file_close(fd, MYF(MY_WME)); + fd= (File)-1; + + /* Find the next relay log file. */ + if((err= rli->relay_log.find_log_pos(&linfo, log_name, 1)) || + (err= rli->relay_log.find_next_log(&linfo, 1))) + { + char buff[22]; + sql_print_error("next log error: %d offset: %s log: %s", + err, + llstr(linfo.index_file_offset, buff), + log_name); + goto err; + } + strmake_buf(log_name ,linfo.log_file_name); + + if ((fd= open_binlog(&rlog, log_name, &errmsg)) <0) + { + err= 1; + goto err; + } + /* Loop to try again on the new log file. */ } - else - err= retry_handle_relay_log_rotate(ev, &rlog); + + event_type= ev->get_type_code(); + if (!Log_event::is_group_event(event_type)) + { + delete ev; + continue; + } + ev->thd= thd; + + mysql_mutex_lock(&rpt->LOCK_rpl_thread); + qev= rpt->retry_get_qev(ev, orig_qev, log_name, cur_offset, + cur_offset - old_offset); + mysql_mutex_unlock(&rpt->LOCK_rpl_thread); + if (!qev) + { + delete ev; + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + err= 1; + goto err; + } + err= rpt_handle_event(qev, rpt); + ++event_count; + mysql_mutex_lock(&rpt->LOCK_rpl_thread); + rpt->free_qev(qev); + mysql_mutex_unlock(&rpt->LOCK_rpl_thread); + delete_or_keep_event_post_apply(rgi, event_type, ev); DBUG_EXECUTE_IF("rpl_parallel_simulate_double_temp_err_gtid_0_x_100", if (retries == 0) err= dbug_simulate_tmp_error(rgi, thd);); @@ -300,6 +339,7 @@ do_retry: { end_io_cache(&rlog); mysql_file_close(fd, MYF(MY_WME)); + fd= (File)-1; goto do_retry; } sql_print_error("Slave worker thread retried transaction %lu time(s) " @@ -309,15 +349,17 @@ do_retry: } goto err; } - - // ToDo: handle too many retries. - } while (event_count < events_to_execute); err: - end_io_cache(&rlog); - mysql_file_close(fd, MYF(MY_WME)); + if (fd >= 0) + { + end_io_cache(&rlog); + mysql_file_close(fd, MYF(MY_WME)); + } + if (errmsg) + sql_print_error("Error reading relay log event: %s", errmsg); return err; } @@ -340,6 +382,8 @@ handle_rpl_parallel_thread(void *arg) rpl_sql_thread_info sql_info(NULL); size_t total_event_size; int err; + inuse_relaylog *last_ir; + uint64 accumulated_ir_count; struct rpl_parallel_thread *rpt= (struct rpl_parallel_thread *)arg; @@ -683,12 +727,34 @@ handle_rpl_parallel_thread(void *arg) rpt->free_rgi(rgis_to_free); rgis_to_free= next; } + last_ir= NULL; + accumulated_ir_count= 0; while (qevs_to_free) { rpl_parallel_thread::queued_event *next= qevs_to_free->next; + inuse_relaylog *ir= qevs_to_free->ir; + /* Batch up refcount update to reduce use of synchronised operations. */ + if (last_ir != ir) + { + if (last_ir) + { + my_atomic_rwlock_wrlock(&rli->inuse_relaylog_atomic_lock); + my_atomic_add64(&last_ir->dequeued_count, accumulated_ir_count); + my_atomic_rwlock_wrunlock(&rli->inuse_relaylog_atomic_lock); + accumulated_ir_count= 0; + } + last_ir= ir; + } + ++accumulated_ir_count; rpt->free_qev(qevs_to_free); qevs_to_free= next; } + if (last_ir) + { + my_atomic_rwlock_wrlock(&rli->inuse_relaylog_atomic_lock); + my_atomic_add64(&last_ir->dequeued_count, accumulated_ir_count); + my_atomic_rwlock_wrunlock(&rli->inuse_relaylog_atomic_lock); + } if ((events= rpt->event_queue) != NULL) { @@ -1711,6 +1777,8 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev, Queue the event for processing. */ rli->event_relay_log_pos= rli->future_event_relay_log_pos; + qev->ir= rli->last_inuse_relaylog; + ++qev->ir->queued_count; cur_thread->enqueue(qev); unlock_or_exit_cond(rli->sql_driver_thd, &cur_thread->LOCK_rpl_thread, &did_enter_cond, &old_stage); diff --git a/sql/rpl_parallel.h b/sql/rpl_parallel.h index 3b6641523f6..3934fd98648 100644 --- a/sql/rpl_parallel.h +++ b/sql/rpl_parallel.h @@ -9,6 +9,7 @@ struct rpl_parallel_entry; struct rpl_parallel_thread_pool; class Relay_log_info; +struct inuse_relaylog; /* @@ -73,6 +74,7 @@ struct rpl_parallel_thread { queued_event *next; Log_event *ev; rpl_group_info *rgi; + inuse_relaylog *ir; ulonglong future_event_relay_log_pos; char event_relay_log_name[FN_REFLEN]; char future_event_master_log_name[FN_REFLEN]; diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 3a3e22f970a..688068b850f 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -92,6 +92,7 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery) mysql_cond_init(key_relay_log_info_start_cond, &start_cond, NULL); mysql_cond_init(key_relay_log_info_stop_cond, &stop_cond, NULL); mysql_cond_init(key_relay_log_info_log_space_cond, &log_space_cond, NULL); + my_atomic_rwlock_init(&inuse_relaylog_atomic_lock); relay_log.init_pthread_objects(); DBUG_VOID_RETURN; } @@ -117,6 +118,7 @@ Relay_log_info::~Relay_log_info() mysql_cond_destroy(&start_cond); mysql_cond_destroy(&stop_cond); mysql_cond_destroy(&log_space_cond); + my_atomic_rwlock_destroy(&inuse_relaylog_atomic_lock); relay_log.cleanup(); DBUG_VOID_RETURN; } @@ -1365,7 +1367,10 @@ Relay_log_info::alloc_inuse_relaylog(const char *name) if (!inuse_relaylog_list) inuse_relaylog_list= ir; else + { + last_inuse_relaylog->completed= true; last_inuse_relaylog->next= ir; + } last_inuse_relaylog= ir; return 0; diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index c2cdbcdc573..932db0a0b7d 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -170,6 +170,7 @@ public: */ inuse_relaylog *inuse_relaylog_list; inuse_relaylog *last_inuse_relaylog; + my_atomic_rwlock_t inuse_relaylog_atomic_lock; /* Needed to deal properly with cur_log getting closed and re-opened with @@ -481,12 +482,26 @@ private: Each rpl_group_info has a pointer to one of those, corresponding to the first GTID event. - A reference count keeps track of how long a relay log is potentially in use. + A pair of reference count keeps track of how long a relay log is potentially + in use. When the `completed' flag is set, all events have been read out of + the relay log, but the log might still be needed for retry in worker + threads. As worker threads complete an event group, they increment + atomically the `dequeued_count' with number of events queued. Thus, when + completed is set and dequeued_count equals queued_count, the relay log file + is finally done with and can be purged. + + By separating the queued and dequeued count, only the dequeued_count needs + multi-thread synchronisation; the completed flag and queued_count fields + are only accessed by the SQL driver thread and need no synchronisation. */ struct inuse_relaylog { inuse_relaylog *next; - uint64 queued_count; - uint64 dequeued_count; + /* Number of events in this relay log queued for worker threads. */ + int64 queued_count; + /* Number of events completed by worker threads. */ + volatile int64 dequeued_count; + /* Set when all events have been read from a relaylog. */ + bool completed; char name[FN_REFLEN]; }; diff --git a/sql/slave.cc b/sql/slave.cc index ab505a4011f..59375297448 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -6397,6 +6397,7 @@ static Log_event* next_event(rpl_group_info *rgi, ulonglong *event_size) DBUG_ASSERT(rli->cur_log_fd >= 0); mysql_file_close(rli->cur_log_fd, MYF(MY_WME)); rli->cur_log_fd = -1; + rli->last_inuse_relaylog->completed= true; if (relay_log_purge) { From 629b822913348cec56ec7a80a236f0ba2e613585 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Jun 2014 10:31:11 +0200 Subject: [PATCH 04/13] MDEV-5262, MDEV-5914, MDEV-5941, MDEV-6020: Deadlocks during parallel replication causing replication to fail. In parallel replication, we run transactions from the master in parallel, but force them to commit in the same order they did on the master. If we force T1 to commit before T2, but T2 holds eg. a row lock that is needed by T1, we get a deadlock when T2 waits until T1 has committed. Usually, we do not run T1 and T2 in parallel if there is a chance that they can have conflicting locks like this, but there are certain edge cases where it can occasionally happen (eg. MDEV-5914, MDEV-5941, MDEV-6020). The bug was that this would cause replication to hang, eventually getting a lock timeout and causing the slave to stop with error. With this patch, InnoDB will report back to the upper layer whenever a transactions T1 is about to do a lock wait on T2. If T1 and T2 are parallel replication transactions, and T2 needs to commit later than T1, we can thus detect the deadlock; we then kill T2, setting a flag that causes it to catch the kill and convert it to a deadlock error; this error will then cause T2 to roll back and release its locks (so that T1 can commit), and later T2 will be re-tried and eventually also committed. The kill happens asynchroneously in a slave background thread; this is necessary, as the reporting from InnoDB about lock waits happen deep inside the locking code, at a point where it is not possible to directly call THD::awake() due to mutexes held. Deadlock is assumed to be (very) rarely occuring, so this patch tries to minimise the performance impact on the normal case where no deadlocks occur, rather than optimise the handling of the occasional deadlock. Also fix transaction retry due to deadlock when it happens after a transaction already signalled to later transactions that it started to commit. In this case we need to undo this signalling (and later redo it when we commit again during retry), so following transactions will not start too early. Also add a missing thd->send_kill_message() that got triggered during testing (this corrects an incorrect fix for MySQL Bug#58933). --- include/mysql/plugin.h | 52 +++++++ include/mysql/plugin_audit.h.pp | 3 + include/mysql/plugin_auth.h.pp | 3 + include/mysql/plugin_ftparser.h.pp | 3 + mysql-test/r/innodb_mysql_sync.result | 3 + mysql-test/std_data/mdev6020-mysql-bin.000001 | Bin 0 -> 516117 bytes .../suite/perfschema/r/threads_mysql.result | 11 ++ mysql-test/suite/rpl/r/rpl_mdev6020.result | 49 +++++++ mysql-test/suite/rpl/t/rpl_mdev6020.test | 70 +++++++++ sql/log.cc | 14 +- sql/log_event.cc | 21 ++- sql/mysqld.cc | 25 +++- sql/mysqld.h | 10 +- sql/rpl_parallel.cc | 135 +++++++++++++++--- sql/rpl_rli.cc | 31 ++++ sql/rpl_rli.h | 2 + sql/slave.cc | 106 ++++++++++++-- sql/slave.h | 1 + sql/sql_admin.cc | 2 +- sql/sql_base.cc | 3 + sql/sql_class.cc | 64 +++++++++ sql/sql_class.h | 3 +- storage/heap/hp_write.c | 2 +- storage/innobase/lock/lock0lock.cc | 14 +- storage/xtradb/lock/lock0lock.cc | 14 +- 25 files changed, 589 insertions(+), 52 deletions(-) create mode 100644 mysql-test/std_data/mdev6020-mysql-bin.000001 create mode 100644 mysql-test/suite/rpl/r/rpl_mdev6020.result create mode 100644 mysql-test/suite/rpl/t/rpl_mdev6020.test diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index ceb6ac93ff5..42c89ce9aa9 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -730,6 +730,58 @@ void thd_set_ha_data(MYSQL_THD thd, const struct handlerton *hton, */ void thd_wakeup_subsequent_commits(MYSQL_THD thd, int wakeup_error); +/* + Used by a storage engine to report that one transaction THD is about to + go to wait for a transactional lock held by another transactions OTHER_THD. + + This is used for parallel replication, where transactions are required to + commit in the same order on the slave as they did on the master. If the + transactions on the slave can encounter lock conflicts on the slave that did + not exist on the master, this can cause deadlocks. + + The storage engine can report such conflicting locks using this call. This + will allow parallel replication to detect such conflicts and resolve the + deadlock (by killing the second transaction to release the locks that the + first is waiting for, and then later re-try the second killed transaction). + + The storage engine should not report false positives. That is, it should not + report any lock waits that do not actually require one transaction to wait + for the other. Nor should it report waits for locks that will be released + before the commit of the other transactions. +*/ +void thd_report_wait_for(const MYSQL_THD thd, MYSQL_THD other_thd); + +/* + This function can optionally be called to check if thd_report_wait_for() + needs to be called for waits done by a given transaction. + + If this function returns false for a given thd, there is no need to do any + calls to thd_report_wait_for() on that thd. + + This call is optional; it is safe to call thd_report_wait_for() in any case. + This call can be used to save some redundant calls to thd_report_wait_for() + if desired. (This is unlikely to matter much unless there are _lots_ of + waits to report, as the overhead of thd_report_wait_for() is small). +*/ +int thd_need_wait_for(const MYSQL_THD thd); + +/* + This function can be called by storage engines to check if the commit order + of two transactions has already been decided by the upper layer. This + happens in parallel replication, where the commit order is forced to be the + same on the slave as it was originally on the master. + + If this function returns false, it means that such commit order will be + enforced. This allows the storage engine to optionally omit gap lock waitss + or similar measures that would otherwise be needed to ensure that + transactions would be serialised in a way that would cause a commit order + that is correct for binlogging for statement-based replication. + + If this function returns true, normal locking should be done as required by + the binlogging and transaction isolation level in effect. +*/ +int thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd); + #ifdef __cplusplus } #endif diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index 98fd089570d..55d416869c7 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -314,6 +314,9 @@ void *thd_get_ha_data(const void* thd, const struct handlerton *hton); void thd_set_ha_data(void* thd, const struct handlerton *hton, const void *ha_data); void thd_wakeup_subsequent_commits(void* thd, int wakeup_error); +void thd_report_wait_for(const void* thd, void *other_thd); +int thd_need_wait_for(const void* thd); +int thd_need_ordering_with(const void* thd, const void* other_thd); struct mysql_event_general { unsigned int event_subclass; diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp index 6d52c5be7f0..552a3abb570 100644 --- a/include/mysql/plugin_auth.h.pp +++ b/include/mysql/plugin_auth.h.pp @@ -314,6 +314,9 @@ void *thd_get_ha_data(const void* thd, const struct handlerton *hton); void thd_set_ha_data(void* thd, const struct handlerton *hton, const void *ha_data); void thd_wakeup_subsequent_commits(void* thd, int wakeup_error); +void thd_report_wait_for(const void* thd, void *other_thd); +int thd_need_wait_for(const void* thd); +int thd_need_ordering_with(const void* thd, const void* other_thd); #include typedef struct st_plugin_vio_info { diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp index cb3e7cafc97..d57185a0ac3 100644 --- a/include/mysql/plugin_ftparser.h.pp +++ b/include/mysql/plugin_ftparser.h.pp @@ -267,6 +267,9 @@ void *thd_get_ha_data(const void* thd, const struct handlerton *hton); void thd_set_ha_data(void* thd, const struct handlerton *hton, const void *ha_data); void thd_wakeup_subsequent_commits(void* thd, int wakeup_error); +void thd_report_wait_for(const void* thd, void *other_thd); +int thd_need_wait_for(const void* thd); +int thd_need_ordering_with(const void* thd, const void* other_thd); enum enum_ftparser_mode { MYSQL_FTPARSER_SIMPLE_MODE= 0, diff --git a/mysql-test/r/innodb_mysql_sync.result b/mysql-test/r/innodb_mysql_sync.result index 21e9cd04c22..49d69d13e40 100644 --- a/mysql-test/r/innodb_mysql_sync.result +++ b/mysql-test/r/innodb_mysql_sync.result @@ -86,7 +86,10 @@ SET DEBUG_SYNC= 'now SIGNAL killed'; # Reaping: OPTIMIZE TABLE t1 Table Op Msg_type Msg_text test.t1 optimize note Table does not support optimize, doing recreate + analyze instead +test.t1 optimize error Query execution was interrupted test.t1 optimize status Operation failed +Warnings: +Error 1317 Query execution was interrupted # Connection default DROP TABLE t1; SET DEBUG_SYNC= 'RESET'; diff --git a/mysql-test/std_data/mdev6020-mysql-bin.000001 b/mysql-test/std_data/mdev6020-mysql-bin.000001 new file mode 100644 index 0000000000000000000000000000000000000000..49853674e9f26c2d85acbf59ed23de4518bfba59 GIT binary patch literal 516117 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

K2Lup@b9A5P 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 } - if (wfc && wfc->wakeup_error) - { - my_error(ER_PRIOR_COMMIT_FAILED, MYF(0)); - DBUG_RETURN(-1); - } - /* If the transaction we were waiting for has already put us into the group commit queue (and possibly already done the entire binlog commit for us), @@ -6861,6 +6855,12 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry) if (orig_entry->queued_by_other) DBUG_RETURN(0); + if (wfc && wfc->wakeup_error) + { + my_error(ER_PRIOR_COMMIT_FAILED, MYF(0)); + DBUG_RETURN(-1); + } + /* Now enqueue ourselves in the group commit queue. */ DEBUG_SYNC(orig_entry->thd, "commit_before_enqueue"); orig_entry->thd->clear_wakeup_ready(); @@ -9064,6 +9064,8 @@ binlog_background_thread(void *arg __attribute__((unused))) thd->thread_id= thread_id++; mysql_mutex_unlock(&LOCK_thread_count); thd->store_globals(); + thd->security_ctx->skip_grants(); + thd->set_command(COM_DAEMON); /* Load the slave replication GTID state from the mysql.gtid_slave_pos diff --git a/sql/log_event.cc b/sql/log_event.cc index e9cd0ee3179..cf9f4242280 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -216,8 +216,19 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error, thd->get_stmt_da()->sql_conditions(); Relay_log_info const *rli= rgi->rli; const Sql_condition *err; + Relay_log_info const *rli= rgi->rli; buff[0]= 0; + /* + In parallel replication, deadlocks or other temporary errors can happen + occasionally in normal operation, they will be handled correctly and + automatically by re-trying the transactions. So do not pollute the error + log with messages about them. + */ + if (rgi->is_parallel_exec && + (rgi->killed_for_retry || has_temporary_error(thd))) + return; + for (err= it++, slider= buff; err && slider < buff_end - 1; slider += len, err= it++) { @@ -7306,6 +7317,13 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi) err= rpl_global_gtid_slave_state.record_gtid(thd, >id, sub_id, true, false); if (err) { + /* + Do not report an error if this is really a kill due to a deadlock. + In this case, the transaction will be re-tried instead. + */ + if (rgi->killed_for_retry && + thd->get_stmt_da()->sql_errno() == ER_QUERY_INTERRUPTED) + return err; rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, rgi->gtid_info(), "Error during XID COMMIT: failed to update GTID state in " "%s.%s: %d: %s", @@ -9631,7 +9649,8 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) if (open_and_lock_tables(thd, rgi->tables_to_lock, FALSE, 0)) { uint actual_error= thd->get_stmt_da()->sql_errno(); - if (thd->is_slave_error || thd->is_fatal_error) + if ((thd->is_slave_error || thd->is_fatal_error) && + !(rgi->killed_for_retry && actual_error == ER_QUERY_INTERRUPTED)) { /* Error reporting borrowed from Query_log_event with many excessive diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 63f392f438d..d3d262c736b 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -368,6 +368,7 @@ static I_List thread_cache; static bool binlog_format_used= false; LEX_STRING opt_init_connect, opt_init_slave; static mysql_cond_t COND_thread_cache, COND_flush_thread_cache; +mysql_cond_t COND_slave_background; static DYNAMIC_ARRAY all_options; /* Global variables */ @@ -706,7 +707,7 @@ mysql_mutex_t LOCK_crypt, LOCK_global_system_variables, LOCK_user_conn, LOCK_slave_list, LOCK_active_mi, - LOCK_connection_count, LOCK_error_messages; + LOCK_connection_count, LOCK_error_messages, LOCK_slave_background; mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats, LOCK_global_table_stats, LOCK_global_index_stats; @@ -880,7 +881,8 @@ PSI_mutex_key key_LOCK_stats, key_LOCK_wakeup_ready, key_LOCK_wait_commit; PSI_mutex_key key_LOCK_gtid_waiting; -PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered; +PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered, + key_LOCK_slave_background; PSI_mutex_key key_TABLE_SHARE_LOCK_share; static PSI_mutex_info all_server_mutexes[]= @@ -943,6 +945,7 @@ static PSI_mutex_info all_server_mutexes[]= { &key_LOCK_error_messages, "LOCK_error_messages", PSI_FLAG_GLOBAL}, { &key_LOCK_prepare_ordered, "LOCK_prepare_ordered", PSI_FLAG_GLOBAL}, { &key_LOCK_commit_ordered, "LOCK_commit_ordered", PSI_FLAG_GLOBAL}, + { &key_LOCK_slave_background, "LOCK_slave_background", PSI_FLAG_GLOBAL}, { &key_LOG_INFO_lock, "LOG_INFO::lock", 0}, { &key_LOCK_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL}, { &key_LOCK_thread_cache, "LOCK_thread_cache", PSI_FLAG_GLOBAL}, @@ -997,7 +1000,7 @@ PSI_cond_key key_TC_LOG_MMAP_COND_queue_busy; PSI_cond_key key_COND_rpl_thread_queue, key_COND_rpl_thread, key_COND_rpl_thread_pool, key_COND_parallel_entry, key_COND_group_commit_orderer, - key_COND_prepare_ordered; + key_COND_prepare_ordered, key_COND_slave_background; PSI_cond_key key_COND_wait_gtid, key_COND_gtid_ignore_duplicates; static PSI_cond_info all_server_conds[]= @@ -1046,6 +1049,7 @@ static PSI_cond_info all_server_conds[]= { &key_COND_parallel_entry, "COND_parallel_entry", 0}, { &key_COND_group_commit_orderer, "COND_group_commit_orderer", 0}, { &key_COND_prepare_ordered, "COND_prepare_ordered", 0}, + { &key_COND_slave_background, "COND_slave_background", 0}, { &key_COND_wait_gtid, "COND_wait_gtid", 0}, { &key_COND_gtid_ignore_duplicates, "COND_gtid_ignore_duplicates", 0} }; @@ -1053,7 +1057,7 @@ static PSI_cond_info all_server_conds[]= PSI_thread_key key_thread_bootstrap, key_thread_delayed_insert, key_thread_handle_manager, key_thread_main, key_thread_one_connection, key_thread_signal_hand, - key_thread_slave_init, key_rpl_parallel_thread; + key_thread_slave_background, key_rpl_parallel_thread; static PSI_thread_info all_server_threads[]= { @@ -1079,7 +1083,7 @@ static PSI_thread_info all_server_threads[]= { &key_thread_main, "main", PSI_FLAG_GLOBAL}, { &key_thread_one_connection, "one_connection", 0}, { &key_thread_signal_hand, "signal_handler", PSI_FLAG_GLOBAL}, - { &key_thread_slave_init, "slave_init", PSI_FLAG_GLOBAL}, + { &key_thread_slave_background, "slave_background", PSI_FLAG_GLOBAL}, { &key_rpl_parallel_thread, "rpl_parallel_thread", 0} }; @@ -2173,6 +2177,8 @@ static void clean_up_mutexes() mysql_mutex_destroy(&LOCK_prepare_ordered); mysql_cond_destroy(&COND_prepare_ordered); mysql_mutex_destroy(&LOCK_commit_ordered); + mysql_mutex_destroy(&LOCK_slave_background); + mysql_cond_destroy(&COND_slave_background); DBUG_VOID_RETURN; } @@ -4387,6 +4393,9 @@ static int init_thread_environment() mysql_cond_init(key_COND_prepare_ordered, &COND_prepare_ordered, NULL); mysql_mutex_init(key_LOCK_commit_ordered, &LOCK_commit_ordered, MY_MUTEX_INIT_SLOW); + mysql_mutex_init(key_LOCK_slave_background, &LOCK_slave_background, + MY_MUTEX_INIT_SLOW); + mysql_cond_init(key_COND_slave_background, &COND_slave_background, NULL); #ifdef HAVE_OPENSSL mysql_mutex_init(key_LOCK_des_key_file, @@ -9468,6 +9477,8 @@ PSI_stage_info stage_waiting_for_room_in_worker_thread= { 0, "Waiting for room i PSI_stage_info stage_master_gtid_wait_primary= { 0, "Waiting in MASTER_GTID_WAIT() (primary waiter)", 0}; PSI_stage_info stage_master_gtid_wait= { 0, "Waiting in MASTER_GTID_WAIT()", 0}; PSI_stage_info stage_gtid_wait_other_connection= { 0, "Waiting for other master connection to process GTID received on multiple master connections", 0}; +PSI_stage_info stage_slave_background_process_request= { 0, "Processing requests", 0}; +PSI_stage_info stage_slave_background_wait_request= { 0, "Waiting for requests", 0}; #ifdef HAVE_PSI_INTERFACE @@ -9591,7 +9602,9 @@ PSI_stage_info *all_server_stages[]= & stage_waiting_to_get_readlock, & stage_master_gtid_wait_primary, & stage_master_gtid_wait, - & stage_gtid_wait_other_connection + & stage_gtid_wait_other_connection, + & stage_slave_background_process_request, + & stage_slave_background_wait_request }; PSI_socket_key key_socket_tcpip, key_socket_unix, key_socket_client_connection; diff --git a/sql/mysqld.h b/sql/mysqld.h index e7eea3dfa1a..5b28fefb082 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -309,8 +309,8 @@ extern PSI_cond_key key_COND_wait_gtid, key_COND_gtid_ignore_duplicates; extern PSI_thread_key key_thread_bootstrap, key_thread_delayed_insert, key_thread_handle_manager, key_thread_kill_server, key_thread_main, - key_thread_one_connection, key_thread_signal_hand, key_thread_slave_init, - key_rpl_parallel_thread; + key_thread_one_connection, key_thread_signal_hand, + key_thread_slave_background, key_rpl_parallel_thread; extern PSI_file_key key_file_binlog, key_file_binlog_index, key_file_casetest, key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file, @@ -451,6 +451,8 @@ extern PSI_stage_info stage_waiting_for_room_in_worker_thread; extern PSI_stage_info stage_master_gtid_wait_primary; extern PSI_stage_info stage_master_gtid_wait; extern PSI_stage_info stage_gtid_wait_other_connection; +extern PSI_stage_info stage_slave_background_process_request; +extern PSI_stage_info stage_slave_background_wait_request; #ifdef HAVE_PSI_STATEMENT_INTERFACE /** @@ -518,7 +520,8 @@ extern mysql_mutex_t LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_system_variables, LOCK_user_conn, - LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count; + LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count, + LOCK_slave_background; extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_thread_count; #ifdef HAVE_OPENSSL extern mysql_mutex_t LOCK_des_key_file; @@ -529,6 +532,7 @@ extern mysql_rwlock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; extern mysql_rwlock_t LOCK_system_variables_hash; extern mysql_cond_t COND_thread_count; extern mysql_cond_t COND_manager; +extern mysql_cond_t COND_slave_background; extern int32 thread_running; extern int32 thread_count; extern my_atomic_rwlock_t thread_running_lock, thread_count_lock; diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 67d61b7cf11..65461b3f990 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -156,6 +156,7 @@ finish_event_group(THD *thd, uint64 sub_id, rpl_parallel_entry *entry, mysql_mutex_unlock(&entry->LOCK_parallel_entry); thd->clear_error(); + thd->reset_killed(); thd->get_stmt_da()->reset_diagnostics_area(); wfc->wakeup_subsequent_commits(rgi->worker_error); } @@ -188,6 +189,25 @@ unlock_or_exit_cond(THD *thd, mysql_mutex_t *lock, bool *did_enter_cond, } +static void +register_wait_for_prior_event_group_commit(rpl_group_info *rgi, + rpl_parallel_entry *entry) +{ + mysql_mutex_assert_owner(&entry->LOCK_parallel_entry); + if (rgi->wait_commit_sub_id > entry->last_committed_sub_id) + { + /* + Register that the commit of this event group must wait for the + commit of the previous event group to complete before it may + complete itself, so that we preserve commit order. + */ + wait_for_commit *waitee= + &rgi->wait_commit_group_info->commit_orderer; + rgi->commit_orderer.register_wait_for_prior_commit(waitee); + } +} + + #ifndef DBUG_OFF static int dbug_simulate_tmp_error(rpl_group_info *rgi, THD *thd) @@ -205,6 +225,40 @@ dbug_simulate_tmp_error(rpl_group_info *rgi, THD *thd) #endif +/* + If we detect a deadlock due to eg. storage engine locks that conflict with + the fixed commit order, then the later transaction will be killed + asynchroneously to allow the former to complete its commit. + + In this case, we convert the 'killed' error into a deadlock error, and retry + the later transaction. */ +static void +convert_kill_to_deadlock_error(rpl_group_info *rgi) +{ + THD *thd= rgi->thd; + + if (thd->get_stmt_da()->sql_errno() == ER_QUERY_INTERRUPTED && + rgi->killed_for_retry) + { + thd->clear_error(); + thd->get_stmt_da()->reset_diagnostics_area(); + my_error(ER_LOCK_DEADLOCK, MYF(0)); + rgi->killed_for_retry= false; + thd->reset_killed(); + } +} + + +static bool +is_group_ending(Log_event *ev, Log_event_type event_type) +{ + return event_type == XID_EVENT || + (event_type == QUERY_EVENT && + (((Query_log_event *)ev)->is_commit() || + ((Query_log_event *)ev)->is_rollback())); +} + + static int retry_event_group(rpl_group_info *rgi, rpl_parallel_thread *rpt, rpl_parallel_thread::queued_event *orig_qev) @@ -221,11 +275,46 @@ retry_event_group(rpl_group_info *rgi, rpl_parallel_thread *rpt, ulonglong cur_offset, old_offset; char log_name[FN_REFLEN]; THD *thd= rgi->thd; + rpl_parallel_entry *entry= rgi->parallel_entry; ulong retries= 0; do_retry: event_count= 0; err= 0; + + /* + If we already started committing before getting the deadlock (or other + error) that caused us to need to retry, we have already signalled + subsequent transactions that we have started committing. This is + potentially a problem, as now we will rollback, and if subsequent + transactions would start to execute now, they could see an unexpected + state of the database and get eg. key not found or duplicate key error. + + However, to get a deadlock in the first place, there must have been + another earlier transaction that is waiting for us. Thus that other + transaction has _not_ yet started to commit, and any subsequent + transactions will still be waiting at this point. + + So here, we decrement back the count of transactions that started + committing (if we already incremented it), undoing the effect of an + earlier mark_start_commit(). Then later, when the retry succeeds and we + commit again, we can do a new mark_start_commit() and eventually wake up + subsequent transactions at the proper time. + + We need to do the unmark before the rollback, to be sure that the + transaction we deadlocked with will not signal that it started to commit + until after the unmark. + */ + rgi->unmark_start_commit(); + + /* + We might get the deadlock error that causes the retry during commit, while + sitting in wait_for_prior_commit(). If this happens, we will have a + pending error in the wait_for_commit object. So clear this by + unregistering (and later re-registering) the wait. + */ + if(thd->wait_for_commit_ptr) + thd->wait_for_commit_ptr->unregister_wait_for_prior_commit(); rgi->cleanup_context(thd, 1); mysql_mutex_lock(&rli->data_lock); @@ -233,6 +322,10 @@ do_retry: statistic_increment(slave_retried_transactions, LOCK_status); mysql_mutex_unlock(&rli->data_lock); + mysql_mutex_lock(&entry->LOCK_parallel_entry); + register_wait_for_prior_event_group_commit(rgi, entry); + mysql_mutex_unlock(&entry->LOCK_parallel_entry); + strcpy(log_name, ir->name); if ((fd= open_binlog(&rlog, log_name, &errmsg)) <0) { @@ -319,6 +412,9 @@ do_retry: err= 1; goto err; } + if (is_group_ending(ev, event_type)) + rgi->mark_start_commit(); + err= rpt_handle_event(qev, rpt); ++event_count; mysql_mutex_lock(&rpt->LOCK_rpl_thread); @@ -332,6 +428,7 @@ do_retry: err= dbug_simulate_tmp_error(rgi, thd);); if (err) { + convert_kill_to_deadlock_error(rgi); if (has_temporary_error(thd)) { ++retries; @@ -599,17 +696,9 @@ handle_rpl_parallel_thread(void *arg) if (unlikely(entry->stop_on_error_sub_id <= rgi->wait_commit_sub_id)) skip_event_group= true; - else if (rgi->wait_commit_sub_id > entry->last_committed_sub_id) - { - /* - Register that the commit of this event group must wait for the - commit of the previous event group to complete before it may - complete itself, so that we preserve commit order. - */ - wait_for_commit *waitee= - &rgi->wait_commit_group_info->commit_orderer; - rgi->commit_orderer.register_wait_for_prior_commit(waitee); - } + else + register_wait_for_prior_event_group_commit(rgi, entry); + unlock_or_exit_cond(thd, &entry->LOCK_parallel_entry, &did_enter_cond, &old_stage); @@ -651,10 +740,7 @@ handle_rpl_parallel_thread(void *arg) } } - group_ending= event_type == XID_EVENT || - (event_type == QUERY_EVENT && - (((Query_log_event *)events->ev)->is_commit() || - ((Query_log_event *)events->ev)->is_rollback())); + group_ending= is_group_ending(events->ev, event_type); if (group_ending && likely(!rgi->worker_error)) { DEBUG_SYNC(thd, "rpl_parallel_before_mark_start_commit"); @@ -674,8 +760,12 @@ handle_rpl_parallel_thread(void *arg) delete_or_keep_event_post_apply(rgi, event_type, events->ev); DBUG_EXECUTE_IF("rpl_parallel_simulate_temp_err_gtid_0_x_100", err= dbug_simulate_tmp_error(rgi, thd);); - if (err && has_temporary_error(thd)) - err= retry_event_group(rgi, rpt, events); + if (err) + { + convert_kill_to_deadlock_error(rgi); + if (has_temporary_error(thd) && slave_trans_retries > 0) + err= retry_event_group(rgi, rpt, events); + } } else { @@ -691,10 +781,14 @@ handle_rpl_parallel_thread(void *arg) events->next= qevs_to_free; qevs_to_free= events; - if (unlikely(err) && !rgi->worker_error) + if (unlikely(err)) { - slave_output_error_info(rgi, thd); - signal_error_to_sql_driver_thread(thd, rgi, err); + if (!rgi->worker_error) + { + slave_output_error_info(rgi, thd); + signal_error_to_sql_driver_thread(thd, rgi, err); + } + thd->reset_killed(); } if (end_of_group) { @@ -1096,6 +1190,7 @@ rpl_parallel_thread::get_rgi(Relay_log_info *rli, Gtid_log_event *gtid_ev, rgi->relay_log= rli->last_inuse_relaylog; rgi->retry_start_offset= rli->future_event_relay_log_pos-event_size; rgi->retry_event_count= 0; + rgi->killed_for_retry= false; return rgi; } diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 688068b850f..9c315271387 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1843,6 +1843,7 @@ rpl_group_info::mark_start_commit() } +<<<<<<< TREE /* Format the current GTID as a string suitable for printing in error messages. @@ -1863,6 +1864,36 @@ rpl_group_info::gtid_info() } +======= +/* + Undo the effect of a prior mark_start_commit(). + + This is only used for retrying a transaction in parallel replication, after + we have encountered a deadlock or other temporary error. + + When we get such a deadlock, it means that the current group of transactions + did not yet all start committing (else they would not have deadlocked). So + we will not yet have woken up anything in the next group, our rgi->gco is + still live, and we can simply decrement the counter (to be incremented again + later, when the retry succeeds and reaches the commit step). +*/ +void +rpl_group_info::unmark_start_commit() +{ + rpl_parallel_entry *e; + + if (!did_mark_start_commit) + return; + + e= this->parallel_entry; + mysql_mutex_lock(&e->LOCK_parallel_entry); + --e->count_committing_event_groups; + mysql_mutex_unlock(&e->LOCK_parallel_entry); + did_mark_start_commit= false; +} + + +>>>>>>> MERGE-SOURCE rpl_sql_thread_info::rpl_sql_thread_info(Rpl_filter *filter) : rpl_filter(filter) { diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 932db0a0b7d..b44e794a795 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -646,6 +646,7 @@ struct rpl_group_info inuse_relaylog *relay_log; uint64 retry_start_offset; uint64 retry_event_count; + bool killed_for_retry; rpl_group_info(Relay_log_info *rli_); ~rpl_group_info(); @@ -735,6 +736,7 @@ struct rpl_group_info void mark_start_commit_no_lock(); void mark_start_commit(); char *gtid_info(); + void unmark_start_commit(); time_t get_row_stmt_start_timestamp() { diff --git a/sql/slave.cc b/sql/slave.cc index 59375297448..3d84dfe36ef 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -287,13 +287,22 @@ static void init_slave_psi_keys(void) #endif /* HAVE_PSI_INTERFACE */ -static bool slave_init_thread_running; +static bool slave_background_thread_running; +static bool slave_background_thread_gtid_loaded; + +struct slave_background_kill_t { + slave_background_kill_t *next; + THD *to_kill; + int errcode; +} *slave_background_kill_list; pthread_handler_t -handle_slave_init(void *arg __attribute__((unused))) +handle_slave_background(void *arg __attribute__((unused))) { THD *thd; + PSI_stage_info old_stage; + bool stop; my_thread_init(); thd= new THD; @@ -301,7 +310,10 @@ handle_slave_init(void *arg __attribute__((unused))) mysql_mutex_lock(&LOCK_thread_count); thd->thread_id= thread_id++; mysql_mutex_unlock(&LOCK_thread_count); + thd->system_thread = SYSTEM_THREAD_SLAVE_BACKGROUND; thd->store_globals(); + thd->security_ctx->skip_grants(); + thd->set_command(COM_DAEMON); thd_proc_info(thd, "Loading slave GTID position from table"); if (rpl_load_gtid_slave_state(thd)) @@ -311,13 +323,53 @@ handle_slave_init(void *arg __attribute__((unused))) thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message()); + mysql_mutex_lock(&LOCK_thread_count); + threads.append(thd); + slave_background_thread_gtid_loaded= true; + mysql_cond_broadcast(&COND_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); + + THD_STAGE_INFO(thd, stage_slave_background_process_request); + do + { + slave_background_kill_t *kill_list; + + mysql_mutex_lock(&LOCK_slave_background); + thd->ENTER_COND(&COND_slave_background, &LOCK_slave_background, + &stage_slave_background_wait_request, + &old_stage); + for (;;) + { + stop= abort_loop || thd->killed; + kill_list= slave_background_kill_list; + if (stop || kill_list) + break; + mysql_cond_wait(&COND_slave_background, &LOCK_slave_background); + } + + slave_background_kill_list= NULL; + thd->EXIT_COND(&old_stage); + + while (kill_list) + { + slave_background_kill_t *p = kill_list; + kill_list= p->next; + + mysql_mutex_lock(&p->to_kill->LOCK_thd_data); + /* ToDo: mark the p->errcode error code somehow ... ? */ + p->to_kill->awake(KILL_QUERY); + mysql_mutex_unlock(&p->to_kill->LOCK_thd_data); + my_free(p); + } + } while (!stop); + mysql_mutex_lock(&LOCK_thread_count); delete thd; mysql_mutex_unlock(&LOCK_thread_count); my_thread_end(); mysql_mutex_lock(&LOCK_thread_count); - slave_init_thread_running= false; + slave_background_thread_running= false; mysql_cond_broadcast(&COND_thread_count); mysql_mutex_unlock(&LOCK_thread_count); @@ -325,21 +377,57 @@ handle_slave_init(void *arg __attribute__((unused))) } +void +slave_background_kill_request(THD *to_kill, int errcode) +{ + slave_background_kill_t *p= + (slave_background_kill_t *)my_malloc(sizeof(*p), MYF(MY_WME)); + if (p) + { + p->to_kill= to_kill; + p->errcode= errcode; + to_kill->rgi_slave->killed_for_retry= true; + mysql_mutex_lock(&LOCK_slave_background); + p->next= slave_background_kill_list; + slave_background_kill_list= p; + mysql_mutex_unlock(&LOCK_slave_background); + mysql_cond_signal(&COND_slave_background); + } +} + + +/* + Start the slave background thread. + + This thread is currently used for two purposes: + + 1. To load the GTID state from mysql.gtid_slave_pos at server start; reading + from table requires valid THD, which is otherwise not available during + server init. + + 2. To kill worker thread transactions during parallel replication, when a + storage engine attempts to take an errorneous conflicting lock that would + cause a deadlock. Killing is done asynchroneously, as the kill may not + be safe within the context of a callback from inside storage engine + locking code. +*/ static int -run_slave_init_thread() +start_slave_background_thread() { pthread_t th; - slave_init_thread_running= true; - if (mysql_thread_create(key_thread_slave_init, &th, &connection_attrib, - handle_slave_init, NULL)) + slave_background_thread_running= true; + slave_background_thread_gtid_loaded= false; + if (mysql_thread_create(key_thread_slave_background, + &th, &connection_attrib, handle_slave_background, + NULL)) { sql_print_error("Failed to create thread while initialising slave"); return 1; } mysql_mutex_lock(&LOCK_thread_count); - while (slave_init_thread_running) + while (!slave_background_thread_gtid_loaded) mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); mysql_mutex_unlock(&LOCK_thread_count); @@ -358,7 +446,7 @@ int init_slave() init_slave_psi_keys(); #endif - if (run_slave_init_thread()) + if (start_slave_background_thread()) return 1; /* diff --git a/sql/slave.h b/sql/slave.h index 4b5bc1686fb..467e6fcc949 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -238,6 +238,7 @@ pthread_handler_t handle_slave_io(void *arg); void slave_output_error_info(rpl_group_info *rgi, THD *thd); pthread_handler_t handle_slave_sql(void *arg); bool net_request_file(NET* net, const char* fname); +void slave_background_kill_request(THD *to_kill, int errcode); extern bool volatile abort_loop; extern Master_info main_mi, *active_mi; /* active_mi for multi-master */ diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 34a076cc327..0d42294430d 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -914,7 +914,7 @@ send_result_message: protocol->store(operator_name, system_charset_info); if (result_code) // either mysql_recreate_table or analyze failed { - DBUG_ASSERT(thd->is_error() || thd->killed); + DBUG_ASSERT(thd->is_error()); if (thd->is_error()) { const char *err_msg= thd->get_stmt_da()->message(); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 055806609e7..8d5d5058ed1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2084,7 +2084,10 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, DBUG_RETURN(TRUE); if (!(flags & MYSQL_OPEN_IGNORE_KILLED) && thd->killed) + { + thd->send_kill_message(); DBUG_RETURN(TRUE); + } /* Check if we're trying to take a write lock in a read only transaction. diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a48ebd450bb..4449a77a715 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4217,6 +4217,70 @@ extern "C" int thd_rpl_is_parallel(const MYSQL_THD thd) return thd->rgi_slave && thd->rgi_slave->is_parallel_exec; } +extern "C" int +thd_need_wait_for(const MYSQL_THD thd) +{ + return thd && thd->rgi_slave && thd->rgi_slave->is_parallel_exec; +} + +extern "C" void +thd_report_wait_for(const MYSQL_THD thd, MYSQL_THD other_thd) +{ + rpl_group_info *rgi; + rpl_group_info *other_rgi; + + if (!thd || !other_thd) + return; + rgi= thd->rgi_slave; + other_rgi= other_thd->rgi_slave; + if (!rgi || !other_rgi) + return; + if (!rgi->is_parallel_exec) + return; + if (rgi->rli != other_rgi->rli) + return; + if (!rgi->gtid_sub_id) + return; + if (rgi->current_gtid.domain_id != other_rgi->current_gtid.domain_id) + return; + if (rgi->gtid_sub_id > other_rgi->gtid_sub_id) + return; + /* + This transaction is about to wait for another transaction that is required + by replication binlog order to commit after. This would cause a deadlock. + + So send a kill to the other transaction, with a temporary error; this will + cause replication to rollback (and later re-try) the other transaction, + releasing the lock for this transaction so replication can proceed. + */ + +#ifdef HAVE_REPLICATION + slave_background_kill_request(other_thd, ER_LOCK_DEADLOCK); +#endif +} + +extern "C" int +thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd) +{ + rpl_group_info *rgi= thd->rgi_slave; + rpl_group_info *other_rgi= other_thd->rgi_slave; + if (!rgi || !other_rgi) + return 1; + if (!rgi->is_parallel_exec) + return 1; + if (rgi->rli != other_rgi->rli) + return 1; + if (rgi->current_gtid.domain_id != other_rgi->current_gtid.domain_id) + return 1; + /* + These two threads are doing parallel replication within the same + replication domain. Their commit order is already fixed, so we do not need + gap locks or similar to otherwise enforce ordering (and in fact such locks + could lead to unnecessary deadlocks and transaction retry). + */ + return 0; +} + extern "C" int thd_non_transactional_update(const MYSQL_THD thd) { return(thd->transaction.all.modified_non_trans_table); diff --git a/sql/sql_class.h b/sql/sql_class.h index 5898d9e2cf8..986e371bb4e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1357,7 +1357,8 @@ enum enum_thread_type SYSTEM_THREAD_NDBCLUSTER_BINLOG= 8, SYSTEM_THREAD_EVENT_SCHEDULER= 16, SYSTEM_THREAD_EVENT_WORKER= 32, - SYSTEM_THREAD_BINLOG_BACKGROUND= 64 + SYSTEM_THREAD_BINLOG_BACKGROUND= 64, + SYSTEM_THREAD_SLAVE_BACKGROUND= 128, }; inline char const * diff --git a/storage/heap/hp_write.c b/storage/heap/hp_write.c index 6b96e1c31a3..783dc12d178 100644 --- a/storage/heap/hp_write.c +++ b/storage/heap/hp_write.c @@ -156,7 +156,7 @@ static uchar *next_free_record_pos(HP_SHARE *info) ("record file full. records: %lu max_records: %lu " "data_length: %llu index_length: %llu " "max_table_size: %llu", - info->records, info->max_records, + (unsigned long)info->records, info->max_records, info->data_length, info->index_length, info->max_table_size)); my_errno=HA_ERR_RECORD_FILE_FULL; diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index e4db2c30751..811ac89b948 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -49,6 +49,7 @@ Created 5/7/1996 Heikki Tuuri #include "btr0btr.h" #include "dict0boot.h" #include +#include "mysql/plugin.h" /* Restricts the length of search we will do in the waits-for graph of transactions */ @@ -3873,7 +3874,15 @@ lock_deadlock_search( /* Select the joining transaction as the victim. */ return(ctx->start->id); - } else if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + } else { + /* We do not need to report autoinc locks to the upper + layer. These locks are released before commit, so they can + not cause deadlocks with binlog-fixed commit order. */ + if (lock_get_type_low(lock) != LOCK_TABLE || + lock_get_mode(lock) != LOCK_AUTO_INC) + thd_report_wait_for(ctx->start->mysql_thd, + lock->trx->mysql_thd); + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { /* Another trx ahead has requested a lock in an incompatible mode, and is itself waiting for a lock. */ @@ -3898,8 +3907,9 @@ lock_deadlock_search( lock = lock_get_next_lock(ctx, lock, heap_no); } - } else { + } else { lock = lock_get_next_lock(ctx, lock, heap_no); + } } } diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index 4f9395e27d8..08ac936e9d3 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -49,6 +49,7 @@ Created 5/7/1996 Heikki Tuuri #include "btr0btr.h" #include "dict0boot.h" #include +#include "mysql/plugin.h" /* Restricts the length of search we will do in the waits-for graph of transactions */ @@ -3896,7 +3897,15 @@ lock_deadlock_search( /* Select the joining transaction as the victim. */ return(ctx->start->id); - } else if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + } else { + /* We do not need to report autoinc locks to the upper + layer. These locks are released before commit, so they can + not cause deadlocks with binlog-fixed commit order. */ + if (lock_get_type_low(lock) != LOCK_TABLE || + lock_get_mode(lock) != LOCK_AUTO_INC) + thd_report_wait_for(ctx->start->mysql_thd, + lock->trx->mysql_thd); + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { /* Another trx ahead has requested a lock in an incompatible mode, and is itself waiting for a lock. */ @@ -3921,8 +3930,9 @@ lock_deadlock_search( lock = lock_get_next_lock(ctx, lock, heap_no); } - } else { + } else { lock = lock_get_next_lock(ctx, lock, heap_no); + } } } From bd4153a8c2978af6d39a60a7f1c4e13c68fbbaab Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 10 Jun 2014 10:13:15 +0200 Subject: [PATCH 05/13] MDEV-5262, MDEV-5914, MDEV-5941, MDEV-6020: Deadlocks during parallel replication causing replication to fail. Remove the temporary fix for MDEV-5914, which used READ COMMITTED for parallel replication worker threads. Replace it with a better, more selective solution. The issue is with certain edge cases of InnoDB gap locks, for example between INSERT and ranged DELETE. It is possible for the gap lock set by the DELETE to block the INSERT, if the DELETE runs first, while the record lock set by INSERT does not block the DELETE, if the INSERT runs first. This can cause a conflict between the two in parallel replication on the slave even though they ran without conflicts on the master. With this patch, InnoDB will ask the server layer about the two involved transactions before blocking on a gap lock. If the server layer tells InnoDB that the transactions are already fixed wrt. commit order, as they are in parallel replication, InnoDB will ignore the gap lock and allow the two transactions to proceed in parallel, avoiding the conflict. Improve the fix for MDEV-6020. When InnoDB itself detects a deadlock, it now asks the server layer for any preferences about which transaction to roll back. In case of parallel replication with two transactions T1 and T2 fixed to commit T1 before T2, the server layer will ask InnoDB to roll back T2 as the deadlock victim, not T1. This helps in some cases to avoid excessive deadlock rollback, as T2 will in any case need to wait for T1 to complete before it can itself commit. Also some misc. fixes found during development and testing: - Remove thd_rpl_is_parallel(), it is not used or needed. - Use KILL_CONNECTION instead of KILL_QUERY when a parallel replication worker thread is killed to resolve a deadlock with fixed commit ordering. There are some cases, eg. in sql/sql_parse.cc, where a KILL_QUERY can be ignored if the query otherwise completed successfully, and this could cause the deadlock kill to be lost, so that the deadlock was not correctly resolved. - Fix random test failure due to missing wait_for_binlog_checkpoint.inc. - Make sure that deadlock or other temporary errors during parallel replication are not printed to the the error log; there were some places around the replication code with extra error logging. These conditions can occur occasionally and are handled automatically without breaking replication, so they should not pollute the error log. - Fix handling of rgi->gtid_sub_id. We need to be able to access this also at the end of a transaction, to be able to detect and resolve deadlocks due to commit ordering. But this value was also used as a flag to mark whether record_gtid() had been called, by being set to zero, losing the value. Now, introduce a separate flag rgi->gtid_pending, so rgi->gtid_sub_id remains valid for the entire duration of the transaction. - Fix one place where the code to handle ignored errors called reset_killed() unconditionally, even if no error was caught that should be ignored. This could cause loss of a deadlock kill signal, breaking deadlock detection and resolution. - Fix a couple of missing mysql_reset_thd_for_next_command(). This could cause a prior error condition to remain for the next event executed, causing assertions about errors already being set and possibly giving incorrect error handling for following event executions. - Fix code that cleared thd->rgi_slave in the parallel replication worker threads after each event execution; this caused the deadlock detection and handling code to not be able to correctly process the associated transactions as belonging to replication worker threads. - Remove useless error code in slave_background_kill_request(). - Fix bug where wfc->wakeup_error was not cleared at wait_for_commit::unregister_wait_for_prior_commit(). This could cause the error condition to wrongly propagate to a later wait_for_prior_commit(), causing spurious ER_PRIOR_COMMIT_FAILED errors. - Do not put the binlog background thread into the processlist. It causes too many result differences in mtr, but also it probably is not useful for users to pollute the process list with a system thread that does not really perform any user-visible tasks... --- include/mysql/plugin.h | 23 ++++- include/mysql/plugin_audit.h.pp | 2 +- include/mysql/plugin_auth.h.pp | 2 +- include/mysql/plugin_ftparser.h.pp | 2 +- mysql-test/suite/rpl/r/rpl_parallel.result | 6 +- mysql-test/suite/rpl/t/rpl_parallel.test | 7 +- sql/log.cc | 2 +- sql/log_event.cc | 103 +++++++++++++-------- sql/rpl_gtid.cc | 6 +- sql/rpl_parallel.cc | 47 +--------- sql/rpl_parallel.h | 2 +- sql/rpl_rli.cc | 5 +- sql/rpl_rli.h | 2 + sql/slave.cc | 52 +++++++---- sql/slave.h | 2 +- sql/sql_class.cc | 68 +++++++++++--- sql/sql_class.h | 2 + storage/innobase/handler/ha_innodb.cc | 7 +- storage/innobase/lock/lock0lock.cc | 22 +++++ storage/innobase/trx/trx0trx.cc | 33 +++---- storage/xtradb/handler/ha_innodb.cc | 7 +- storage/xtradb/lock/lock0lock.cc | 22 +++++ storage/xtradb/trx/trx0trx.cc | 28 ++---- 23 files changed, 273 insertions(+), 179 deletions(-) diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index 42c89ce9aa9..e23799e493b 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -622,7 +622,6 @@ void **thd_ha_data(const MYSQL_THD thd, const struct handlerton *hton); void thd_storage_lock_wait(MYSQL_THD thd, long long value); int thd_tx_isolation(const MYSQL_THD thd); int thd_tx_is_read_only(const MYSQL_THD thd); -int thd_rpl_is_parallel(const MYSQL_THD thd); /** Create a temporary file. @@ -782,6 +781,28 @@ int thd_need_wait_for(const MYSQL_THD thd); */ int thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd); +/* + If the storage engine detects a deadlock, and needs to choose a victim + transaction to roll back, it can call this function to ask the upper + server layer for which of two possible transactions is prefered to be + aborted and rolled back. + + In parallel replication, if two transactions are running in parallel and + one is fixed to commit before the other, then the one that commits later + will be prefered as the victim - chosing the early transaction as a victim + will not resolve the deadlock anyway, as the later transaction still needs + to wait for the earlier to commit. + + Otherwise, a transaction that uses only transactional tables, and can thus + be safely rolled back, will be prefered as a deadlock victim over a + transaction that also modified non-transactional (eg. MyISAM) tables. + + The return value is -1 if the first transaction is prefered as a deadlock + victim, 1 if the second transaction is prefered, or 0 for no preference (in + which case the storage engine can make the choice as it prefers). +*/ +int thd_deadlock_victim_preference(const MYSQL_THD thd1, const MYSQL_THD thd2); + #ifdef __cplusplus } #endif diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index 55d416869c7..414d76ae740 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -303,7 +303,6 @@ void **thd_ha_data(const void* thd, const struct handlerton *hton); void thd_storage_lock_wait(void* thd, long long value); int thd_tx_isolation(const void* thd); int thd_tx_is_read_only(const void* thd); -int thd_rpl_is_parallel(const void* thd); int mysql_tmpfile(const char *prefix); unsigned long thd_get_thread_id(const void* thd); void thd_get_xid(const void* thd, MYSQL_XID *xid); @@ -317,6 +316,7 @@ void thd_wakeup_subsequent_commits(void* thd, int wakeup_error); void thd_report_wait_for(const void* thd, void *other_thd); int thd_need_wait_for(const void* thd); int thd_need_ordering_with(const void* thd, const void* other_thd); +int thd_deadlock_victim_preference(const void* thd1, const void* thd2); struct mysql_event_general { unsigned int event_subclass; diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp index 552a3abb570..1ffc0f9fe9b 100644 --- a/include/mysql/plugin_auth.h.pp +++ b/include/mysql/plugin_auth.h.pp @@ -303,7 +303,6 @@ void **thd_ha_data(const void* thd, const struct handlerton *hton); void thd_storage_lock_wait(void* thd, long long value); int thd_tx_isolation(const void* thd); int thd_tx_is_read_only(const void* thd); -int thd_rpl_is_parallel(const void* thd); int mysql_tmpfile(const char *prefix); unsigned long thd_get_thread_id(const void* thd); void thd_get_xid(const void* thd, MYSQL_XID *xid); @@ -317,6 +316,7 @@ void thd_wakeup_subsequent_commits(void* thd, int wakeup_error); void thd_report_wait_for(const void* thd, void *other_thd); int thd_need_wait_for(const void* thd); int thd_need_ordering_with(const void* thd, const void* other_thd); +int thd_deadlock_victim_preference(const void* thd1, const void* thd2); #include typedef struct st_plugin_vio_info { diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp index d57185a0ac3..4c39fb9f584 100644 --- a/include/mysql/plugin_ftparser.h.pp +++ b/include/mysql/plugin_ftparser.h.pp @@ -256,7 +256,6 @@ void **thd_ha_data(const void* thd, const struct handlerton *hton); void thd_storage_lock_wait(void* thd, long long value); int thd_tx_isolation(const void* thd); int thd_tx_is_read_only(const void* thd); -int thd_rpl_is_parallel(const void* thd); int mysql_tmpfile(const char *prefix); unsigned long thd_get_thread_id(const void* thd); void thd_get_xid(const void* thd, MYSQL_XID *xid); @@ -270,6 +269,7 @@ void thd_wakeup_subsequent_commits(void* thd, int wakeup_error); void thd_report_wait_for(const void* thd, void *other_thd); int thd_need_wait_for(const void* thd); int thd_need_ordering_with(const void* thd, const void* other_thd); +int thd_deadlock_victim_preference(const void* thd1, const void* thd2); enum enum_ftparser_mode { MYSQL_FTPARSER_SIMPLE_MODE= 0, diff --git a/mysql-test/suite/rpl/r/rpl_parallel.result b/mysql-test/suite/rpl/r/rpl_parallel.result index 20b75cbbdab..70ac0b579f3 100644 --- a/mysql-test/suite/rpl/r/rpl_parallel.result +++ b/mysql-test/suite/rpl/r/rpl_parallel.result @@ -314,7 +314,7 @@ SET debug_sync='now WAIT_FOR t1_ready'; KILL THD_ID; SET debug_sync='now WAIT_FOR t2_killed'; SET debug_sync='now SIGNAL t1_cont'; -include/wait_for_slave_sql_error.inc [errno=1317,1964] +include/wait_for_slave_sql_error.inc [errno=1317,1927,1964] STOP SLAVE IO_THREAD; SELECT * FROM t3 WHERE a >= 30 ORDER BY a; a b @@ -398,7 +398,7 @@ SET debug_sync='now WAIT_FOR t1_ready'; KILL THD_ID; SET debug_sync='now WAIT_FOR t2_killed'; SET debug_sync='now SIGNAL t1_cont'; -include/wait_for_slave_sql_error.inc [errno=1317,1964] +include/wait_for_slave_sql_error.inc [errno=1317,1927,1964] SET debug_sync='RESET'; SET GLOBAL slave_parallel_threads=0; SET GLOBAL slave_parallel_threads=10; @@ -481,7 +481,7 @@ SET debug_sync='now WAIT_FOR t1_ready'; KILL THD_ID; SET debug_sync='now WAIT_FOR t2_killed'; SET debug_sync='now SIGNAL t1_cont'; -include/wait_for_slave_sql_error.inc [errno=1317,1964] +include/wait_for_slave_sql_error.inc [errno=1317,1927,1964] SELECT * FROM t3 WHERE a >= 50 ORDER BY a; a b 51 51 diff --git a/mysql-test/suite/rpl/t/rpl_parallel.test b/mysql-test/suite/rpl/t/rpl_parallel.test index 9b68d6648e0..09111fb7461 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel.test +++ b/mysql-test/suite/rpl/t/rpl_parallel.test @@ -438,7 +438,7 @@ SET debug_sync='now WAIT_FOR t2_killed'; # Now we can allow T1 to proceed. SET debug_sync='now SIGNAL t1_cont'; ---let $slave_sql_errno= 1317,1964 +--let $slave_sql_errno= 1317,1927,1964 --source include/wait_for_slave_sql_error.inc STOP SLAVE IO_THREAD; SELECT * FROM t3 WHERE a >= 30 ORDER BY a; @@ -573,7 +573,7 @@ SET debug_sync='now WAIT_FOR t2_killed'; # Now we can allow T1 to proceed. SET debug_sync='now SIGNAL t1_cont'; ---let $slave_sql_errno= 1317,1964 +--let $slave_sql_errno= 1317,1927,1964 --source include/wait_for_slave_sql_error.inc # Now we have to disable the debug_sync statements, so they do not trigger @@ -712,7 +712,7 @@ SET debug_sync='now WAIT_FOR t2_killed'; # Now we can allow T1 to proceed. SET debug_sync='now SIGNAL t1_cont'; ---let $slave_sql_errno= 1317,1964 +--let $slave_sql_errno= 1317,1927,1964 --source include/wait_for_slave_sql_error.inc SELECT * FROM t3 WHERE a >= 50 ORDER BY a; @@ -1277,6 +1277,7 @@ eval SELECT IF('$io_pos' = '$sql_pos', "OK", "Not ok, $io_pos <> $sql_pos") AS t --connection server_1 FLUSH LOGS; +--source include/wait_for_binlog_checkpoint.inc --save_master_pos --connection server_2 diff --git a/sql/log.cc b/sql/log.cc index 66be81562a5..9d9c263b5c2 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -6836,7 +6836,7 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry) /* Interrupted by kill. */ DEBUG_SYNC(orig_entry->thd, "group_commit_waiting_for_prior_killed"); wfc->wakeup_error= orig_entry->thd->killed_errno(); - if (wfc->wakeup_error) + if (!wfc->wakeup_error) wfc->wakeup_error= ER_QUERY_INTERRUPTED; my_message(wfc->wakeup_error, ER(wfc->wakeup_error), MYF(0)); DBUG_RETURN(-1); diff --git a/sql/log_event.cc b/sql/log_event.cc index cf9f4242280..3470c211567 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -190,6 +190,28 @@ static const char *HA_ERR(int i) return "No Error!"; } + +/* + Return true if an error caught during event execution is a temporary error + that will cause automatic retry of the event group during parallel + replication, false otherwise. + + In parallel replication, conflicting transactions can occasionally cause + deadlocks; such errors are handled automatically by rolling back re-trying + the transactions, so should not pollute the error log. +*/ +static bool +is_parallel_retry_error(rpl_group_info *rgi, int err) +{ + if (!rgi->is_parallel_exec) + return false; + if (rgi->killed_for_retry && + (err == ER_QUERY_INTERRUPTED || err == ER_CONNECTION_KILLED)) + return true; + return has_temporary_error(rgi->thd); +} + + /** Error reporting facility for Rows_log_event::do_apply_event @@ -218,6 +240,7 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error, const Sql_condition *err; Relay_log_info const *rli= rgi->rli; buff[0]= 0; + int errcode= thd->is_error() ? thd->get_stmt_da()->sql_errno() : 0; /* In parallel replication, deadlocks or other temporary errors can happen @@ -225,8 +248,7 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error, automatically by re-trying the transactions. So do not pollute the error log with messages about them. */ - if (rgi->is_parallel_exec && - (rgi->killed_for_retry || has_temporary_error(thd))) + if (is_parallel_retry_error(rgi, errcode)) return; for (err= it++, slider= buff; err && slider < buff_end - 1; @@ -238,8 +260,7 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error, } if (ha_error != 0) - rli->report(level, thd->is_error() ? thd->get_stmt_da()->sql_errno() : 0, - rgi->gtid_info(), + rli->report(level, errcode, rgi->gtid_info(), "Could not execute %s event on table %s.%s;" "%s handler error %s; " "the event's master log %s, end_log_pos %lu", @@ -247,8 +268,7 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error, buff, handler_error == NULL ? "" : handler_error, log_name, pos); else - rli->report(level, thd->is_error() ? thd->get_stmt_da()->sql_errno() : 0, - rgi->gtid_info(), + rli->report(level, errcode, rgi->gtid_info(), "Could not execute %s event on table %s.%s;" "%s the event's master log %s, end_log_pos %lu", type, table->s->db.str, table->s->table_name.str, @@ -4098,7 +4118,8 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, */ int error; char llbuff[22]; - if ((error= rows_event_stmt_cleanup(rgi, thd))) + if ((error= rows_event_stmt_cleanup(rgi, thd)) && + !is_parallel_retry_error(rgi, error)) { rli->report(ERROR_LEVEL, error, rgi->gtid_info(), "Error in cleaning up after an event preceding the commit; " @@ -4245,22 +4266,24 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, Record any GTID in the same transaction, so slave state is transactionally consistent. */ - if (current_stmt_is_commit && (sub_id= rgi->gtid_sub_id)) + if (current_stmt_is_commit && rgi->gtid_pending) { - /* Clear the GTID from the RLI so we don't accidentally reuse it. */ - rgi->gtid_sub_id= 0; + sub_id= rgi->gtid_sub_id; + rgi->gtid_pending= false; gtid= rgi->current_gtid; thd->variables.option_bits&= ~OPTION_GTID_BEGIN; if (rpl_global_gtid_slave_state.record_gtid(thd, >id, sub_id, true, false)) { - rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, - rgi->gtid_info(), - "Error during COMMIT: failed to update GTID state in " - "%s.%s: %d: %s", - "mysql", rpl_gtid_slave_state_table_name.str, - thd->get_stmt_da()->sql_errno(), - thd->get_stmt_da()->message()); + int errcode= thd->get_stmt_da()->sql_errno(); + if (!is_parallel_retry_error(rgi, errcode)) + rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, + rgi->gtid_info(), + "Error during COMMIT: failed to update GTID state in " + "%s.%s: %d: %s", + "mysql", rpl_gtid_slave_state_table_name.str, + errcode, + thd->get_stmt_da()->message()); trans_rollback(thd); sub_id= 0; thd->is_slave_error= 1; @@ -4407,18 +4430,21 @@ Default database: '%s'. Query: '%s'", { DBUG_PRINT("info",("error ignored")); clear_all_errors(thd, const_cast(rli)); - thd->reset_killed(); + if (actual_error == ER_QUERY_INTERRUPTED || + actual_error == ER_CONNECTION_KILLED) + thd->reset_killed(); } /* Other cases: mostly we expected no error and get one. */ else if (thd->is_slave_error || thd->is_fatal_error) { - rli->report(ERROR_LEVEL, actual_error, rgi->gtid_info(), - "Error '%s' on query. Default database: '%s'. Query: '%s'", - (actual_error ? thd->get_stmt_da()->message() : - "unexpected success or fatal error"), - print_slave_db_safe(thd->db), query_arg); + if (!is_parallel_retry_error(rgi, actual_error)) + rli->report(ERROR_LEVEL, actual_error, rgi->gtid_info(), + "Error '%s' on query. Default database: '%s'. Query: '%s'", + (actual_error ? thd->get_stmt_da()->message() : + "unexpected success or fatal error"), + print_slave_db_safe(thd->db), query_arg); thd->is_slave_error= 1; } @@ -6518,12 +6544,10 @@ Gtid_log_event::do_apply_event(rpl_group_info *rgi) thd->variables.server_id= this->server_id; thd->variables.gtid_domain_id= this->domain_id; thd->variables.gtid_seq_no= this->seq_no; + mysql_reset_thd_for_next_command(thd); if (opt_gtid_strict_mode && opt_bin_log && opt_log_slave_updates) { - /* Need to reset prior "ok" status to give an error. */ - thd->clear_error(); - thd->get_stmt_da()->reset_diagnostics_area(); if (mysql_bin_log.check_strict_gtid_sequence(this->domain_id, this->server_id, this->seq_no)) return 1; @@ -7301,35 +7325,34 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi) bool res; int err; rpl_gtid gtid; - uint64 sub_id; + uint64 sub_id= 0; Relay_log_info const *rli= rgi->rli; + mysql_reset_thd_for_next_command(thd); /* Record any GTID in the same transaction, so slave state is transactionally consistent. */ - if ((sub_id= rgi->gtid_sub_id)) + if (rgi->gtid_pending) { - /* Clear the GTID from the RLI so we don't accidentally reuse it. */ - rgi->gtid_sub_id= 0; + sub_id= rgi->gtid_sub_id; + rgi->gtid_pending= false; gtid= rgi->current_gtid; err= rpl_global_gtid_slave_state.record_gtid(thd, >id, sub_id, true, false); if (err) { + int ec= thd->get_stmt_da()->sql_errno(); /* Do not report an error if this is really a kill due to a deadlock. In this case, the transaction will be re-tried instead. */ - if (rgi->killed_for_retry && - thd->get_stmt_da()->sql_errno() == ER_QUERY_INTERRUPTED) - return err; - rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, rgi->gtid_info(), - "Error during XID COMMIT: failed to update GTID state in " - "%s.%s: %d: %s", - "mysql", rpl_gtid_slave_state_table_name.str, - thd->get_stmt_da()->sql_errno(), - thd->get_stmt_da()->message()); + if (!is_parallel_retry_error(rgi, ec)) + rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, rgi->gtid_info(), + "Error during XID COMMIT: failed to update GTID state in " + "%s.%s: %d: %s", + "mysql", rpl_gtid_slave_state_table_name.str, ec, + thd->get_stmt_da()->message()); trans_rollback(thd); thd->is_slave_error= 1; return err; @@ -9650,7 +9673,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) { uint actual_error= thd->get_stmt_da()->sql_errno(); if ((thd->is_slave_error || thd->is_fatal_error) && - !(rgi->killed_for_retry && actual_error == ER_QUERY_INTERRUPTED)) + !is_parallel_retry_error(rgi, actual_error)) { /* Error reporting borrowed from Query_log_event with many excessive diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc index dc7c7b972b9..c8d5e2a2db0 100644 --- a/sql/rpl_gtid.cc +++ b/sql/rpl_gtid.cc @@ -65,16 +65,16 @@ rpl_slave_state::update_state_hash(uint64 sub_id, rpl_gtid *gtid, int rpl_slave_state::record_and_update_gtid(THD *thd, rpl_group_info *rgi) { - uint64 sub_id; DBUG_ENTER("rpl_slave_state::record_and_update_gtid"); /* Update the GTID position, if we have it and did not already update it in a GTID transaction. */ - if ((sub_id= rgi->gtid_sub_id)) + if (rgi->gtid_pending) { - rgi->gtid_sub_id= 0; + uint64 sub_id= rgi->gtid_sub_id; + rgi->gtid_pending= false; if (rgi->gtid_ignore_duplicate_state!=rpl_group_info::GTID_DUPLICATE_IGNORE) { if (record_gtid(thd, &rgi->current_gtid, sub_id, false, false)) diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 65461b3f990..621ebc024bb 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -23,7 +23,6 @@ rpt_handle_event(rpl_parallel_thread::queued_event *qev, Relay_log_info *rli= rgi->rli; THD *thd= rgi->thd; - thd->rgi_slave= rgi; thd->system_thread_info.rpl_sql_info->rpl_filter = rli->mi->rpl_filter; /* ToDo: Access to thd, and what about rli, split out a parallel part? */ @@ -35,7 +34,6 @@ rpt_handle_event(rpl_parallel_thread::queued_event *qev, rgi->future_event_relay_log_pos= qev->future_event_relay_log_pos; strcpy(rgi->future_event_master_log_name, qev->future_event_master_log_name); err= apply_event_and_update_pos(qev->ev, thd, rgi, rpt); - thd->rgi_slave= NULL; thread_safe_increment64(&rli->executed_entries, &slave_executed_entries_lock); @@ -236,8 +234,9 @@ static void convert_kill_to_deadlock_error(rpl_group_info *rgi) { THD *thd= rgi->thd; + int err_code= thd->get_stmt_da()->sql_errno(); - if (thd->get_stmt_da()->sql_errno() == ER_QUERY_INTERRUPTED && + if ((err_code == ER_QUERY_INTERRUPTED || err_code == ER_CONNECTION_KILLED) && rgi->killed_for_retry) { thd->clear_error(); @@ -510,39 +509,6 @@ handle_rpl_parallel_thread(void *arg) thd->set_time(); thd->variables.lock_wait_timeout= LONG_TIMEOUT; thd->system_thread_info.rpl_sql_info= &sql_info; - /* - For now, we need to run the replication parallel worker threads in - READ COMMITTED. This is needed because gap locks are not symmetric. - For example, a gap lock from a DELETE blocks an insert intention lock, - but not vice versa. So an INSERT followed by DELETE can group commit - on the master, but if we are unlucky with thread scheduling we can - then deadlock on the slave because the INSERT ends up waiting for a - gap lock from the DELETE (and the DELETE in turn waits for the INSERT - in wait_for_prior_commit()). See also MDEV-5914. - - It should be mostly safe to run in READ COMMITTED in the slave anyway. - The commit order is already fixed from on the master, so we do not - risk logging into the binlog in an incorrect order between worker - threads (one that would cause different results if executed on a - lower-level slave that uses this slave as a master). The only - potential problem is with transactions run in a different master - connection (using multi-source replication), or run directly on the - slave by an application; when using READ COMMITTED we are not - guaranteed serialisability of binlogged statements. - - In practice, this is unlikely to be an issue. In GTID mode, such - parallel transactions from multi-source or application must in any - case use a different replication domain, in which case binlog order - by definition must be independent between the different domain. Even - in non-GTID mode, normally one will assume that the external - transactions are not conflicting with those applied by the slave, so - that isolation level should make no difference. It would be rather - strange if the result of applying query events from one master would - depend on the timing and nature of other queries executed from - different multi-source connections or done directly on the slave by - an application. Still, something to be aware of. - */ - thd->variables.tx_isolation= ISO_READ_COMMITTED; mysql_mutex_lock(&rpt->LOCK_rpl_thread); rpt->thd= thd; @@ -598,7 +564,7 @@ handle_rpl_parallel_thread(void *arg) continue; } - group_rgi= rgi; + thd->rgi_slave= group_rgi= rgi; gco= rgi->gco; /* Handle a new event group, which will be initiated by a GTID event. */ if ((event_type= events->ev->get_type_code()) == GTID_EVENT) @@ -607,7 +573,6 @@ handle_rpl_parallel_thread(void *arg) PSI_stage_info old_stage; uint64 wait_count; - thd->tx_isolation= (enum_tx_isolation)thd->variables.tx_isolation; in_event_group= true; /* If the standalone flag is set, then this event group consists of a @@ -618,9 +583,7 @@ handle_rpl_parallel_thread(void *arg) (0 != (static_cast(events->ev)->flags2 & Gtid_log_event::FL_STANDALONE)); - /* Save this, as it gets cleared when the event group commits. */ event_gtid_sub_id= rgi->gtid_sub_id; - rgi->thd= thd; /* @@ -796,7 +759,7 @@ handle_rpl_parallel_thread(void *arg) finish_event_group(thd, event_gtid_sub_id, entry, rgi); rgi->next= rgis_to_free; rgis_to_free= rgi; - group_rgi= rgi= NULL; + thd->rgi_slave= group_rgi= rgi= NULL; skip_event_group= false; DEBUG_SYNC(thd, "rpl_parallel_end_of_group"); } @@ -879,7 +842,7 @@ handle_rpl_parallel_thread(void *arg) in_event_group= false; mysql_mutex_lock(&rpt->LOCK_rpl_thread); rpt->free_rgi(group_rgi); - group_rgi= NULL; + thd->rgi_slave= group_rgi= NULL; skip_event_group= false; } if (!in_event_group) diff --git a/sql/rpl_parallel.h b/sql/rpl_parallel.h index 3934fd98648..415259cd3c4 100644 --- a/sql/rpl_parallel.h +++ b/sql/rpl_parallel.h @@ -182,7 +182,7 @@ struct rpl_parallel_entry { Event groups commit in order, so the rpl_group_info for an event group will be alive (at least) as long as - rpl_grou_info::gtid_sub_id > last_committed_sub_id. This can be used to + rpl_group_info::gtid_sub_id > last_committed_sub_id. This can be used to safely refer back to previous event groups if they are still executing, and ignore them if they completed, without requiring explicit synchronisation between the threads. diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 9c315271387..08327588698 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1563,6 +1563,8 @@ rpl_group_info::reinit(Relay_log_info *rli) tables_to_lock_count= 0; trans_retries= 0; last_event_start_time= 0; + gtid_sub_id= 0; + gtid_pending= false; worker_error= 0; row_stmt_start_timestamp= 0; long_find_row_note_printed= false; @@ -1572,7 +1574,7 @@ rpl_group_info::reinit(Relay_log_info *rli) } rpl_group_info::rpl_group_info(Relay_log_info *rli) - : thd(0), gtid_sub_id(0), wait_commit_sub_id(0), + : thd(0), wait_commit_sub_id(0), wait_commit_group_info(0), parallel_entry(0), deferred_events(NULL), m_annotate_event(0), is_parallel_exec(false) { @@ -1606,6 +1608,7 @@ event_group_new_gtid(rpl_group_info *rgi, Gtid_log_event *gev) rgi->current_gtid.server_id= gev->server_id; rgi->current_gtid.domain_id= gev->domain_id; rgi->current_gtid.seq_no= gev->seq_no; + rgi->gtid_pending= true; return 0; } diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index b44e794a795..f914451cf96 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -609,6 +609,8 @@ struct rpl_group_info */ char future_event_master_log_name[FN_REFLEN]; bool is_parallel_exec; + /* When gtid_pending is true, we have not yet done record_gtid(). */ + bool gtid_pending; int worker_error; /* Set true when we signalled that we reach the commit phase. Used to avoid diff --git a/sql/slave.cc b/sql/slave.cc index 3d84dfe36ef..8cc0c99d049 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -288,12 +288,12 @@ static void init_slave_psi_keys(void) static bool slave_background_thread_running; +static bool slave_background_thread_stop; static bool slave_background_thread_gtid_loaded; struct slave_background_kill_t { slave_background_kill_t *next; THD *to_kill; - int errcode; } *slave_background_kill_list; @@ -323,24 +323,21 @@ handle_slave_background(void *arg __attribute__((unused))) thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message()); - mysql_mutex_lock(&LOCK_thread_count); - threads.append(thd); + mysql_mutex_lock(&LOCK_slave_background); slave_background_thread_gtid_loaded= true; - mysql_cond_broadcast(&COND_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); + mysql_cond_broadcast(&COND_slave_background); THD_STAGE_INFO(thd, stage_slave_background_process_request); do { slave_background_kill_t *kill_list; - mysql_mutex_lock(&LOCK_slave_background); thd->ENTER_COND(&COND_slave_background, &LOCK_slave_background, &stage_slave_background_wait_request, &old_stage); for (;;) { - stop= abort_loop || thd->killed; + stop= abort_loop || thd->killed || slave_background_thread_stop; kill_list= slave_background_kill_list; if (stop || kill_list) break; @@ -356,36 +353,34 @@ handle_slave_background(void *arg __attribute__((unused))) kill_list= p->next; mysql_mutex_lock(&p->to_kill->LOCK_thd_data); - /* ToDo: mark the p->errcode error code somehow ... ? */ - p->to_kill->awake(KILL_QUERY); + p->to_kill->awake(KILL_CONNECTION); mysql_mutex_unlock(&p->to_kill->LOCK_thd_data); my_free(p); } + mysql_mutex_lock(&LOCK_slave_background); } while (!stop); + slave_background_thread_running= false; + mysql_cond_broadcast(&COND_slave_background); + mysql_mutex_unlock(&LOCK_slave_background); + mysql_mutex_lock(&LOCK_thread_count); delete thd; mysql_mutex_unlock(&LOCK_thread_count); my_thread_end(); - mysql_mutex_lock(&LOCK_thread_count); - slave_background_thread_running= false; - mysql_cond_broadcast(&COND_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); - return 0; } void -slave_background_kill_request(THD *to_kill, int errcode) +slave_background_kill_request(THD *to_kill) { slave_background_kill_t *p= (slave_background_kill_t *)my_malloc(sizeof(*p), MYF(MY_WME)); if (p) { p->to_kill= to_kill; - p->errcode= errcode; to_kill->rgi_slave->killed_for_retry= true; mysql_mutex_lock(&LOCK_slave_background); p->next= slave_background_kill_list; @@ -417,6 +412,7 @@ start_slave_background_thread() pthread_t th; slave_background_thread_running= true; + slave_background_thread_stop= false; slave_background_thread_gtid_loaded= false; if (mysql_thread_create(key_thread_slave_background, &th, &connection_attrib, handle_slave_background, @@ -426,15 +422,27 @@ start_slave_background_thread() return 1; } - mysql_mutex_lock(&LOCK_thread_count); + mysql_mutex_lock(&LOCK_slave_background); while (!slave_background_thread_gtid_loaded) - mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); + mysql_cond_wait(&COND_slave_background, &LOCK_slave_background); + mysql_mutex_unlock(&LOCK_slave_background); return 0; } +static void +stop_slave_background_thread() +{ + mysql_mutex_lock(&LOCK_slave_background); + slave_background_thread_stop= true; + mysql_cond_broadcast(&COND_slave_background); + while (slave_background_thread_running) + mysql_cond_wait(&COND_slave_background, &LOCK_slave_background); + mysql_mutex_unlock(&LOCK_slave_background); +} + + /* Initialize slave structures */ int init_slave() @@ -1076,6 +1084,9 @@ void end_slave() master_info_index= 0; active_mi= 0; mysql_mutex_unlock(&LOCK_active_mi); + + stop_slave_background_thread(); + global_rpl_thread_pool.destroy(); free_all_rpl_filters(); DBUG_VOID_RETURN; @@ -3399,7 +3410,7 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Make sure we do not errorneously update gtid_slave_pos with a lingering GTID from this failed event group (MDEV-4906). */ - rgi->gtid_sub_id= 0; + rgi->gtid_pending= false; } DBUG_RETURN(exec_res ? 1 : 0); @@ -4557,6 +4568,7 @@ pthread_handler_t handle_slave_sql(void *arg) mysql_mutex_unlock(&rli->log_space_lock); serial_rgi->gtid_sub_id= 0; + serial_rgi->gtid_pending= false; if (init_relay_log_pos(rli, rli->group_relay_log_name, rli->group_relay_log_pos, diff --git a/sql/slave.h b/sql/slave.h index 467e6fcc949..3ec4d1dadeb 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -238,7 +238,7 @@ pthread_handler_t handle_slave_io(void *arg); void slave_output_error_info(rpl_group_info *rgi, THD *thd); pthread_handler_t handle_slave_sql(void *arg); bool net_request_file(NET* net, const char* fname); -void slave_background_kill_request(THD *to_kill, int errcode); +void slave_background_kill_request(THD *to_kill); extern bool volatile abort_loop; extern Master_info main_mi, *active_mi; /* active_mi for multi-master */ diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 4449a77a715..dfad764c022 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4211,16 +4211,17 @@ extern "C" int thd_slave_thread(const MYSQL_THD thd) return(thd->slave_thread); } -/* Returns true for a worker thread in parallel replication. */ -extern "C" int thd_rpl_is_parallel(const MYSQL_THD thd) -{ - return thd->rgi_slave && thd->rgi_slave->is_parallel_exec; -} - extern "C" int thd_need_wait_for(const MYSQL_THD thd) { - return thd && thd->rgi_slave && thd->rgi_slave->is_parallel_exec; + rpl_group_info *rgi; + + if (!thd) + return false; + rgi= thd->rgi_slave; + if (!rgi) + return false; + return rgi->is_parallel_exec; } extern "C" void @@ -4239,7 +4240,7 @@ thd_report_wait_for(const MYSQL_THD thd, MYSQL_THD other_thd) return; if (rgi->rli != other_rgi->rli) return; - if (!rgi->gtid_sub_id) + if (!rgi->gtid_sub_id || !other_rgi->gtid_sub_id) return; if (rgi->current_gtid.domain_id != other_rgi->current_gtid.domain_id) return; @@ -4255,15 +4256,19 @@ thd_report_wait_for(const MYSQL_THD thd, MYSQL_THD other_thd) */ #ifdef HAVE_REPLICATION - slave_background_kill_request(other_thd, ER_LOCK_DEADLOCK); + slave_background_kill_request(other_thd); #endif } extern "C" int thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd) { - rpl_group_info *rgi= thd->rgi_slave; - rpl_group_info *other_rgi= other_thd->rgi_slave; + rpl_group_info *rgi, *other_rgi; + + if (!thd || !other_thd) + return 1; + rgi= thd->rgi_slave; + other_rgi= other_thd->rgi_slave; if (!rgi || !other_rgi) return 1; if (!rgi->is_parallel_exec) @@ -4281,6 +4286,46 @@ thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd) return 0; } + +extern "C" int +thd_deadlock_victim_preference(const MYSQL_THD thd1, const MYSQL_THD thd2) +{ + rpl_group_info *rgi1, *rgi2; + bool nontrans1, nontrans2; + + if (!thd1 || !thd2) + return 0; + + /* + If the transactions are participating in the same replication domain in + parallel replication, then request to select the one that will commit + later (in the fixed commit order from the master) as the deadlock victim. + */ + rgi1= thd1->rgi_slave; + rgi2= thd2->rgi_slave; + if (rgi1 && rgi2 && + rgi1->is_parallel_exec && + rgi1->rli == rgi2->rli && + rgi1->current_gtid.domain_id == rgi2->current_gtid.domain_id) + return rgi1->gtid_sub_id < rgi2->gtid_sub_id ? 1 : -1; + + /* + If one transaction has modified non-transactional tables (so that it + cannot be safely rolled back), and the other has not, then prefer to + select the purely transactional one as the victim. + */ + nontrans1= thd1->transaction.all.modified_non_trans_table; + nontrans2= thd2->transaction.all.modified_non_trans_table; + if (nontrans1 && !nontrans2) + return 1; + else if (!nontrans1 && nontrans2) + return -1; + + /* No preferences, let the storage engine decide. */ + return 0; +} + + extern "C" int thd_non_transactional_update(const MYSQL_THD thd) { return(thd->transaction.all.modified_non_trans_table); @@ -6457,6 +6502,7 @@ wait_for_commit::unregister_wait_for_prior_commit2() this->waitee= NULL; } } + wakeup_error= 0; mysql_mutex_unlock(&LOCK_wait_commit); } diff --git a/sql/sql_class.h b/sql/sql_class.h index 986e371bb4e..0cad7a933e2 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1741,6 +1741,8 @@ struct wait_for_commit { if (waitee) unregister_wait_for_prior_commit2(); + else + wakeup_error= 0; } /* Remove a waiter from the list in the waitee. Used to unregister a wait. diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 3673dd2906e..fe8ed66f20b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4274,14 +4274,11 @@ handler::Table_flags ha_innobase::table_flags() const /*============================*/ { - THD *thd = ha_thd(); /* Need to use tx_isolation here since table flags is (also) called before prebuilt is inited. */ - ulong const tx_isolation = thd_tx_isolation(thd); + ulong const tx_isolation = thd_tx_isolation(ha_thd()); - if (tx_isolation <= ISO_READ_COMMITTED && - !(tx_isolation == ISO_READ_COMMITTED && - thd_rpl_is_parallel(thd))) { + if (tx_isolation <= ISO_READ_COMMITTED) { return(int_table_flags); } diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 811ac89b948..b95eb059051 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -1016,6 +1016,28 @@ lock_rec_has_to_wait( return(FALSE); } + if ((type_mode & LOCK_GAP || lock_rec_get_gap(lock2)) && + !thd_need_ordering_with(trx->mysql_thd, + lock2->trx->mysql_thd)) { + /* If the upper server layer has already decided on the + commit order between the transaction requesting the + lock and the transaction owning the lock, we do not + need to wait for gap locks. Such ordeering by the upper + server layer happens in parallel replication, where the + commit order is fixed to match the original order on the + master. + + Such gap locks are mainly needed to get serialisability + between transactions so that they will be binlogged in + the correct order so that statement-based replication + will give the correct results. Since the right order + was already determined on the master, we do not need + to enforce it again here (and doing so could lead to + occasional deadlocks). */ + + return (FALSE); + } + return(TRUE); } diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index a07167168fc..a2a7b77606c 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1903,9 +1903,8 @@ trx_assert_started( #endif /* UNIV_DEBUG */ /*******************************************************************//** -Compares the "weight" (or size) of two transactions. Transactions that -have edited non-transactional tables are considered heavier than ones -that have not. +Compares the "weight" (or size) of two transactions. The heavier the weight, +the more reluctant we will be to choose the transaction as a deadlock victim. @return TRUE if weight(a) >= weight(b) */ UNIV_INTERN ibool @@ -1914,26 +1913,18 @@ trx_weight_ge( const trx_t* a, /*!< in: the first transaction to be compared */ const trx_t* b) /*!< in: the second transaction to be compared */ { - ibool a_notrans_edit; - ibool b_notrans_edit; + int pref; - /* If mysql_thd is NULL for a transaction we assume that it has - not edited non-transactional tables. */ + /* First ask the upper server layer if it has any preference for which + to prefer as a deadlock victim. */ + pref= thd_deadlock_victim_preference(a->mysql_thd, b->mysql_thd); + if (pref < 0) + return FALSE; + else if (pref > 0) + return TRUE; - a_notrans_edit = a->mysql_thd != NULL - && thd_has_edited_nontrans_tables(a->mysql_thd); - - b_notrans_edit = b->mysql_thd != NULL - && thd_has_edited_nontrans_tables(b->mysql_thd); - - if (a_notrans_edit != b_notrans_edit) { - - return(a_notrans_edit); - } - - /* Either both had edited non-transactional tables or both had - not, we fall back to comparing the number of altered/locked - rows. */ + /* Upper server layer had no preference, we fall back to comparing the + number of altered/locked rows. */ #if 0 fprintf(stderr, diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index d5f0966cda8..4ea5a76784a 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -4732,14 +4732,11 @@ handler::Table_flags ha_innobase::table_flags() const /*============================*/ { - THD *thd = ha_thd(); /* Need to use tx_isolation here since table flags is (also) called before prebuilt is inited. */ - ulong const tx_isolation = thd_tx_isolation(thd); + ulong const tx_isolation = thd_tx_isolation(ha_thd()); - if (tx_isolation <= ISO_READ_COMMITTED && - !(tx_isolation == ISO_READ_COMMITTED && - thd_rpl_is_parallel(thd))) { + if (tx_isolation <= ISO_READ_COMMITTED) { return(int_table_flags); } diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index 08ac936e9d3..7d580c4ff81 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -1017,6 +1017,28 @@ lock_rec_has_to_wait( return(FALSE); } + if ((type_mode & LOCK_GAP || lock_rec_get_gap(lock2)) && + !thd_need_ordering_with(trx->mysql_thd, + lock2->trx->mysql_thd)) { + /* If the upper server layer has already decided on the + commit order between the transaction requesting the + lock and the transaction owning the lock, we do not + need to wait for gap locks. Such ordeering by the upper + server layer happens in parallel replication, where the + commit order is fixed to match the original order on the + master. + + Such gap locks are mainly needed to get serialisability + between transactions so that they will be binlogged in + the correct order so that statement-based replication + will give the correct results. Since the right order + was already determined on the master, we do not need + to enforce it again here (and doing so could lead to + occasional deadlocks). */ + + return (FALSE); + } + return(TRUE); } diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc index f2c78bafd86..8af385b274c 100644 --- a/storage/xtradb/trx/trx0trx.cc +++ b/storage/xtradb/trx/trx0trx.cc @@ -2150,26 +2150,18 @@ trx_weight_ge( const trx_t* a, /*!< in: the first transaction to be compared */ const trx_t* b) /*!< in: the second transaction to be compared */ { - ibool a_notrans_edit; - ibool b_notrans_edit; + int pref; - /* If mysql_thd is NULL for a transaction we assume that it has - not edited non-transactional tables. */ + /* First ask the upper server layer if it has any preference for which + to prefer as a deadlock victim. */ + pref= thd_deadlock_victim_preference(a->mysql_thd, b->mysql_thd); + if (pref < 0) + return FALSE; + else if (pref > 0) + return TRUE; - a_notrans_edit = a->mysql_thd != NULL - && thd_has_edited_nontrans_tables(a->mysql_thd); - - b_notrans_edit = b->mysql_thd != NULL - && thd_has_edited_nontrans_tables(b->mysql_thd); - - if (a_notrans_edit != b_notrans_edit) { - - return(a_notrans_edit); - } - - /* Either both had edited non-transactional tables or both had - not, we fall back to comparing the number of altered/locked - rows. */ + /* Upper server layer had no preference, we fall back to comparing the + number of altered/locked rows. */ #if 0 fprintf(stderr, From e5149fa0d905c6702bd6dcc64c5e3194b6a630fc Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Fri, 4 Jul 2014 07:44:55 +0200 Subject: [PATCH 06/13] Fix that gap locks are only skipped within one group commit. --- sql/sql_class.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index dfad764c022..d2aa1f520de 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4277,6 +4277,8 @@ thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd) return 1; if (rgi->current_gtid.domain_id != other_rgi->current_gtid.domain_id) return 1; + if (rgi->commit_id != other_rgi->commit_id) + return 1; /* These two threads are doing parallel replication within the same replication domain. Their commit order is already fixed, so we do not need From 98fc5b3af8b1954e4480ac33d30493aa4de66ec4 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Tue, 8 Jul 2014 12:54:47 +0200 Subject: [PATCH 07/13] MDEV-5262, MDEV-5914, MDEV-5941, MDEV-6020: Deadlocks during parallel replication causing replication to fail. After-review changes. For this patch in 10.0, we do not introduce a new public storage engine API, we just fix the InnoDB/XtraDB issues. In 10.1, we will make a better public API that can be used for all storage engines (MDEV-6429). Eliminate the background thread that did deadlock kills asynchroneously. Instead, we ensure that the InnoDB/XtraDB code can handle doing the kill from inside the deadlock detection code (when thd_report_wait_for() needs to kill a later thread to resolve a deadlock). (We preserve the part of the original patch that introduces dedicated mutex and condition for the slave init thread, to remove the abuse of LOCK_thread_count for start/stop synchronisation of the slave init thread). --- include/mysql/plugin.h | 75 +--------- include/mysql/plugin_audit.h.pp | 5 +- include/mysql/plugin_auth.h.pp | 5 +- include/mysql/plugin_ftparser.h.pp | 5 +- .../suite/perfschema/r/threads_mysql.result | 11 -- sql/log.cc | 4 +- sql/log_event.cc | 7 + sql/mysqld.cc | 30 ++-- sql/mysqld.h | 10 +- sql/rpl_parallel.cc | 3 +- sql/rpl_rli.cc | 4 +- sql/rpl_rli.h | 2 + sql/slave.cc | 131 +++--------------- sql/slave.h | 1 - sql/sql_class.cc | 112 ++++++++++++++- sql/sql_class.h | 2 +- storage/heap/hp_write.c | 2 +- storage/innobase/handler/ha_innodb.cc | 9 +- storage/innobase/include/trx0trx.h | 5 + storage/innobase/lock/lock0lock.cc | 101 ++++++++++++-- storage/innobase/trx/trx0trx.cc | 3 + storage/xtradb/handler/ha_innodb.cc | 11 +- storage/xtradb/include/trx0trx.h | 5 + storage/xtradb/lock/lock0lock.cc | 101 ++++++++++++-- storage/xtradb/trx/trx0trx.cc | 3 + 25 files changed, 382 insertions(+), 265 deletions(-) diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index e23799e493b..ceb6ac93ff5 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -622,6 +622,7 @@ void **thd_ha_data(const MYSQL_THD thd, const struct handlerton *hton); void thd_storage_lock_wait(MYSQL_THD thd, long long value); int thd_tx_isolation(const MYSQL_THD thd); int thd_tx_is_read_only(const MYSQL_THD thd); +int thd_rpl_is_parallel(const MYSQL_THD thd); /** Create a temporary file. @@ -729,80 +730,6 @@ void thd_set_ha_data(MYSQL_THD thd, const struct handlerton *hton, */ void thd_wakeup_subsequent_commits(MYSQL_THD thd, int wakeup_error); -/* - Used by a storage engine to report that one transaction THD is about to - go to wait for a transactional lock held by another transactions OTHER_THD. - - This is used for parallel replication, where transactions are required to - commit in the same order on the slave as they did on the master. If the - transactions on the slave can encounter lock conflicts on the slave that did - not exist on the master, this can cause deadlocks. - - The storage engine can report such conflicting locks using this call. This - will allow parallel replication to detect such conflicts and resolve the - deadlock (by killing the second transaction to release the locks that the - first is waiting for, and then later re-try the second killed transaction). - - The storage engine should not report false positives. That is, it should not - report any lock waits that do not actually require one transaction to wait - for the other. Nor should it report waits for locks that will be released - before the commit of the other transactions. -*/ -void thd_report_wait_for(const MYSQL_THD thd, MYSQL_THD other_thd); - -/* - This function can optionally be called to check if thd_report_wait_for() - needs to be called for waits done by a given transaction. - - If this function returns false for a given thd, there is no need to do any - calls to thd_report_wait_for() on that thd. - - This call is optional; it is safe to call thd_report_wait_for() in any case. - This call can be used to save some redundant calls to thd_report_wait_for() - if desired. (This is unlikely to matter much unless there are _lots_ of - waits to report, as the overhead of thd_report_wait_for() is small). -*/ -int thd_need_wait_for(const MYSQL_THD thd); - -/* - This function can be called by storage engines to check if the commit order - of two transactions has already been decided by the upper layer. This - happens in parallel replication, where the commit order is forced to be the - same on the slave as it was originally on the master. - - If this function returns false, it means that such commit order will be - enforced. This allows the storage engine to optionally omit gap lock waitss - or similar measures that would otherwise be needed to ensure that - transactions would be serialised in a way that would cause a commit order - that is correct for binlogging for statement-based replication. - - If this function returns true, normal locking should be done as required by - the binlogging and transaction isolation level in effect. -*/ -int thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd); - -/* - If the storage engine detects a deadlock, and needs to choose a victim - transaction to roll back, it can call this function to ask the upper - server layer for which of two possible transactions is prefered to be - aborted and rolled back. - - In parallel replication, if two transactions are running in parallel and - one is fixed to commit before the other, then the one that commits later - will be prefered as the victim - chosing the early transaction as a victim - will not resolve the deadlock anyway, as the later transaction still needs - to wait for the earlier to commit. - - Otherwise, a transaction that uses only transactional tables, and can thus - be safely rolled back, will be prefered as a deadlock victim over a - transaction that also modified non-transactional (eg. MyISAM) tables. - - The return value is -1 if the first transaction is prefered as a deadlock - victim, 1 if the second transaction is prefered, or 0 for no preference (in - which case the storage engine can make the choice as it prefers). -*/ -int thd_deadlock_victim_preference(const MYSQL_THD thd1, const MYSQL_THD thd2); - #ifdef __cplusplus } #endif diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index 414d76ae740..98fd089570d 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -303,6 +303,7 @@ void **thd_ha_data(const void* thd, const struct handlerton *hton); void thd_storage_lock_wait(void* thd, long long value); int thd_tx_isolation(const void* thd); int thd_tx_is_read_only(const void* thd); +int thd_rpl_is_parallel(const void* thd); int mysql_tmpfile(const char *prefix); unsigned long thd_get_thread_id(const void* thd); void thd_get_xid(const void* thd, MYSQL_XID *xid); @@ -313,10 +314,6 @@ void *thd_get_ha_data(const void* thd, const struct handlerton *hton); void thd_set_ha_data(void* thd, const struct handlerton *hton, const void *ha_data); void thd_wakeup_subsequent_commits(void* thd, int wakeup_error); -void thd_report_wait_for(const void* thd, void *other_thd); -int thd_need_wait_for(const void* thd); -int thd_need_ordering_with(const void* thd, const void* other_thd); -int thd_deadlock_victim_preference(const void* thd1, const void* thd2); struct mysql_event_general { unsigned int event_subclass; diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp index 1ffc0f9fe9b..6d52c5be7f0 100644 --- a/include/mysql/plugin_auth.h.pp +++ b/include/mysql/plugin_auth.h.pp @@ -303,6 +303,7 @@ void **thd_ha_data(const void* thd, const struct handlerton *hton); void thd_storage_lock_wait(void* thd, long long value); int thd_tx_isolation(const void* thd); int thd_tx_is_read_only(const void* thd); +int thd_rpl_is_parallel(const void* thd); int mysql_tmpfile(const char *prefix); unsigned long thd_get_thread_id(const void* thd); void thd_get_xid(const void* thd, MYSQL_XID *xid); @@ -313,10 +314,6 @@ void *thd_get_ha_data(const void* thd, const struct handlerton *hton); void thd_set_ha_data(void* thd, const struct handlerton *hton, const void *ha_data); void thd_wakeup_subsequent_commits(void* thd, int wakeup_error); -void thd_report_wait_for(const void* thd, void *other_thd); -int thd_need_wait_for(const void* thd); -int thd_need_ordering_with(const void* thd, const void* other_thd); -int thd_deadlock_victim_preference(const void* thd1, const void* thd2); #include typedef struct st_plugin_vio_info { diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp index 4c39fb9f584..cb3e7cafc97 100644 --- a/include/mysql/plugin_ftparser.h.pp +++ b/include/mysql/plugin_ftparser.h.pp @@ -256,6 +256,7 @@ void **thd_ha_data(const void* thd, const struct handlerton *hton); void thd_storage_lock_wait(void* thd, long long value); int thd_tx_isolation(const void* thd); int thd_tx_is_read_only(const void* thd); +int thd_rpl_is_parallel(const void* thd); int mysql_tmpfile(const char *prefix); unsigned long thd_get_thread_id(const void* thd); void thd_get_xid(const void* thd, MYSQL_XID *xid); @@ -266,10 +267,6 @@ void *thd_get_ha_data(const void* thd, const struct handlerton *hton); void thd_set_ha_data(void* thd, const struct handlerton *hton, const void *ha_data); void thd_wakeup_subsequent_commits(void* thd, int wakeup_error); -void thd_report_wait_for(const void* thd, void *other_thd); -int thd_need_wait_for(const void* thd); -int thd_need_ordering_with(const void* thd, const void* other_thd); -int thd_deadlock_victim_preference(const void* thd1, const void* thd2); enum enum_ftparser_mode { MYSQL_FTPARSER_SIMPLE_MODE= 0, diff --git a/mysql-test/suite/perfschema/r/threads_mysql.result b/mysql-test/suite/perfschema/r/threads_mysql.result index b57deea012b..4da857f83fc 100644 --- a/mysql-test/suite/perfschema/r/threads_mysql.result +++ b/mysql-test/suite/perfschema/r/threads_mysql.result @@ -44,16 +44,6 @@ processlist_info NULL unified_parent_thread_id unified parent_thread_id role NULL instrumented YES -name thread/sql/slave_background -type BACKGROUND -processlist_user NULL -processlist_host NULL -processlist_db NULL -processlist_command NULL -processlist_info NULL -unified_parent_thread_id unified parent_thread_id -role NULL -instrumented YES CREATE TEMPORARY TABLE t1 AS SELECT thread_id FROM performance_schema.threads WHERE name LIKE 'thread/sql%'; @@ -115,5 +105,4 @@ parent_thread_name child_thread_name thread/sql/event_scheduler thread/sql/event_worker thread/sql/main thread/sql/one_connection thread/sql/main thread/sql/signal_handler -thread/sql/main thread/sql/slave_background thread/sql/one_connection thread/sql/event_scheduler diff --git a/sql/log.cc b/sql/log.cc index 9d9c263b5c2..80df9d5c1fa 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -4115,7 +4115,7 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included) included= false; break; } - if (!included && 0 == strcmp(ir->name, rli->group_relay_log_name)) + if (!included && !strcmp(ir->name, rli->group_relay_log_name)) break; if (!next) { @@ -9369,7 +9369,7 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name, file= -1; } - if (0 == strcmp(linfo->log_file_name, last_log_name)) + if (!strcmp(linfo->log_file_name, last_log_name)) break; // No more files to do if ((file= open_binlog(&log, linfo->log_file_name, &errmsg)) < 0) { diff --git a/sql/log_event.cc b/sql/log_event.cc index 3470c211567..eb05b3b5749 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -7328,6 +7328,13 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi) uint64 sub_id= 0; Relay_log_info const *rli= rgi->rli; + /* + XID_EVENT works like a COMMIT statement. And it also updates the + mysql.gtid_slave_pos table with the GTID of the current transaction. + + Therefore, it acts much like a normal SQL statement, so we need to do + mysql_reset_thd_for_next_command() as if starting a new statement. + */ mysql_reset_thd_for_next_command(thd); /* Record any GTID in the same transaction, so slave state is transactionally diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d3d262c736b..8b641cbc903 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -368,7 +368,7 @@ static I_List thread_cache; static bool binlog_format_used= false; LEX_STRING opt_init_connect, opt_init_slave; static mysql_cond_t COND_thread_cache, COND_flush_thread_cache; -mysql_cond_t COND_slave_background; +mysql_cond_t COND_slave_init; static DYNAMIC_ARRAY all_options; /* Global variables */ @@ -707,7 +707,7 @@ mysql_mutex_t LOCK_crypt, LOCK_global_system_variables, LOCK_user_conn, LOCK_slave_list, LOCK_active_mi, - LOCK_connection_count, LOCK_error_messages, LOCK_slave_background; + LOCK_connection_count, LOCK_error_messages, LOCK_slave_init; mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats, LOCK_global_table_stats, LOCK_global_index_stats; @@ -882,7 +882,7 @@ PSI_mutex_key key_LOCK_stats, PSI_mutex_key key_LOCK_gtid_waiting; PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered, - key_LOCK_slave_background; + key_LOCK_slave_init; PSI_mutex_key key_TABLE_SHARE_LOCK_share; static PSI_mutex_info all_server_mutexes[]= @@ -945,7 +945,7 @@ static PSI_mutex_info all_server_mutexes[]= { &key_LOCK_error_messages, "LOCK_error_messages", PSI_FLAG_GLOBAL}, { &key_LOCK_prepare_ordered, "LOCK_prepare_ordered", PSI_FLAG_GLOBAL}, { &key_LOCK_commit_ordered, "LOCK_commit_ordered", PSI_FLAG_GLOBAL}, - { &key_LOCK_slave_background, "LOCK_slave_background", PSI_FLAG_GLOBAL}, + { &key_LOCK_slave_init, "LOCK_slave_init", PSI_FLAG_GLOBAL}, { &key_LOG_INFO_lock, "LOG_INFO::lock", 0}, { &key_LOCK_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL}, { &key_LOCK_thread_cache, "LOCK_thread_cache", PSI_FLAG_GLOBAL}, @@ -1000,7 +1000,7 @@ PSI_cond_key key_TC_LOG_MMAP_COND_queue_busy; PSI_cond_key key_COND_rpl_thread_queue, key_COND_rpl_thread, key_COND_rpl_thread_pool, key_COND_parallel_entry, key_COND_group_commit_orderer, - key_COND_prepare_ordered, key_COND_slave_background; + key_COND_prepare_ordered, key_COND_slave_init; PSI_cond_key key_COND_wait_gtid, key_COND_gtid_ignore_duplicates; static PSI_cond_info all_server_conds[]= @@ -1049,7 +1049,7 @@ static PSI_cond_info all_server_conds[]= { &key_COND_parallel_entry, "COND_parallel_entry", 0}, { &key_COND_group_commit_orderer, "COND_group_commit_orderer", 0}, { &key_COND_prepare_ordered, "COND_prepare_ordered", 0}, - { &key_COND_slave_background, "COND_slave_background", 0}, + { &key_COND_slave_init, "COND_slave_init", 0}, { &key_COND_wait_gtid, "COND_wait_gtid", 0}, { &key_COND_gtid_ignore_duplicates, "COND_gtid_ignore_duplicates", 0} }; @@ -1057,7 +1057,7 @@ static PSI_cond_info all_server_conds[]= PSI_thread_key key_thread_bootstrap, key_thread_delayed_insert, key_thread_handle_manager, key_thread_main, key_thread_one_connection, key_thread_signal_hand, - key_thread_slave_background, key_rpl_parallel_thread; + key_thread_slave_init, key_rpl_parallel_thread; static PSI_thread_info all_server_threads[]= { @@ -1083,7 +1083,7 @@ static PSI_thread_info all_server_threads[]= { &key_thread_main, "main", PSI_FLAG_GLOBAL}, { &key_thread_one_connection, "one_connection", 0}, { &key_thread_signal_hand, "signal_handler", PSI_FLAG_GLOBAL}, - { &key_thread_slave_background, "slave_background", PSI_FLAG_GLOBAL}, + { &key_thread_slave_init, "slave_init", PSI_FLAG_GLOBAL}, { &key_rpl_parallel_thread, "rpl_parallel_thread", 0} }; @@ -2177,8 +2177,8 @@ static void clean_up_mutexes() mysql_mutex_destroy(&LOCK_prepare_ordered); mysql_cond_destroy(&COND_prepare_ordered); mysql_mutex_destroy(&LOCK_commit_ordered); - mysql_mutex_destroy(&LOCK_slave_background); - mysql_cond_destroy(&COND_slave_background); + mysql_mutex_destroy(&LOCK_slave_init); + mysql_cond_destroy(&COND_slave_init); DBUG_VOID_RETURN; } @@ -4393,9 +4393,9 @@ static int init_thread_environment() mysql_cond_init(key_COND_prepare_ordered, &COND_prepare_ordered, NULL); mysql_mutex_init(key_LOCK_commit_ordered, &LOCK_commit_ordered, MY_MUTEX_INIT_SLOW); - mysql_mutex_init(key_LOCK_slave_background, &LOCK_slave_background, + mysql_mutex_init(key_LOCK_slave_init, &LOCK_slave_init, MY_MUTEX_INIT_SLOW); - mysql_cond_init(key_COND_slave_background, &COND_slave_background, NULL); + mysql_cond_init(key_COND_slave_init, &COND_slave_init, NULL); #ifdef HAVE_OPENSSL mysql_mutex_init(key_LOCK_des_key_file, @@ -9477,8 +9477,6 @@ PSI_stage_info stage_waiting_for_room_in_worker_thread= { 0, "Waiting for room i PSI_stage_info stage_master_gtid_wait_primary= { 0, "Waiting in MASTER_GTID_WAIT() (primary waiter)", 0}; PSI_stage_info stage_master_gtid_wait= { 0, "Waiting in MASTER_GTID_WAIT()", 0}; PSI_stage_info stage_gtid_wait_other_connection= { 0, "Waiting for other master connection to process GTID received on multiple master connections", 0}; -PSI_stage_info stage_slave_background_process_request= { 0, "Processing requests", 0}; -PSI_stage_info stage_slave_background_wait_request= { 0, "Waiting for requests", 0}; #ifdef HAVE_PSI_INTERFACE @@ -9602,9 +9600,7 @@ PSI_stage_info *all_server_stages[]= & stage_waiting_to_get_readlock, & stage_master_gtid_wait_primary, & stage_master_gtid_wait, - & stage_gtid_wait_other_connection, - & stage_slave_background_process_request, - & stage_slave_background_wait_request + & stage_gtid_wait_other_connection }; PSI_socket_key key_socket_tcpip, key_socket_unix, key_socket_client_connection; diff --git a/sql/mysqld.h b/sql/mysqld.h index 5b28fefb082..6f7938443c5 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -309,8 +309,8 @@ extern PSI_cond_key key_COND_wait_gtid, key_COND_gtid_ignore_duplicates; extern PSI_thread_key key_thread_bootstrap, key_thread_delayed_insert, key_thread_handle_manager, key_thread_kill_server, key_thread_main, - key_thread_one_connection, key_thread_signal_hand, - key_thread_slave_background, key_rpl_parallel_thread; + key_thread_one_connection, key_thread_signal_hand, key_thread_slave_init, + key_rpl_parallel_thread; extern PSI_file_key key_file_binlog, key_file_binlog_index, key_file_casetest, key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file, @@ -451,8 +451,6 @@ extern PSI_stage_info stage_waiting_for_room_in_worker_thread; extern PSI_stage_info stage_master_gtid_wait_primary; extern PSI_stage_info stage_master_gtid_wait; extern PSI_stage_info stage_gtid_wait_other_connection; -extern PSI_stage_info stage_slave_background_process_request; -extern PSI_stage_info stage_slave_background_wait_request; #ifdef HAVE_PSI_STATEMENT_INTERFACE /** @@ -521,7 +519,7 @@ extern mysql_mutex_t LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_system_variables, LOCK_user_conn, LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count, - LOCK_slave_background; + LOCK_slave_init; extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_thread_count; #ifdef HAVE_OPENSSL extern mysql_mutex_t LOCK_des_key_file; @@ -532,7 +530,7 @@ extern mysql_rwlock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; extern mysql_rwlock_t LOCK_system_variables_hash; extern mysql_cond_t COND_thread_count; extern mysql_cond_t COND_manager; -extern mysql_cond_t COND_slave_background; +extern mysql_cond_t COND_slave_init; extern int32 thread_running; extern int32 thread_count; extern my_atomic_rwlock_t thread_running_lock, thread_count_lock; diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 621ebc024bb..98753865568 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -240,7 +240,6 @@ convert_kill_to_deadlock_error(rpl_group_info *rgi) rgi->killed_for_retry) { thd->clear_error(); - thd->get_stmt_da()->reset_diagnostics_area(); my_error(ER_LOCK_DEADLOCK, MYF(0)); rgi->killed_for_retry= false; thd->reset_killed(); @@ -325,7 +324,7 @@ do_retry: register_wait_for_prior_event_group_commit(rgi, entry); mysql_mutex_unlock(&entry->LOCK_parallel_entry); - strcpy(log_name, ir->name); + strmake_buf(log_name, ir->name); if ((fd= open_binlog(&rlog, log_name, &errmsg)) <0) { err= 1; diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 08327588698..ee1ca37ccc5 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1362,7 +1362,7 @@ Relay_log_info::alloc_inuse_relaylog(const char *name) my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*ir)); return 1; } - strcpy(ir->name, name); + strmake_buf(ir->name, name); if (!inuse_relaylog_list) inuse_relaylog_list= ir; @@ -1564,6 +1564,7 @@ rpl_group_info::reinit(Relay_log_info *rli) trans_retries= 0; last_event_start_time= 0; gtid_sub_id= 0; + commit_id= 0; gtid_pending= false; worker_error= 0; row_stmt_start_timestamp= 0; @@ -1608,6 +1609,7 @@ event_group_new_gtid(rpl_group_info *rgi, Gtid_log_event *gev) rgi->current_gtid.server_id= gev->server_id; rgi->current_gtid.domain_id= gev->domain_id; rgi->current_gtid.seq_no= gev->seq_no; + rgi->commit_id= gev->commit_id; rgi->gtid_pending= true; return 0; } diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index f914451cf96..ce30813790c 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -170,6 +170,7 @@ public: */ inuse_relaylog *inuse_relaylog_list; inuse_relaylog *last_inuse_relaylog; + /* Lock used to protect inuse_relaylog::dequeued_count */ my_atomic_rwlock_t inuse_relaylog_atomic_lock; /* @@ -532,6 +533,7 @@ struct rpl_group_info */ uint64 gtid_sub_id; rpl_gtid current_gtid; + uint64 commit_id; /* This is used to keep transaction commit order. We will signal this when we commit, and can register it to wait for the diff --git a/sql/slave.cc b/sql/slave.cc index 8cc0c99d049..2f832309d94 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -287,22 +287,13 @@ static void init_slave_psi_keys(void) #endif /* HAVE_PSI_INTERFACE */ -static bool slave_background_thread_running; -static bool slave_background_thread_stop; -static bool slave_background_thread_gtid_loaded; - -struct slave_background_kill_t { - slave_background_kill_t *next; - THD *to_kill; -} *slave_background_kill_list; +static bool slave_init_thread_running; pthread_handler_t -handle_slave_background(void *arg __attribute__((unused))) +handle_slave_init(void *arg __attribute__((unused))) { THD *thd; - PSI_stage_info old_stage; - bool stop; my_thread_init(); thd= new THD; @@ -310,7 +301,7 @@ handle_slave_background(void *arg __attribute__((unused))) mysql_mutex_lock(&LOCK_thread_count); thd->thread_id= thread_id++; mysql_mutex_unlock(&LOCK_thread_count); - thd->system_thread = SYSTEM_THREAD_SLAVE_BACKGROUND; + thd->system_thread = SYSTEM_THREAD_SLAVE_INIT; thd->store_globals(); thd->security_ctx->skip_grants(); thd->set_command(COM_DAEMON); @@ -323,126 +314,49 @@ handle_slave_background(void *arg __attribute__((unused))) thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message()); - mysql_mutex_lock(&LOCK_slave_background); - slave_background_thread_gtid_loaded= true; - mysql_cond_broadcast(&COND_slave_background); - - THD_STAGE_INFO(thd, stage_slave_background_process_request); - do - { - slave_background_kill_t *kill_list; - - thd->ENTER_COND(&COND_slave_background, &LOCK_slave_background, - &stage_slave_background_wait_request, - &old_stage); - for (;;) - { - stop= abort_loop || thd->killed || slave_background_thread_stop; - kill_list= slave_background_kill_list; - if (stop || kill_list) - break; - mysql_cond_wait(&COND_slave_background, &LOCK_slave_background); - } - - slave_background_kill_list= NULL; - thd->EXIT_COND(&old_stage); - - while (kill_list) - { - slave_background_kill_t *p = kill_list; - kill_list= p->next; - - mysql_mutex_lock(&p->to_kill->LOCK_thd_data); - p->to_kill->awake(KILL_CONNECTION); - mysql_mutex_unlock(&p->to_kill->LOCK_thd_data); - my_free(p); - } - mysql_mutex_lock(&LOCK_slave_background); - } while (!stop); - - slave_background_thread_running= false; - mysql_cond_broadcast(&COND_slave_background); - mysql_mutex_unlock(&LOCK_slave_background); - mysql_mutex_lock(&LOCK_thread_count); delete thd; mysql_mutex_unlock(&LOCK_thread_count); my_thread_end(); + mysql_mutex_lock(&LOCK_slave_init); + slave_init_thread_running= false; + mysql_cond_broadcast(&COND_slave_init); + mysql_mutex_unlock(&LOCK_slave_init); + return 0; } -void -slave_background_kill_request(THD *to_kill) -{ - slave_background_kill_t *p= - (slave_background_kill_t *)my_malloc(sizeof(*p), MYF(MY_WME)); - if (p) - { - p->to_kill= to_kill; - to_kill->rgi_slave->killed_for_retry= true; - mysql_mutex_lock(&LOCK_slave_background); - p->next= slave_background_kill_list; - slave_background_kill_list= p; - mysql_mutex_unlock(&LOCK_slave_background); - mysql_cond_signal(&COND_slave_background); - } -} - - /* - Start the slave background thread. + Start the slave init thread. - This thread is currently used for two purposes: - - 1. To load the GTID state from mysql.gtid_slave_pos at server start; reading - from table requires valid THD, which is otherwise not available during - server init. - - 2. To kill worker thread transactions during parallel replication, when a - storage engine attempts to take an errorneous conflicting lock that would - cause a deadlock. Killing is done asynchroneously, as the kill may not - be safe within the context of a callback from inside storage engine - locking code. + This thread is used to load the GTID state from mysql.gtid_slave_pos at + server start; reading from table requires valid THD, which is otherwise not + available during server init. */ static int -start_slave_background_thread() +run_slave_init_thread() { pthread_t th; - slave_background_thread_running= true; - slave_background_thread_stop= false; - slave_background_thread_gtid_loaded= false; - if (mysql_thread_create(key_thread_slave_background, - &th, &connection_attrib, handle_slave_background, - NULL)) + slave_init_thread_running= true; + if (mysql_thread_create(key_thread_slave_init, &th, &connection_attrib, + handle_slave_init, NULL)) { sql_print_error("Failed to create thread while initialising slave"); return 1; } - mysql_mutex_lock(&LOCK_slave_background); - while (!slave_background_thread_gtid_loaded) - mysql_cond_wait(&COND_slave_background, &LOCK_slave_background); - mysql_mutex_unlock(&LOCK_slave_background); + mysql_mutex_lock(&LOCK_slave_init); + while (!slave_init_thread_running) + mysql_cond_wait(&COND_slave_init, &LOCK_slave_init); + mysql_mutex_unlock(&LOCK_slave_init); return 0; } -static void -stop_slave_background_thread() -{ - mysql_mutex_lock(&LOCK_slave_background); - slave_background_thread_stop= true; - mysql_cond_broadcast(&COND_slave_background); - while (slave_background_thread_running) - mysql_cond_wait(&COND_slave_background, &LOCK_slave_background); - mysql_mutex_unlock(&LOCK_slave_background); -} - - /* Initialize slave structures */ int init_slave() @@ -454,7 +368,7 @@ int init_slave() init_slave_psi_keys(); #endif - if (start_slave_background_thread()) + if (run_slave_init_thread()) return 1; /* @@ -1084,9 +998,6 @@ void end_slave() master_info_index= 0; active_mi= 0; mysql_mutex_unlock(&LOCK_active_mi); - - stop_slave_background_thread(); - global_rpl_thread_pool.destroy(); free_all_rpl_filters(); DBUG_VOID_RETURN; diff --git a/sql/slave.h b/sql/slave.h index 3ec4d1dadeb..4b5bc1686fb 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -238,7 +238,6 @@ pthread_handler_t handle_slave_io(void *arg); void slave_output_error_info(rpl_group_info *rgi, THD *thd); pthread_handler_t handle_slave_sql(void *arg); bool net_request_file(NET* net, const char* fname); -void slave_background_kill_request(THD *to_kill); extern bool volatile abort_loop; extern Master_info main_mi, *active_mi; /* active_mi for multi-master */ diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d2aa1f520de..e3e52e1c3a2 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4211,6 +4211,24 @@ extern "C" int thd_slave_thread(const MYSQL_THD thd) return(thd->slave_thread); } +/* Returns true for a worker thread in parallel replication. */ +extern "C" int thd_rpl_is_parallel(const MYSQL_THD thd) +{ + return thd->rgi_slave && thd->rgi_slave->is_parallel_exec; +} + +/* + This function can optionally be called to check if thd_report_wait_for() + needs to be called for waits done by a given transaction. + + If this function returns false for a given thd, there is no need to do any + calls to thd_report_wait_for() on that thd. + + This call is optional; it is safe to call thd_report_wait_for() in any case. + This call can be used to save some redundant calls to thd_report_wait_for() + if desired. (This is unlikely to matter much unless there are _lots_ of + waits to report, as the overhead of thd_report_wait_for() is small). +*/ extern "C" int thd_need_wait_for(const MYSQL_THD thd) { @@ -4224,6 +4242,31 @@ thd_need_wait_for(const MYSQL_THD thd) return rgi->is_parallel_exec; } +/* + Used by InnoDB/XtraDB to report that one transaction THD is about to go to + wait for a transactional lock held by another transactions OTHER_THD. + + This is used for parallel replication, where transactions are required to + commit in the same order on the slave as they did on the master. If the + transactions on the slave encounters lock conflicts on the slave that did + not exist on the master, this can cause deadlocks. + + Normally, such conflicts will not occur, because the same conflict would + have prevented the two transactions from committing in parallel on the + master, thus preventing them from running in parallel on the slave in the + first place. However, it is possible in case when the optimizer chooses a + different plan on the slave than on the master (eg. table scan instead of + index scan). + + InnoDB/XtraDB reports lock waits using this call. If a lock wait causes a + deadlock with the pre-determined commit order, we kill the later transaction, + and later re-try it, to resolve the deadlock. + + This call need only receive reports about waits for locks that will remain + until the holding transaction commits. InnoDB/XtraDB auto-increment locks + are released earlier, and so need not be reported. (Such false positives are + not harmful, but could lead to unnecessary kill and retry, so best avoided). +*/ extern "C" void thd_report_wait_for(const MYSQL_THD thd, MYSQL_THD other_thd) { @@ -4254,12 +4297,51 @@ thd_report_wait_for(const MYSQL_THD thd, MYSQL_THD other_thd) cause replication to rollback (and later re-try) the other transaction, releasing the lock for this transaction so replication can proceed. */ - -#ifdef HAVE_REPLICATION - slave_background_kill_request(other_thd); -#endif + other_rgi->killed_for_retry= true; + mysql_mutex_lock(&other_thd->LOCK_thd_data); + other_thd->awake(KILL_CONNECTION); + mysql_mutex_unlock(&other_thd->LOCK_thd_data); } +/* + This function is called from InnoDB/XtraDB to check if the commit order of + two transactions has already been decided by the upper layer. This happens + in parallel replication, where the commit order is forced to be the same on + the slave as it was originally on the master. + + If this function returns false, it means that such commit order will be + enforced. This allows the storage engine to optionally omit gap lock waits + or similar measures that would otherwise be needed to ensure that + transactions would be serialised in a way that would cause a commit order + that is correct for binlogging for statement-based replication. + + Since transactions are only run in parallel on the slave if they ran without + lock conflicts on the master, normally no lock conflicts on the slave happen + during parallel replication. However, there are a couple of corner cases + where it can happen, like these secondary-index operations: + + T1: INSERT INTO t1 VALUES (7, NULL); + T2: DELETE FROM t1 WHERE b <= 3; + + T1: UPDATE t1 SET secondary=NULL WHERE primary=1 + T2: DELETE t1 WHERE secondary <= 3 + + The DELETE takes a gap lock that can block the INSERT/UPDATE, but the row + locks set by INSERT/UPDATE do not block the DELETE. Thus, the execution + order of the transactions determine whether a lock conflict occurs or + not. Thus a lock conflict can occur on the slave where it did not on the + master. + + If this function returns true, normal locking should be done as required by + the binlogging and transaction isolation level in effect. But if it returns + false, the correct order will be enforced anyway, and InnoDB/XtraDB can + avoid taking the gap lock, preventing the lock conflict. + + Calling this function is just an optimisation to avoid unnecessary + deadlocks. If it was not used, a gap lock would be set that could eventually + cause a deadlock; the deadlock would be caught by thd_report_wait_for() and + the transaction T2 killed and rolled back (and later re-tried). +*/ extern "C" int thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd) { @@ -4277,7 +4359,7 @@ thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd) return 1; if (rgi->current_gtid.domain_id != other_rgi->current_gtid.domain_id) return 1; - if (rgi->commit_id != other_rgi->commit_id) + if (!rgi->commit_id || rgi->commit_id != other_rgi->commit_id) return 1; /* These two threads are doing parallel replication within the same @@ -4289,6 +4371,26 @@ thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd) } +/* + If the storage engine detects a deadlock, and needs to choose a victim + transaction to roll back, it can call this function to ask the upper + server layer for which of two possible transactions is prefered to be + aborted and rolled back. + + In parallel replication, if two transactions are running in parallel and + one is fixed to commit before the other, then the one that commits later + will be prefered as the victim - chosing the early transaction as a victim + will not resolve the deadlock anyway, as the later transaction still needs + to wait for the earlier to commit. + + Otherwise, a transaction that uses only transactional tables, and can thus + be safely rolled back, will be prefered as a deadlock victim over a + transaction that also modified non-transactional (eg. MyISAM) tables. + + The return value is -1 if the first transaction is prefered as a deadlock + victim, 1 if the second transaction is prefered, or 0 for no preference (in + which case the storage engine can make the choice as it prefers). +*/ extern "C" int thd_deadlock_victim_preference(const MYSQL_THD thd1, const MYSQL_THD thd2) { diff --git a/sql/sql_class.h b/sql/sql_class.h index 0cad7a933e2..b24f098f519 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1358,7 +1358,7 @@ enum enum_thread_type SYSTEM_THREAD_EVENT_SCHEDULER= 16, SYSTEM_THREAD_EVENT_WORKER= 32, SYSTEM_THREAD_BINLOG_BACKGROUND= 64, - SYSTEM_THREAD_SLAVE_BACKGROUND= 128, + SYSTEM_THREAD_SLAVE_INIT= 128, }; inline char const * diff --git a/storage/heap/hp_write.c b/storage/heap/hp_write.c index 783dc12d178..6b96e1c31a3 100644 --- a/storage/heap/hp_write.c +++ b/storage/heap/hp_write.c @@ -156,7 +156,7 @@ static uchar *next_free_record_pos(HP_SHARE *info) ("record file full. records: %lu max_records: %lu " "data_length: %llu index_length: %llu " "max_table_size: %llu", - (unsigned long)info->records, info->max_records, + info->records, info->max_records, info->data_length, info->index_length, info->max_table_size)); my_errno=HA_ERR_RECORD_FILE_FULL; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index fe8ed66f20b..4058807266f 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4220,13 +4220,18 @@ innobase_kill_query( if (trx) { + THD *cur = current_thd; + THD *owner = trx->current_lock_mutex_owner; + /* Cancel a pending lock request. */ - lock_mutex_enter(); + if (owner != cur) + lock_mutex_enter(); trx_mutex_enter(trx); if (trx->lock.wait_lock) lock_cancel_waiting_and_release(trx->lock.wait_lock); trx_mutex_exit(trx); - lock_mutex_exit(); + if (owner != cur) + lock_mutex_exit(); } DBUG_VOID_RETURN; diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 34e4c0067e2..fcc9ed05081 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -992,6 +992,11 @@ struct trx_t{ count of tables being flushed. */ /*------------------------------*/ + THD* current_lock_mutex_owner; + /*!< If this is equal to current_thd, + then in innobase_kill_query() we know we + already hold the lock_sys->mutex. */ + /*------------------------------*/ #ifdef UNIV_DEBUG ulint start_line; /*!< Track where it was started from */ const char* start_file; /*!< Filename where it was started */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index b95eb059051..80f2c043871 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -374,6 +374,11 @@ struct lock_stack_t { ulint heap_no; /*!< heap number if rec lock */ }; +extern "C" void thd_report_wait_for(const MYSQL_THD thd, MYSQL_THD other_thd); +extern "C" int thd_need_wait_for(const MYSQL_THD thd); +extern "C" +int thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd); + /** Stack to use during DFS search. Currently only a single stack is required because there is no parallel deadlock check. This stack is protected by the lock_sys_t::mutex. */ @@ -392,6 +397,14 @@ UNIV_INTERN mysql_pfs_key_t lock_sys_wait_mutex_key; #ifdef UNIV_DEBUG UNIV_INTERN ibool lock_print_waits = FALSE; +/* Buffer to collect THDs to report waits for. */ +struct thd_wait_reports { + struct thd_wait_reports *next; + ulint used; + trx_t *waitees[64]; +}; + + /*********************************************************************//** Validates the lock system. @return TRUE if ok */ @@ -1032,8 +1045,12 @@ lock_rec_has_to_wait( the correct order so that statement-based replication will give the correct results. Since the right order was already determined on the master, we do not need - to enforce it again here (and doing so could lead to - occasional deadlocks). */ + to enforce it again here. + + Skipping the locks is not essential for correctness, + since in case of deadlock we will just kill the later + transaction and retry it. But it can save some + unnecessary rollbacks and retries. */ return (FALSE); } @@ -3821,7 +3838,8 @@ static trx_id_t lock_deadlock_search( /*=================*/ - lock_deadlock_ctx_t* ctx) /*!< in/out: deadlock context */ + lock_deadlock_ctx_t* ctx, /*!< in/out: deadlock context */ + struct thd_wait_reports*waitee_ptr) /*!< in/out: list of waitees */ { const lock_t* lock; ulint heap_no; @@ -3900,10 +3918,24 @@ lock_deadlock_search( /* We do not need to report autoinc locks to the upper layer. These locks are released before commit, so they can not cause deadlocks with binlog-fixed commit order. */ - if (lock_get_type_low(lock) != LOCK_TABLE || - lock_get_mode(lock) != LOCK_AUTO_INC) - thd_report_wait_for(ctx->start->mysql_thd, - lock->trx->mysql_thd); + if (waitee_ptr && (lock_get_type_low(lock) != LOCK_TABLE || + lock_get_mode(lock) != LOCK_AUTO_INC)) { + if (waitee_ptr->used == sizeof(waitee_ptr->waitees)/ + sizeof(waitee_ptr->waitees[0])) { + waitee_ptr->next = + (struct thd_wait_reports *) + mem_alloc(sizeof(*waitee_ptr)); + waitee_ptr = waitee_ptr->next; + if (!waitee_ptr) { + ctx->too_deep = TRUE; + return(ctx->start->id); + } + waitee_ptr->next = NULL; + waitee_ptr->used = 0; + } + waitee_ptr->waitees[waitee_ptr->used++] = lock->trx; + } + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { /* Another trx ahead has requested a lock in an @@ -3996,6 +4028,41 @@ lock_deadlock_trx_rollback( trx_mutex_exit(trx); } +static void +mysql_report_waiters(struct thd_wait_reports *waitee_buf_ptr, + THD *mysql_thd, + trx_id_t victim_trx_id) +{ + struct thd_wait_reports *p = waitee_buf_ptr; + while (p) { + struct thd_wait_reports *q; + ulint i = 0; + + while (i < p->used) { + trx_t *w_trx = p->waitees[i]; + /* There is no need to report waits to a trx already + selected as a victim. */ + if (w_trx->id != victim_trx_id) + { + /* If thd_report_wait_for() decides to kill the + transaction, then we will get a call back into + innobase_kill_query. We mark this by setting + current_lock_mutex_owner, so we can avoid trying + to recursively take lock_sys->mutex. */ + w_trx->current_lock_mutex_owner = mysql_thd; + thd_report_wait_for(mysql_thd, w_trx->mysql_thd); + w_trx->current_lock_mutex_owner = NULL; + } + ++i; + } + q = p->next; + if (p != waitee_buf_ptr) + mem_free(q); + p = q; + } +} + + /********************************************************************//** Checks if a joining lock request results in a deadlock. If a deadlock is found this function will resolve the dadlock by choosing a victim transaction @@ -4012,12 +4079,20 @@ lock_deadlock_check_and_resolve( const trx_t* trx) /*!< in: transaction */ { trx_id_t victim_trx_id; + struct thd_wait_reports waitee_buf, *waitee_buf_ptr; + THD* start_mysql_thd; ut_ad(trx != NULL); ut_ad(lock != NULL); ut_ad(lock_mutex_own()); assert_trx_in_list(trx); + start_mysql_thd = trx->mysql_thd; + if (start_mysql_thd && thd_need_wait_for(start_mysql_thd)) + waitee_buf_ptr = &waitee_buf; + else + waitee_buf_ptr = NULL; + /* Try and resolve as many deadlocks as possible. */ do { lock_deadlock_ctx_t ctx; @@ -4030,7 +4105,17 @@ lock_deadlock_check_and_resolve( ctx.wait_lock = lock; ctx.mark_start = lock_mark_counter; - victim_trx_id = lock_deadlock_search(&ctx); + if (waitee_buf_ptr) { + waitee_buf_ptr->next = NULL; + waitee_buf_ptr->used = 0; + } + + victim_trx_id = lock_deadlock_search(&ctx, waitee_buf_ptr); + + /* Report waits to upper layer, as needed. */ + if (waitee_buf_ptr) + mysql_report_waiters(waitee_buf_ptr, start_mysql_thd, + victim_trx_id); /* Search too deep, we rollback the joining transaction. */ if (ctx.too_deep) { diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index a2a7b77606c..7247080d4f2 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -50,6 +50,9 @@ Created 3/26/1996 Heikki Tuuri #include +extern "C" +int thd_deadlock_victim_preference(const MYSQL_THD thd1, const MYSQL_THD thd2); + /** Set of table_id */ typedef std::set table_id_set; diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 4ea5a76784a..6cf41f846c1 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -4702,12 +4702,15 @@ innobase_kill_connection( DBUG_ENTER("innobase_kill_connection"); DBUG_ASSERT(hton == innodb_hton_ptr); - lock_mutex_enter(); - trx = thd_to_trx(thd); if (trx) { + THD *cur = current_thd; + THD *owner = trx->current_lock_mutex_owner; + + if (owner != cur) + lock_mutex_enter(); trx_mutex_enter(trx); /* Cancel a pending lock request. */ @@ -4715,10 +4718,10 @@ innobase_kill_connection( lock_cancel_waiting_and_release(trx->lock.wait_lock); trx_mutex_exit(trx); + if (owner != cur) + lock_mutex_exit(); } - lock_mutex_exit(); - DBUG_VOID_RETURN; } diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h index aaa74724a14..7d1074ceaeb 100644 --- a/storage/xtradb/include/trx0trx.h +++ b/storage/xtradb/include/trx0trx.h @@ -1019,6 +1019,11 @@ struct trx_t{ count of tables being flushed. */ /*------------------------------*/ + THD* current_lock_mutex_owner; + /*!< If this is equal to current_thd, + then in innobase_kill_query() we know we + already hold the lock_sys->mutex. */ + /*------------------------------*/ #ifdef UNIV_DEBUG ulint start_line; /*!< Track where it was started from */ const char* start_file; /*!< Filename where it was started */ diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index 7d580c4ff81..27425a68697 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -374,6 +374,11 @@ struct lock_stack_t { ulint heap_no; /*!< heap number if rec lock */ }; +extern "C" void thd_report_wait_for(const MYSQL_THD thd, MYSQL_THD other_thd); +extern "C" int thd_need_wait_for(const MYSQL_THD thd); +extern "C" +int thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd); + /** Stack to use during DFS search. Currently only a single stack is required because there is no parallel deadlock check. This stack is protected by the lock_sys_t::mutex. */ @@ -392,6 +397,14 @@ UNIV_INTERN mysql_pfs_key_t lock_sys_wait_mutex_key; #ifdef UNIV_DEBUG UNIV_INTERN ibool lock_print_waits = FALSE; +/* Buffer to collect THDs to report waits for. */ +struct thd_wait_reports { + struct thd_wait_reports *next; + ulint used; + trx_t *waitees[64]; +}; + + /*********************************************************************//** Validates the lock system. @return TRUE if ok */ @@ -1033,8 +1046,12 @@ lock_rec_has_to_wait( the correct order so that statement-based replication will give the correct results. Since the right order was already determined on the master, we do not need - to enforce it again here (and doing so could lead to - occasional deadlocks). */ + to enforce it again here. + + Skipping the locks is not essential for correctness, + since in case of deadlock we will just kill the later + transaction and retry it. But it can save some + unnecessary rollbacks and retries. */ return (FALSE); } @@ -3844,7 +3861,8 @@ static trx_id_t lock_deadlock_search( /*=================*/ - lock_deadlock_ctx_t* ctx) /*!< in/out: deadlock context */ + lock_deadlock_ctx_t* ctx, /*!< in/out: deadlock context */ + struct thd_wait_reports*waitee_ptr) /*!< in/out: list of waitees */ { const lock_t* lock; ulint heap_no; @@ -3923,10 +3941,24 @@ lock_deadlock_search( /* We do not need to report autoinc locks to the upper layer. These locks are released before commit, so they can not cause deadlocks with binlog-fixed commit order. */ - if (lock_get_type_low(lock) != LOCK_TABLE || - lock_get_mode(lock) != LOCK_AUTO_INC) - thd_report_wait_for(ctx->start->mysql_thd, - lock->trx->mysql_thd); + if (waitee_ptr && (lock_get_type_low(lock) != LOCK_TABLE || + lock_get_mode(lock) != LOCK_AUTO_INC)) { + if (waitee_ptr->used == sizeof(waitee_ptr->waitees)/ + sizeof(waitee_ptr->waitees[0])) { + waitee_ptr->next = + (struct thd_wait_reports *) + mem_alloc(sizeof(*waitee_ptr)); + waitee_ptr = waitee_ptr->next; + if (!waitee_ptr) { + ctx->too_deep = TRUE; + return(ctx->start->id); + } + waitee_ptr->next = NULL; + waitee_ptr->used = 0; + } + waitee_ptr->waitees[waitee_ptr->used++] = lock->trx; + } + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { /* Another trx ahead has requested a lock in an @@ -4019,6 +4051,41 @@ lock_deadlock_trx_rollback( trx_mutex_exit(trx); } +static void +mysql_report_waiters(struct thd_wait_reports *waitee_buf_ptr, + THD *mysql_thd, + trx_id_t victim_trx_id) +{ + struct thd_wait_reports *p = waitee_buf_ptr; + while (p) { + struct thd_wait_reports *q; + ulint i = 0; + + while (i < p->used) { + trx_t *w_trx = p->waitees[i]; + /* There is no need to report waits to a trx already + selected as a victim. */ + if (w_trx->id != victim_trx_id) + { + /* If thd_report_wait_for() decides to kill the + transaction, then we will get a call back into + innobase_kill_query. We mark this by setting + current_lock_mutex_owner, so we can avoid trying + to recursively take lock_sys->mutex. */ + w_trx->current_lock_mutex_owner = mysql_thd; + thd_report_wait_for(mysql_thd, w_trx->mysql_thd); + w_trx->current_lock_mutex_owner = NULL; + } + ++i; + } + q = p->next; + if (p != waitee_buf_ptr) + mem_free(q); + p = q; + } +} + + /********************************************************************//** Checks if a joining lock request results in a deadlock. If a deadlock is found this function will resolve the dadlock by choosing a victim transaction @@ -4035,12 +4102,20 @@ lock_deadlock_check_and_resolve( const trx_t* trx) /*!< in: transaction */ { trx_id_t victim_trx_id; + struct thd_wait_reports waitee_buf, *waitee_buf_ptr; + THD* start_mysql_thd; ut_ad(trx != NULL); ut_ad(lock != NULL); ut_ad(lock_mutex_own()); assert_trx_in_list(trx); + start_mysql_thd = trx->mysql_thd; + if (start_mysql_thd && thd_need_wait_for(start_mysql_thd)) + waitee_buf_ptr = &waitee_buf; + else + waitee_buf_ptr = NULL; + /* Try and resolve as many deadlocks as possible. */ do { lock_deadlock_ctx_t ctx; @@ -4053,7 +4128,17 @@ lock_deadlock_check_and_resolve( ctx.wait_lock = lock; ctx.mark_start = lock_mark_counter; - victim_trx_id = lock_deadlock_search(&ctx); + if (waitee_buf_ptr) { + waitee_buf_ptr->next = NULL; + waitee_buf_ptr->used = 0; + } + + victim_trx_id = lock_deadlock_search(&ctx, waitee_buf_ptr); + + /* Report waits to upper layer, as needed. */ + if (waitee_buf_ptr) + mysql_report_waiters(waitee_buf_ptr, start_mysql_thd, + victim_trx_id); /* Search too deep, we rollback the joining transaction. */ if (ctx.too_deep) { diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc index 8af385b274c..64a7c9edd40 100644 --- a/storage/xtradb/trx/trx0trx.cc +++ b/storage/xtradb/trx/trx0trx.cc @@ -51,6 +51,9 @@ Created 3/26/1996 Heikki Tuuri #include +extern "C" +int thd_deadlock_victim_preference(const MYSQL_THD thd1, const MYSQL_THD thd2); + /** Set of table_id */ typedef std::set table_id_set; From 92577cc0ebb737b279592729eb547021182eb640 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Tue, 8 Jul 2014 14:54:53 +0200 Subject: [PATCH 08/13] MDEV-5262, MDEV-5914, MDEV-5941, MDEV-6020: Deadlocks during parallel replication causing replication to fail. Fix small (but nasty) typo. --- storage/innobase/lock/lock0lock.cc | 2 +- storage/xtradb/lock/lock0lock.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 80f2c043871..c84ac017c82 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -4057,7 +4057,7 @@ mysql_report_waiters(struct thd_wait_reports *waitee_buf_ptr, } q = p->next; if (p != waitee_buf_ptr) - mem_free(q); + mem_free(p); p = q; } } diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index 27425a68697..6cd24e43aad 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -4080,7 +4080,7 @@ mysql_report_waiters(struct thd_wait_reports *waitee_buf_ptr, } q = p->next; if (p != waitee_buf_ptr) - mem_free(q); + mem_free(p); p = q; } } From ba4e56d8d753b57815edd38fb17bd2a2a1d9ca8c Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Tue, 8 Jul 2014 15:59:03 +0200 Subject: [PATCH 09/13] Fix small merge errors after rebase --- sql/log_event.cc | 1 - sql/rpl_rli.cc | 3 --- 2 files changed, 4 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index eb05b3b5749..188aa87ae51 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -238,7 +238,6 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error, thd->get_stmt_da()->sql_conditions(); Relay_log_info const *rli= rgi->rli; const Sql_condition *err; - Relay_log_info const *rli= rgi->rli; buff[0]= 0; int errcode= thd->is_error() ? thd->get_stmt_da()->sql_errno() : 0; diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index ee1ca37ccc5..3307293e656 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1848,7 +1848,6 @@ rpl_group_info::mark_start_commit() } -<<<<<<< TREE /* Format the current GTID as a string suitable for printing in error messages. @@ -1869,7 +1868,6 @@ rpl_group_info::gtid_info() } -======= /* Undo the effect of a prior mark_start_commit(). @@ -1898,7 +1896,6 @@ rpl_group_info::unmark_start_commit() } ->>>>>>> MERGE-SOURCE rpl_sql_thread_info::rpl_sql_thread_info(Rpl_filter *filter) : rpl_filter(filter) { From 45f6262f54c5d1ef535c0529c399a7352b5fdea4 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Wed, 9 Jul 2014 13:02:52 +0200 Subject: [PATCH 10/13] MDEV-5262, MDEV-5914, MDEV-5941, MDEV-6020: Deadlocks during parallel replication causing replication to fail. After-review changes. Fix InnoDB coding style issues. --- storage/innobase/handler/ha_innodb.cc | 30 +++--- storage/innobase/lock/lock0lock.cc | 146 ++++++++++++++------------ storage/innobase/trx/trx0trx.cc | 5 +- storage/xtradb/handler/ha_innodb.cc | 9 +- storage/xtradb/lock/lock0lock.cc | 146 ++++++++++++++------------ storage/xtradb/trx/trx0trx.cc | 10 +- 6 files changed, 189 insertions(+), 157 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 4058807266f..58ff6561180 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4218,21 +4218,23 @@ innobase_kill_query( trx = thd_to_trx(thd); - if (trx) - { - THD *cur = current_thd; - THD *owner = trx->current_lock_mutex_owner; + if (trx) { + THD *cur = current_thd; + THD *owner = trx->current_lock_mutex_owner; - /* Cancel a pending lock request. */ - if (owner != cur) - lock_mutex_enter(); - trx_mutex_enter(trx); - if (trx->lock.wait_lock) - lock_cancel_waiting_and_release(trx->lock.wait_lock); - trx_mutex_exit(trx); - if (owner != cur) - lock_mutex_exit(); - } + /* Cancel a pending lock request. */ + if (owner != cur) { + lock_mutex_enter(); + } + trx_mutex_enter(trx); + if (trx->lock.wait_lock) { + lock_cancel_waiting_and_release(trx->lock.wait_lock); + } + trx_mutex_exit(trx); + if (owner != cur) { + lock_mutex_exit(); + } + } DBUG_VOID_RETURN; } diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index c84ac017c82..786da144a48 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -399,9 +399,9 @@ UNIV_INTERN ibool lock_print_waits = FALSE; /* Buffer to collect THDs to report waits for. */ struct thd_wait_reports { - struct thd_wait_reports *next; - ulint used; - trx_t *waitees[64]; + struct thd_wait_reports *next; /*!< List link */ + ulint used; /*!< How many elements in waitees[] */ + trx_t *waitees[64]; /*!< Trxs for thd_report_wait_for() */ }; @@ -3915,55 +3915,58 @@ lock_deadlock_search( return(ctx->start->id); } else { - /* We do not need to report autoinc locks to the upper - layer. These locks are released before commit, so they can - not cause deadlocks with binlog-fixed commit order. */ - if (waitee_ptr && (lock_get_type_low(lock) != LOCK_TABLE || - lock_get_mode(lock) != LOCK_AUTO_INC)) { - if (waitee_ptr->used == sizeof(waitee_ptr->waitees)/ - sizeof(waitee_ptr->waitees[0])) { - waitee_ptr->next = - (struct thd_wait_reports *) - mem_alloc(sizeof(*waitee_ptr)); - waitee_ptr = waitee_ptr->next; - if (!waitee_ptr) { - ctx->too_deep = TRUE; - return(ctx->start->id); - } - waitee_ptr->next = NULL; - waitee_ptr->used = 0; - } - waitee_ptr->waitees[waitee_ptr->used++] = lock->trx; - } - - if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - - /* Another trx ahead has requested a lock in an - incompatible mode, and is itself waiting for a lock. */ - - ++ctx->cost; - - /* Save current search state. */ - if (!lock_deadlock_push(ctx, lock, heap_no)) { - - /* Unable to save current search state, stack - size not big enough. */ - - ctx->too_deep = TRUE; - - return(ctx->start->id); + /* We do not need to report autoinc locks to the upper + layer. These locks are released before commit, so they + can not cause deadlocks with binlog-fixed commit + order. */ + if (waitee_ptr && + (lock_get_type_low(lock) != LOCK_TABLE || + lock_get_mode(lock) != LOCK_AUTO_INC)) { + if (waitee_ptr->used == + sizeof(waitee_ptr->waitees) / + sizeof(waitee_ptr->waitees[0])) { + waitee_ptr->next = + (struct thd_wait_reports *) + mem_alloc(sizeof(*waitee_ptr)); + waitee_ptr = waitee_ptr->next; + if (!waitee_ptr) { + ctx->too_deep = TRUE; + return(ctx->start->id); + } + waitee_ptr->next = NULL; + waitee_ptr->used = 0; + } + waitee_ptr->waitees[waitee_ptr->used++] = lock->trx; } - ctx->wait_lock = lock->trx->lock.wait_lock; - lock = lock_get_first_lock(ctx, &heap_no); + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - if (lock->trx->lock.deadlock_mark > ctx->mark_start) { + /* Another trx ahead has requested a lock in an + incompatible mode, and is itself waiting for a lock. */ + + ++ctx->cost; + + /* Save current search state. */ + if (!lock_deadlock_push(ctx, lock, heap_no)) { + + /* Unable to save current search state, stack + size not big enough. */ + + ctx->too_deep = TRUE; + + return(ctx->start->id); + } + + ctx->wait_lock = lock->trx->lock.wait_lock; + lock = lock_get_first_lock(ctx, &heap_no); + + if (lock->trx->lock.deadlock_mark > ctx->mark_start) { + lock = lock_get_next_lock(ctx, lock, heap_no); + } + + } else { lock = lock_get_next_lock(ctx, lock, heap_no); } - - } else { - lock = lock_get_next_lock(ctx, lock, heap_no); - } } } @@ -4028,22 +4031,28 @@ lock_deadlock_trx_rollback( trx_mutex_exit(trx); } -static void -mysql_report_waiters(struct thd_wait_reports *waitee_buf_ptr, - THD *mysql_thd, - trx_id_t victim_trx_id) +static +void +lock_report_waiters_to_mysql( +/*=======================*/ + struct thd_wait_reports* waitee_buf_ptr, /*!< in: set of trxs */ + THD* mysql_thd, /*!< in: THD */ + trx_id_t victim_trx_id) /*!< in: Trx selected + as deadlock victim, if + any */ { - struct thd_wait_reports *p = waitee_buf_ptr; - while (p) { - struct thd_wait_reports *q; - ulint i = 0; + struct thd_wait_reports* p; + struct thd_wait_reports* q; + ulint i; + p = waitee_buf_ptr; + while (p) { + i = 0; while (i < p->used) { trx_t *w_trx = p->waitees[i]; /* There is no need to report waits to a trx already selected as a victim. */ - if (w_trx->id != victim_trx_id) - { + if (w_trx->id != victim_trx_id) { /* If thd_report_wait_for() decides to kill the transaction, then we will get a call back into innobase_kill_query. We mark this by setting @@ -4056,8 +4065,9 @@ mysql_report_waiters(struct thd_wait_reports *waitee_buf_ptr, ++i; } q = p->next; - if (p != waitee_buf_ptr) + if (p != waitee_buf_ptr) { mem_free(p); + } p = q; } } @@ -4078,9 +4088,10 @@ lock_deadlock_check_and_resolve( const lock_t* lock, /*!< in: lock the transaction is requesting */ const trx_t* trx) /*!< in: transaction */ { - trx_id_t victim_trx_id; - struct thd_wait_reports waitee_buf, *waitee_buf_ptr; - THD* start_mysql_thd; + trx_id_t victim_trx_id; + struct thd_wait_reports waitee_buf; + struct thd_wait_reports*waitee_buf_ptr; + THD* start_mysql_thd; ut_ad(trx != NULL); ut_ad(lock != NULL); @@ -4088,10 +4099,11 @@ lock_deadlock_check_and_resolve( assert_trx_in_list(trx); start_mysql_thd = trx->mysql_thd; - if (start_mysql_thd && thd_need_wait_for(start_mysql_thd)) + if (start_mysql_thd && thd_need_wait_for(start_mysql_thd)) { waitee_buf_ptr = &waitee_buf; - else + } else { waitee_buf_ptr = NULL; + } /* Try and resolve as many deadlocks as possible. */ do { @@ -4113,9 +4125,11 @@ lock_deadlock_check_and_resolve( victim_trx_id = lock_deadlock_search(&ctx, waitee_buf_ptr); /* Report waits to upper layer, as needed. */ - if (waitee_buf_ptr) - mysql_report_waiters(waitee_buf_ptr, start_mysql_thd, - victim_trx_id); + if (waitee_buf_ptr) { + lock_report_waiters_to_mysql(waitee_buf_ptr, + start_mysql_thd, + victim_trx_id); + } /* Search too deep, we rollback the joining transaction. */ if (ctx.too_deep) { diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 7247080d4f2..4f8e4ad4487 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1921,10 +1921,11 @@ trx_weight_ge( /* First ask the upper server layer if it has any preference for which to prefer as a deadlock victim. */ pref= thd_deadlock_victim_preference(a->mysql_thd, b->mysql_thd); - if (pref < 0) + if (pref < 0) { return FALSE; - else if (pref > 0) + } else if (pref > 0) { return TRUE; + } /* Upper server layer had no preference, we fall back to comparing the number of altered/locked rows. */ diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 6cf41f846c1..06b9d8d8075 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -4704,13 +4704,13 @@ innobase_kill_connection( trx = thd_to_trx(thd); - if (trx) - { + if (trx) { THD *cur = current_thd; THD *owner = trx->current_lock_mutex_owner; - if (owner != cur) + if (owner != cur) { lock_mutex_enter(); + } trx_mutex_enter(trx); /* Cancel a pending lock request. */ @@ -4718,8 +4718,9 @@ innobase_kill_connection( lock_cancel_waiting_and_release(trx->lock.wait_lock); trx_mutex_exit(trx); - if (owner != cur) + if (owner != cur) { lock_mutex_exit(); + } } DBUG_VOID_RETURN; diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index 6cd24e43aad..ce0f9bd3dd2 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -399,9 +399,9 @@ UNIV_INTERN ibool lock_print_waits = FALSE; /* Buffer to collect THDs to report waits for. */ struct thd_wait_reports { - struct thd_wait_reports *next; - ulint used; - trx_t *waitees[64]; + struct thd_wait_reports *next; /*!< List link */ + ulint used; /*!< How many elements in waitees[] */ + trx_t *waitees[64]; /*!< Trxs for thd_report_wait_for() */ }; @@ -3938,55 +3938,58 @@ lock_deadlock_search( return(ctx->start->id); } else { - /* We do not need to report autoinc locks to the upper - layer. These locks are released before commit, so they can - not cause deadlocks with binlog-fixed commit order. */ - if (waitee_ptr && (lock_get_type_low(lock) != LOCK_TABLE || - lock_get_mode(lock) != LOCK_AUTO_INC)) { - if (waitee_ptr->used == sizeof(waitee_ptr->waitees)/ - sizeof(waitee_ptr->waitees[0])) { - waitee_ptr->next = - (struct thd_wait_reports *) - mem_alloc(sizeof(*waitee_ptr)); - waitee_ptr = waitee_ptr->next; - if (!waitee_ptr) { - ctx->too_deep = TRUE; - return(ctx->start->id); - } - waitee_ptr->next = NULL; - waitee_ptr->used = 0; - } - waitee_ptr->waitees[waitee_ptr->used++] = lock->trx; - } - - if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - - /* Another trx ahead has requested a lock in an - incompatible mode, and is itself waiting for a lock. */ - - ++ctx->cost; - - /* Save current search state. */ - if (!lock_deadlock_push(ctx, lock, heap_no)) { - - /* Unable to save current search state, stack - size not big enough. */ - - ctx->too_deep = TRUE; - - return(ctx->start->id); + /* We do not need to report autoinc locks to the upper + layer. These locks are released before commit, so they + can not cause deadlocks with binlog-fixed commit + order. */ + if (waitee_ptr && + (lock_get_type_low(lock) != LOCK_TABLE || + lock_get_mode(lock) != LOCK_AUTO_INC)) { + if (waitee_ptr->used == + sizeof(waitee_ptr->waitees) / + sizeof(waitee_ptr->waitees[0])) { + waitee_ptr->next = + (struct thd_wait_reports *) + mem_alloc(sizeof(*waitee_ptr)); + waitee_ptr = waitee_ptr->next; + if (!waitee_ptr) { + ctx->too_deep = TRUE; + return(ctx->start->id); + } + waitee_ptr->next = NULL; + waitee_ptr->used = 0; + } + waitee_ptr->waitees[waitee_ptr->used++] = lock->trx; } - ctx->wait_lock = lock->trx->lock.wait_lock; - lock = lock_get_first_lock(ctx, &heap_no); + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - if (lock->trx->lock.deadlock_mark > ctx->mark_start) { + /* Another trx ahead has requested a lock in an + incompatible mode, and is itself waiting for a lock. */ + + ++ctx->cost; + + /* Save current search state. */ + if (!lock_deadlock_push(ctx, lock, heap_no)) { + + /* Unable to save current search state, stack + size not big enough. */ + + ctx->too_deep = TRUE; + + return(ctx->start->id); + } + + ctx->wait_lock = lock->trx->lock.wait_lock; + lock = lock_get_first_lock(ctx, &heap_no); + + if (lock->trx->lock.deadlock_mark > ctx->mark_start) { + lock = lock_get_next_lock(ctx, lock, heap_no); + } + + } else { lock = lock_get_next_lock(ctx, lock, heap_no); } - - } else { - lock = lock_get_next_lock(ctx, lock, heap_no); - } } } @@ -4051,22 +4054,28 @@ lock_deadlock_trx_rollback( trx_mutex_exit(trx); } -static void -mysql_report_waiters(struct thd_wait_reports *waitee_buf_ptr, - THD *mysql_thd, - trx_id_t victim_trx_id) +static +void +lock_report_waiters_to_mysql( +/*=======================*/ + struct thd_wait_reports* waitee_buf_ptr, /*!< in: set of trxs */ + THD* mysql_thd, /*!< in: THD */ + trx_id_t victim_trx_id) /*!< in: Trx selected + as deadlock victim, if + any */ { - struct thd_wait_reports *p = waitee_buf_ptr; - while (p) { - struct thd_wait_reports *q; - ulint i = 0; + struct thd_wait_reports* p; + struct thd_wait_reports* q; + ulint i; + p = waitee_buf_ptr; + while (p) { + i = 0; while (i < p->used) { trx_t *w_trx = p->waitees[i]; /* There is no need to report waits to a trx already selected as a victim. */ - if (w_trx->id != victim_trx_id) - { + if (w_trx->id != victim_trx_id) { /* If thd_report_wait_for() decides to kill the transaction, then we will get a call back into innobase_kill_query. We mark this by setting @@ -4079,8 +4088,9 @@ mysql_report_waiters(struct thd_wait_reports *waitee_buf_ptr, ++i; } q = p->next; - if (p != waitee_buf_ptr) + if (p != waitee_buf_ptr) { mem_free(p); + } p = q; } } @@ -4101,9 +4111,10 @@ lock_deadlock_check_and_resolve( const lock_t* lock, /*!< in: lock the transaction is requesting */ const trx_t* trx) /*!< in: transaction */ { - trx_id_t victim_trx_id; - struct thd_wait_reports waitee_buf, *waitee_buf_ptr; - THD* start_mysql_thd; + trx_id_t victim_trx_id; + struct thd_wait_reports waitee_buf; + struct thd_wait_reports*waitee_buf_ptr; + THD* start_mysql_thd; ut_ad(trx != NULL); ut_ad(lock != NULL); @@ -4111,10 +4122,11 @@ lock_deadlock_check_and_resolve( assert_trx_in_list(trx); start_mysql_thd = trx->mysql_thd; - if (start_mysql_thd && thd_need_wait_for(start_mysql_thd)) + if (start_mysql_thd && thd_need_wait_for(start_mysql_thd)) { waitee_buf_ptr = &waitee_buf; - else + } else { waitee_buf_ptr = NULL; + } /* Try and resolve as many deadlocks as possible. */ do { @@ -4136,9 +4148,11 @@ lock_deadlock_check_and_resolve( victim_trx_id = lock_deadlock_search(&ctx, waitee_buf_ptr); /* Report waits to upper layer, as needed. */ - if (waitee_buf_ptr) - mysql_report_waiters(waitee_buf_ptr, start_mysql_thd, - victim_trx_id); + if (waitee_buf_ptr) { + lock_report_waiters_to_mysql(waitee_buf_ptr, + start_mysql_thd, + victim_trx_id); + } /* Search too deep, we rollback the joining transaction. */ if (ctx.too_deep) { diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc index 64a7c9edd40..1239dd2e026 100644 --- a/storage/xtradb/trx/trx0trx.cc +++ b/storage/xtradb/trx/trx0trx.cc @@ -2142,9 +2142,8 @@ trx_assert_started( #endif /* UNIV_DEBUG */ /*******************************************************************//** -Compares the "weight" (or size) of two transactions. Transactions that -have edited non-transactional tables are considered heavier than ones -that have not. +Compares the "weight" (or size) of two transactions. The heavier the weight, +the more reluctant we will be to choose the transaction as a deadlock victim. @return TRUE if weight(a) >= weight(b) */ UNIV_INTERN ibool @@ -2158,10 +2157,11 @@ trx_weight_ge( /* First ask the upper server layer if it has any preference for which to prefer as a deadlock victim. */ pref= thd_deadlock_victim_preference(a->mysql_thd, b->mysql_thd); - if (pref < 0) + if (pref < 0) { return FALSE; - else if (pref > 0) + } else if (pref > 0) { return TRUE; + } /* Upper server layer had no preference, we fall back to comparing the number of altered/locked rows. */ From 8f21a3166908d71b5828d50bfce65b480508c6c1 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Thu, 10 Jul 2014 13:55:53 +0200 Subject: [PATCH 11/13] MDEV-6435: Assertion `m_status == DA_ERROR' failed in Diagnostics_area::sql_errno() with parallel replication When a MyISAM query is killed midway, the query is logged to the binlog marked with the error. The slave does not attempt to run the query, but aborts with a suitable error message in the error log for the DBA to act on. In this case, the parallel replication code would check the sql_errno() code, even no my_error() had been set. In debug builds, this causes an assertion. Fixed the code to check that we actually have an error set before querying for an error code. --- mysql-test/suite/rpl/r/rpl_parallel.result | 28 +++++++++++- mysql-test/suite/rpl/t/rpl_parallel.test | 50 +++++++++++++++++++++- sql/rpl_parallel.cc | 5 ++- sql/sp_head.cc | 2 + 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_parallel.result b/mysql-test/suite/rpl/r/rpl_parallel.result index 70ac0b579f3..1c686e44a25 100644 --- a/mysql-test/suite/rpl/r/rpl_parallel.result +++ b/mysql-test/suite/rpl/r/rpl_parallel.result @@ -819,11 +819,37 @@ test_check OK test_check OK +*** MDEV_6435: Incorrect error handling when query binlogged partially on master with "killed" error *** +CREATE TABLE t6 (a INT) ENGINE=MyISAM; +CREATE TRIGGER tr AFTER INSERT ON t6 FOR EACH ROW SET @a = 1; +SET @old_format= @@binlog_format; +SET binlog_format= statement; +SET debug_sync='sp_head_execute_before_loop SIGNAL ready WAIT_FOR cont'; +INSERT INTO t6 VALUES (1), (2), (3); +SET debug_sync='now WAIT_FOR ready'; +KILL QUERY CONID; +SET debug_sync='now SIGNAL cont'; +ERROR 70100: Query execution was interrupted +SET binlog_format= @old_format; +SET debug_sync='RESET'; +SET debug_sync='RESET'; +include/wait_for_slave_sql_error.inc [errno=1317] +STOP SLAVE IO_THREAD; +SET GLOBAL gtid_slave_pos= 'AFTER_ERROR_GTID_POS'; +include/start_slave.inc +INSERT INTO t6 VALUES (4); +SELECT * FROM t6 ORDER BY a; +a +1 +4 +SELECT * FROM t6 ORDER BY a; +a +4 include/stop_slave.inc SET GLOBAL slave_parallel_threads=@old_parallel_threads; include/start_slave.inc SET DEBUG_SYNC= 'RESET'; DROP function foo; -DROP TABLE t1,t2,t3,t4,t5; +DROP TABLE t1,t2,t3,t4,t5,t6; SET DEBUG_SYNC= 'RESET'; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel.test b/mysql-test/suite/rpl/t/rpl_parallel.test index 09111fb7461..0f679fa18ee 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel.test +++ b/mysql-test/suite/rpl/t/rpl_parallel.test @@ -1292,6 +1292,54 @@ eval SELECT IF('$io_pos' = '$sql_pos', "OK", "Not ok, $io_pos <> $sql_pos") AS t --enable_query_log +--echo *** MDEV_6435: Incorrect error handling when query binlogged partially on master with "killed" error *** + +--connection server_1 +CREATE TABLE t6 (a INT) ENGINE=MyISAM; +CREATE TRIGGER tr AFTER INSERT ON t6 FOR EACH ROW SET @a = 1; + +--connection con1 +SET @old_format= @@binlog_format; +SET binlog_format= statement; +--let $conid = `SELECT CONNECTION_ID()` +SET debug_sync='sp_head_execute_before_loop SIGNAL ready WAIT_FOR cont'; +send INSERT INTO t6 VALUES (1), (2), (3); + +--connection server_1 +SET debug_sync='now WAIT_FOR ready'; +--replace_result $conid CONID +eval KILL QUERY $conid; +SET debug_sync='now SIGNAL cont'; + +--connection con1 +--error ER_QUERY_INTERRUPTED +--reap +SET binlog_format= @old_format; +SET debug_sync='RESET'; +--let $after_error_gtid_pos= `SELECT @@gtid_binlog_pos` + +--connection server_1 +SET debug_sync='RESET'; + + +--connection server_2 +--let $slave_sql_errno= 1317 +--source include/wait_for_slave_sql_error.inc +STOP SLAVE IO_THREAD; +--replace_result $after_error_gtid_pos AFTER_ERROR_GTID_POS +eval SET GLOBAL gtid_slave_pos= '$after_error_gtid_pos'; +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t6 VALUES (4); +SELECT * FROM t6 ORDER BY a; +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t6 ORDER BY a; + + --connection server_2 --source include/stop_slave.inc SET GLOBAL slave_parallel_threads=@old_parallel_threads; @@ -1300,7 +1348,7 @@ SET DEBUG_SYNC= 'RESET'; --connection server_1 DROP function foo; -DROP TABLE t1,t2,t3,t4,t5; +DROP TABLE t1,t2,t3,t4,t5,t6; SET DEBUG_SYNC= 'RESET'; --source include/rpl_end.inc diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 98753865568..0d23248539c 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -234,8 +234,11 @@ static void convert_kill_to_deadlock_error(rpl_group_info *rgi) { THD *thd= rgi->thd; - int err_code= thd->get_stmt_da()->sql_errno(); + int err_code; + if (!thd->get_stmt_da()->is_error()) + return; + err_code= thd->get_stmt_da()->sql_errno(); if ((err_code == ER_QUERY_INTERRUPTED || err_code == ER_CONNECTION_KILLED) && rgi->killed_for_retry) { diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 8a9e8ddc816..73218b4fda8 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -43,6 +43,7 @@ #include "sql_base.h" // close_thread_tables #include "transaction.h" // trans_commit_stmt #include "sql_audit.h" +#include "debug_sync.h" /* Sufficient max length of printed destinations and frame offsets (all uints). @@ -1309,6 +1310,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) /* Discard the initial part of executing routines. */ thd->profiling.discard_current_query(); #endif + DEBUG_SYNC(thd, "sp_head_execute_before_loop"); do { sp_instr *i; From 5b75891b7b2d2803d93115f244f00d91c12b79d6 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Thu, 10 Jul 2014 14:24:53 +0200 Subject: [PATCH 12/13] Fix compile failure in non-debug build. --- storage/innobase/lock/lock0lock.cc | 6 +++--- storage/xtradb/lock/lock0lock.cc | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 786da144a48..74e00def11f 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -394,9 +394,6 @@ UNIV_INTERN mysql_pfs_key_t lock_sys_mutex_key; UNIV_INTERN mysql_pfs_key_t lock_sys_wait_mutex_key; #endif /* UNIV_PFS_MUTEX */ -#ifdef UNIV_DEBUG -UNIV_INTERN ibool lock_print_waits = FALSE; - /* Buffer to collect THDs to report waits for. */ struct thd_wait_reports { struct thd_wait_reports *next; /*!< List link */ @@ -405,6 +402,9 @@ struct thd_wait_reports { }; +#ifdef UNIV_DEBUG +UNIV_INTERN ibool lock_print_waits = FALSE; + /*********************************************************************//** Validates the lock system. @return TRUE if ok */ diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index ce0f9bd3dd2..c5938509c22 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -394,9 +394,6 @@ UNIV_INTERN mysql_pfs_key_t lock_sys_mutex_key; UNIV_INTERN mysql_pfs_key_t lock_sys_wait_mutex_key; #endif /* UNIV_PFS_MUTEX */ -#ifdef UNIV_DEBUG -UNIV_INTERN ibool lock_print_waits = FALSE; - /* Buffer to collect THDs to report waits for. */ struct thd_wait_reports { struct thd_wait_reports *next; /*!< List link */ @@ -405,6 +402,9 @@ struct thd_wait_reports { }; +#ifdef UNIV_DEBUG +UNIV_INTERN ibool lock_print_waits = FALSE; + /*********************************************************************//** Validates the lock system. @return TRUE if ok */ From e81ecc9c72d240a1b6d9d6619f4654d412da4090 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Fri, 11 Jul 2014 10:54:43 +0200 Subject: [PATCH 13/13] MDEV-5262, MDEV-5914, MDEV-5941, MDEV-6020: Deadlocks during parallel replication causing replication to fail. Fix a bug discovered in Buildbot valgrind. The logic in checking for slave init thread completion was reversed, so depending on thread scheduling server startup could hang. Also add another variant of SSL valgrind suppression, needed for different library version. --- mysql-test/valgrind.supp | 11 +++++++++++ sql/slave.cc | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 45499e5891f..f1bc19e27eb 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -1137,6 +1137,17 @@ } +{ + OpenSSL still reachable. + Memcheck:Leak + fun:*alloc + fun:CRYPTO_malloc + obj:*libssl* + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init +} + + { Problem with udf and libresolve Memcheck:Cond diff --git a/sql/slave.cc b/sql/slave.cc index 2f832309d94..2fa4ebaef0f 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -349,7 +349,7 @@ run_slave_init_thread() } mysql_mutex_lock(&LOCK_slave_init); - while (!slave_init_thread_running) + while (slave_init_thread_running) mysql_cond_wait(&COND_slave_init, &LOCK_slave_init); mysql_mutex_unlock(&LOCK_slave_init);