mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-5363: Make parallel replication waits killable
Add a test case for killing a waiting query in parallel replication. Fix several bugs found: - We should not wakeup_subsequent_commits() in ha_rollback_trans(), since we do not know the right wakeup_error() to give. - When a wait_for_prior_commit() is killed, we must unregister from the waitee so we do not race and get an extra (non-kill) wakeup. - We need to deal with error propagation correctly in queue_for_group_commit when one thread is killed. - Fix one locking issue in queue_for_group_commit(), we could unlock the waitee lock too early and this end up processing wakeup() with insufficient locking. - Fix Xid_log_event::do_apply_event; if commit fails it must not update the in-memory @@gtid_slave_pos state. - Fix and cleanup some things in the rpl_parallel.cc error handling. - Add a missing check for killed in the slave sql driver thread, to avoid a race.
This commit is contained in:
@@ -5786,25 +5786,49 @@ int
|
||||
wait_for_commit::wait_for_prior_commit2(THD *thd)
|
||||
{
|
||||
const char *old_msg;
|
||||
wait_for_commit *loc_waitee;
|
||||
|
||||
mysql_mutex_lock(&LOCK_wait_commit);
|
||||
old_msg= thd->enter_cond(&COND_wait_commit, &LOCK_wait_commit,
|
||||
"Waiting for prior transaction to commit");
|
||||
while (waiting_for_commit && !thd->check_killed())
|
||||
mysql_cond_wait(&COND_wait_commit, &LOCK_wait_commit);
|
||||
thd->exit_cond(old_msg);
|
||||
waitee= NULL;
|
||||
if (!waiting_for_commit)
|
||||
{
|
||||
if (wakeup_error)
|
||||
my_error(ER_PRIOR_COMMIT_FAILED, MYF(0));
|
||||
return wakeup_error;
|
||||
goto end;
|
||||
}
|
||||
/* Wait was interrupted by kill, so give the error. */
|
||||
/*
|
||||
Wait was interrupted by kill. We need to unregister our wait and give the
|
||||
error. But if a wakeup is already in progress, then we must ignore the
|
||||
kill and not give error, otherwise we get inconsistency between waitee and
|
||||
waiter as to whether we succeed or fail (eg. we may roll back but waitee
|
||||
might attempt to commit both us and any subsequent commits waiting for us).
|
||||
*/
|
||||
loc_waitee= this->waitee;
|
||||
mysql_mutex_lock(&loc_waitee->LOCK_wait_commit);
|
||||
if (loc_waitee->wakeup_subsequent_commits_running)
|
||||
{
|
||||
/* We are being woken up; ignore the kill and just wait. */
|
||||
mysql_mutex_unlock(&loc_waitee->LOCK_wait_commit);
|
||||
do
|
||||
{
|
||||
mysql_cond_wait(&COND_wait_commit, &LOCK_wait_commit);
|
||||
} while (waiting_for_commit);
|
||||
goto end;
|
||||
}
|
||||
remove_from_list(&loc_waitee->subsequent_commits_list);
|
||||
mysql_mutex_unlock(&loc_waitee->LOCK_wait_commit);
|
||||
|
||||
wakeup_error= thd->killed_errno();
|
||||
if (!wakeup_error)
|
||||
wakeup_error= ER_QUERY_INTERRUPTED;
|
||||
my_message(wakeup_error, ER(wakeup_error), MYF(0));
|
||||
|
||||
end:
|
||||
thd->exit_cond(old_msg);
|
||||
waitee= NULL;
|
||||
return wakeup_error;
|
||||
}
|
||||
|
||||
@@ -5891,7 +5915,6 @@ wait_for_commit::unregister_wait_for_prior_commit2()
|
||||
if (waiting_for_commit)
|
||||
{
|
||||
wait_for_commit *loc_waitee= this->waitee;
|
||||
wait_for_commit **next_ptr_ptr, *cur;
|
||||
mysql_mutex_lock(&loc_waitee->LOCK_wait_commit);
|
||||
if (loc_waitee->wakeup_subsequent_commits_running)
|
||||
{
|
||||
@@ -5909,17 +5932,7 @@ wait_for_commit::unregister_wait_for_prior_commit2()
|
||||
else
|
||||
{
|
||||
/* Remove ourselves from the list in the waitee. */
|
||||
next_ptr_ptr= &loc_waitee->subsequent_commits_list;
|
||||
while ((cur= *next_ptr_ptr) != NULL)
|
||||
{
|
||||
if (cur == this)
|
||||
{
|
||||
*next_ptr_ptr= this->next_subsequent_commit;
|
||||
break;
|
||||
}
|
||||
next_ptr_ptr= &cur->next_subsequent_commit;
|
||||
}
|
||||
waiting_for_commit= false;
|
||||
remove_from_list(&loc_waitee->subsequent_commits_list);
|
||||
mysql_mutex_unlock(&loc_waitee->LOCK_wait_commit);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user