diff options
author | Kentoku SHIBA <kentokushiba@gmail.com> | 2013-12-11 00:31:04 +0900 |
---|---|---|
committer | Sergey Vojtovich <svoj@mariadb.org> | 2013-12-11 00:31:04 +0900 |
commit | 3771e14ea9957dde8f25ccf9f99df7a2aa906fcb (patch) | |
tree | 3d81343ced2061564af76d33138d9f450f3270c9 | |
parent | 1f9d4819ad80528ac16c29f81dc397d93965f296 (diff) | |
download | mariadb-git-3771e14ea9957dde8f25ccf9f99df7a2aa906fcb.tar.gz |
add metadata_lock_info
12 files changed, 301 insertions, 2 deletions
diff --git a/plugin/metadata_lock_info/CMakeLists.txt b/plugin/metadata_lock_info/CMakeLists.txt new file mode 100644 index 00000000000..44393c09eb6 --- /dev/null +++ b/plugin/metadata_lock_info/CMakeLists.txt @@ -0,0 +1,2 @@ +SET(METADATA_LOCK_INFO_SOURCES metadata_lock_info.cc) +MYSQL_ADD_PLUGIN(metadata_lock_info ${METADATA_LOCK_INFO_SOURCES} MODULE_OUTPUT_NAME "metadata_lock_info") diff --git a/plugin/metadata_lock_info/metadata_lock_info.cc b/plugin/metadata_lock_info/metadata_lock_info.cc new file mode 100644 index 00000000000..0ddde226553 --- /dev/null +++ b/plugin/metadata_lock_info/metadata_lock_info.cc @@ -0,0 +1,188 @@ +/* Copyright (C) 2013 Kentoku Shiba + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#define MYSQL_SERVER 1 +#include "mysql_version.h" +#include "mysql/plugin.h" +#include "sql_class.h" +#include "sql_show.h" + +static const LEX_STRING metadata_lock_info_lock_name[] = { + { C_STRING_WITH_LEN("Global read lock") }, + { C_STRING_WITH_LEN("Schema metadata lock") }, + { C_STRING_WITH_LEN("Table metadata lock") }, + { C_STRING_WITH_LEN("Stored function metadata lock") }, + { C_STRING_WITH_LEN("Stored procedure metadata lock") }, + { C_STRING_WITH_LEN("Trigger metadata lock") }, + { C_STRING_WITH_LEN("Event metadata lock") }, + { C_STRING_WITH_LEN("Commit lock") }, + { C_STRING_WITH_LEN("User lock") }, +}; + +static const LEX_STRING metadata_lock_info_lock_mode[] = { + { C_STRING_WITH_LEN("MDL_INTENTION_EXCLUSIVE") }, + { C_STRING_WITH_LEN("MDL_SHARED") }, + { C_STRING_WITH_LEN("MDL_SHARED_HIGH_PRIO") }, + { C_STRING_WITH_LEN("MDL_SHARED_READ") }, + { C_STRING_WITH_LEN("MDL_SHARED_WRITE") }, + { C_STRING_WITH_LEN("MDL_SHARED_NO_WRITE") }, + { C_STRING_WITH_LEN("MDL_SHARED_NO_READ_WRITE") }, + { C_STRING_WITH_LEN("MDL_EXCLUSIVE") }, +}; + +static const LEX_STRING metadata_lock_info_duration[] = { + { C_STRING_WITH_LEN("MDL_STATEMENT") }, + { C_STRING_WITH_LEN("MDL_TRANSACTION") }, + { C_STRING_WITH_LEN("MDL_EXPLICIT") }, +}; + +static ST_FIELD_INFO i_s_metadata_lock_info_fields_info[] = +{ + {"THREAD_ID", 20, MYSQL_TYPE_LONGLONG, 0, + MY_I_S_UNSIGNED, "thread_id", SKIP_OPEN_TABLE}, + {"LOCK_MODE", 24, MYSQL_TYPE_STRING, 0, + MY_I_S_MAYBE_NULL, "lock_mode", SKIP_OPEN_TABLE}, + {"LOCK_DURATION", 30, MYSQL_TYPE_STRING, 0, + MY_I_S_MAYBE_NULL, "lock_duration", SKIP_OPEN_TABLE}, + {"LOCK_TYPE", 30, MYSQL_TYPE_STRING, 0, + MY_I_S_MAYBE_NULL, "lock_type", SKIP_OPEN_TABLE}, + {"TABLE_SCHEMA", 64, MYSQL_TYPE_STRING, 0, + MY_I_S_MAYBE_NULL, "table_schema", SKIP_OPEN_TABLE}, + {"TABLE_NAME", 64, MYSQL_TYPE_STRING, 0, + MY_I_S_MAYBE_NULL, "table_name", SKIP_OPEN_TABLE}, + {NULL, 0, MYSQL_TYPE_STRING, 0, 0, NULL, 0} +}; + +struct st_i_s_metadata_param +{ + THD *thd; + TABLE *table; +}; + +int i_s_metadata_lock_info_fill_row( + MDL_ticket *mdl_ticket, + void *arg +) { + st_i_s_metadata_param *param = (st_i_s_metadata_param *) arg; + THD *thd = param->thd; + TABLE *table = param->table; + DBUG_ENTER("i_s_metadata_lock_info_fill_row"); + MDL_request mdl_request; + enum_mdl_duration mdl_duration; + MDL_context *mdl_ctx = mdl_ticket->get_ctx(); + enum_mdl_type mdl_ticket_type = mdl_ticket->get_type(); + MDL_key *mdl_key = mdl_ticket->get_key(); + MDL_key::enum_mdl_namespace mdl_namespace = mdl_key->mdl_namespace(); + mdl_request.init(mdl_key, mdl_ticket_type, MDL_STATEMENT); + mdl_ctx->find_ticket(&mdl_request, &mdl_duration); + table->field[0]->store((longlong) mdl_ctx->get_thread_id(), TRUE); + table->field[1]->set_notnull(); + table->field[1]->store( + metadata_lock_info_lock_mode[(int) mdl_ticket_type].str, + metadata_lock_info_lock_mode[(int) mdl_ticket_type].length, + system_charset_info); + table->field[2]->set_notnull(); + table->field[2]->store( + metadata_lock_info_duration[(int) mdl_duration].str, + metadata_lock_info_duration[(int) mdl_duration].length, + system_charset_info); + table->field[3]->set_notnull(); + table->field[3]->store( + metadata_lock_info_lock_name[(int) mdl_namespace].str, + metadata_lock_info_lock_name[(int) mdl_namespace].length, + system_charset_info); + table->field[4]->set_notnull(); + table->field[4]->store(mdl_key->db_name(), + mdl_key->db_name_length(), system_charset_info); + table->field[5]->set_notnull(); + table->field[5]->store(mdl_key->name(), + mdl_key->name_length(), system_charset_info); + if (schema_table_store_record(thd, table)) + DBUG_RETURN(1); + DBUG_RETURN(0); +} + +int i_s_metadata_lock_info_fill_table( + THD *thd, + TABLE_LIST *tables, + COND *cond +) { + st_i_s_metadata_param param; + DBUG_ENTER("i_s_metadata_lock_info_fill_table"); + param.table = tables->table; + param.thd = thd; + DBUG_RETURN(mdl_iterate(i_s_metadata_lock_info_fill_row, ¶m)); +} + +static int i_s_metadata_lock_info_init( + void *p +) { + ST_SCHEMA_TABLE *schema = (ST_SCHEMA_TABLE *) p; + DBUG_ENTER("i_s_metadata_lock_info_init"); + schema->fields_info = i_s_metadata_lock_info_fields_info; + schema->fill_table = i_s_metadata_lock_info_fill_table; + schema->idx_field1 = 0; + DBUG_RETURN(0); +} + +static int i_s_metadata_lock_info_deinit( + void *p +) { + DBUG_ENTER("i_s_metadata_lock_info_deinit"); + DBUG_RETURN(0); +} + +static struct st_mysql_information_schema i_s_metadata_lock_info_plugin = +{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION }; + +#ifdef MARIADB_BASE_VERSION +maria_declare_plugin(metadata_lock_info) +{ + MYSQL_INFORMATION_SCHEMA_PLUGIN, + &i_s_metadata_lock_info_plugin, + "METADATA_LOCK_INFO", + "Kentoku Shiba", + "Metadata locking viewer", + PLUGIN_LICENSE_GPL, + i_s_metadata_lock_info_init, + i_s_metadata_lock_info_deinit, + 0x0001, + NULL, + NULL, + NULL, + MariaDB_PLUGIN_MATURITY_ALPHA, +} +maria_declare_plugin_end; +#else +mysql_declare_plugin(metadata_lock_info) +{ + MYSQL_INFORMATION_SCHEMA_PLUGIN, + &i_s_metadata_lock_info_plugin, + "METADATA_LOCK_INFO", + "Kentoku Shiba", + "Metadata locking viewer", + PLUGIN_LICENSE_GPL, + i_s_metadata_lock_info_init, + i_s_metadata_lock_info_deinit, + 0x0001, + NULL, + NULL, + NULL, +#if MYSQL_VERSION_ID >= 50600 + 0, +#endif +} +mysql_declare_plugin_end; +#endif diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/global_read_lock.result b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/global_read_lock.result new file mode 100644 index 00000000000..9840aeecf97 --- /dev/null +++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/global_read_lock.result @@ -0,0 +1,10 @@ +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +lock_mode lock_duration lock_type table_schema table_name +FLUSH TABLES WITH READ LOCK; +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +lock_mode lock_duration lock_type table_schema table_name +MDL_SHARED MDL_EXPLICIT Global read lock +MDL_SHARED MDL_EXPLICIT Commit lock +UNLOCK TABLES; +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +lock_mode lock_duration lock_type table_schema table_name diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/table_metadata_lock.result b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/table_metadata_lock.result new file mode 100644 index 00000000000..280c8284c54 --- /dev/null +++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/table_metadata_lock.result @@ -0,0 +1,13 @@ +CREATE TABLE IF NOT EXISTS t1(a int); +BEGIN; +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +lock_mode lock_duration lock_type table_schema table_name +SELECT * FROM t1; +a +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +lock_mode lock_duration lock_type table_schema table_name +MDL_SHARED_READ MDL_TRANSACTION Table metadata lock test t1 +ROLLBACK; +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +lock_mode lock_duration lock_type table_schema table_name +DROP TABLE t1; diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/user_lock.result b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/user_lock.result new file mode 100644 index 00000000000..9e3779e0336 --- /dev/null +++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/user_lock.result @@ -0,0 +1,13 @@ +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +lock_mode lock_duration lock_type table_schema table_name +SELECT GET_LOCK('LOCK1',0); +GET_LOCK('LOCK1',0) +1 +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +lock_mode lock_duration lock_type table_schema table_name +MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT User lock LOCK1 +SELECT RELEASE_LOCK('LOCK1'); +RELEASE_LOCK('LOCK1') +1 +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +lock_mode lock_duration lock_type table_schema table_name diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.opt b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.opt new file mode 100644 index 00000000000..638f267c166 --- /dev/null +++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.opt @@ -0,0 +1,2 @@ +--loose-metadata_lock_info +--plugin-load=$METADATA_LOCK_INFO_SO diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.pm b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.pm new file mode 100644 index 00000000000..3dcf7c99999 --- /dev/null +++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.pm @@ -0,0 +1,8 @@ +package My::Suite::Metadata_lock_info; + +@ISA = qw(My::Suite); + +return "No Metadata_lock_info plugin" unless $ENV{METADATA_LOCK_INFO_SO}; + +bless { }; + diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/global_read_lock.test b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/global_read_lock.test new file mode 100644 index 00000000000..f221191255e --- /dev/null +++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/global_read_lock.test @@ -0,0 +1,5 @@ +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +FLUSH TABLES WITH READ LOCK; +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +UNLOCK TABLES; +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/table_metadata_lock.test b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/table_metadata_lock.test new file mode 100644 index 00000000000..3451dff039d --- /dev/null +++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/table_metadata_lock.test @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS t1(a int); +BEGIN; +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +SELECT * FROM t1; +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +ROLLBACK; +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +DROP TABLE t1; diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/user_lock.test b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/user_lock.test new file mode 100644 index 00000000000..85dec3dcf75 --- /dev/null +++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/user_lock.test @@ -0,0 +1,5 @@ +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +SELECT GET_LOCK('LOCK1',0); +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; +SELECT RELEASE_LOCK('LOCK1'); +SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info; diff --git a/sql/mdl.cc b/sql/mdl.cc index c3a78f4c40b..d8aa6e1d1b4 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -158,6 +158,7 @@ private: I_P_List_counter> Lock_cache; Lock_cache m_unused_locks_cache; + friend int mdl_iterate(int (*)(MDL_ticket *, void *), void *); }; @@ -187,6 +188,7 @@ private: MDL_lock *m_global_lock; /** Pre-allocated MDL_lock object for COMMIT namespace. */ MDL_lock *m_commit_lock; + friend int mdl_iterate(int (*)(MDL_ticket *, void *), void *); }; @@ -706,6 +708,46 @@ void mdl_destroy() } +static inline int mdl_iterate_lock(MDL_lock *lock, + int (*callback)(MDL_ticket *ticket, void *arg), + void *arg) +{ + MDL_lock::Ticket_iterator ticket_it(lock->m_granted); + MDL_ticket *ticket; + int res= 0; + mysql_prlock_rdlock(&lock->m_rwlock); + while ((ticket= ticket_it++) && !(res= callback(ticket, arg))) /* no-op */; + mysql_prlock_unlock(&lock->m_rwlock); + return res; +} + + +int mdl_iterate(int (*callback)(MDL_ticket *ticket, void *arg), void *arg) +{ + uint i, j; + int res; + DBUG_ENTER("mdl_iterate"); + + if ((res= mdl_iterate_lock(mdl_locks.m_global_lock, callback, arg)) || + (res= mdl_iterate_lock(mdl_locks.m_commit_lock, callback, arg))) + DBUG_RETURN(res); + + for (i= 0; i < mdl_locks.m_partitions.elements(); i++) + { + MDL_map_partition *part= mdl_locks.m_partitions.at(i); + mysql_mutex_lock(&part->m_mutex); + for (j= 0; j < part->m_locks.records; j++) + { + if ((res= mdl_iterate_lock((MDL_lock*) my_hash_element(&part->m_locks, j), + callback, arg))) + break; + } + mysql_mutex_unlock(&part->m_mutex); + } + DBUG_RETURN(res); +} + + /** Initialize the container for all MDL locks. */ void MDL_map::init() diff --git a/sql/mdl.h b/sql/mdl.h index e79df9b6cd7..4b24c0b7f59 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -904,14 +904,14 @@ private: MDL_wait_for_subgraph *m_waiting_for; private: THD *get_thd() const { return m_owner->get_thd(); } - MDL_ticket *find_ticket(MDL_request *mdl_req, - enum_mdl_duration *duration); void release_locks_stored_before(enum_mdl_duration duration, MDL_ticket *sentinel); void release_lock(enum_mdl_duration duration, MDL_ticket *ticket); bool try_acquire_lock_impl(MDL_request *mdl_request, MDL_ticket **out_ticket); public: + MDL_ticket *find_ticket(MDL_request *mdl_req, + enum_mdl_duration *duration); void find_deadlock(); ulong get_thread_id() const { return thd_get_thread_id(get_thd()); } @@ -988,4 +988,7 @@ static const ulong MDL_LOCKS_HASH_PARTITIONS_DEFAULT = 8; to avoid starving out weak, low-prio locks. */ extern "C" ulong max_write_lock_count; + +extern MYSQL_PLUGIN_IMPORT +int mdl_iterate(int (*callback)(MDL_ticket *ticket, void *arg), void *arg); #endif |