Cherry-picking a patch from Bug 12828477 from mysql-5.5
to mysql-5.5.16-release. Original revision: # revision-id: dmitry.lenev@oracle.com-20110811155849-feyt3h7tj48padiu # parent: tatjana.nuernberg@oracle.com-20110811120945-c6x9a5d2du8s9oj2 # committer: Dmitry Lenev <Dmitry.Lenev@oracle.com> # branch nick: mysql-5.5-12828477 # timestamp: Thu 2011-08-11 19:58:49 +0400 # message: # Fix for bug #12828477 - "MDL SUBSYSTEM CREATES BIG OVERHEAD # FOR CERTAIN QUERIES TO INFORMATION_SCHEMA". # # The problem was that metadata locking subsystem introduced # too much overhead for queries to I_S which were processed by # opening only .FRM or .TRG files and had to scanned a lot of # tables (e.g. SELECT COUNT(*) FROM I_S.TRIGGERS was affected). # The same effect was not observed for similar queries which # performed full-blown table open in order to fill I_S table. # # The problem stemmed from the fact that in case when I_S # implementation opened only .FRM or .TRG file for each table # processed it didn't release metadata lock it has acquired on # the table after finishing its processing. As result, list # of acquired metadata locks were growing until the end of # statement. Since acquisition of each new lock required # search in the list of already acquired locks performance # degraded. # # The same effect is not observed when I_S implementation # performs full-blown table open for each table being # processed, as in the latter cases metadata lock on the # table is released right after table processing. # # This fix addressed the problem by ensuring that I_S # implementation releases metadata lock after processing # the table in both cases of full-blown table open and in # case when only .FRM or .TRG file is read.
This commit is contained in:
parent
6e5bbf5138
commit
457cbab0d6
@ -1849,5 +1849,119 @@ unlock tables;
|
|||||||
drop table t1;
|
drop table t1;
|
||||||
drop view v1;
|
drop view v1;
|
||||||
#
|
#
|
||||||
|
# Test for bug #12828477 - "MDL SUBSYSTEM CREATES BIG OVERHEAD FOR
|
||||||
|
# CERTAIN QUERIES TO INFORMATION_SCHEMA".
|
||||||
|
#
|
||||||
|
# Check that metadata locks which are acquired during the process
|
||||||
|
# of opening tables/.FRMs/.TRG files while filling I_S table are
|
||||||
|
# not kept to the end of statement. Keeping the locks has caused
|
||||||
|
# performance problems in cases when big number of tables (.FRMs
|
||||||
|
# or .TRG files) were scanned as cost of new lock acquisition has
|
||||||
|
# increased linearly.
|
||||||
|
drop database if exists mysqltest;
|
||||||
|
create database mysqltest;
|
||||||
|
use mysqltest;
|
||||||
|
create table t0 (i int);
|
||||||
|
create table t1 (j int);
|
||||||
|
create table t2 (k int);
|
||||||
|
#
|
||||||
|
# Test that we don't keep locks in case when we to fill
|
||||||
|
# I_S table we perform full-blown table open.
|
||||||
|
#
|
||||||
|
# Acquire lock on 't2' so upcoming RENAME is
|
||||||
|
# blocked.
|
||||||
|
lock tables t2 read;
|
||||||
|
#
|
||||||
|
# Switching to connection 'con12828477_1'.
|
||||||
|
#
|
||||||
|
# The below RENAME should wait on 't2' while
|
||||||
|
# keeping X lock on 't1'.
|
||||||
|
rename table t1 to t3, t2 to t1, t3 to t2;
|
||||||
|
#
|
||||||
|
# Switching to connection 'con12828477_2'.
|
||||||
|
#
|
||||||
|
# Wait while the above RENAME is blocked.
|
||||||
|
# Issue query to I_S which will open 't0' and get
|
||||||
|
# blocked on 't1' because of RENAME.
|
||||||
|
select table_name, auto_increment from information_schema.tables where table_schema='mysqltest';
|
||||||
|
#
|
||||||
|
# Switching to connection 'con12828477_3'.
|
||||||
|
#
|
||||||
|
# Wait while the above SELECT is blocked.
|
||||||
|
#
|
||||||
|
# Check that it holds no lock on 't0' so it can be renamed.
|
||||||
|
rename table t0 to t4;
|
||||||
|
#
|
||||||
|
# Switching to connection 'default'.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Unblock the first RENAME.
|
||||||
|
unlock tables;
|
||||||
|
#
|
||||||
|
# Switching to connection 'con12828477_1'.
|
||||||
|
#
|
||||||
|
# Reap the first RENAME
|
||||||
|
#
|
||||||
|
# Switching to connection 'con12828477_2'.
|
||||||
|
#
|
||||||
|
# Reap SELECT to I_S.
|
||||||
|
table_name auto_increment
|
||||||
|
t0 NULL
|
||||||
|
t1 NULL
|
||||||
|
t2 NULL
|
||||||
|
#
|
||||||
|
# Switching to connection 'default'.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Now test that we don't keep locks in case when we to fill
|
||||||
|
# I_S table we read .FRM or .TRG file only (this was the case
|
||||||
|
# for which problem existed).
|
||||||
|
#
|
||||||
|
rename table t4 to t0;
|
||||||
|
# Acquire lock on 't2' so upcoming RENAME is
|
||||||
|
# blocked.
|
||||||
|
lock tables t2 read;
|
||||||
|
#
|
||||||
|
# Switching to connection 'con12828477_1'.
|
||||||
|
#
|
||||||
|
# The below RENAME should wait on 't2' while
|
||||||
|
# keeping X lock on 't1'.
|
||||||
|
rename table t1 to t3, t2 to t1, t3 to t2;
|
||||||
|
#
|
||||||
|
# Switching to connection 'con12828477_2'.
|
||||||
|
#
|
||||||
|
# Wait while the above RENAME is blocked.
|
||||||
|
# Issue query to I_S which will open 't0' and get
|
||||||
|
# blocked on 't1' because of RENAME.
|
||||||
|
select event_object_table, trigger_name from information_schema.triggers where event_object_schema='mysqltest';
|
||||||
|
#
|
||||||
|
# Switching to connection 'con12828477_3'.
|
||||||
|
#
|
||||||
|
# Wait while the above SELECT is blocked.
|
||||||
|
#
|
||||||
|
# Check that it holds no lock on 't0' so it can be renamed.
|
||||||
|
rename table t0 to t4;
|
||||||
|
#
|
||||||
|
# Switching to connection 'default'.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Unblock the first RENAME.
|
||||||
|
unlock tables;
|
||||||
|
#
|
||||||
|
# Switching to connection 'con12828477_1'.
|
||||||
|
#
|
||||||
|
# Reap the first RENAME
|
||||||
|
#
|
||||||
|
# Switching to connection 'con12828477_2'.
|
||||||
|
#
|
||||||
|
# Reap SELECT to I_S.
|
||||||
|
event_object_table trigger_name
|
||||||
|
#
|
||||||
|
# Switching to connection 'default'.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Clean-up.
|
||||||
|
drop database mysqltest;
|
||||||
|
#
|
||||||
# End of 5.5 tests
|
# End of 5.5 tests
|
||||||
#
|
#
|
||||||
|
@ -1543,8 +1543,6 @@ DROP TABLE t1, information_schema.tables;
|
|||||||
LOCK TABLES t1 READ, information_schema.tables READ;
|
LOCK TABLES t1 READ, information_schema.tables READ;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
# Wait till all disconnects are completed
|
|
||||||
--source include/wait_until_count_sessions.inc
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Bug #43834 Assertion in Natural_join_column::db_name() on an I_S query
|
# Bug #43834 Assertion in Natural_join_column::db_name() on an I_S query
|
||||||
@ -1608,6 +1606,186 @@ drop table t1;
|
|||||||
drop view v1;
|
drop view v1;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Test for bug #12828477 - "MDL SUBSYSTEM CREATES BIG OVERHEAD FOR
|
||||||
|
--echo # CERTAIN QUERIES TO INFORMATION_SCHEMA".
|
||||||
|
--echo #
|
||||||
|
--echo # Check that metadata locks which are acquired during the process
|
||||||
|
--echo # of opening tables/.FRMs/.TRG files while filling I_S table are
|
||||||
|
--echo # not kept to the end of statement. Keeping the locks has caused
|
||||||
|
--echo # performance problems in cases when big number of tables (.FRMs
|
||||||
|
--echo # or .TRG files) were scanned as cost of new lock acquisition has
|
||||||
|
--echo # increased linearly.
|
||||||
|
--disable_warnings
|
||||||
|
drop database if exists mysqltest;
|
||||||
|
--enable_warnings
|
||||||
|
create database mysqltest;
|
||||||
|
use mysqltest;
|
||||||
|
create table t0 (i int);
|
||||||
|
create table t1 (j int);
|
||||||
|
create table t2 (k int);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Test that we don't keep locks in case when we to fill
|
||||||
|
--echo # I_S table we perform full-blown table open.
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo # Acquire lock on 't2' so upcoming RENAME is
|
||||||
|
--echo # blocked.
|
||||||
|
lock tables t2 read;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Switching to connection 'con12828477_1'.
|
||||||
|
--echo #
|
||||||
|
connect (con12828477_1, localhost, root,,mysqltest);
|
||||||
|
--echo # The below RENAME should wait on 't2' while
|
||||||
|
--echo # keeping X lock on 't1'.
|
||||||
|
--send rename table t1 to t3, t2 to t1, t3 to t2
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Switching to connection 'con12828477_2'.
|
||||||
|
--echo #
|
||||||
|
connect (con12828477_2, localhost, root,,mysqltest);
|
||||||
|
--echo # Wait while the above RENAME is blocked.
|
||||||
|
let $wait_condition=
|
||||||
|
select count(*) = 1 from information_schema.processlist
|
||||||
|
where state = "Waiting for table metadata lock" and
|
||||||
|
info = "rename table t1 to t3, t2 to t1, t3 to t2";
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
|
--echo # Issue query to I_S which will open 't0' and get
|
||||||
|
--echo # blocked on 't1' because of RENAME.
|
||||||
|
--send select table_name, auto_increment from information_schema.tables where table_schema='mysqltest'
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Switching to connection 'con12828477_3'.
|
||||||
|
--echo #
|
||||||
|
connect (con12828477_3, localhost, root,,mysqltest);
|
||||||
|
--echo # Wait while the above SELECT is blocked.
|
||||||
|
let $wait_condition=
|
||||||
|
select count(*) = 1 from information_schema.processlist
|
||||||
|
where state = "Waiting for table metadata lock" and
|
||||||
|
info = "select table_name, auto_increment from information_schema.tables where table_schema='mysqltest'";
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Check that it holds no lock on 't0' so it can be renamed.
|
||||||
|
rename table t0 to t4;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Switching to connection 'default'.
|
||||||
|
--echo #
|
||||||
|
connection default;
|
||||||
|
--echo #
|
||||||
|
--echo # Unblock the first RENAME.
|
||||||
|
unlock tables;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Switching to connection 'con12828477_1'.
|
||||||
|
--echo #
|
||||||
|
connection con12828477_1;
|
||||||
|
--echo # Reap the first RENAME
|
||||||
|
--reap
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Switching to connection 'con12828477_2'.
|
||||||
|
--echo #
|
||||||
|
connection con12828477_2;
|
||||||
|
--echo # Reap SELECT to I_S.
|
||||||
|
--reap
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Switching to connection 'default'.
|
||||||
|
--echo #
|
||||||
|
connection default;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Now test that we don't keep locks in case when we to fill
|
||||||
|
--echo # I_S table we read .FRM or .TRG file only (this was the case
|
||||||
|
--echo # for which problem existed).
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
rename table t4 to t0;
|
||||||
|
--echo # Acquire lock on 't2' so upcoming RENAME is
|
||||||
|
--echo # blocked.
|
||||||
|
lock tables t2 read;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Switching to connection 'con12828477_1'.
|
||||||
|
--echo #
|
||||||
|
connection con12828477_1;
|
||||||
|
--echo # The below RENAME should wait on 't2' while
|
||||||
|
--echo # keeping X lock on 't1'.
|
||||||
|
--send rename table t1 to t3, t2 to t1, t3 to t2
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Switching to connection 'con12828477_2'.
|
||||||
|
--echo #
|
||||||
|
connection con12828477_2;
|
||||||
|
--echo # Wait while the above RENAME is blocked.
|
||||||
|
let $wait_condition=
|
||||||
|
select count(*) = 1 from information_schema.processlist
|
||||||
|
where state = "Waiting for table metadata lock" and
|
||||||
|
info = "rename table t1 to t3, t2 to t1, t3 to t2";
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
|
--echo # Issue query to I_S which will open 't0' and get
|
||||||
|
--echo # blocked on 't1' because of RENAME.
|
||||||
|
--send select event_object_table, trigger_name from information_schema.triggers where event_object_schema='mysqltest'
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Switching to connection 'con12828477_3'.
|
||||||
|
--echo #
|
||||||
|
connection con12828477_3;
|
||||||
|
--echo # Wait while the above SELECT is blocked.
|
||||||
|
let $wait_condition=
|
||||||
|
select count(*) = 1 from information_schema.processlist
|
||||||
|
where state = "Waiting for table metadata lock" and
|
||||||
|
info = "select event_object_table, trigger_name from information_schema.triggers where event_object_schema='mysqltest'";
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Check that it holds no lock on 't0' so it can be renamed.
|
||||||
|
rename table t0 to t4;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Switching to connection 'default'.
|
||||||
|
--echo #
|
||||||
|
connection default;
|
||||||
|
--echo #
|
||||||
|
--echo # Unblock the first RENAME.
|
||||||
|
unlock tables;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Switching to connection 'con12828477_1'.
|
||||||
|
--echo #
|
||||||
|
connection con12828477_1;
|
||||||
|
--echo # Reap the first RENAME
|
||||||
|
--reap
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Switching to connection 'con12828477_2'.
|
||||||
|
--echo #
|
||||||
|
connection con12828477_2;
|
||||||
|
--echo # Reap SELECT to I_S.
|
||||||
|
--reap
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Switching to connection 'default'.
|
||||||
|
--echo #
|
||||||
|
connection default;
|
||||||
|
disconnect con12828477_1;
|
||||||
|
disconnect con12828477_2;
|
||||||
|
disconnect con12828477_3;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Clean-up.
|
||||||
|
drop database mysqltest;
|
||||||
|
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 5.5 tests
|
--echo # End of 5.5 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
|
||||||
|
# Wait till all disconnects are completed
|
||||||
|
--source include/wait_until_count_sessions.inc
|
||||||
|
@ -3157,6 +3157,10 @@ end:
|
|||||||
*/
|
*/
|
||||||
thd->temporary_tables= NULL;
|
thd->temporary_tables= NULL;
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
|
/*
|
||||||
|
Release metadata lock we might have acquired.
|
||||||
|
See comment in fill_schema_table_from_frm() for details.
|
||||||
|
*/
|
||||||
thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp);
|
thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp);
|
||||||
|
|
||||||
thd->lex= old_lex;
|
thd->lex= old_lex;
|
||||||
@ -3339,6 +3343,9 @@ try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table,
|
|||||||
@param[in] db_name database name
|
@param[in] db_name database name
|
||||||
@param[in] table_name table name
|
@param[in] table_name table name
|
||||||
@param[in] schema_table_idx I_S table index
|
@param[in] schema_table_idx I_S table index
|
||||||
|
@param[in] open_tables_state_backup Open_tables_state object which is used
|
||||||
|
to save/restore original state of metadata
|
||||||
|
locks.
|
||||||
@param[in] can_deadlock Indicates that deadlocks are possible
|
@param[in] can_deadlock Indicates that deadlocks are possible
|
||||||
due to metadata locks, so to avoid
|
due to metadata locks, so to avoid
|
||||||
them we should not wait in case if
|
them we should not wait in case if
|
||||||
@ -3356,6 +3363,7 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
|
|||||||
LEX_STRING *db_name,
|
LEX_STRING *db_name,
|
||||||
LEX_STRING *table_name,
|
LEX_STRING *table_name,
|
||||||
enum enum_schema_tables schema_table_idx,
|
enum enum_schema_tables schema_table_idx,
|
||||||
|
Open_tables_backup *open_tables_state_backup,
|
||||||
bool can_deadlock)
|
bool can_deadlock)
|
||||||
{
|
{
|
||||||
TABLE *table= tables->table;
|
TABLE *table= tables->table;
|
||||||
@ -3501,13 +3509,27 @@ end_share:
|
|||||||
|
|
||||||
end_unlock:
|
end_unlock:
|
||||||
mysql_mutex_unlock(&LOCK_open);
|
mysql_mutex_unlock(&LOCK_open);
|
||||||
/*
|
|
||||||
Don't release the MDL lock, it can be part of a transaction.
|
|
||||||
If it is not, it will be released by the call to
|
|
||||||
MDL_context::rollback_to_savepoint() in the caller.
|
|
||||||
*/
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
/*
|
||||||
|
Release metadata lock we might have acquired.
|
||||||
|
|
||||||
|
Without this step metadata locks acquired for each table processed
|
||||||
|
will be accumulated. In situation when a lot of tables are processed
|
||||||
|
by I_S query this will result in transaction with too many metadata
|
||||||
|
locks. As result performance of acquisition of new lock will suffer.
|
||||||
|
|
||||||
|
Of course, the fact that we don't hold metadata lock on tables which
|
||||||
|
were processed till the end of I_S query makes execution less isolated
|
||||||
|
from concurrent DDL. Consequently one might get 'dirty' results from
|
||||||
|
such a query. But we have never promised serializability of I_S queries
|
||||||
|
anyway.
|
||||||
|
|
||||||
|
We don't have any tables open since we took backup, so rolling back to
|
||||||
|
savepoint is safe.
|
||||||
|
*/
|
||||||
|
DBUG_ASSERT(thd->open_tables == NULL);
|
||||||
|
thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp);
|
||||||
thd->clear_error();
|
thd->clear_error();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -3758,6 +3780,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||||||
int res= fill_schema_table_from_frm(thd, tables, schema_table,
|
int res= fill_schema_table_from_frm(thd, tables, schema_table,
|
||||||
db_name, table_name,
|
db_name, table_name,
|
||||||
schema_table_idx,
|
schema_table_idx,
|
||||||
|
&open_tables_state_backup,
|
||||||
can_deadlock);
|
can_deadlock);
|
||||||
|
|
||||||
thd->pop_internal_handler();
|
thd->pop_internal_handler();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user