List:Commits« Previous MessageNext Message »
From:Konstantin Osipov Date:August 6 2010 6:26pm
Subject:bzr commit into mysql-trunk-runtime branch (kostja:3096) Bug#41158
View as plain text  
#At file:///opt/local/work/trunk-runtime/ based on revid:dlenev@stripped

 3096 Konstantin Osipov	2010-08-06
      A fix for Bug#41158 "DROP TABLE holds LOCK_open during unlink()". 
      
      Remove acquisition of LOCK_open around file system operations,
      since such operations are now protected by metadata locks.
      Rework table discovery algorithm to not require LOCK_open.
     @ mysql-test/t/disabled.def
        Disable NDB tests due to Bug#55799.
     @ sql/datadict.cc
        No longer necessary to protect ha_create_table() with
        LOCK_open. Serial execution is now ensured by metadata
        locks.
     @ sql/ha_ndbcluster.cc
        Do not manipulate with LOCK_open in cluster code.
     @ sql/ha_ndbcluster_binlog.cc
        Do not manipulate with LOCK_open in cluster code.
     @ sql/ha_ndbcluster_binlog.h
        Update function signature.
     @ sql/handler.cc
        Implement ha_check_if_table_exists().
        @todo: some engines provide ha_table_exists_in_engine()
        handlerton call, for those we perhaps shouldn't
        call ha_discover(), to be more efficient.
        Since currently it's only NDB, postpone till
        integration with NDB.
     @ sql/handler.h
        Declare ha_check_if_table_exists() function.
     @ sql/mdl.cc
        Remove an obsolete comment.
     @ sql/sql_base.cc
        Update to a new signature of close_cachded_tables():
        from now on we always call it without LOCK_open.
        Update comments.
        Remove get_table_share_with_create(), we should
        not attempt to create a table under LOCK_open.
        Introduce get_table_share_with_discover() instead,
        which would request a back off action if the table
        exists in engine.
        Do not attempt to discover views or MyISAM
        Merge engine children.
        Remove acquisition of LOCK_open for 
        data dictionary operations, such as check_if_table_exists().
        Do not use get_table_share_with_create/discover for views,
        where it's not needed.
        Make tdc_remove_table() optionally acquire LOCK_open
        to simplify usage of this function.
        Use the right mutex in the partitioning code when
        manipulating with thd->open_tables.
     @ sql/sql_base.h
        Update signatures of changes functions.
     @ sql/sql_insert.cc
        Do not wrap quick_rm_table() with LOCK_open acquisition, 
        this is unnecessary.
     @ sql/sql_parse.cc
        Update to the new calling convention of tdc_remove_table().
        Update to the new signature of close_cached_tables().
        Update comments.
     @ sql/sql_rename.cc
        Update to the new calling convention of tdc_remove_table().
        Remove acquisition of LOCK_open around filesystem
        operations.
     @ sql/sql_show.cc
        Remove get_trigger_table_impl().
        Do not acquire LOCK_open for a dirty read of the trigger
        file.
     @ sql/sql_table.cc
        Do not acquire LOCK_open for filesystem operations.
     @ sql/sql_trigger.cc
        Do not require LOCK_open for trigger file I/O.
     @ sql/sql_truncate.cc
        Update to the new signature of tdc_remove_table().
     @ sql/sql_view.cc
        Do not require LOCK_open for view I/O.
        Use tdc_remove_table() to expel view share.
        Update comments.
     @ sql/sys_vars.cc
        Update to the new signature of close_cached_tables().

    modified:
      mysql-test/t/disabled.def
      sql/datadict.cc
      sql/ha_ndbcluster.cc
      sql/ha_ndbcluster_binlog.cc
      sql/ha_ndbcluster_binlog.h
      sql/handler.cc
      sql/handler.h
      sql/mdl.cc
      sql/sql_base.cc
      sql/sql_base.h
      sql/sql_insert.cc
      sql/sql_parse.cc
      sql/sql_rename.cc
      sql/sql_show.cc
      sql/sql_table.cc
      sql/sql_trigger.cc
      sql/sql_truncate.cc
      sql/sql_view.cc
      sql/sys_vars.cc
=== modified file 'mysql-test/t/disabled.def'
--- a/mysql-test/t/disabled.def	2010-06-30 09:27:38 +0000
+++ b/mysql-test/t/disabled.def	2010-08-06 18:26:41 +0000
@@ -17,3 +17,4 @@ plugin_load              : Bug#42144 200
 partition_innodb_plugin  : Bug#53307 2010-04-30 VasilDimov valgrind warnings
 query_cache_28249        : Bug#43861 2009-03-25 main.query_cache_28249 fails sporadically
 sp_sync                  : Bug#48157 2010-02-06 5.5-m3 demands a differnt solution
+ctype_utf8mb4_ndb	: Bug#55799, Bug#51907, disabled by Konstantin 2010-08-06

=== modified file 'sql/datadict.cc'
--- a/sql/datadict.cc	2010-06-06 11:19:29 +0000
+++ b/sql/datadict.cc	2010-08-06 18:26:41 +0000
@@ -152,9 +152,7 @@ bool dd_recreate_table(THD *thd, const c
   build_table_filename(path, sizeof(path) - 1, db, table_name, "", 0);
 
   /* Attempt to reconstruct the table. */
-  mysql_mutex_lock(&LOCK_open);
   error= ha_create_table(thd, path, db, table_name, &create_info, TRUE);
-  mysql_mutex_unlock(&LOCK_open);
 
   DBUG_RETURN(error);
 }

=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc	2010-07-29 15:35:22 +0000
+++ b/sql/ha_ndbcluster.cc	2010-08-06 18:26:41 +0000
@@ -680,7 +680,7 @@ int ha_ndbcluster::ndb_err(NdbTransactio
     bzero((char*) &table_list,sizeof(table_list));
     table_list.db= m_dbname;
     table_list.alias= table_list.table_name= m_tabname;
-    close_cached_tables(thd, &table_list, FALSE, FALSE);
+    close_cached_tables(thd, &table_list, FALSE);
     break;
   }
   default:
@@ -5702,7 +5702,7 @@ int ha_ndbcluster::create(const char *na
                                m_table->getObjectVersion(),
                                (is_truncate) ?
 			       SOT_TRUNCATE_TABLE : SOT_CREATE_TABLE, 
-			       0, 0, 1);
+			       0, 0);
       break;
     }
   }
@@ -6143,7 +6143,7 @@ int ha_ndbcluster::rename_table(const ch
                                old_dbname, m_tabname,
                                ndb_table_id, ndb_table_version,
                                SOT_RENAME_TABLE,
-                               m_dbname, new_tabname, 1);
+                               m_dbname, new_tabname);
   }
 
   // If we are moving tables between databases, we need to recreate
@@ -6337,7 +6337,7 @@ retry_temporary_error1:
                              thd->query(), thd->query_length(),
                              share->db, share->table_name,
                              ndb_table_id, ndb_table_version,
-                             SOT_DROP_TABLE, 0, 0, 1);
+                             SOT_DROP_TABLE, 0, 0);
   }
   else if (table_dropped && share && share->op) /* ndbcluster_log_schema_op
                                                    will do a force GCP */
@@ -7019,7 +7019,6 @@ int ndbcluster_drop_database_impl(const 
   while ((tabname=it++))
   {
     tablename_to_filename(tabname, tmp, FN_REFLEN - (tmp - full_path)-1);
-    mysql_mutex_lock(&LOCK_open);
     if (ha_ndbcluster::delete_table(0, ndb, full_path, dbname, tabname))
     {
       const NdbError err= dict->getNdbError();
@@ -7029,7 +7028,6 @@ int ndbcluster_drop_database_impl(const 
         ret= ndb_to_mysql_error(&err);
       }
     }
-    mysql_mutex_unlock(&LOCK_open);
   }
   DBUG_RETURN(ret);      
 }
@@ -7056,7 +7054,7 @@ static void ndbcluster_drop_database(han
   ha_ndbcluster::set_dbname(path, db);
   ndbcluster_log_schema_op(thd, 0,
                            thd->query(), thd->query_length(),
-                           db, "", 0, 0, SOT_DROP_DB, 0, 0, 0);
+                           db, "", 0, 0, SOT_DROP_DB, 0, 0);
 #endif
   DBUG_VOID_RETURN;
 }
@@ -7181,7 +7179,6 @@ int ndbcluster_find_all_files(THD *thd)
       my_free(data);
       my_free(pack_data);
 
-      mysql_mutex_lock(&LOCK_open);
       if (discover)
       {
         /* ToDo 4.1 database needs to be created if missing */
@@ -7199,7 +7196,6 @@ int ndbcluster_find_all_files(THD *thd)
                                        TRUE);
       }
 #endif
-      mysql_mutex_unlock(&LOCK_open);
     }
   }
   while (unhandled && retries);
@@ -7292,19 +7288,16 @@ int ndbcluster_find_files(handlerton *ht
                            file_name->str, reg_ext, 0);
       if (my_access(name, F_OK))
       {
-        mysql_mutex_lock(&LOCK_open);
         DBUG_PRINT("info", ("Table %s listed and need discovery",
                             file_name->str));
         if (ndb_create_table_from_engine(thd, db, file_name->str))
         {
-          mysql_mutex_unlock(&LOCK_open);
           push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                               ER_TABLE_EXISTS_ERROR,
                               "Discover of table %s.%s failed",
                               db, file_name->str);
           continue;
         }
-        mysql_mutex_unlock(&LOCK_open);
       }
       DBUG_PRINT("info", ("%s existed in NDB _and_ on disk ", file_name->str));
       file_on_disk= TRUE;
@@ -7361,10 +7354,8 @@ int ndbcluster_find_files(handlerton *ht
       file_name_str= (char*)my_hash_element(&ok_tables, i);
       end= end1 +
         tablename_to_filename(file_name_str, end1, sizeof(name) - (end1 - name));
-      mysql_mutex_lock(&LOCK_open);
       ndbcluster_create_binlog_setup(ndb, name, end-name,
                                      db, file_name_str, TRUE);
-      mysql_mutex_unlock(&LOCK_open);
     }
   }
 #endif
@@ -7426,7 +7417,6 @@ int ndbcluster_find_files(handlerton *ht
   }
 
   /* Lock mutex before creating .FRM files. */
-  mysql_mutex_lock(&LOCK_open);
   /* Create new files. */
   List_iterator_fast<char> it2(create_list);
   while ((file_name_str=it2++))
@@ -7441,8 +7431,6 @@ int ndbcluster_find_files(handlerton *ht
     }
   }
 
-  mysql_mutex_unlock(&LOCK_open);
-
   my_hash_free(&ok_tables);
   my_hash_free(&ndb_tables);
 
@@ -8452,8 +8440,7 @@ int handle_trailing_share(NDB_SHARE *sha
   bzero((char*) &table_list,sizeof(table_list));
   table_list.db= share->db;
   table_list.alias= table_list.table_name= share->table_name;
-  mysql_mutex_assert_owner(&LOCK_open);
-  close_cached_tables(thd, &table_list, TRUE, FALSE);
+  close_cached_tables(thd, &table_list, FALSE);
 
   mysql_mutex_lock(&ndbcluster_mutex);
   /* ndb_share reference temporary free */
@@ -10612,13 +10599,13 @@ int ndbcluster_alter_tablespace(handlert
                              thd->query(), thd->query_length(),
                              "", alter_info->tablespace_name,
                              0, 0,
-                             SOT_TABLESPACE, 0, 0, 0);
+                             SOT_TABLESPACE, 0, 0);
   else
     ndbcluster_log_schema_op(thd, 0,
                              thd->query(), thd->query_length(),
                              "", alter_info->logfile_group_name,
                              0, 0,
-                             SOT_LOGFILE_GROUP, 0, 0, 0);
+                             SOT_LOGFILE_GROUP, 0, 0);
 #endif
   DBUG_RETURN(FALSE);
 

=== modified file 'sql/ha_ndbcluster_binlog.cc'
--- a/sql/ha_ndbcluster_binlog.cc	2010-07-29 16:27:20 +0000
+++ b/sql/ha_ndbcluster_binlog.cc	2010-08-06 18:26:41 +0000
@@ -360,7 +360,6 @@ ndbcluster_binlog_open_table(THD *thd, N
   int error;
   DBUG_ENTER("ndbcluster_binlog_open_table");
   
-  mysql_mutex_assert_owner(&LOCK_open);
   init_tmp_table_share(thd, table_share, share->db, 0, share->table_name, 
                        share->key);
   if ((error= open_table_def(thd, table_share, 0)))
@@ -376,7 +375,9 @@ ndbcluster_binlog_open_table(THD *thd, N
     free_table_share(table_share);
     DBUG_RETURN(error);
   }
+  mysql_mutex_lock(&LOCK_open);
   assign_new_table_id(table_share);
+  mysql_mutex_unlock(&LOCK_open);
 
   if (!reopen)
   {
@@ -625,7 +626,7 @@ ndbcluster_binlog_log_query(handlerton *
   {
     ndbcluster_log_schema_op(thd, 0, query, query_length,
                              db, table_name, 0, 0, type,
-                             0, 0, 0);
+                             0, 0);
   }
   DBUG_VOID_RETURN;
 }
@@ -908,9 +909,7 @@ int ndbcluster_setup_binlog_table_shares
   if (!ndb_schema_share &&
       ndbcluster_check_ndb_schema_share() == 0)
   {
-    mysql_mutex_lock(&LOCK_open);
     ndb_create_table_from_engine(thd, NDB_REP_DB, NDB_SCHEMA_TABLE);
-    mysql_mutex_unlock(&LOCK_open);
     if (!ndb_schema_share)
     {
       ndbcluster_create_schema_table(thd);
@@ -922,9 +921,7 @@ int ndbcluster_setup_binlog_table_shares
   if (!ndb_apply_status_share &&
       ndbcluster_check_ndb_apply_status_share() == 0)
   {
-    mysql_mutex_lock(&LOCK_open);
     ndb_create_table_from_engine(thd, NDB_REP_DB, NDB_APPLY_TABLE);
-    mysql_mutex_unlock(&LOCK_open);
     if (!ndb_apply_status_share)
     {
       ndbcluster_create_ndb_apply_status_table(thd);
@@ -934,12 +931,10 @@ int ndbcluster_setup_binlog_table_shares
   }
   if (!ndbcluster_find_all_files(thd))
   {
-    mysql_mutex_lock(&LOCK_open);
     ndb_binlog_tables_inited= TRUE;
     if (opt_ndb_extra_logging)
       sql_print_information("NDB Binlog: ndb tables writable");
-    close_cached_tables(NULL, NULL, TRUE, FALSE);
-    mysql_mutex_unlock(&LOCK_open);
+    close_cached_tables(NULL, NULL, FALSE);
     /* Signal injector thread that all is setup */
     mysql_cond_signal(&injector_cond);
   }
@@ -1276,8 +1271,7 @@ int ndbcluster_log_schema_op(THD *thd, N
                              uint32 ndb_table_id,
                              uint32 ndb_table_version,
                              enum SCHEMA_OP_TYPE type,
-                             const char *new_db, const char *new_table_name,
-                             int have_lock_open)
+                             const char *new_db, const char *new_table_name)
 {
   DBUG_ENTER("ndbcluster_log_schema_op");
   Thd_ndb *thd_ndb= get_thd_ndb(thd);
@@ -1580,11 +1574,6 @@ end:
 
     int max_timeout= DEFAULT_SYNC_TIMEOUT;
     mysql_mutex_lock(&ndb_schema_object->mutex);
-    if (have_lock_open)
-    {
-      mysql_mutex_assert_owner(&LOCK_open);
-      mysql_mutex_unlock(&LOCK_open);
-    }
     while (1)
     {
       struct timespec abstime;
@@ -1640,10 +1629,6 @@ end:
                              "distributing", ndb_schema_object->key);
       }
     }
-    if (have_lock_open)
-    {
-      mysql_mutex_lock(&LOCK_open);
-    }
     mysql_mutex_unlock(&ndb_schema_object->mutex);
   }
 
@@ -1726,7 +1711,6 @@ ndb_handle_schema_change(THD *thd, Ndb *
     {
       DBUG_DUMP("frm", (uchar*) altered_table->getFrmData(), 
                 altered_table->getFrmLength());
-      mysql_mutex_lock(&LOCK_open);
       Ndb_table_guard ndbtab_g(dict, tabname);
       const NDBTAB *old= ndbtab_g.get_table();
       if (!old &&
@@ -1752,7 +1736,7 @@ ndb_handle_schema_change(THD *thd, Ndb *
       bzero((char*) &table_list,sizeof(table_list));
       table_list.db= (char *)dbname;
       table_list.alias= table_list.table_name= (char *)tabname;
-      close_cached_tables(thd, &table_list, TRUE, FALSE);
+      close_cached_tables(thd, &table_list, FALSE);
 
       if ((error= ndbcluster_binlog_open_table(thd, share,
                                                table_share, table, 1)))
@@ -1763,8 +1747,6 @@ ndb_handle_schema_change(THD *thd, Ndb *
       table_share= share->table_share;
       dbname= table_share->db.str;
       tabname= table_share->table_name.str;
-
-      mysql_mutex_unlock(&LOCK_open);
     }
     my_free(data);
     my_free(pack_data);
@@ -1858,7 +1840,7 @@ ndb_handle_schema_change(THD *thd, Ndb *
     bzero((char*) &table_list,sizeof(table_list));
     table_list.db= (char *)dbname;
     table_list.alias= table_list.table_name= (char *)tabname;
-    close_cached_tables(thd, &table_list, FALSE, FALSE);
+    close_cached_tables(thd, &table_list, FALSE);
     /* ndb_share reference create free */
     DBUG_PRINT("NDB_SHARE", ("%s create free  use_count: %u",
                              share->key, share->use_count));
@@ -1979,7 +1961,7 @@ ndb_binlog_thread_handle_schema_event(TH
             bzero((char*) &table_list,sizeof(table_list));
             table_list.db= schema->db;
             table_list.alias= table_list.table_name= schema->name;
-            close_cached_tables(thd, &table_list, FALSE, FALSE);
+            close_cached_tables(thd, &table_list, FALSE);
           }
           /* ndb_share reference temporary free */
           if (share)
@@ -1991,7 +1973,6 @@ ndb_binlog_thread_handle_schema_event(TH
         }
         // fall through
         case SOT_CREATE_TABLE:
-          mysql_mutex_lock(&LOCK_open);
           if (ndbcluster_check_if_local_table(schema->db, schema->name))
           {
             DBUG_PRINT("info", ("NDB Binlog: Skipping locally defined table '%s.%s'",
@@ -2005,7 +1986,6 @@ ndb_binlog_thread_handle_schema_event(TH
           {
             print_could_not_discover_error(thd, schema);
           }
-          mysql_mutex_unlock(&LOCK_open);
           log_query= 1;
           break;
         case SOT_DROP_DB:
@@ -2096,7 +2076,7 @@ ndb_binlog_thread_handle_schema_event(TH
       mysql_mutex_unlock(&ndb_schema_share_mutex);
       /* end protect ndb_schema_share */
 
-      close_cached_tables(NULL, NULL, FALSE, FALSE);
+      close_cached_tables(NULL, NULL, FALSE);
       // fall through
     case NDBEVENT::TE_ALTER:
       ndb_handle_schema_change(thd, ndb, pOp, tmp_share);
@@ -2253,7 +2233,7 @@ ndb_binlog_thread_handle_schema_event_po
           bzero((char*) &table_list,sizeof(table_list));
           table_list.db= schema->db;
           table_list.alias= table_list.table_name= schema->name;
-          close_cached_tables(thd, &table_list, FALSE, FALSE);
+          close_cached_tables(thd, &table_list, FALSE);
         }
         if (schema_type != SOT_ALTER_TABLE)
           break;
@@ -2274,7 +2254,6 @@ ndb_binlog_thread_handle_schema_event_po
             free_share(&share);
             share= 0;
           }
-          mysql_mutex_lock(&LOCK_open);
           if (ndbcluster_check_if_local_table(schema->db, schema->name))
           {
             DBUG_PRINT("info", ("NDB Binlog: Skipping locally defined table '%s.%s'",
@@ -2288,7 +2267,6 @@ ndb_binlog_thread_handle_schema_event_po
           {
             print_could_not_discover_error(thd, schema);
           }
-          mysql_mutex_unlock(&LOCK_open);
         }
         break;
       default:
@@ -3154,8 +3132,6 @@ ndbcluster_handle_drop_table(Ndb *ndb, c
 #ifdef SYNC_DROP_
   thd->proc_info= "Syncing ndb table schema operation and binlog";
   mysql_mutex_lock(&share->mutex);
-  mysql_mutex_assert_owner(&LOCK_open);
-  mysql_mutex_unlock(&LOCK_open);
   int max_timeout= DEFAULT_SYNC_TIMEOUT;
   while (share->op)
   {
@@ -3181,7 +3157,6 @@ ndbcluster_handle_drop_table(Ndb *ndb, c
                            type_str, share->key);
     }
   }
-  mysql_mutex_lock(&LOCK_open);
   mysql_mutex_unlock(&share->mutex);
 #else
   mysql_mutex_lock(&share->mutex);

=== modified file 'sql/ha_ndbcluster_binlog.h'
--- a/sql/ha_ndbcluster_binlog.h	2010-03-31 14:05:33 +0000
+++ b/sql/ha_ndbcluster_binlog.h	2010-08-06 18:26:41 +0000
@@ -158,8 +158,7 @@ int ndbcluster_log_schema_op(THD *thd, N
                              uint32 ndb_table_version,
                              enum SCHEMA_OP_TYPE type,
                              const char *new_db,
-                             const char *new_table_name,
-                             int have_lock_open);
+                             const char *new_table_name);
 int ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
                                  NDB_SHARE *share,
                                  const char *type_str);

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2010-07-27 14:32:42 +0000
+++ b/sql/handler.cc	2010-08-06 18:26:41 +0000
@@ -3670,6 +3670,34 @@ int ha_create_table_from_engine(THD* thd
   DBUG_RETURN(error != 0);
 }
 
+
+/**
+  Try to find a table in a storage engine. 
+
+  @param db   Normalized table schema name
+  @param name Normalized table name.
+  @param[out] exists Only valid if the function succeeded.
+
+  @retval TRUE   An error is found
+  @retval FALSE  Success, check *exists
+*/
+
+bool
+ha_check_if_table_exists(THD* thd, const char *db, const char *name,
+                         bool *exists)
+{
+  uchar *frmblob= NULL;
+  size_t frmlen;
+  DBUG_ENTER("ha_check_if_table_exists");
+
+  *exists= ! ha_discover(thd, db, name, &frmblob, &frmlen);
+  if (*exists)
+    my_free(frmblob);
+
+  DBUG_RETURN(FALSE);
+}
+
+
 void st_ha_check_opt::init()
 {
   flags= sql_flags= 0;

=== modified file 'sql/handler.h'
--- a/sql/handler.h	2010-07-27 14:32:42 +0000
+++ b/sql/handler.h	2010-08-06 18:26:41 +0000
@@ -2120,6 +2120,8 @@ bool ha_show_status(THD *thd, handlerton
 
 /* discovery */
 int ha_create_table_from_engine(THD* thd, const char *db, const char *name);
+bool ha_check_if_table_exists(THD* thd, const char *db, const char *name,
+                             bool *exists);
 int ha_discover(THD* thd, const char* dbname, const char* name,
                 uchar** frmblob, size_t* frmlen);
 int ha_find_files(THD *thd,const char *db,const char *path,

=== modified file 'sql/mdl.cc'
--- a/sql/mdl.cc	2010-08-06 11:29:37 +0000
+++ b/sql/mdl.cc	2010-08-06 18:26:41 +0000
@@ -494,14 +494,6 @@ mdl_locks_key(const uchar *record, size_
   the associated condition variable: LOCK_mdl and COND_mdl.
   These locking primitives are implementation details of the MDL
   subsystem and are private to it.
-
-  Note, that even though the new implementation adds acquisition
-  of a new global mutex to the execution flow of almost every SQL
-  statement, the design capitalizes on that to later save on
-  look ups in the table definition cache. This leads to reduced
-  contention overall and on LOCK_open in particular.
-  Please see the description of MDL_context::acquire_lock()
-  for details.
 */
 
 void mdl_init()

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2010-08-06 11:29:37 +0000
+++ b/sql/sql_base.cc	2010-08-06 18:26:41 +0000
@@ -314,8 +314,6 @@ void table_def_start_shutdown(void)
   if (table_def_inited)
   {
     mysql_mutex_lock(&LOCK_open);
-    /* Free all cached but unused TABLEs and TABLE_SHAREs first. */
-    close_cached_tables(NULL, NULL, TRUE, FALSE);
     /*
       Ensure that TABLE and TABLE_SHARE objects which are created for
       tables that are open during process of plugins' shutdown are
@@ -324,6 +322,8 @@ void table_def_start_shutdown(void)
     */
     table_def_shutdown_in_progress= TRUE;
     mysql_mutex_unlock(&LOCK_open);
+    /* Free all cached but unused TABLEs and TABLE_SHAREs. */
+    close_cached_tables(NULL, NULL, FALSE);
   }
 }
 
@@ -516,10 +516,10 @@ TABLE_SHARE *get_table_share(THD *thd, T
   }
 
   /*
-    We assign a new table id under the protection of the LOCK_open and
-    the share's own mutex.  We do this insted of creating a new mutex
+    We assign a new table id under the protection of the LOCK_open.
+    We do this instead of creating a new mutex
     and using it for the sole purpose of serializing accesses to a
-    static variable, we assign the table id here.  We assign it to the
+    static variable, we assign the table id here. We assign it to the
     share before inserting it into the table_def_cache to be really
     sure that it cannot be read from the cache without having a table
     id assigned.
@@ -547,7 +547,7 @@ TABLE_SHARE *get_table_share(THD *thd, T
   DBUG_RETURN(share);
 
 found:
-  /* 
+  /*
      We found an existing table definition. Return it if we didn't get
      an error when reading the table definition from file.
   */
@@ -589,21 +589,21 @@ found:
 }
 
 
-/*
+/**
   Get a table share. If it didn't exist, try creating it from engine
 
-  For arguments and return values, see get_table_from_share()
+  For arguments and return values, see get_table_share()
 */
 
-static TABLE_SHARE
-*get_table_share_with_create(THD *thd, TABLE_LIST *table_list,
-                             char *key, uint key_length,
-                             uint db_flags, int *error,
-                             my_hash_value_type hash_value)
+static TABLE_SHARE *
+get_table_share_with_discover(THD *thd, TABLE_LIST *table_list,
+                              char *key, uint key_length,
+                              uint db_flags, int *error,
+                              my_hash_value_type hash_value)
 
 {
   TABLE_SHARE *share;
-  int tmp;
+  bool exists;
   DBUG_ENTER("get_table_share_with_create");
 
   share= get_table_share(thd, table_list, key, key_length, db_flags, error,
@@ -617,10 +617,15 @@ static TABLE_SHARE
     from the pre-locking list. In this case we still need to try
     auto-discover before returning a NULL share.
 
+    Or, we're inside SHOW CREATE VIEW, which
+    also installs a silencer for ER_NO_SUCH_TABLE error.
+
     If share is NULL and the error is ER_NO_SUCH_TABLE, this is
-    the same as above, only that the error was not silenced by 
-    pre-locking. Once again, we need to try to auto-discover
-    the share.
+    the same as above, only that the error was not silenced by
+    pre-locking or SHOW CREATE VIEW.
+
+    In both these cases it won't harm to try to discover the
+    table.
 
     Finally, if share is still NULL, it's a real error and we need
     to abort.
@@ -628,20 +633,25 @@ static TABLE_SHARE
     @todo Rework alternative ways to deal with ER_NO_SUCH TABLE.
   */
   if (share || (thd->is_error() && thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE))
-
     DBUG_RETURN(share);
 
+  *error= 0;
+
   /* Table didn't exist. Check if some engine can provide it */
-  tmp= ha_create_table_from_engine(thd, table_list->db,
-                                   table_list->table_name);
-  if (tmp < 0)
+  if (ha_check_if_table_exists(thd, table_list->db, table_list->table_name,
+                               &exists))
+  {
+    thd->clear_error();
+    /* Conventionally, the storage engine API does not report errors. */
+    my_error(ER_OUT_OF_RESOURCES, MYF(0));
+  }
+  else if (! exists)
   {
     /*
       No such table in any engine.
       Hide "Table doesn't exist" errors if the table belongs to a view.
       The check for thd->is_error() is necessary to not push an
-      unwanted error in case of pre-locking, which silences
-      "no such table" errors.
+      unwanted error in case the error was already silenced.
       @todo Rework the alternative ways to deal with ER_NO_SUCH TABLE.
     */
     if (thd->is_error())
@@ -659,27 +669,13 @@ static TABLE_SHARE
                  view->view_db.str, view->view_name.str);
       }
     }
-    DBUG_RETURN(0);
   }
-  if (tmp)
-  {
-    /* Give right error message */
-    thd->clear_error();
-    DBUG_PRINT("error", ("Discovery of %s/%s failed", table_list->db,
-                         table_list->table_name));
-    my_printf_error(ER_UNKNOWN_ERROR,
-                    "Failed to open '%-.64s', error while "
-                    "unpacking from engine",
-                    MYF(0), table_list->table_name);
-    DBUG_RETURN(0);
-  }
-  /* Table existed in engine. Let's open it */
-  thd->warning_info->clear_warning_info(thd->query_id);
-  thd->clear_error();                           // Clear error message
-  DBUG_RETURN(get_table_share(thd, table_list, key, key_length,
-                              db_flags, error, hash_value));
+  else
+    *error= 7; /* Run auto-discover. */
+  DBUG_RETURN(NULL);
 }
 
+
 /**
   Mark that we are not using table share anymore.
 
@@ -926,7 +922,6 @@ static void kill_delayed_threads_for_tab
 
   @param thd Thread context
   @param tables List of tables to remove from the cache
-  @param have_lock If LOCK_open is locked
   @param wait_for_refresh Wait for a impending flush
 
   @note THD can be NULL, but then wait_for_refresh must be FALSE
@@ -940,16 +935,14 @@ static void kill_delayed_threads_for_tab
         lock taken by thread trying to obtain global read lock.
 */
 
-bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock,
-                         bool wait_for_refresh)
+bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool wait_for_refresh)
 {
   bool result= FALSE;
   bool found= TRUE;
   DBUG_ENTER("close_cached_tables");
   DBUG_ASSERT(thd || (!wait_for_refresh && !tables));
 
-  if (!have_lock)
-    mysql_mutex_lock(&LOCK_open);
+  mysql_mutex_lock(&LOCK_open);
   if (!tables)
   {
     refresh_version++;				// Force close of open tables
@@ -978,7 +971,7 @@ bool close_cached_tables(THD *thd, TABLE
         kill_delayed_threads_for_table(share);
         /* tdc_remove_table() also sets TABLE_SHARE::version to 0. */
         tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED, table->db,
-                         table->table_name);
+                         table->table_name, TRUE);
 	found=1;
       }
     }
@@ -986,15 +979,11 @@ bool close_cached_tables(THD *thd, TABLE
       wait_for_refresh=0;			// Nothing to wait for
   }
 
-  if (!have_lock)
-    mysql_mutex_unlock(&LOCK_open);
+  mysql_mutex_unlock(&LOCK_open);
 
   if (!wait_for_refresh)
     DBUG_RETURN(result);
 
-  /* Code below assume that LOCK_open is released. */
-  DBUG_ASSERT(!have_lock);
-
   if (thd->locked_tables_mode)
   {
     /*
@@ -1108,7 +1097,7 @@ err_with_reopen:
 */
 
 bool close_cached_connection_tables(THD *thd, bool if_wait_for_refresh,
-                                    LEX_STRING *connection, bool have_lock)
+                                    LEX_STRING *connection)
 {
   uint idx;
   TABLE_LIST tmp, *tables= NULL;
@@ -1118,8 +1107,7 @@ bool close_cached_connection_tables(THD 
 
   bzero(&tmp, sizeof(TABLE_LIST));
 
-  if (!have_lock)
-    mysql_mutex_lock(&LOCK_open);
+  mysql_mutex_lock(&LOCK_open);
 
   for (idx= 0; idx < table_def_cache.records; idx++)
   {
@@ -1147,12 +1135,10 @@ bool close_cached_connection_tables(THD 
     tables= (TABLE_LIST *) memdup_root(thd->mem_root, (char*)&tmp, 
                                        sizeof(TABLE_LIST));
   }
+  mysql_mutex_unlock(&LOCK_open);
 
   if (tables)
-    result= close_cached_tables(thd, tables, TRUE, FALSE);
-
-  if (!have_lock)
-    mysql_mutex_unlock(&LOCK_open);
+    result= close_cached_tables(thd, tables, FALSE);
 
   if (if_wait_for_refresh)
   {
@@ -1355,9 +1341,8 @@ close_all_tables_for_name(THD *thd, TABL
     }
   }
   /* Remove the table share from the cache. */
-  mysql_mutex_lock(&LOCK_open);
-  tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db, table_name);
-  mysql_mutex_unlock(&LOCK_open);
+  tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db, table_name,
+                   FALSE);
   /*
     There could be a FLUSH thread waiting
     on the table to go away. Wake it up.
@@ -2201,10 +2186,9 @@ bool wait_while_table_is_used(THD *thd, 
              table->mdl_ticket, thd->variables.lock_wait_timeout))
     DBUG_RETURN(TRUE);
 
-  mysql_mutex_lock(&LOCK_open);
   tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN,
-                   table->s->db.str, table->s->table_name.str);
-  mysql_mutex_unlock(&LOCK_open);
+                   table->s->db.str, table->s->table_name.str,
+                   FALSE);
   /* extra() call must come only after all instances above are closed */
   (void) table->file->extra(function);
   DBUG_RETURN(FALSE);
@@ -2245,9 +2229,8 @@ void drop_open_table(THD *thd, TABLE *ta
     table->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
     close_thread_table(thd, &thd->open_tables);
     /* Remove the table share from the table cache. */
-    mysql_mutex_lock(&LOCK_open);
-    tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db_name, table_name);
-    mysql_mutex_unlock(&LOCK_open);
+    tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db_name, table_name,
+                     FALSE);
     /* Remove the table from the storage engine and rm the .frm. */
     quick_rm_table(table_type, db_name, table_name, 0);
   }
@@ -2279,16 +2262,20 @@ void drop_open_table(THD *thd, TABLE *ta
 bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists)
 {
   char path[FN_REFLEN + 1];
-  int rc= 0;
+  TABLE_SHARE *share;
   DBUG_ENTER("check_if_table_exists");
 
-  mysql_mutex_assert_not_owner(&LOCK_open);
-
   *exists= TRUE;
 
+  DBUG_ASSERT(thd->mdl_context.
+              is_lock_owner(MDL_key::TABLE, table->db,
+                            table->table_name, MDL_SHARED));
+
   mysql_mutex_lock(&LOCK_open);
+  share= get_cached_table_share(table->db, table->table_name);
+  mysql_mutex_unlock(&LOCK_open);
 
-  if (get_cached_table_share(table->db, table->table_name))
+  if (share)
     goto end;
 
   build_table_filename(path, sizeof(path) - 1, table->db, table->table_name,
@@ -2298,24 +2285,14 @@ bool check_if_table_exists(THD *thd, TAB
     goto end;
 
   /* .FRM file doesn't exist. Check if some engine can provide it. */
-
-  rc= ha_create_table_from_engine(thd, table->db, table->table_name);
-
-  if (rc < 0)
-  {
-    /* Table does not exists in engines as well. */
-    *exists= FALSE;
-    rc= 0;
-  }
-  else if (rc)
+  if (ha_check_if_table_exists(thd, table->db, table->table_name, exists))
   {
-    my_printf_error(ER_UNKNOWN_ERROR, "Failed to open '%-.64s', error while "
+    my_printf_error(ER_OUT_OF_RESOURCES, "Failed to open '%-.64s', error while "
                     "unpacking from engine", MYF(0), table->table_name);
+    DBUG_RETURN(TRUE);
   }
-
 end:
-  mysql_mutex_unlock(&LOCK_open);
-  DBUG_RETURN(test(rc));
+  DBUG_RETURN(FALSE);
 }
 
 
@@ -2812,11 +2789,26 @@ bool open_table(THD *thd, TABLE_LIST *ta
 
   mysql_mutex_lock(&LOCK_open);
 
-  if (!(share= get_table_share_with_create(thd, table_list, key,
-                                           key_length, OPEN_VIEW,
-                                           &error,
-                                           hash_value)))
-    goto err_unlock2;
+  if (!(share= get_table_share_with_discover(thd, table_list, key,
+                                             key_length, OPEN_VIEW,
+                                             &error,
+                                             hash_value)))
+  {
+    mysql_mutex_unlock(&LOCK_open);
+    /*
+      If thd->is_error() is not set, we either need discover
+      (error == 7), or the error was silenced by the prelocking
+      handler (error == 0), in which case we should skip this
+      table.
+    */
+    if (error == 7)
+    {
+      DBUG_ASSERT(! thd->is_error());
+      (void) ot_ctx->request_backoff_action(Open_table_context::OT_DISCOVER,
+                                            table_list);
+    }
+    DBUG_RETURN(TRUE);
+  }
 
   if (share->is_view)
   {
@@ -3010,7 +3002,6 @@ err_lock:
   mysql_mutex_lock(&LOCK_open);
 err_unlock:
   release_table_share(share);
-err_unlock2:
   mysql_mutex_unlock(&LOCK_open);
 
   DBUG_RETURN(TRUE);
@@ -3633,10 +3624,10 @@ bool tdc_open_view(THD *thd, TABLE_LIST 
                            cache_key_length);
   mysql_mutex_lock(&LOCK_open);
 
-  if (!(share= get_table_share_with_create(thd, table_list, cache_key,
-                                           cache_key_length, 
-                                           OPEN_VIEW, &error,
-                                           hash_value)))
+  if (!(share= get_table_share(thd, table_list, cache_key,
+                               cache_key_length,
+                               OPEN_VIEW, &error,
+                               hash_value)))
     goto err;
 
   if (share->is_view &&
@@ -3738,10 +3729,10 @@ static bool auto_repair_table(THD *thd, 
                            cache_key_length);
   mysql_mutex_lock(&LOCK_open);
 
-  if (!(share= get_table_share_with_create(thd, table_list, cache_key,
-                                           cache_key_length,
-                                           OPEN_VIEW, &not_used,
-                                           hash_value)))
+  if (!(share= get_table_share(thd, table_list, cache_key,
+                               cache_key_length,
+                               OPEN_VIEW, &not_used,
+                               hash_value)))
     goto end_unlock;
 
   if (share->is_view)
@@ -3786,7 +3777,8 @@ static bool auto_repair_table(THD *thd, 
   release_table_share(share);
   /* Remove the repaired share from the table cache. */
   tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
-                   table_list->db, table_list->table_name);
+                   table_list->db, table_list->table_name,
+                   TRUE);
 end_unlock:
   mysql_mutex_unlock(&LOCK_open);
   return result;
@@ -3908,12 +3900,10 @@ recover_from_failed_open(THD *thd)
                                       MYSQL_OPEN_SKIP_TEMPORARY)))
           break;
 
-        mysql_mutex_lock(&LOCK_open);
         tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
-                         m_failed_table->table_name);
+                         m_failed_table->table_name, FALSE);
         ha_create_table_from_engine(thd, m_failed_table->db,
                                     m_failed_table->table_name);
-        mysql_mutex_unlock(&LOCK_open);
 
         thd->warning_info->clear_warning_info(thd->query_id);
         thd->clear_error();                 // Clear error message
@@ -3927,10 +3917,8 @@ recover_from_failed_open(THD *thd)
                                       MYSQL_OPEN_SKIP_TEMPORARY)))
           break;
 
-        mysql_mutex_lock(&LOCK_open);
         tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
-                         m_failed_table->table_name);
-        mysql_mutex_unlock(&LOCK_open);
+                         m_failed_table->table_name, FALSE);
 
         result= auto_repair_table(thd, m_failed_table);
         thd->mdl_context.release_transactional_locks();
@@ -8541,7 +8529,7 @@ void tdc_flush_unused_tables()
   mysql_mutex_lock(&LOCK_open);
   while (unused_tables)
     free_cache_entry(unused_tables);
-  (void) mysql_mutex_unlock(&LOCK_open);
+  mysql_mutex_unlock(&LOCK_open);
 }
 
 
@@ -8646,20 +8634,25 @@ bool mysql_notify_thread_having_shared_l
                                                 remove TABLE_SHARE).
    @param  db           Name of database
    @param  table_name   Name of table
+   @param  has_lock     If TRUE, LOCK_open is already acquired
 
    @note It assumes that table instances are already not used by any
    (other) thread (this should be achieved by using meta-data locks).
 */
 
 void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
-                      const char *db, const char *table_name)
+                      const char *db, const char *table_name,
+                      bool has_lock)
 {
   char key[MAX_DBKEY_LENGTH];
   uint key_length;
   TABLE *table;
   TABLE_SHARE *share;
 
-  mysql_mutex_assert_owner(&LOCK_open);
+  if (! has_lock)
+    mysql_mutex_lock(&LOCK_open);
+  else
+    mysql_mutex_assert_owner(&LOCK_open);
 
   DBUG_ASSERT(remove_type == TDC_RT_REMOVE_UNUSED ||
               thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, table_name,
@@ -8700,6 +8693,9 @@ void tdc_remove_table(THD *thd, enum_tdc
     else
       (void) my_hash_delete(&table_def_cache, (uchar*) share);
   }
+
+  if (! has_lock)
+    mysql_mutex_unlock(&LOCK_open);
 }
 
 
@@ -8905,11 +8901,6 @@ static int alter_close_tables(ALTER_PART
   TABLE *table;
   DBUG_ENTER("alter_close_tables");
   /*
-    We must keep LOCK_open while manipulating with thd->open_tables.
-    Another thread may be working on it.
-  */
-  mysql_mutex_lock(&LOCK_open);
-  /*
     We can safely remove locks for all tables with the same name:
     later they will all be closed anyway in
     alter_partition_lock_handling().
@@ -8920,8 +8911,10 @@ static int alter_close_tables(ALTER_PART
 	!strcmp(table->s->db.str, share->db.str))
     {
       mysql_lock_remove(thd, thd->lock, table);
+      mysql_mutex_lock(&thd->LOCK_thd_data);
       table->file->close();
       table->db_stat= 0;                        // Mark file closed
+      mysql_mutex_unlock(&thd->LOCK_thd_data);
       /*
         Ensure that we won't end up with a crippled table instance
         in the table cache if an error occurs before we reach
@@ -8930,10 +8923,10 @@ static int alter_close_tables(ALTER_PART
       */
       tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
                        table->s->db.str,
-                       table->s->table_name.str);
+                       table->s->table_name.str,
+                       FALSE);
     }
   }
-  mysql_mutex_unlock(&LOCK_open);
   DBUG_RETURN(0);
 }
 

=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h	2010-08-04 16:29:13 +0000
+++ b/sql/sql_base.h	2010-08-06 18:26:41 +0000
@@ -226,16 +226,15 @@ TABLE *open_performance_schema_table(THD
                                      Open_tables_state *backup);
 void close_performance_schema_table(THD *thd, Open_tables_state *backup);
 
-bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock,
-                         bool wait_for_refresh);
+bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool wait_for_refresh);
 bool close_cached_connection_tables(THD *thd, bool wait_for_refresh,
-                                    LEX_STRING *connect_string,
-                                    bool have_lock = FALSE);
+                                    LEX_STRING *connect_string);
 void close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
                                bool remove_from_locked_tables);
 OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild);
 void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
-                      const char *db, const char *table_name);
+                      const char *db, const char *table_name,
+                      bool has_lock);
 bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias,
                    char *cache_key, uint cache_key_length,
                    MEM_ROOT *mem_root, uint flags);

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2010-07-27 10:25:53 +0000
+++ b/sql/sql_insert.cc	2010-08-06 18:26:41 +0000
@@ -3600,11 +3600,9 @@ static TABLE *create_table_from_items(TH
         */
         if (open_table(thd, create_table, thd->mem_root, &ot_ctx))
         {
-          mysql_mutex_lock(&LOCK_open);
           quick_rm_table(create_info->db_type, create_table->db,
                          table_case_name(create_info, create_table->table_name),
                          0);
-          mysql_mutex_unlock(&LOCK_open);
         }
         else
           table= create_table->table;

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-07-29 12:32:11 +0000
+++ b/sql/sql_parse.cc	2010-08-06 18:26:41 +0000
@@ -1789,11 +1789,9 @@ static bool flush_tables_with_read_lock(
        table_list= table_list->next_global)
   {
     /* Remove the table from cache. */
-    mysql_mutex_lock(&LOCK_open);
     tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
                      table_list->db,
-                     table_list->table_name);
-    mysql_mutex_unlock(&LOCK_open);
+                     table_list->table_name, FALSE);
 
     /* Skip views and temporary tables. */
     table_list->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */
@@ -3414,7 +3412,7 @@ end_with_restore_list:
       /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
       thd->variables.option_bits|= OPTION_KEEP_LOG;
     }
-    /* DDL and binlog write order protected by LOCK_open */
+    /* DDL and binlog write order are protected by metadata locks. */
     res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
 			lex->drop_temporary);
   }
@@ -6854,7 +6852,7 @@ bool reload_acl_and_cache(THD *thd, ulon
       tmp_write_to_binlog= 0;
       if (thd->global_read_lock.lock_global_read_lock(thd))
 	return 1;                               // Killed
-      if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
+      if (close_cached_tables(thd, tables, (options & REFRESH_FAST) ?
                               FALSE : TRUE))
           result= 1;
       
@@ -6894,7 +6892,7 @@ bool reload_acl_and_cache(THD *thd, ulon
         }
       }
 
-      if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
+      if (close_cached_tables(thd, tables, (options & REFRESH_FAST) ?
                               FALSE : TRUE))
         result= 1;
     }

=== modified file 'sql/sql_rename.cc'
--- a/sql/sql_rename.cc	2010-07-01 13:53:46 +0000
+++ b/sql/sql_rename.cc	2010-08-06 18:26:41 +0000
@@ -147,13 +147,15 @@ bool mysql_rename_tables(THD *thd, TABLE
                        MYSQL_OPEN_SKIP_TEMPORARY))
     goto err;
 
-  mysql_mutex_lock(&LOCK_open);
-
   for (ren_table= table_list; ren_table; ren_table= ren_table->next_local)
     tdc_remove_table(thd, TDC_RT_REMOVE_ALL, ren_table->db,
-                     ren_table->table_name);
+                     ren_table->table_name, FALSE);
 
   error=0;
+  /*
+    An exclusive lock on table names is satisfactory to ensure
+    no other thread accesses this table.
+  */
   if ((ren_table=rename_tables(thd,table_list,0)))
   {
     /* Rename didn't succeed;  rename back the tables in reverse order */
@@ -175,17 +177,6 @@ bool mysql_rename_tables(THD *thd, TABLE
 
     error= 1;
   }
-  /*
-    An exclusive lock on table names is satisfactory to ensure
-    no other thread accesses this table.
-    However, NDB assumes that handler::rename_tables is called under
-    LOCK_open. And it indeed is, from ALTER TABLE.
-    TODO: remove this limitation.
-    We still should unlock LOCK_open as early as possible, to provide
-    higher concurrency - query_cache_invalidate can take minutes to
-    complete.
-  */
-  mysql_mutex_unlock(&LOCK_open);
 
   if (!silent && !error)
   {

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2010-07-29 12:32:11 +0000
+++ b/sql/sql_show.cc	2010-08-06 18:26:41 +0000
@@ -7657,7 +7657,7 @@ static bool show_create_trigger_impl(THD
 */
 
 static
-TABLE_LIST *get_trigger_table_impl(THD *thd, const sp_name *trg_name)
+TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name)
 {
   char trn_path_buff[FN_REFLEN];
   LEX_STRING trn_path= { trn_path_buff, 0 };
@@ -7694,39 +7694,6 @@ TABLE_LIST *get_trigger_table_impl(THD *
   return table;
 }
 
-/**
-  Read TRN and TRG files to obtain base table name for the specified
-  trigger name and construct TABE_LIST object for the base table. Acquire
-  LOCK_open when doing this.
-
-  @param thd      Thread context.
-  @param trg_name Trigger name.
-
-  @return TABLE_LIST object corresponding to the base table.
-*/
-
-static
-TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name)
-{
-  /* Acquire LOCK_open (stop the server). */
-
-  mysql_mutex_lock(&LOCK_open);
-
-  /*
-    Load base table name from the TRN-file and create TABLE_LIST object.
-  */
-
-  TABLE_LIST *lst= get_trigger_table_impl(thd, trg_name);
-
-  /* Release LOCK_open (continue the server). */
-
-  mysql_mutex_unlock(&LOCK_open);
-
-  /* That's it. */
-
-  return lst;
-}
-
 
 /**
   SHOW CREATE TRIGGER high-level implementation.

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2010-07-29 12:32:11 +0000
+++ b/sql/sql_table.cc	2010-08-06 18:26:41 +0000
@@ -1723,7 +1723,6 @@ bool mysql_write_frm(ALTER_PARTITION_PAR
       completing this we write a new phase to the log entry that will
       deactivate it.
     */
-    mysql_mutex_lock(&LOCK_open);
     if (mysql_file_delete(key_file_frm, frm_name, MYF(MY_WME)) ||
 #ifdef WITH_PARTITION_STORAGE_ENGINE
         lpt->table->file->ha_create_handler_files(path, shadow_path,
@@ -1779,7 +1778,6 @@ bool mysql_write_frm(ALTER_PARTITION_PAR
 #endif
 
 err:
-    mysql_mutex_unlock(&LOCK_open);
 #ifdef WITH_PARTITION_STORAGE_ENGINE
     deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos);
     part_info->frm_log_entry= NULL;
@@ -1955,10 +1953,11 @@ int mysql_rm_table_part2(THD *thd, TABLE
       if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
                            MYSQL_OPEN_SKIP_TEMPORARY))
         DBUG_RETURN(1);
-      mysql_mutex_lock(&LOCK_open);
       for (table= tables; table; table= table->next_local)
-        tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name);
-      mysql_mutex_unlock(&LOCK_open);
+      {
+        tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
+                         FALSE);
+      }
     }
     else
     {
@@ -2104,14 +2103,9 @@ int mysql_rm_table_part2(THD *thd, TABLE
                                         table->internal_tmp_table ?
                                         FN_IS_TMP : 0);
     }
-    /*
-      TODO: Investigate what should be done to remove this lock completely.
-            Is exclusive meta-data lock enough ?
-    */
     DEBUG_SYNC(thd, "rm_table_part2_before_delete_table");
     DBUG_EXECUTE_IF("sleep_before_part2_delete_table",
                     my_sleep(100000););
-    mysql_mutex_lock(&LOCK_open);
     if (drop_temporary ||
         ((access(path, F_OK) &&
           ha_create_table_from_engine(thd, db, alias)) ||
@@ -2131,8 +2125,7 @@ int mysql_rm_table_part2(THD *thd, TABLE
       char *end;
       /*
         Cannot use the db_type from the table, since that might have changed
-        while waiting for the exclusive name lock. We are under LOCK_open,
-        so reading from the frm-file is safe.
+        while waiting for the exclusive name lock.
       */
       if (frm_db_type == DB_TYPE_UNKNOWN)
       {
@@ -2173,7 +2166,6 @@ int mysql_rm_table_part2(THD *thd, TABLE
         error|= new_error;
       }
     }
-    mysql_mutex_unlock(&LOCK_open);
     if (error)
     {
       if (wrong_tables.length())
@@ -4053,7 +4045,6 @@ bool mysql_create_table_no_lock(THD *thd
     goto err;
   }
 
-  mysql_mutex_lock(&LOCK_open);
   if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
   {
     if (!access(path,F_OK))
@@ -4061,7 +4052,7 @@ bool mysql_create_table_no_lock(THD *thd
       if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
         goto warn;
       my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
-      goto unlock_and_end;
+      goto err;
     }
     /*
       We don't assert here, but check the result, because the table could be
@@ -4071,11 +4062,14 @@ bool mysql_create_table_no_lock(THD *thd
       Then she could create the table. This case is pretty obscure and
       therefore we don't introduce a new error message only for it.
     */
+    mysql_mutex_lock(&LOCK_open);
     if (get_cached_table_share(db, table_name))
     {
+      mysql_mutex_unlock(&LOCK_open);
       my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
-      goto unlock_and_end;
+      goto err;
     }
+    mysql_mutex_unlock(&LOCK_open);
   }
 
   /*
@@ -4083,7 +4077,7 @@ bool mysql_create_table_no_lock(THD *thd
     exist in any storage engine. In such a case it should
     be discovered and the error ER_TABLE_EXISTS_ERROR be returned
     unless user specified CREATE TABLE IF EXISTS
-    The LOCK_open mutex has been locked to make sure no
+    An exclusive metadata lock ensures that no
     one else is attempting to discover the table. Since
     it's not on disk as a frm file, no one could be using it!
   */
@@ -4104,12 +4098,12 @@ bool mysql_create_table_no_lock(THD *thd
         if (create_if_not_exists)
           goto warn;
         my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
-        goto unlock_and_end;
+        goto err;
         break;
       default:
         DBUG_PRINT("info", ("error: %u from storage engine", retcode));
         my_error(retcode, MYF(0),table_name);
-        goto unlock_and_end;
+        goto err;
     }
   }
 
@@ -4142,7 +4136,7 @@ bool mysql_create_table_no_lock(THD *thd
       if (test_if_data_home_dir(dirpath))
       {
         my_error(ER_WRONG_ARGUMENTS, MYF(0), "DATA DIRECTORY");
-        goto unlock_and_end;
+        goto err;
       }
     }
     if (create_info->index_file_name)
@@ -4151,7 +4145,7 @@ bool mysql_create_table_no_lock(THD *thd
       if (test_if_data_home_dir(dirpath))
       {
         my_error(ER_WRONG_ARGUMENTS, MYF(0), "INDEX DIRECTORY");
-        goto unlock_and_end;
+        goto err;
       }
     }
   }
@@ -4159,7 +4153,7 @@ bool mysql_create_table_no_lock(THD *thd
 #ifdef WITH_PARTITION_STORAGE_ENGINE
   if (check_partition_dirs(thd->lex->part_info))
   {
-    goto unlock_and_end;
+    goto err;
   }
 #endif /* WITH_PARTITION_STORAGE_ENGINE */
 
@@ -4182,7 +4176,7 @@ bool mysql_create_table_no_lock(THD *thd
   if (rea_create_table(thd, path, db, table_name,
                        create_info, alter_info->create_list,
                        key_count, key_info_buffer, file))
-    goto unlock_and_end;
+    goto err;
 
   if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
   {
@@ -4190,15 +4184,12 @@ bool mysql_create_table_no_lock(THD *thd
     if (!(open_temporary_table(thd, path, db, table_name, 1)))
     {
       (void) rm_temporary_table(create_info->db_type, path);
-      goto unlock_and_end;
+      goto err;
     }
     thd->thread_specific_used= TRUE;
   }
 
   error= FALSE;
-unlock_and_end:
-  mysql_mutex_unlock(&LOCK_open);
-
 err:
   thd_proc_info(thd, "After create");
   delete file;
@@ -4210,7 +4201,7 @@ warn:
                       ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
                       alias);
   create_info->table_existed= 1;		// Mark that table existed
-  goto unlock_and_end;
+  goto err;
 }
 
 
@@ -4459,20 +4450,19 @@ static int prepare_for_repair(THD *thd, 
 
     hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);
     mysql_mutex_lock(&LOCK_open);
-    if (!(share= (get_table_share(thd, table_list, key, key_length, 0,
-                                  &error, hash_value))))
-    {
-      mysql_mutex_unlock(&LOCK_open);
+    share= get_table_share(thd, table_list, key, key_length, 0,
+                           &error, hash_value);
+    mysql_mutex_unlock(&LOCK_open);
+    if (share == NULL)
       DBUG_RETURN(0);				// Can't open frm file
-    }
 
     if (open_table_from_share(thd, share, "", 0, 0, 0, &tmp_table, FALSE))
     {
+      mysql_mutex_lock(&LOCK_open);
       release_table_share(share);
       mysql_mutex_unlock(&LOCK_open);
       DBUG_RETURN(0);                           // Out of memory
     }
-    mysql_mutex_unlock(&LOCK_open);
     table= &tmp_table;
   }
 
@@ -5136,10 +5126,8 @@ send_result_message:
       }
       else if (open_for_modify || fatal_error)
       {
-        mysql_mutex_lock(&LOCK_open);
         tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
-                         table->db, table->table_name);
-        mysql_mutex_unlock(&LOCK_open);
+                         table->db, table->table_name, FALSE);
         /*
           May be something modified. Consequently, we have to
           invalidate the query cache.
@@ -6775,7 +6763,6 @@ bool mysql_alter_table(THD *thd,char *ne
       else
       {
         *fn_ext(new_name)=0;
-        mysql_mutex_lock(&LOCK_open);
         if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
           error= -1;
         else if (Table_triggers_list::change_table_name(thd, db, table_name,
@@ -6785,7 +6772,6 @@ bool mysql_alter_table(THD *thd,char *ne
                                     table_name, 0);
           error= -1;
         }
-        mysql_mutex_unlock(&LOCK_open);
       }
     }
 
@@ -7404,7 +7390,6 @@ bool mysql_alter_table(THD *thd,char *ne
     /* This type cannot happen in regular ALTER. */
     new_db_type= old_db_type= NULL;
   }
-  mysql_mutex_lock(&LOCK_open);
   if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
                          FN_TO_IS_TMP))
   {
@@ -7431,8 +7416,6 @@ bool mysql_alter_table(THD *thd,char *ne
   if (! error)
     (void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
 
-  mysql_mutex_unlock(&LOCK_open);
-
   if (error)
   {
     /* This shouldn't happen. But let us play it safe. */

=== modified file 'sql/sql_trigger.cc'
--- a/sql/sql_trigger.cc	2010-07-27 10:25:53 +0000
+++ b/sql/sql_trigger.cc	2010-08-06 18:26:41 +0000
@@ -394,9 +394,7 @@ bool mysql_create_or_drop_trigger(THD *t
   /*
     We don't want perform our operations while global read lock is held
     so we have to wait until its end and then prevent it from occurring
-    again until we are done, unless we are under lock tables. (Acquiring
-    LOCK_open is not enough because global read lock is held without holding
-    LOCK_open).
+    again until we are done, unless we are under lock tables.
   */
   if (!thd->locked_tables_mode &&
       thd->global_read_lock.wait_if_global_read_lock(thd, FALSE, TRUE))
@@ -516,11 +514,9 @@ bool mysql_create_or_drop_trigger(THD *t
       goto end;
   }
 
-  mysql_mutex_lock(&LOCK_open);
   result= (create ?
            table->triggers->create_trigger(thd, tables, &stmt_query):
            table->triggers->drop_trigger(thd, tables, &stmt_query));
-  mysql_mutex_unlock(&LOCK_open);
 
   if (result)
     goto end;
@@ -1680,9 +1676,6 @@ bool add_table_for_trigger(THD *thd,
   @param db       schema for table
   @param name     name for table
 
-  @note
-    The calling thread should hold the LOCK_open mutex;
-
   @retval
     False   success
   @retval
@@ -1912,14 +1905,10 @@ bool Table_triggers_list::change_table_n
 
   /*
     This method interfaces the mysql server code protected by
-    either LOCK_open mutex or with an exclusive metadata lock.
-    In the future, only an exclusive metadata lock will be enough.
+    an exclusive metadata lock.
   */
-#ifndef DBUG_OFF
-  if (thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, old_table,
-                                     MDL_EXCLUSIVE))
-    mysql_mutex_assert_owner(&LOCK_open);
-#endif
+  DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, old_table,
+                                             MDL_EXCLUSIVE));
 
   DBUG_ASSERT(my_strcasecmp(table_alias_charset, db, new_db) ||
               my_strcasecmp(table_alias_charset, old_table, new_table));

=== modified file 'sql/sql_truncate.cc'
--- a/sql/sql_truncate.cc	2010-07-13 08:39:24 +0000
+++ b/sql/sql_truncate.cc	2010-08-06 18:26:41 +0000
@@ -310,10 +310,8 @@ static bool open_and_lock_table_for_trun
           upgrade_shared_lock_to_exclusive(table_ref->mdl_request.ticket,
                                            timeout))
         DBUG_RETURN(TRUE);
-      mysql_mutex_lock(&LOCK_open);
       tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table_ref->db,
-                       table_ref->table_name);
-      mysql_mutex_unlock(&LOCK_open);
+                       table_ref->table_name, FALSE);
     }
   }
   else

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	2010-07-01 13:53:46 +0000
+++ b/sql/sql_view.cc	2010-08-06 18:26:41 +0000
@@ -658,7 +658,6 @@ bool mysql_create_view(THD *thd, TABLE_L
     goto err;
   }
 
-  mysql_mutex_lock(&LOCK_open);
   res= mysql_register_view(thd, view, mode);
 
   if (mysql_bin_log.is_open())
@@ -705,7 +704,6 @@ bool mysql_create_view(THD *thd, TABLE_L
       res= TRUE;
   }
 
-  mysql_mutex_unlock(&LOCK_open);
   if (mode != VIEW_CREATE_NEW)
     query_cache_invalidate3(thd, view, 0);
   thd->global_read_lock.start_waiting_global_read_lock(thd);
@@ -1656,10 +1654,8 @@ bool mysql_drop_view(THD *thd, TABLE_LIS
                        MYSQL_OPEN_SKIP_TEMPORARY))
     DBUG_RETURN(TRUE);
 
-  mysql_mutex_lock(&LOCK_open);
   for (view= views; view; view= view->next_local)
   {
-    TABLE_SHARE *share;
     frm_type_enum type= FRMTYPE_ERROR;
     build_table_filename(path, sizeof(path) - 1,
                          view->db, view->table_name, reg_ext, 0);
@@ -1698,16 +1694,12 @@ bool mysql_drop_view(THD *thd, TABLE_LIS
     some_views_deleted= TRUE;
 
     /*
-      For a view, there is only one table_share object which should never
-      be used outside of LOCK_open
+      For a view, there is a TABLE_SHARE object, but its
+      ref_count never goes above 1. Remove it from the table
+      definition cache, in case the view was cached.
     */
-    if ((share= get_cached_table_share(view->db, view->table_name)))
-    {
-      DBUG_ASSERT(share->ref_count == 0);
-      share->ref_count++;
-      share->version= 0;
-      release_table_share(share);
-    }
+    tdc_remove_table(thd, TDC_RT_REMOVE_ALL, view->db, view->table_name,
+                     FALSE);
     query_cache_invalidate3(thd, view, 0);
     sp_cache_invalidate();
   }
@@ -1732,8 +1724,6 @@ bool mysql_drop_view(THD *thd, TABLE_LIS
       something_wrong= 1;
   }
 
-  mysql_mutex_unlock(&LOCK_open);
-  
   if (something_wrong)
   {
     DBUG_RETURN(TRUE);

=== modified file 'sql/sys_vars.cc'
--- a/sql/sys_vars.cc	2010-07-27 14:32:42 +0000
+++ b/sql/sys_vars.cc	2010-08-06 18:26:41 +0000
@@ -1492,7 +1492,7 @@ static bool fix_read_only(sys_var *self,
     can cause to wait on a read lock, it's required for the client application
     to unlock everything, and acceptable for the server to wait on all locks.
   */
-  if ((result= close_cached_tables(thd, NULL, FALSE, TRUE)))
+  if ((result= close_cached_tables(thd, NULL, TRUE)))
     goto end_with_read_lock;
 
   if ((result= thd->global_read_lock.make_global_read_lock_block_commit(thd)))


Attachment: [text/bzr-bundle] bzr/kostja@sun.com-20100806182641-dmk83qz3rjhk6a44.bundle
Thread
bzr commit into mysql-trunk-runtime branch (kostja:3096) Bug#41158Konstantin Osipov6 Aug