summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKentoku SHIBA <kentokushiba@gmail.com>2013-12-11 00:31:04 +0900
committerSergey Vojtovich <svoj@mariadb.org>2013-12-11 00:31:04 +0900
commit3771e14ea9957dde8f25ccf9f99df7a2aa906fcb (patch)
tree3d81343ced2061564af76d33138d9f450f3270c9
parent1f9d4819ad80528ac16c29f81dc397d93965f296 (diff)
downloadmariadb-git-3771e14ea9957dde8f25ccf9f99df7a2aa906fcb.tar.gz
add metadata_lock_info
-rw-r--r--plugin/metadata_lock_info/CMakeLists.txt2
-rw-r--r--plugin/metadata_lock_info/metadata_lock_info.cc188
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/global_read_lock.result10
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/table_metadata_lock.result13
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/user_lock.result13
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.opt2
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.pm8
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/global_read_lock.test5
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/table_metadata_lock.test8
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/user_lock.test5
-rw-r--r--sql/mdl.cc42
-rw-r--r--sql/mdl.h7
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, &param));
+}
+
+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