Commit 3d1433cf authored by Jon Olav Hauglid's avatar Jon Olav Hauglid

Backport of revno: 2617.69.34

Bug #45949 Assertion `!tables->table' in open_tables() on 
           ALTER + INSERT DELAYED

The assertion was caused by improperly closing tables when 
INSERT DELAYED needed to reopen tables. This patch replaces
the call to close_thread_tables with close_tables_for_reopen
which fixes the problem.

The only way I was able to trigger the reopen code path and 
thus the assertion, was if ALTER TABLE killed the delayed
insert thread and the delayed insert thread was able to enter
the reopen code path before it noticed that thd->killed had
been set. Note that in these cases reopen will always fail 
since open_table() will check thd->killed and return. This patch
therefore adds two more thd->killed checks to minimize the 
chance of entering the reopen code path without hope for success.

The patch also changes it so that if the delayed insert is killed
using KILL_CONNECTION, the error message that is copied to the
connection thread is ER_QUERY_INTERRUPTED rather than 
ER_SERVER_SHUTDOWN. This means that if INSERT DELAYED fails, 
the user will now see "Query execution was interrupted" rather
than the misleading "Server shutdown in progress".

No test case is supplied. This is for two reasons:
1) Unable to reproduce the error without having the delayed insert
thread in a killed state which means that reopen is futile and
was not supposed to be attempted.
2) Difficulty of using sync points in other threads than 
the connection thread.
The patch has been successfully tested with the RQG and the grammar
supplied in the bug description.
parent fcae9927
...@@ -1974,6 +1974,11 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) ...@@ -1974,6 +1974,11 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
} }
pthread_mutex_unlock(&di->mutex); pthread_mutex_unlock(&di->mutex);
thd_proc_info(thd, "got old table"); thd_proc_info(thd, "got old table");
if (thd->killed)
{
di->unlock();
goto end_create;
}
if (di->thd.killed) if (di->thd.killed)
{ {
if (di->thd.is_error()) if (di->thd.is_error())
...@@ -1981,20 +1986,19 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) ...@@ -1981,20 +1986,19 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
/* /*
Copy the error message. Note that we don't treat fatal Copy the error message. Note that we don't treat fatal
errors in the delayed thread as fatal errors in the errors in the delayed thread as fatal errors in the
main thread. Use of my_message will enable stored main thread. If delayed thread was killed, we don't
procedures continue handlers. want to send "Server shutdown in progress" in the
INSERT THREAD.
*/ */
my_message(di->thd.stmt_da->sql_errno(), di->thd.stmt_da->message(), if (di->thd.stmt_da->sql_errno() == ER_SERVER_SHUTDOWN)
MYF(0)); my_message(ER_QUERY_INTERRUPTED, ER(ER_QUERY_INTERRUPTED), MYF(0));
} else
di->unlock(); my_message(di->thd.stmt_da->sql_errno(), di->thd.stmt_da->message(),
MYF(0));
}
di->unlock();
goto end_create; goto end_create;
} }
if (thd->killed)
{
di->unlock();
goto end_create;
}
pthread_mutex_lock(&LOCK_delayed_insert); pthread_mutex_lock(&LOCK_delayed_insert);
delayed_threads.append(di); delayed_threads.append(di);
pthread_mutex_unlock(&LOCK_delayed_insert); pthread_mutex_unlock(&LOCK_delayed_insert);
...@@ -2061,8 +2065,11 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) ...@@ -2061,8 +2065,11 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
goto error; goto error;
if (dead) if (dead)
{ {
my_message(thd.stmt_da->sql_errno(), thd.stmt_da->message(), MYF(0)); /* Don't copy over "Server shutdown in progress". */
goto error; if (thd.stmt_da->sql_errno() == ER_SERVER_SHUTDOWN)
my_message(ER_QUERY_INTERRUPTED, ER(ER_QUERY_INTERRUPTED), MYF(0));
else
my_message(thd.stmt_da->sql_errno(), thd.stmt_da->message(), MYF(0));
} }
} }
share= table->s; share= table->s;
...@@ -2412,7 +2419,7 @@ pthread_handler_t handle_delayed_insert(void *arg) ...@@ -2412,7 +2419,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
for (;;) for (;;)
{ {
if (thd->killed == THD::KILL_CONNECTION) if (thd->killed)
{ {
uint lock_count; uint lock_count;
/* /*
...@@ -2474,7 +2481,7 @@ pthread_handler_t handle_delayed_insert(void *arg) ...@@ -2474,7 +2481,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
} }
thd_proc_info(&(di->thd), 0); thd_proc_info(&(di->thd), 0);
if (di->tables_in_use && ! thd->lock) if (di->tables_in_use && ! thd->lock && !thd->killed)
{ {
bool need_reopen; bool need_reopen;
/* /*
...@@ -2491,14 +2498,15 @@ pthread_handler_t handle_delayed_insert(void *arg) ...@@ -2491,14 +2498,15 @@ pthread_handler_t handle_delayed_insert(void *arg)
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK, MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK,
&need_reopen))) &need_reopen)))
{ {
if (need_reopen) if (need_reopen && !thd->killed)
{ {
/* /*
We were waiting to obtain TL_WRITE_DELAYED (probably due to We were waiting to obtain TL_WRITE_DELAYED (probably due to
someone having or requesting TL_WRITE_ALLOW_READ) and got someone having or requesting TL_WRITE_ALLOW_READ) and got
aborted. Try to reopen table and if it fails die. aborted. Try to reopen table and if it fails die.
*/ */
close_thread_tables(thd); TABLE_LIST *tl_ptr = &di->table_list;
close_tables_for_reopen(thd, &tl_ptr);
di->table= 0; di->table= 0;
if (di->open_and_lock_table()) if (di->open_and_lock_table())
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment