Fix for bug #21587: FLUSH TABLES causes server crash when used with HANDLER statements

Problems (appear only under some circumstances): 
  1. we get a reference to a deleted table searching in the 
     thd->handler_tables_hash in the mysql_ha_read().

  2. DBUG_ASSERT(table->file->inited == handler::NONE); assert fails in the
     close_thread_table().

Fix: end open index scans and table scans and remove references to the 
tables from the handler tables hash. After this preparation it is safe 
to close the tables. The close can no longer fail on open index/table 
scans and the closed table will not be used again by handler functions.
                                 
parent bc9ca699
...@@ -941,6 +941,7 @@ bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *, ...@@ -941,6 +941,7 @@ bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows); List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags, int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags,
bool is_locked); bool is_locked);
void mysql_ha_mark_tables_for_reopen(THD *thd, TABLE *table);
/* mysql_ha_flush mode_flags bits */ /* mysql_ha_flush mode_flags bits */
#define MYSQL_HA_CLOSE_FINAL 0x00 #define MYSQL_HA_CLOSE_FINAL 0x00
#define MYSQL_HA_REOPEN_ON_USAGE 0x01 #define MYSQL_HA_REOPEN_ON_USAGE 0x01
......
...@@ -519,7 +519,15 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) ...@@ -519,7 +519,15 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
DBUG_PRINT("info", ("thd->open_tables: %p", thd->open_tables)); DBUG_PRINT("info", ("thd->open_tables: %p", thd->open_tables));
found_old_table= 0;
/*
End open index scans and table scans and remove references to the tables
from the handler tables hash. After this preparation it is safe to close
the tables.
*/
mysql_ha_mark_tables_for_reopen(thd, thd->open_tables);
found_old_table= 0;
while (thd->open_tables) while (thd->open_tables)
found_old_table|=close_thread_table(thd, &thd->open_tables); found_old_table|=close_thread_table(thd, &thd->open_tables);
thd->some_tables_deleted=0; thd->some_tables_deleted=0;
......
...@@ -748,3 +748,41 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) ...@@ -748,3 +748,41 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags)
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/*
Mark tables for reopen.
SYNOPSIS
mysql_ha_mark_tables_for_reopen()
thd Thread identifier.
table Table list to mark for reopen.
DESCRIPTION
For each table found in the handler hash mark it as closed
(ready for reopen) and end all index/table scans.
NOTE
The caller must lock LOCK_open.
*/
void mysql_ha_mark_tables_for_reopen(THD *thd, TABLE *table)
{
DBUG_ENTER("mysql_ha_mark_tables_for_reopen");
safe_mutex_assert_owner(&LOCK_open);
for (; table; table= table->next)
{
TABLE_LIST *hash_tables;
if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
(byte*) table->alias,
strlen(table->alias) + 1)))
{
/* Mark table as ready for reopen. */
hash_tables->table= NULL;
/* End open index/table scans. */
table->file->ha_index_or_rnd_end();
}
}
DBUG_VOID_RETURN;
}
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