List:Commits« Previous MessageNext Message »
From:Dmitry Lenev Date:June 16 2011 4:07pm
Subject:bzr commit into mysql-trunk branch (Dmitry.Lenev:3215) Bug#12641342
View as plain text  
#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#12641342Dmitry Lenev16 Jun