summaryrefslogtreecommitdiff
path: root/sql/sql_class.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_class.cc')
-rw-r--r--sql/sql_class.cc60
1 files changed, 45 insertions, 15 deletions
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index d1edec140b6..8abdd53469f 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -5783,12 +5783,53 @@ wait_for_commit::register_wait_for_prior_commit(wait_for_commit *waitee)
returns immediately.
*/
int
-wait_for_commit::wait_for_prior_commit2()
+wait_for_commit::wait_for_prior_commit2(THD *thd)
{
+ const char *old_msg;
+ wait_for_commit *loc_waitee;
+
mysql_mutex_lock(&LOCK_wait_commit);
- while (waiting_for_commit)
+ DEBUG_SYNC(thd, "wait_for_prior_commit_waiting");
+ 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);
- mysql_mutex_unlock(&LOCK_wait_commit);
+ if (!waiting_for_commit)
+ {
+ if (wakeup_error)
+ my_error(ER_PRIOR_COMMIT_FAILED, MYF(0));
+ goto end;
+ }
+ /*
+ 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);
+
+ DEBUG_SYNC(thd, "wait_for_prior_commit_killed");
+ 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;
}
@@ -5876,7 +5917,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)
{
@@ -5894,17 +5934,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);
}
}