diff options
Diffstat (limited to 'sql/sql_class.cc')
-rw-r--r-- | sql/sql_class.cc | 60 |
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); } } |