#At file:///home/dlenev/src/bzr/mysql-trunk-mrg/ based on revid:mayank.prasad@stripped
3215 Dmitry Lenev 2011-06-16 [merge]
Merged fix for bug #12641342 - "61401: UPDATE PERFORMANCE
DEGRADES GRADUALLY IF A TRIGGER EXISTS" into mysql-trunk.
modified:
mysql-test/r/flush.result
mysql-test/t/flush.test
sql/mdl.h
sql/sql_class.cc
sql/sql_class.h
sql/sql_parse.cc
=== modified file 'mysql-test/r/flush.result'
--- a/mysql-test/r/flush.result 2011-03-07 09:08:10 +0000
+++ b/mysql-test/r/flush.result 2011-06-16 15:18:16 +0000
@@ -466,3 +466,26 @@ 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;
+#
+# Test for bug #12641342 - "61401: UPDATE PERFORMANCE DEGRADES
+# GRADUALLY IF A TRIGGER EXISTS".
+#
+# One of side-effects of this bug was that a transaction which
+# involved DML statements requiring prelocking blocked concurrent
+# FLUSH TABLES WITH READ LOCK for the whole its duration, while
+# correct behavior in this case is to block FTWRL only for duration
+# of individual DML statements.
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (id INT PRIMARY KEY, value INT);
+INSERT INTO t1 VALUES (1, 1);
+CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW SET @var = "a";
+BEGIN;
+UPDATE t1 SET value= value + 1 WHERE id = 1;
+# Switching to connection 'con1'.
+# The below FLUSH TABLES WITH READ LOCK should succeed and
+# should not be blocked by the transaction in default connection.
+FLUSH TABLES WITH READ LOCK;
+UNLOCK TABLES;
+# Switching to connection 'default'.
+COMMIT;
+DROP TABLE t1;
=== modified file 'mysql-test/t/flush.test'
--- a/mysql-test/t/flush.test 2011-03-07 09:08:10 +0000
+++ b/mysql-test/t/flush.test 2011-06-16 15:18:16 +0000
@@ -668,3 +668,36 @@ ALTER TABLE t1 COMMENT 'test';
UNLOCK TABLES;
DROP TABLE t1;
+
+
+--echo #
+--echo # Test for bug #12641342 - "61401: UPDATE PERFORMANCE DEGRADES
+--echo # GRADUALLY IF A TRIGGER EXISTS".
+--echo #
+--echo # One of side-effects of this bug was that a transaction which
+--echo # involved DML statements requiring prelocking blocked concurrent
+--echo # FLUSH TABLES WITH READ LOCK for the whole its duration, while
+--echo # correct behavior in this case is to block FTWRL only for duration
+--echo # of individual DML statements.
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+CREATE TABLE t1 (id INT PRIMARY KEY, value INT);
+INSERT INTO t1 VALUES (1, 1);
+CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW SET @var = "a";
+BEGIN;
+UPDATE t1 SET value= value + 1 WHERE id = 1;
+
+--echo # Switching to connection 'con1'.
+connect(con1, localhost, root);
+--echo # The below FLUSH TABLES WITH READ LOCK should succeed and
+--echo # should not be blocked by the transaction in default connection.
+FLUSH TABLES WITH READ LOCK;
+UNLOCK TABLES;
+disconnect con1;
+--source include/wait_until_disconnected.inc
+
+--echo # Switching to connection 'default'.
+connection default;
+COMMIT;
+DROP TABLE t1;
=== modified file 'sql/mdl.h'
--- a/sql/mdl.h 2011-04-11 11:52:24 +0000
+++ b/sql/mdl.h 2011-06-16 16:06:32 +0000
@@ -187,11 +187,24 @@ enum enum_mdl_type {
/** Duration of metadata lock. */
-enum enum_mdl_duration { MDL_STATEMENT= 0,
- MDL_TRANSACTION,
- MDL_EXPLICIT,
- /* This should be the last ! */
- MDL_DURATION_END };
+enum enum_mdl_duration {
+ /**
+ Locks with statement duration are automatically released at the end
+ of statement or transaction.
+ */
+ MDL_STATEMENT= 0,
+ /**
+ Locks with transaction duration are automatically released at the end
+ of transaction.
+ */
+ MDL_TRANSACTION,
+ /**
+ Locks with explicit duration survive the end of statement and transaction.
+ They have to be released explicitly by calling MDL_context::release_lock().
+ */
+ MDL_EXPLICIT,
+ /* This should be the last ! */
+ MDL_DURATION_END };
/** Maximal length of key for metadata locking subsystem. */
=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc 2011-06-10 16:57:01 +0000
+++ b/sql/sql_class.cc 2011-06-16 16:06:32 +0000
@@ -3974,16 +3974,24 @@ void THD::set_mysys_var(struct st_my_thr
void THD::leave_locked_tables_mode()
{
+ if (locked_tables_mode == LTM_LOCK_TABLES)
+ {
+ /*
+ When leaving LOCK TABLES mode we have to change the duration of most
+ of the metadata locks being held, except for HANDLER and GRL locks,
+ to transactional for them to be properly released at UNLOCK TABLES.
+ */
+ mdl_context.set_transaction_duration_for_all_locks();
+ /*
+ Make sure we don't release the global read lock and commit blocker
+ when leaving LTM.
+ */
+ global_read_lock.set_explicit_lock_duration(this);
+ /* Also ensure that we don't release metadata locks for open HANDLERs. */
+ if (handler_tables_hash.records)
+ mysql_ha_set_explicit_lock_duration(this);
+ }
locked_tables_mode= LTM_NONE;
- mdl_context.set_transaction_duration_for_all_locks();
- /*
- Make sure we don't release the global read lock and commit blocker
- when leaving LTM.
- */
- global_read_lock.set_explicit_lock_duration(this);
- /* Also ensure that we don't release metadata locks for open HANDLERs. */
- if (handler_tables_hash.records)
- mysql_ha_set_explicit_lock_duration(this);
}
void THD::get_definer(LEX_USER *definer)
=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h 2011-06-10 16:57:01 +0000
+++ b/sql/sql_class.h 2011-06-16 16:06:32 +0000
@@ -3202,7 +3202,19 @@ public:
{
DBUG_ASSERT(locked_tables_mode == LTM_NONE);
- mdl_context.set_explicit_duration_for_all_locks();
+ if (mode_arg == LTM_LOCK_TABLES)
+ {
+ /*
+ When entering LOCK TABLES mode we should set explicit duration
+ for all metadata locks acquired so far in order to avoid releasing
+ them till UNLOCK TABLES statement.
+ We don't do this when entering prelocked mode since sub-statements
+ don't release metadata locks and restoring status-quo after leaving
+ prelocking mode gets complicated.
+ */
+ mdl_context.set_explicit_duration_for_all_locks();
+ }
+
locked_tables_mode= mode_arg;
}
void leave_locked_tables_mode();
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2011-06-10 16:57:01 +0000
+++ b/sql/sql_parse.cc 2011-06-16 16:06:32 +0000
@@ -2171,6 +2171,11 @@ mysql_execute_command(THD *thd)
*/
if (stmt_causes_implicit_commit(thd, CF_IMPLICT_COMMIT_BEGIN))
{
+ /*
+ Note that this should never happen inside of stored functions
+ or triggers as all such statements prohibited there.
+ */
+ DBUG_ASSERT(! thd->in_sub_stmt);
/* Commit or rollback the statement transaction. */
thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
/* Commit the normal transaction if one is active. */
No bundle (reason: revision is a merge).
| Thread |
|---|
| • bzr commit into mysql-trunk branch (Dmitry.Lenev:3215) Bug#12641342 | Dmitry Lenev | 16 Jun |