#At file:///export/home/x/mysql-5.5-bug57649/ based on revid:alexander.barkov@stripped
3368 Jon Olav Hauglid 2011-03-03
Bug #57649 FLUSH TABLES under FLUSH TABLES <list> WITH READ LOCK leads
to assert failure.
This assert was triggered if a statement tried up upgrade a metadata
lock with an active FLUSH TABLE <list> WITH READ LOCK. The assert
checks that the connection already holds a global intention exclusive
metadata lock. However, FLUSH TABLE <list> WITH READ LOCK does not
acquire this lock in order to be compatible with FLUSH TABLES WITH
READ LOCK. Therefore any metadata lock upgrade caused the assert to
be triggered.
This patch fixes the problem by preventing metadata lock upgrade
if the connection has an active FLUSH TABLE <list> WITH READ LOCK.
ER_TABLE_NOT_LOCKED_FOR_WRITE will instead be reported to the client.
Test case added to flush.test.
modified:
mysql-test/r/flush.result
mysql-test/t/flush.test
sql/sql_base.cc
sql/sql_base.h
sql/sql_reload.cc
sql/sql_table.cc
sql/sql_trigger.cc
sql/sql_truncate.cc
=== modified file 'mysql-test/r/flush.result'
--- a/mysql-test/r/flush.result 2010-11-11 17:11:05 +0000
+++ b/mysql-test/r/flush.result 2011-03-03 15:45:28 +0000
@@ -451,3 +451,18 @@ unlock tables;
handler t1 close;
# Cleanup.
drop tables t1, t2;
+#
+# Bug#57649 FLUSH TABLES under FLUSH TABLES <list> WITH READ LOCK leads
+# to assert failure.
+#
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (a INT);
+FLUSH TABLES t1 WITH READ LOCK;
+FLUSH TABLES;
+ERROR HY000: Table 't1' was locked with a READ lock and can't be updated
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a= 1;
+ERROR HY000: Table 't1' was locked with a READ lock and can't be updated
+ALTER TABLE t1 COMMENT 'test';
+ERROR HY000: Table 't1' was locked with a READ lock and can't be updated
+UNLOCK TABLES;
+DROP TABLE t1;
=== modified file 'mysql-test/t/flush.test'
--- a/mysql-test/t/flush.test 2010-11-11 17:11:05 +0000
+++ b/mysql-test/t/flush.test 2011-03-03 15:45:28 +0000
@@ -644,3 +644,27 @@ disconnect con2;
--source include/wait_until_disconnected.inc
connection default;
drop tables t1, t2;
+
+
+--echo #
+--echo # Bug#57649 FLUSH TABLES under FLUSH TABLES <list> WITH READ LOCK leads
+--echo # to assert failure.
+--echo #
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (a INT);
+FLUSH TABLES t1 WITH READ LOCK;
+
+# All these triggered the assertion
+--error ER_TABLE_NOT_LOCKED_FOR_WRITE
+FLUSH TABLES;
+--error ER_TABLE_NOT_LOCKED_FOR_WRITE
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a= 1;
+--error ER_TABLE_NOT_LOCKED_FOR_WRITE
+ALTER TABLE t1 COMMENT 'test';
+
+UNLOCK TABLES;
+DROP TABLE t1;
=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc 2011-02-08 15:47:33 +0000
+++ b/sql/sql_base.cc 2011-03-03 15:45:28 +0000
@@ -1026,7 +1026,7 @@ bool close_cached_tables(THD *thd, TABLE
table_list= table_list->next_global)
{
/* A check that the table was locked for write is done by the caller. */
- TABLE *table= find_table_for_mdl_upgrade(thd->open_tables, table_list->db,
+ TABLE *table= find_table_for_mdl_upgrade(thd, table_list->db,
table_list->table_name, TRUE);
/* May return NULL if this table has already been closed via an alias. */
@@ -3120,7 +3120,7 @@ TABLE *find_locked_table(TABLE *list, co
lock from the list of open tables, emit error if no such table
found.
- @param list List of TABLE objects to be searched
+ @param thd Thread context
@param db Database name.
@param table_name Name of table.
@param no_error Don't emit error if no suitable TABLE
@@ -3131,11 +3131,10 @@ TABLE *find_locked_table(TABLE *list, co
lock, NULL otherwise.
*/
-TABLE *find_table_for_mdl_upgrade(TABLE *list, const char *db,
- const char *table_name,
- bool no_error)
+TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db,
+ const char *table_name, bool no_error)
{
- TABLE *tab= find_locked_table(list, db, table_name);
+ TABLE *tab= find_locked_table(thd->open_tables, db, table_name);
if (!tab)
{
@@ -3143,19 +3142,28 @@ TABLE *find_table_for_mdl_upgrade(TABLE
my_error(ER_TABLE_NOT_LOCKED, MYF(0), table_name);
return NULL;
}
- else
+
+ /*
+ It is not safe to upgrade the metadata lock without GLOBAL IX lock.
+ This can happen with FLUSH TABLES <list> WITH READ LOCK as we in these
+ cases don't take a GLOBAL IX lock in order to be compatible with
+ global read lock.
+ */
+ if (!thd->mdl_context.is_lock_owner(MDL_key::GLOBAL, "", "",
+ MDL_INTENTION_EXCLUSIVE))
{
- while (tab->mdl_ticket != NULL &&
- !tab->mdl_ticket->is_upgradable_or_exclusive() &&
- (tab= find_locked_table(tab->next, db, table_name)))
- continue;
- if (!tab)
- {
- if (!no_error)
- my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_name);
- return 0;
- }
+ my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_name);
+ return NULL;
}
+
+ while (tab->mdl_ticket != NULL &&
+ !tab->mdl_ticket->is_upgradable_or_exclusive() &&
+ (tab= find_locked_table(tab->next, db, table_name)))
+ continue;
+
+ if (!tab && !no_error)
+ my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_name);
+
return tab;
}
@@ -4653,8 +4661,7 @@ open_tables_check_upgradable_mdl(THD *th
Note that find_table_for_mdl_upgrade() will report an error if
no suitable ticket is found.
*/
- if (!find_table_for_mdl_upgrade(thd->open_tables, table->db,
- table->table_name, FALSE))
+ if (!find_table_for_mdl_upgrade(thd, table->db, table->table_name, FALSE))
return TRUE;
}
}
=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h 2010-11-11 17:11:05 +0000
+++ b/sql/sql_base.h 2011-03-03 15:45:28 +0000
@@ -290,7 +290,7 @@ bool tdc_open_view(THD *thd, TABLE_LIST
char *cache_key, uint cache_key_length,
MEM_ROOT *mem_root, uint flags);
void tdc_flush_unused_tables();
-TABLE *find_table_for_mdl_upgrade(TABLE *list, const char *db,
+TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db,
const char *table_name,
bool no_error);
void mark_tmp_table_for_reuse(TABLE *table);
=== modified file 'sql/sql_reload.cc'
--- a/sql/sql_reload.cc 2010-12-07 16:11:13 +0000
+++ b/sql/sql_reload.cc 2011-03-03 15:45:28 +0000
@@ -220,8 +220,7 @@ bool reload_acl_and_cache(THD *thd, unsi
if (tables)
{
for (TABLE_LIST *t= tables; t; t= t->next_local)
- if (!find_table_for_mdl_upgrade(thd->open_tables, t->db,
- t->table_name, FALSE))
+ if (!find_table_for_mdl_upgrade(thd, t->db, t->table_name, false))
return 1;
}
else
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2011-01-26 13:23:29 +0000
+++ b/sql/sql_table.cc 2011-03-03 15:45:28 +0000
@@ -1917,7 +1917,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST
by parser) it is safe to cache pointer to the TABLE instances
in its elements.
*/
- table->table= find_table_for_mdl_upgrade(thd->open_tables, table->db,
+ table->table= find_table_for_mdl_upgrade(thd, table->db,
table->table_name, false);
if (!table->table)
DBUG_RETURN(true);
=== modified file 'sql/sql_trigger.cc'
--- a/sql/sql_trigger.cc 2010-11-11 17:11:05 +0000
+++ b/sql/sql_trigger.cc 2011-03-03 15:45:28 +0000
@@ -467,8 +467,7 @@ bool mysql_create_or_drop_trigger(THD *t
if (thd->locked_tables_mode)
{
/* Under LOCK TABLES we must only accept write locked tables. */
- if (!(tables->table= find_table_for_mdl_upgrade(thd->open_tables,
- tables->db,
+ if (!(tables->table= find_table_for_mdl_upgrade(thd, tables->db,
tables->table_name,
FALSE)))
goto end;
=== modified file 'sql/sql_truncate.cc'
--- a/sql/sql_truncate.cc 2010-10-29 14:10:53 +0000
+++ b/sql/sql_truncate.cc 2011-03-03 15:45:28 +0000
@@ -327,7 +327,7 @@ bool Truncate_statement::lock_table(THD
*/
if (thd->locked_tables_mode)
{
- if (!(table= find_table_for_mdl_upgrade(thd->open_tables, table_ref->db,
+ if (!(table= find_table_for_mdl_upgrade(thd, table_ref->db,
table_ref->table_name, FALSE)))
DBUG_RETURN(TRUE);
Attachment: [text/bzr-bundle] bzr/jon.hauglid@oracle.com-20110303154528-n3yisjjrdpjj0e2y.bundle
| Thread |
|---|
| • bzr commit into mysql-5.5 branch (jon.hauglid:3368) Bug#57649 | Jon Olav Hauglid | 3 Mar |