List:Commits« Previous MessageNext Message »
From:Konstantin Osipov Date:July 16 2010 12:58pm
Subject:bzr commit into mysql-trunk-runtime branch (kostja:3082)
View as plain text  
#At file:///opt/local/work/trunk-runtime/ based on revid:kostja@stripped

 3082 Konstantin Osipov	2010-07-16
      Intermediate commit: remove the release of metadata locks
      from close_thread_tables().

    modified:
      sql/event_db_repository.cc
      sql/events.cc
      sql/ha_ndbcluster_binlog.cc
      sql/log.cc
      sql/log_event.cc
      sql/rpl_rli.cc
      sql/slave.cc
      sql/sp.cc
      sql/sql_acl.cc
      sql/sql_base.cc
      sql/sql_insert.cc
      sql/sql_parse.cc
      sql/sql_partition.cc
      sql/sql_plugin.cc
      sql/sql_prepare.cc
      sql/sql_servers.cc
      sql/sql_table.cc
      sql/sql_trigger.cc
      sql/sql_udf.cc
=== modified file 'sql/event_db_repository.cc'
--- a/sql/event_db_repository.cc	2010-07-16 08:55:35 +0000
+++ b/sql/event_db_repository.cc	2010-07-16 12:57:19 +0000
@@ -546,6 +546,26 @@ Event_db_repository::fill_schema_events(
     ret= table_scan_all_for_i_s(thd, schema_table, event_table);
 
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
 
   DBUG_PRINT("info", ("Return code=%d", ret));
   DBUG_RETURN(ret);
@@ -697,7 +717,29 @@ Event_db_repository::create_event(THD *t
 
 end:
   if (table)
+  {
     close_thread_tables(thd);
+    /*
+      - If inside a multi-statement transaction,
+      defer the release of metadata locks until the current
+      transaction is either committed or rolled back. This prevents
+      other statements from modifying the table for the entire
+      duration of this transaction.  This provides commit ordering
+      and guarantees serializability across multiple transactions.
+      - If closing a system table, defer the release of metadata locks
+      to the caller. We have no sentinel in MDL subsystem to guard
+      transactional locks from system tables locks, so don't know
+      which locks are which here.
+      - If in autocommit mode, or outside a transactional context,
+      automatically release metadata locks of the current statement.
+    */
+    if (! thd->in_multi_stmt_transaction_mode() &&
+        ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+        ! thd->locked_tables_mode)
+    {
+      thd->mdl_context.release_transactional_locks();
+    }
+  }
   thd->variables.sql_mode= saved_mode;
   DBUG_RETURN(test(ret));
 }
@@ -808,7 +850,29 @@ Event_db_repository::update_event(THD *t
 
 end:
   if (table)
+  {
     close_thread_tables(thd);
+    /*
+      - If inside a multi-statement transaction,
+      defer the release of metadata locks until the current
+      transaction is either committed or rolled back. This prevents
+      other statements from modifying the table for the entire
+      duration of this transaction.  This provides commit ordering
+      and guarantees serializability across multiple transactions.
+      - If closing a system table, defer the release of metadata locks
+      to the caller. We have no sentinel in MDL subsystem to guard
+      transactional locks from system tables locks, so don't know
+      which locks are which here.
+      - If in autocommit mode, or outside a transactional context,
+      automatically release metadata locks of the current statement.
+    */
+    if (! thd->in_multi_stmt_transaction_mode() &&
+        ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+        ! thd->locked_tables_mode)
+    {
+      thd->mdl_context.release_transactional_locks();
+    }
+  }
   thd->variables.sql_mode= saved_mode;
   DBUG_RETURN(test(ret));
 }
@@ -862,7 +926,29 @@ Event_db_repository::drop_event(THD *thd
 
 end:
   if (table)
+  {
     close_thread_tables(thd);
+    /*
+      - If inside a multi-statement transaction,
+      defer the release of metadata locks until the current
+      transaction is either committed or rolled back. This prevents
+      other statements from modifying the table for the entire
+      duration of this transaction.  This provides commit ordering
+      and guarantees serializability across multiple transactions.
+      - If closing a system table, defer the release of metadata locks
+      to the caller. We have no sentinel in MDL subsystem to guard
+      transactional locks from system tables locks, so don't know
+      which locks are which here.
+      - If in autocommit mode, or outside a transactional context,
+      automatically release metadata locks of the current statement.
+    */
+    if (! thd->in_multi_stmt_transaction_mode() &&
+        ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+        ! thd->locked_tables_mode)
+    {
+      thd->mdl_context.release_transactional_locks();
+    }
+  }
 
   DBUG_RETURN(test(ret));
 }
@@ -986,6 +1072,26 @@ Event_db_repository::drop_events_by_fiel
   }
   end_read_record(&read_record_info);
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
 
   DBUG_VOID_RETURN;
 }
@@ -1024,6 +1130,26 @@ Event_db_repository::load_named_event(TH
       my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
 
     close_thread_tables(thd);
+    /*
+      - If inside a multi-statement transaction,
+      defer the release of metadata locks until the current
+      transaction is either committed or rolled back. This prevents
+      other statements from modifying the table for the entire
+      duration of this transaction.  This provides commit ordering
+      and guarantees serializability across multiple transactions.
+      - If closing a system table, defer the release of metadata locks
+      to the caller. We have no sentinel in MDL subsystem to guard
+      transactional locks from system tables locks, so don't know
+      which locks are which here.
+      - If in autocommit mode, or outside a transactional context,
+      automatically release metadata locks of the current statement.
+    */
+    if (! thd->in_multi_stmt_transaction_mode() &&
+        ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+        ! thd->locked_tables_mode)
+    {
+      thd->mdl_context.release_transactional_locks();
+    }
   }
 
   thd->variables.sql_mode= saved_mode;
@@ -1101,7 +1227,29 @@ update_timing_fields_for_event(THD *thd,
 
 end:
   if (table)
+  {
     close_thread_tables(thd);
+    /*
+      - If inside a multi-statement transaction,
+      defer the release of metadata locks until the current
+      transaction is either committed or rolled back. This prevents
+      other statements from modifying the table for the entire
+      duration of this transaction.  This provides commit ordering
+      and guarantees serializability across multiple transactions.
+      - If closing a system table, defer the release of metadata locks
+      to the caller. We have no sentinel in MDL subsystem to guard
+      transactional locks from system tables locks, so don't know
+      which locks are which here.
+      - If in autocommit mode, or outside a transactional context,
+      automatically release metadata locks of the current statement.
+    */
+    if (! thd->in_multi_stmt_transaction_mode() &&
+        ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+        ! thd->locked_tables_mode)
+    {
+      thd->mdl_context.release_transactional_locks();
+    }
+  }
   /* Restore the state of binlog format */
   DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
   if (save_binlog_row_based)
@@ -1149,6 +1297,26 @@ Event_db_repository::check_system_tables
       ret= 1;
 
     close_thread_tables(thd);
+    /*
+      - If inside a multi-statement transaction,
+      defer the release of metadata locks until the current
+      transaction is either committed or rolled back. This prevents
+      other statements from modifying the table for the entire
+      duration of this transaction.  This provides commit ordering
+      and guarantees serializability across multiple transactions.
+      - If closing a system table, defer the release of metadata locks
+      to the caller. We have no sentinel in MDL subsystem to guard
+      transactional locks from system tables locks, so don't know
+      which locks are which here.
+      - If in autocommit mode, or outside a transactional context,
+      automatically release metadata locks of the current statement.
+    */
+    if (! thd->in_multi_stmt_transaction_mode() &&
+        ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+        ! thd->locked_tables_mode)
+    {
+      thd->mdl_context.release_transactional_locks();
+    }
   }
   /* Check mysql.user */
   tables.init_one_table("mysql", 5, "user", 4, "user", TL_READ);
@@ -1169,6 +1337,26 @@ Event_db_repository::check_system_tables
       ret= 1;
     }
     close_thread_tables(thd);
+    /*
+      - If inside a multi-statement transaction,
+      defer the release of metadata locks until the current
+      transaction is either committed or rolled back. This prevents
+      other statements from modifying the table for the entire
+      duration of this transaction.  This provides commit ordering
+      and guarantees serializability across multiple transactions.
+      - If closing a system table, defer the release of metadata locks
+      to the caller. We have no sentinel in MDL subsystem to guard
+      transactional locks from system tables locks, so don't know
+      which locks are which here.
+      - If in autocommit mode, or outside a transactional context,
+      automatically release metadata locks of the current statement.
+    */
+    if (! thd->in_multi_stmt_transaction_mode() &&
+        ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+        ! thd->locked_tables_mode)
+    {
+      thd->mdl_context.release_transactional_locks();
+    }
   }
   /* Check mysql.event */
   tables.init_one_table("mysql", 5, "event", 5, "event", TL_READ);
@@ -1183,6 +1371,26 @@ Event_db_repository::check_system_tables
     if (table_intact.check(tables.table, &event_table_def))
       ret= 1;
     close_thread_tables(thd);
+    /*
+      - If inside a multi-statement transaction,
+      defer the release of metadata locks until the current
+      transaction is either committed or rolled back. This prevents
+      other statements from modifying the table for the entire
+      duration of this transaction.  This provides commit ordering
+      and guarantees serializability across multiple transactions.
+      - If closing a system table, defer the release of metadata locks
+      to the caller. We have no sentinel in MDL subsystem to guard
+      transactional locks from system tables locks, so don't know
+      which locks are which here.
+      - If in autocommit mode, or outside a transactional context,
+      automatically release metadata locks of the current statement.
+    */
+    if (! thd->in_multi_stmt_transaction_mode() &&
+        ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+        ! thd->locked_tables_mode)
+    {
+      thd->mdl_context.release_transactional_locks();
+    }
   }
 
   DBUG_RETURN(test(ret));

=== modified file 'sql/events.cc'
--- a/sql/events.cc	2010-04-19 12:09:44 +0000
+++ b/sql/events.cc	2010-07-16 12:57:19 +0000
@@ -1162,6 +1162,26 @@ end:
   end_read_record(&read_record_info);
 
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
 
   DBUG_RETURN(ret);
 }

=== modified file 'sql/ha_ndbcluster_binlog.cc'
--- a/sql/ha_ndbcluster_binlog.cc	2010-07-08 21:20:08 +0000
+++ b/sql/ha_ndbcluster_binlog.cc	2010-07-16 12:57:19 +0000
@@ -2423,6 +2423,26 @@ int ndb_add_ndb_binlog_index(THD *thd, v
 
 add_ndb_binlog_index_err:
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   ndb_binlog_index= 0;
   thd->variables.option_bits= saved_options;
   return error;
@@ -3970,6 +3990,26 @@ restart:
       if (ndb_binlog_index->s->needs_reopen())
       {
         close_thread_tables(thd);
+        /*
+          - If inside a multi-statement transaction,
+          defer the release of metadata locks until the current
+          transaction is either committed or rolled back. This prevents
+          other statements from modifying the table for the entire
+          duration of this transaction.  This provides commit ordering
+          and guarantees serializability across multiple transactions.
+          - If closing a system table, defer the release of metadata locks
+          to the caller. We have no sentinel in MDL subsystem to guard
+          transactional locks from system tables locks, so don't know
+          which locks are which here.
+          - If in autocommit mode, or outside a transactional context,
+          automatically release metadata locks of the current statement.
+        */
+        if (! thd->in_multi_stmt_transaction_mode() &&
+            ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+            ! thd->locked_tables_mode)
+        {
+          thd->mdl_context.release_transactional_locks();
+        }
         ndb_binlog_index= 0;
       }
     }
@@ -4281,6 +4321,26 @@ restart:
   {
     ndb_binlog_tables_inited= FALSE;
     close_thread_tables(thd);
+    /*
+      - If inside a multi-statement transaction,
+      defer the release of metadata locks until the current
+      transaction is either committed or rolled back. This prevents
+      other statements from modifying the table for the entire
+      duration of this transaction.  This provides commit ordering
+      and guarantees serializability across multiple transactions.
+      - If closing a system table, defer the release of metadata locks
+      to the caller. We have no sentinel in MDL subsystem to guard
+      transactional locks from system tables locks, so don't know
+      which locks are which here.
+      - If in autocommit mode, or outside a transactional context,
+      automatically release metadata locks of the current statement.
+    */
+    if (! thd->in_multi_stmt_transaction_mode() &&
+        ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+        ! thd->locked_tables_mode)
+    {
+      thd->mdl_context.release_transactional_locks();
+    }
     ndb_binlog_index= 0;
     goto restart;
   }
@@ -4289,6 +4349,26 @@ err:
   DBUG_PRINT("info",("Shutting down cluster binlog thread"));
   thd->proc_info= "Shutting down";
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   mysql_mutex_lock(&injector_mutex);
   /* don't mess with the injector_ndb anymore from other threads */
   injector_thd= 0;

=== modified file 'sql/log.cc'
--- a/sql/log.cc	2010-07-08 21:20:08 +0000
+++ b/sql/log.cc	2010-07-16 12:57:19 +0000
@@ -27,7 +27,7 @@
 #include "my_global.h"                          /* NO_EMBEDDED_ACCESS_CHECKS */
 #include "sql_priv.h"
 #include "log.h"
-#include "sql_base.h"                           // close_thread_tables
+#include "sql_base.h"                           // open_log_table
 #include "sql_repl.h"
 #include "sql_delete.h"                         // mysql_truncate
 #include "sql_parse.h"                          // command_name

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2010-07-08 21:20:08 +0000
+++ b/sql/log_event.cc	2010-07-16 12:57:19 +0000
@@ -3357,7 +3357,7 @@ Default database: '%s'. Query: '%s'",
         When an error is expected and matches the actual error the
         slave does not report any error and by consequence changes
         on transactional tables are not rolled back in the function
-        close_thread_tables(). For that reason, we explicitly roll
+        mysql_execute_command(). For that reason, we explicitly roll
         them back here.
       */
       if (expected_error && expected_error == actual_error)
@@ -3441,6 +3441,26 @@ end:
   DBUG_PRINT("info", ("end: query= 0"));
   close_thread_tables(thd);
   /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
+  /*
     As a disk space optimization, future masters will not log an event for
     LAST_INSERT_ID() if that function returned 0 (and thus they will be able
     to replace the THD::stmt_depends_on_first_successful_insert_id_in_prev_stmt
@@ -4870,6 +4890,26 @@ error:
   thd->set_db(NULL, 0);                   /* will free the current database */
   thd->set_query(NULL, 0);
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
 
   DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error",
                   thd->is_slave_error= 0; thd->is_fatal_error= 1;);

=== modified file 'sql/rpl_rli.cc'
--- a/sql/rpl_rli.cc	2010-07-08 21:20:08 +0000
+++ b/sql/rpl_rli.cc	2010-07-16 12:57:19 +0000
@@ -1259,6 +1259,26 @@ void Relay_log_info::clear_tables_to_loc
 void Relay_log_info::slave_close_thread_tables(THD *thd)
 {
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   clear_tables_to_lock();
 }
 #endif

=== modified file 'sql/slave.cc'
--- a/sql/slave.cc	2010-07-08 21:20:08 +0000
+++ b/sql/slave.cc	2010-07-16 12:57:19 +0000
@@ -3045,6 +3045,26 @@ err:
   DBUG_ASSERT(thd->net.buff != 0);
   net_end(&thd->net); // destructor will not free it, because net.vio is 0
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   mysql_mutex_lock(&LOCK_thread_count);
   THD_CHECK_SENTRY(thd);
   delete thd;

=== modified file 'sql/sp.cc'
--- a/sql/sp.cc	2010-07-14 15:52:44 +0000
+++ b/sql/sp.cc	2010-07-16 12:57:19 +0000
@@ -451,6 +451,26 @@ static TABLE *open_proc_table_for_update
     DBUG_RETURN(table);
 
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
 
   DBUG_RETURN(NULL);
 
@@ -1162,6 +1182,26 @@ done:
   thd->variables.sql_mode= saved_mode;
 
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   /* Restore the state of binlog format */
   DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
   if (save_binlog_row_based)
@@ -1242,6 +1282,26 @@ sp_drop_routine(THD *thd, int type, sp_n
   }
 
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   /* Restore the state of binlog format */
   DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
   if (save_binlog_row_based)
@@ -1350,6 +1410,26 @@ sp_update_routine(THD *thd, int type, sp
   }
 err:
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   /* Restore the state of binlog format */
   DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
   if (save_binlog_row_based)
@@ -1411,6 +1491,26 @@ sp_drop_db_routines(THD *thd, char *db)
   table->file->ha_index_end();
 
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
 
 err:
   DBUG_RETURN(ret);

=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc	2010-07-16 08:55:35 +0000
+++ b/sql/sql_acl.cc	2010-07-16 12:57:19 +0000
@@ -1654,6 +1654,26 @@ bool change_password(THD *thd, const cha
   }
 end:
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   DBUG_RETURN(result);
 }
 
@@ -3074,6 +3094,26 @@ int mysql_table_grant(THD *thd, TABLE_LI
         column_priv|= column->rights;
       }
       close_thread_tables(thd);
+      /*
+        - If inside a multi-statement transaction,
+        defer the release of metadata locks until the current
+        transaction is either committed or rolled back. This prevents
+        other statements from modifying the table for the entire
+        duration of this transaction.  This provides commit ordering
+        and guarantees serializability across multiple transactions.
+        - If closing a system table, defer the release of metadata locks
+        to the caller. We have no sentinel in MDL subsystem to guard
+        transactional locks from system tables locks, so don't know
+        which locks are which here.
+        - If in autocommit mode, or outside a transactional context,
+        automatically release metadata locks of the current statement.
+      */
+      if (! thd->in_multi_stmt_transaction_mode() &&
+          ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+          ! thd->locked_tables_mode)
+      {
+        thd->mdl_context.release_transactional_locks();
+      }
     }
     else
     {
@@ -3602,6 +3642,26 @@ bool mysql_grant(THD *thd, const char *d
 
   mysql_rwlock_unlock(&LOCK_grant);
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
 
   if (!result)
     my_ok(thd);
@@ -3885,6 +3945,26 @@ static my_bool grant_reload_procs_priv(T
   mysql_rwlock_unlock(&LOCK_grant);
 
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   DBUG_RETURN(return_val);
 }
 
@@ -5875,6 +5955,26 @@ bool mysql_create_user(THD *thd, List <L
 
   mysql_rwlock_unlock(&LOCK_grant);
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   /* Restore the state of binlog format */
   DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
   if (save_binlog_row_based)
@@ -5960,6 +6060,26 @@ bool mysql_drop_user(THD *thd, List <LEX
 
   mysql_rwlock_unlock(&LOCK_grant);
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   thd->variables.sql_mode= old_sql_mode;
   /* Restore the state of binlog format */
   DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
@@ -6057,6 +6177,26 @@ bool mysql_rename_user(THD *thd, List <L
 
   mysql_rwlock_unlock(&LOCK_grant);
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   /* Restore the state of binlog format */
   DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
   if (save_binlog_row_based)
@@ -6255,6 +6395,26 @@ bool mysql_revoke_all(THD *thd,  List <L
 
   mysql_rwlock_unlock(&LOCK_grant);
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
 
   /* Restore the state of binlog format */
   DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
@@ -6403,6 +6563,26 @@ bool sp_revoke_privileges(THD *thd, cons
   mysql_mutex_unlock(&acl_cache->lock);
   mysql_rwlock_unlock(&LOCK_grant);
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
 
   thd->pop_internal_handler();
   /* Restore the state of binlog format */

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2010-07-16 08:55:35 +0000
+++ b/sql/sql_base.cc	2010-07-16 12:57:19 +0000
@@ -1672,26 +1672,6 @@ void close_thread_tables(THD *thd)
   if (thd->open_tables)
     close_open_tables(thd);
 
-  /*
-    - If inside a multi-statement transaction,
-    defer the release of metadata locks until the current
-    transaction is either committed or rolled back. This prevents
-    other statements from modifying the table for the entire
-    duration of this transaction.  This provides commit ordering
-    and guarantees serializability across multiple transactions.
-    - If closing a system table, defer the release of metadata locks
-    to the caller. We have no sentinel in MDL subsystem to guard
-    transactional locks from system tables locks, so don't know
-    which locks are which here.
-    - If in autocommit mode, or outside a transactional context,
-    automatically release metadata locks of the current statement.
-  */
-  if (! thd->in_multi_stmt_transaction_mode() &&
-      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL))
-  {
-    thd->mdl_context.release_transactional_locks();
-  }
-
   DBUG_VOID_RETURN;
 }
 
@@ -3405,6 +3385,27 @@ Locked_tables_list::unlock_locked_tables
     thd->leave_locked_tables_mode();
 
     close_thread_tables(thd);
+
+    /*
+      - If inside a multi-statement transaction,
+      defer the release of metadata locks until the current
+      transaction is either committed or rolled back. This prevents
+      other statements from modifying the table for the entire
+      duration of this transaction.  This provides commit ordering
+      and guarantees serializability across multiple transactions.
+      - If closing a system table, defer the release of metadata locks
+      to the caller. We have no sentinel in MDL subsystem to guard
+      transactional locks from system tables locks, so don't know
+      which locks are which here.
+      - If in autocommit mode, or outside a transactional context,
+      automatically release metadata locks of the current statement.
+    */
+    if (! thd->in_multi_stmt_transaction_mode() &&
+        ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+        ! thd->locked_tables_mode)
+    {
+      thd->mdl_context.release_transactional_locks();
+    }
   }
   /*
     After closing tables we can free memory used for storing lock
@@ -5462,7 +5463,8 @@ end:
                               should work for this statement.
 
   @note
-    The lock will automaticaly be freed by close_thread_tables()
+    The thr_lock locks will automatically be freed by
+    close_thread_tables().
 
   @retval FALSE  OK.
   @retval TRUE   Error
@@ -5497,6 +5499,27 @@ bool open_and_lock_tables(THD *thd, TABL
   DBUG_RETURN(FALSE);
 err:
   close_thread_tables(thd);
+
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   DBUG_RETURN(TRUE);
 }
 
@@ -5534,6 +5557,27 @@ bool open_normal_and_derived_tables(THD 
   DBUG_RETURN(0);
 end:
   close_thread_tables(thd);
+
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   DBUG_RETURN(TRUE); /* purecov: inspected */
 }
 
@@ -5796,6 +5840,27 @@ void close_tables_for_reopen(THD *thd, T
     tmp->cleanup_items();
   }
   close_thread_tables(thd);
+
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   thd->mdl_context.rollback_to_savepoint(start_of_statement_svp);
 }
 
@@ -9262,6 +9327,27 @@ void
 close_system_tables(THD *thd, Open_tables_backup *backup)
 {
   close_thread_tables(thd);
+
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   thd->restore_backup_open_tables_state(backup);
 }
 
@@ -9345,6 +9431,27 @@ open_log_table(THD *thd, TABLE_LIST *one
       state.
     */
     close_thread_tables(thd);
+
+    /*
+      - If inside a multi-statement transaction,
+      defer the release of metadata locks until the current
+      transaction is either committed or rolled back. This prevents
+      other statements from modifying the table for the entire
+      duration of this transaction.  This provides commit ordering
+      and guarantees serializability across multiple transactions.
+      - If closing a system table, defer the release of metadata locks
+      to the caller. We have no sentinel in MDL subsystem to guard
+      transactional locks from system tables locks, so don't know
+      which locks are which here.
+      - If in autocommit mode, or outside a transactional context,
+      automatically release metadata locks of the current statement.
+    */
+    if (! thd->in_multi_stmt_transaction_mode() &&
+        ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+        ! thd->locked_tables_mode)
+    {
+      thd->mdl_context.release_transactional_locks();
+    }
     thd->restore_backup_open_tables_state(backup);
   }
 

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2010-07-08 21:20:08 +0000
+++ b/sql/sql_insert.cc	2010-07-16 12:57:19 +0000
@@ -1862,7 +1862,10 @@ public:
     while ((row=rows.get()))
       delete row;
     if (table)
+    {
       close_thread_tables(&thd);
+      thd.mdl_context.release_transactional_locks();
+    }
     mysql_mutex_lock(&LOCK_thread_count);
     mysql_mutex_destroy(&mutex);
     mysql_cond_destroy(&cond);
@@ -2641,6 +2644,26 @@ pthread_handler_t handle_delayed_insert(
   */
 
   close_thread_tables(thd);			// Free the table
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   di->table=0;
   thd->killed= THD::KILL_CONNECTION;	        // If error
   mysql_cond_broadcast(&di->cond_client);       // Safety

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-07-16 08:55:35 +0000
+++ b/sql/sql_parse.cc	2010-07-16 12:57:19 +0000
@@ -1262,6 +1262,26 @@ bool dispatch_command(enum enum_server_c
     mysqld_list_fields(thd,&table_list,fields);
     thd->lex->unit.cleanup();
     close_thread_tables(thd);
+    /*
+      - If inside a multi-statement transaction,
+      defer the release of metadata locks until the current
+      transaction is either committed or rolled back. This prevents
+      other statements from modifying the table for the entire
+      duration of this transaction.  This provides commit ordering
+      and guarantees serializability across multiple transactions.
+      - If closing a system table, defer the release of metadata locks
+      to the caller. We have no sentinel in MDL subsystem to guard
+      transactional locks from system tables locks, so don't know
+      which locks are which here.
+      - If in autocommit mode, or outside a transactional context,
+      automatically release metadata locks of the current statement.
+    */
+    if (! thd->in_multi_stmt_transaction_mode() &&
+        ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+        ! thd->locked_tables_mode)
+    {
+      thd->mdl_context.release_transactional_locks();
+    }
     thd->cleanup_after_query();
     break;
   }
@@ -3556,10 +3576,7 @@ end_with_restore_list:
       */
       trans_rollback_stmt(thd);
       trans_commit_implicit(thd);
-      /*
-        Close tables and release metadata locks otherwise a later call to
-        close_thread_tables might not release the locks if autocommit is off.
-      */
+      /* Close tables and release metadata locks. */
       close_thread_tables(thd);
       DBUG_ASSERT(!thd->locked_tables_mode);
       thd->mdl_context.release_transactional_locks();
@@ -4768,13 +4785,34 @@ finish:
   thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
   thd->stmt_da->can_overwrite_status= FALSE;
 
-  thd->transaction.stmt.reset();
+  if (! thd->in_sub_stmt)
+    thd->transaction.stmt.reset();
 
   lex->unit.cleanup();
   thd_proc_info(thd, "closing tables");
   /* Free tables */
   close_thread_tables(thd);
   thd_proc_info(thd, 0);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
 
   if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END))
   {

=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc	2010-07-08 21:20:08 +0000
+++ b/sql/sql_partition.cc	2010-07-16 12:57:19 +0000
@@ -6758,7 +6758,6 @@ uint fast_alter_partition_table(THD *thd
                                  table_list, FALSE, NULL,
                                  written_bin_log));
 err:
-  close_thread_tables(thd);
   DBUG_RETURN(TRUE);
 }
 #endif

=== modified file 'sql/sql_plugin.cc'
--- a/sql/sql_plugin.cc	2010-07-16 08:55:35 +0000
+++ b/sql/sql_plugin.cc	2010-07-16 12:57:19 +0000
@@ -1512,6 +1512,7 @@ static void plugin_load(MEM_ROOT *tmp_ro
   end_read_record(&read_record_info);
   table->m_needs_reopen= TRUE;                  // Force close to free memory
   close_thread_tables(new_thd);
+  new_thd->mdl_context.release_transactional_locks();
 end:
   /* Remember that we don't have a THD */
   my_pthread_setspecific_ptr(THR_THD, 0);

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2010-07-14 15:52:44 +0000
+++ b/sql/sql_prepare.cc	2010-07-16 12:57:19 +0000
@@ -3235,6 +3235,26 @@ bool Prepared_statement::prepare(const c
   /* The order is important */
   lex->unit.cleanup();
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
   lex_end(lex);
   cleanup_stmt();
   /*

=== modified file 'sql/sql_servers.cc'
--- a/sql/sql_servers.cc	2010-03-31 14:05:33 +0000
+++ b/sql/sql_servers.cc	2010-07-16 12:57:19 +0000
@@ -626,6 +626,26 @@ int drop_server(THD *thd, LEX_SERVER_OPT
 
   /* close the servers table before we call closed_cached_connection_tables */
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
 
   if (close_cached_connection_tables(thd, TRUE, &name))
   {
@@ -1051,6 +1071,26 @@ int alter_server(THD *thd, LEX_SERVER_OP
 
   /* close the servers table before we call closed_cached_connection_tables */
   close_thread_tables(thd);
+  /*
+    - If inside a multi-statement transaction,
+    defer the release of metadata locks until the current
+    transaction is either committed or rolled back. This prevents
+    other statements from modifying the table for the entire
+    duration of this transaction.  This provides commit ordering
+    and guarantees serializability across multiple transactions.
+    - If closing a system table, defer the release of metadata locks
+    to the caller. We have no sentinel in MDL subsystem to guard
+    transactional locks from system tables locks, so don't know
+    which locks are which here.
+    - If in autocommit mode, or outside a transactional context,
+    automatically release metadata locks of the current statement.
+  */
+  if (! thd->in_multi_stmt_transaction_mode() &&
+      ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+      ! thd->locked_tables_mode)
+  {
+    thd->mdl_context.release_transactional_locks();
+  }
 
   if (close_cached_connection_tables(thd, FALSE, &name))
   {

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2010-07-16 08:55:35 +0000
+++ b/sql/sql_table.cc	2010-07-16 12:57:19 +0000
@@ -2285,10 +2285,7 @@ err:
   {
     /*
       Under LOCK TABLES we should release meta-data locks on the tables
-      which were dropped. Otherwise we can rely on close_thread_tables()
-      doing this. Unfortunately in this case we are likely to get more
-      false positives in try_acquire_lock() function. So
-      it makes sense to remove exclusive meta-data locks in all cases.
+      which were dropped.
 
       Leave LOCK TABLES mode if we managed to drop all tables which were
       locked. Additional check for 'non_temp_tables_count' is to avoid
@@ -4221,7 +4218,7 @@ warn:
   schema) and create the table. Is written to be called from
   mysql_execute_command(), to which it delegates the common parts
   with other commands (i.e. implicit commit before and after,
-  close_thread_tables()).
+  close of thread tables.
 */
 
 bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
@@ -4749,6 +4746,26 @@ static bool mysql_admin_table(THD* thd, 
         trans_rollback_stmt(thd);
         trans_rollback(thd);
         close_thread_tables(thd);
+        /*
+          - If inside a multi-statement transaction,
+          defer the release of metadata locks until the current
+          transaction is either committed or rolled back. This prevents
+          other statements from modifying the table for the entire
+          duration of this transaction.  This provides commit ordering
+          and guarantees serializability across multiple transactions.
+          - If closing a system table, defer the release of metadata locks
+          to the caller. We have no sentinel in MDL subsystem to guard
+          transactional locks from system tables locks, so don't know
+          which locks are which here.
+          - If in autocommit mode, or outside a transactional context,
+          automatically release metadata locks of the current statement.
+        */
+        if (! thd->in_multi_stmt_transaction_mode() &&
+            ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+            ! thd->locked_tables_mode)
+        {
+          thd->mdl_context.release_transactional_locks();
+        }
         DBUG_PRINT("admin", ("simple error, admin next table"));
         continue;
       case -1:           // error, message could be written to net
@@ -5039,7 +5056,7 @@ send_result_message:
       thd->mdl_context.release_transactional_locks();
       if (!result_code) // recreation went ok
       {
-        /* Clear the ticket released in close_thread_tables(). */
+        /* Clear the ticket released above. */
         table->mdl_request.ticket= NULL;
         DEBUG_SYNC(thd, "ha_admin_open_ltable");
         table->mdl_request.set_type(MDL_SHARED_WRITE);
@@ -6726,13 +6743,11 @@ bool mysql_alter_table(THD *thd,char *ne
         goto err;
       DBUG_EXECUTE_IF("sleep_alter_enable_indexes", my_sleep(6000000););
       error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
-      /* COND_refresh will be signaled in close_thread_tables() */
       break;
     case DISABLE:
       if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
         goto err;
       error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
-      /* COND_refresh will be signaled in close_thread_tables() */
       break;
     default:
       DBUG_ASSERT(FALSE);
@@ -6818,8 +6833,8 @@ bool mysql_alter_table(THD *thd,char *ne
     {
       /*
         Under LOCK TABLES we should adjust meta-data locks before finishing
-        statement. Otherwise we can rely on close_thread_tables() releasing
-        them.
+        statement. Otherwise we can rely on them being released
+        along with the implicit commit.
       */
       if (new_name != table_name || new_db != db)
       {
@@ -7357,8 +7372,8 @@ bool mysql_alter_table(THD *thd,char *ne
     5) Write statement to the binary log.
     6) If we are under LOCK TABLES and do ALTER TABLE ... RENAME we
        remove placeholders and release metadata locks.
-    7) If we are not not under LOCK TABLES we rely on close_thread_tables()
-       call to remove placeholders and releasing metadata locks.
+    7) If we are not not under LOCK TABLES we rely on the caller
+      (mysql_execute_command()) to release metadata locks.
   */
 
   thd_proc_info(thd, "rename result table");
@@ -7988,6 +8003,26 @@ bool mysql_checksum_table(THD *thd, TABL
       }
       thd->clear_error();
       close_thread_tables(thd);
+      /*
+        - If inside a multi-statement transaction,
+        defer the release of metadata locks until the current
+        transaction is either committed or rolled back. This prevents
+        other statements from modifying the table for the entire
+        duration of this transaction.  This provides commit ordering
+        and guarantees serializability across multiple transactions.
+        - If closing a system table, defer the release of metadata locks
+        to the caller. We have no sentinel in MDL subsystem to guard
+        transactional locks from system tables locks, so don't know
+        which locks are which here.
+        - If in autocommit mode, or outside a transactional context,
+        automatically release metadata locks of the current statement.
+      */
+      if (! thd->in_multi_stmt_transaction_mode() &&
+          ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) &&
+          ! thd->locked_tables_mode)
+      {
+        thd->mdl_context.release_transactional_locks();
+      }
       table->table=0;				// For query cache
     }
     if (protocol->write())
@@ -7997,10 +8032,7 @@ bool mysql_checksum_table(THD *thd, TABL
   my_eof(thd);
   DBUG_RETURN(FALSE);
 
- err:
-  close_thread_tables(thd);			// Shouldn't be needed
-  if (table)
-    table->table=0;
+err:
   DBUG_RETURN(TRUE);
 }
 

=== modified file 'sql/sql_trigger.cc'
--- a/sql/sql_trigger.cc	2010-07-14 15:52:44 +0000
+++ b/sql/sql_trigger.cc	2010-07-16 12:57:19 +0000
@@ -540,9 +540,9 @@ end:
   }
 
   /*
-    If we are under LOCK TABLES we should restore original state of meta-data
-    locks. Otherwise call to close_thread_tables() will take care about both
-    TABLE instance created by open_n_lock_single_table() and metadata lock.
+    If we are under LOCK TABLES we should restore original state of
+    meta-data locks. Otherwise all locks will be released along
+    with the implicit commit.
   */
   if (thd->locked_tables_mode && tables && lock_upgrade_done)
     mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);

=== modified file 'sql/sql_udf.cc'
--- a/sql/sql_udf.cc	2010-06-11 15:28:18 +0000
+++ b/sql/sql_udf.cc	2010-07-16 12:57:19 +0000
@@ -252,6 +252,7 @@ void udf_init()
 
 end:
   close_thread_tables(new_thd);
+  new_thd->mdl_context.release_transactional_locks();
   delete new_thd;
   /* Remember that we don't have a THD */
   my_pthread_setspecific_ptr(THR_THD,  0);


Attachment: [text/bzr-bundle] bzr/kostja@sun.com-20100716125719-fluo20x4k0ri995x.bundle
Thread
bzr commit into mysql-trunk-runtime branch (kostja:3082)Konstantin Osipov16 Jul