diff options
author | Kristian Nielsen <knielsen@knielsen-hq.org> | 2015-03-30 14:51:25 +0200 |
---|---|---|
committer | Kristian Nielsen <knielsen@knielsen-hq.org> | 2015-03-30 14:51:25 +0200 |
commit | c41e4d3b49d27475a907d225fe326e38cb65f1b0 (patch) | |
tree | ee36a19bc59a217b8d18b0265f8ad88fb9f49e1f /sql/rpl_parallel.cc | |
parent | 323a7e93ee2445e6d5918b4946cbec99b1ab650c (diff) | |
parent | 880f2273fdc39cd1a2ab28f448cdfbf3d6581af2 (diff) | |
download | mariadb-git-c41e4d3b49d27475a907d225fe326e38cb65f1b0.tar.gz |
Merge MDEV-7847 and MDEV-7882 into 10.0.
Conflicts:
mysql-test/suite/rpl/r/rpl_parallel.result
mysql-test/suite/rpl/t/rpl_parallel.test
Diffstat (limited to 'sql/rpl_parallel.cc')
-rw-r--r-- | sql/rpl_parallel.cc | 55 |
1 files changed, 43 insertions, 12 deletions
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 2f47ad8892b..acf6c328cdb 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -113,6 +113,7 @@ finish_event_group(rpl_parallel_thread *rpt, uint64 sub_id, wait_for_commit *wfc= &rgi->commit_orderer; int err; + thd->get_stmt_da()->set_overwrite_status(true); /* Remove any left-over registration to wait for a prior commit to complete. Normally, such wait would already have been removed at @@ -129,14 +130,14 @@ finish_event_group(rpl_parallel_thread *rpt, uint64 sub_id, for us to complete and rely on this also ensuring that any other event in the group has completed. - But in the error case, we have to abort anyway, and it seems best - to just complete as quickly as possible with unregister. Anyone - waiting for us will in any case receive the error back from their - wait_for_prior_commit() call. + And in the error case, correct GCO lifetime relies on the fact that once + the last event group in the GCO has executed wait_for_prior_commit(), + all earlier event groups have also committed; this way no more + mark_start_commit() calls can be made and it is safe to de-allocate + the GCO. */ - if (rgi->worker_error) - wfc->unregister_wait_for_prior_commit(); - else if ((err= wfc->wait_for_prior_commit(thd))) + err= wfc->wait_for_prior_commit(thd); + if (unlikely(err) && !rgi->worker_error) signal_error_to_sql_driver_thread(thd, rgi, err); thd->wait_for_commit_ptr= NULL; @@ -193,6 +194,10 @@ finish_event_group(rpl_parallel_thread *rpt, uint64 sub_id, thd->clear_error(); thd->reset_killed(); + /* + Would do thd->get_stmt_da()->set_overwrite_status(false) here, but + reset_diagnostics_area() already does that. + */ thd->get_stmt_da()->reset_diagnostics_area(); wfc->wakeup_subsequent_commits(rgi->worker_error); } @@ -372,9 +377,34 @@ 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); + for (;;) + { + mysql_mutex_lock(&entry->LOCK_parallel_entry); + register_wait_for_prior_event_group_commit(rgi, entry); + mysql_mutex_unlock(&entry->LOCK_parallel_entry); + + /* + Let us wait for all prior transactions to complete before trying again. + This way, we avoid repeatedly conflicting with and getting deadlock + killed by the same earlier transaction. + */ + if (!(err= thd->wait_for_prior_commit())) + break; + + convert_kill_to_deadlock_error(rgi); + if (!has_temporary_error(thd)) + goto err; + /* + If we get a temporary error such as a deadlock kill, we can safely + ignore it, as we already rolled back. + + But we still want to retry the wait for the prior transaction to + complete its commit. + */ + thd->clear_error(); + if(thd->wait_for_commit_ptr) + thd->wait_for_commit_ptr->unregister_wait_for_prior_commit(); + } strmake_buf(log_name, ir->name); if ((fd= open_binlog(&rlog, log_name, &errmsg)) <0) @@ -751,8 +781,7 @@ handle_rpl_parallel_thread(void *arg) if (unlikely(entry->stop_on_error_sub_id <= rgi->wait_commit_sub_id)) skip_event_group= true; - else - register_wait_for_prior_event_group_commit(rgi, entry); + register_wait_for_prior_event_group_commit(rgi, entry); unlock_or_exit_cond(thd, &entry->LOCK_parallel_entry, &did_enter_cond, &old_stage); @@ -827,7 +856,9 @@ handle_rpl_parallel_thread(void *arg) else { delete qev->ev; + thd->get_stmt_da()->set_overwrite_status(true); err= thd->wait_for_prior_commit(); + thd->get_stmt_da()->set_overwrite_status(false); } end_of_group= |