summaryrefslogtreecommitdiff
path: root/sql/sql_reload.cc
diff options
context:
space:
mode:
authorDmitry Lenev <dlenev@mysql.com>2010-09-09 18:29:14 +0400
committerDmitry Lenev <dlenev@mysql.com>2010-09-09 18:29:14 +0400
commit3326614df1d1dd01b3956a8f9c87003d839c485d (patch)
tree35ae062995fedd4a7b4fba1376edd148d553926b /sql/sql_reload.cc
parent51a3375c98138cee6f51eec807c9a120a84da87a (diff)
downloadmariadb-git-3326614df1d1dd01b3956a8f9c87003d839c485d.tar.gz
Fix for bug #55273 "FLUSH TABLE tm WITH READ LOCK for Merge
table causes assert failure". Attempting to use FLUSH TABLE table_list WITH READ LOCK statement for a MERGE table led to an assertion failure if one of its children was not present in the list of tables to be flushed. The problem was not visible in non-debug builds. The assertion failure was caused by the fact that in such situations FLUSH TABLES table_list WITH READ LOCK implementation tried to use (e.g. lock) such child tables without acquiring metadata lock on them. This happened because when opening tables we assumed metadata locks on all tables were already acquired earlier during statement execution and a such assumption was false for MERGE children. This patch fixes the problem by ensuring at open_tables() time that we try to acquire metadata locks on all tables to be opened. For normal tables such requests are satisfied instantly since locks are already acquired for them. For MERGE children metadata locks are acquired in normal fashion. Note that FLUSH TABLES merge_table WITH READ LOCK will lock for read both the MERGE table and its children but will flush only the MERGE table. To flush children one has to mention them in table list explicitly. This is expected behavior and it is consistent with usage patterns for this statement (e.g. in mysqlhotcopy script).
Diffstat (limited to 'sql/sql_reload.cc')
-rw-r--r--sql/sql_reload.cc42
1 files changed, 23 insertions, 19 deletions
diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc
index bf38af78536..35f27408247 100644
--- a/sql/sql_reload.cc
+++ b/sql/sql_reload.cc
@@ -328,7 +328,6 @@ bool reload_acl_and_cache(THD *thd, unsigned long options,
-------------------------------------
- you can't flush WITH READ LOCK a non-existent table
- you can't flush WITH READ LOCK under LOCK TABLES
- - currently incompatible with the GRL (@todo: fix)
Effect on views and temporary tables.
------------------------------------
@@ -338,6 +337,13 @@ bool reload_acl_and_cache(THD *thd, unsigned long options,
if there is a base table, it's used, otherwise ER_NO_SUCH_TABLE
is returned.
+ Handling of MERGE tables
+ ------------------------
+ For MERGE table this statement will open and lock child tables
+ for read (it is impossible to lock parent table without it).
+ Child tables won't be flushed unless they are explicitly present
+ in the statement's table list.
+
Implicit commit
---------------
This statement causes an implicit commit before and
@@ -354,7 +360,6 @@ bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
{
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
TABLE_LIST *table_list;
- MDL_request_list mdl_requests;
/*
This is called from SQLCOM_FLUSH, the transaction has
@@ -368,17 +373,13 @@ bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
}
/*
- Acquire SNW locks on tables to be flushed. We can't use
- lock_table_names() here as this call will also acquire global IX
- and database-scope IX locks on the tables, and this will make
+ Acquire SNW locks on tables to be flushed. Don't acquire global
+ IX and database-scope IX locks on the tables as this will make
this statement incompatible with FLUSH TABLES WITH READ LOCK.
*/
- for (table_list= all_tables; table_list;
- table_list= table_list->next_global)
- mdl_requests.push_front(&table_list->mdl_request);
-
- if (thd->mdl_context.acquire_locks(&mdl_requests,
- thd->variables.lock_wait_timeout))
+ if (lock_table_names(thd, all_tables, NULL,
+ thd->variables.lock_wait_timeout,
+ MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK))
goto error;
DEBUG_SYNC(thd,"flush_tables_with_read_lock_after_acquire_locks");
@@ -390,21 +391,24 @@ bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
table_list->db,
table_list->table_name, FALSE);
-
- /* Skip views and temporary tables. */
- table_list->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */
- table_list->open_type= OT_BASE_ONLY; /* Ignore temporary tables. */
+ /* Reset ticket to satisfy asserts in open_tables(). */
+ table_list->mdl_request.ticket= NULL;
}
/*
Before opening and locking tables the below call also waits
for old shares to go away, so the fact that we don't pass
MYSQL_LOCK_IGNORE_FLUSH flag to it is important.
+ Also we don't pass MYSQL_OPEN_HAS_MDL_LOCK flag as we want
+ to open underlying tables if merge table is flushed.
+ For underlying tables of the merge the below call has to
+ acquire SNW locks to ensure that they can be locked for
+ read without further waiting.
*/
- if (open_and_lock_tables(thd, all_tables, FALSE,
- MYSQL_OPEN_HAS_MDL_LOCK,
- &lock_tables_prelocking_strategy) ||
- thd->locked_tables_list.init_locked_tables(thd))
+ if (open_and_lock_tables(thd, all_tables, FALSE,
+ MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK,
+ &lock_tables_prelocking_strategy) ||
+ thd->locked_tables_list.init_locked_tables(thd))
{
goto error;
}