diff options
| author | Kristian Nielsen <knielsen@knielsen-hq.org> | 2016-09-08 15:25:40 +0200 |
|---|---|---|
| committer | Kristian Nielsen <knielsen@knielsen-hq.org> | 2016-09-08 15:25:40 +0200 |
| commit | 7e0c9de86484815b6e014ce3ad3e3a9b74ec0ce0 (patch) | |
| tree | b120ad4efafea263a31af73022ca68d03a41a3b6 /sql/rpl_parallel.cc | |
| parent | a02642b66e06f95b80fa9ee592ba50eb61dc2f17 (diff) | |
| download | mariadb-git-7e0c9de86484815b6e014ce3ad3e3a9b74ec0ce0.tar.gz | |
Parallel replication async deadlock kill
When a deadlock kill is detected inside the storage engine, the kill
is not done immediately, to avoid calling back into the storage engine
kill_query method with various lock subsystem mutexes held. Instead the
kill is queued and done later by a slave background thread.
This patch in preparation for fixing TokuDB optimistic parallel
replication, as well as for removing locking hacks in InnoDB/XtraDB in
10.2.
Signed-off-by: Kristian Nielsen <knielsen at knielsen-hq.org>
Diffstat (limited to 'sql/rpl_parallel.cc')
| -rw-r--r-- | sql/rpl_parallel.cc | 30 |
1 files changed, 26 insertions, 4 deletions
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index f2437a6953b..761471fc1cb 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -107,6 +107,25 @@ handle_queued_pos_update(THD *thd, rpl_parallel_thread::queued_event *qev) } +/* + Wait for any pending deadlock kills. Since deadlock kills happen + asynchronously, we need to be sure they will be completed before starting a + new transaction. Otherwise the new transaction might suffer a spurious kill. +*/ +static void +wait_for_pending_deadlock_kill(THD *thd, rpl_group_info *rgi) +{ + PSI_stage_info old_stage; + + mysql_mutex_lock(&thd->LOCK_wakeup_ready); + thd->ENTER_COND(&thd->COND_wakeup_ready, &thd->LOCK_wakeup_ready, + &stage_waiting_for_deadlock_kill, &old_stage); + while (rgi->killed_for_retry == rpl_group_info::RETRY_KILL_PENDING) + mysql_cond_wait(&thd->COND_wakeup_ready, &thd->LOCK_wakeup_ready); + thd->EXIT_COND(&old_stage); +} + + static void finish_event_group(rpl_parallel_thread *rpt, uint64 sub_id, rpl_parallel_entry *entry, rpl_group_info *rgi) @@ -212,6 +231,8 @@ finish_event_group(rpl_parallel_thread *rpt, uint64 sub_id, entry->stop_on_error_sub_id= sub_id; mysql_mutex_unlock(&entry->LOCK_parallel_entry); + if (rgi->killed_for_retry == rpl_group_info::RETRY_KILL_PENDING) + wait_for_pending_deadlock_kill(thd, rgi); thd->clear_error(); thd->reset_killed(); /* @@ -604,7 +625,6 @@ convert_kill_to_deadlock_error(rpl_group_info *rgi) { thd->clear_error(); my_error(ER_LOCK_DEADLOCK, MYF(0)); - rgi->killed_for_retry= false; thd->reset_killed(); } } @@ -695,14 +715,16 @@ do_retry: thd->wait_for_commit_ptr->unregister_wait_for_prior_commit(); DBUG_EXECUTE_IF("inject_mdev8031", { /* Simulate that we get deadlock killed at this exact point. */ - rgi->killed_for_retry= true; + rgi->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED; mysql_mutex_lock(&thd->LOCK_thd_data); thd->killed= KILL_CONNECTION; mysql_mutex_unlock(&thd->LOCK_thd_data); }); rgi->cleanup_context(thd, 1); + wait_for_pending_deadlock_kill(thd, rgi); thd->reset_killed(); thd->clear_error(); + rgi->killed_for_retry = rpl_group_info::RETRY_KILL_NONE; /* If we retry due to a deadlock kill that occurred during the commit step, we @@ -841,7 +863,7 @@ do_retry: { /* Simulate that we get deadlock killed during open_binlog(). */ thd->reset_for_next_command(); - rgi->killed_for_retry= true; + rgi->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED; mysql_mutex_lock(&thd->LOCK_thd_data); thd->killed= KILL_CONNECTION; mysql_mutex_unlock(&thd->LOCK_thd_data); @@ -1741,7 +1763,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; + rgi->killed_for_retry= rpl_group_info::RETRY_KILL_NONE; return rgi; } |
