List:Commits« Previous MessageNext Message »
From:Dmitry Lenev Date:June 19 2008 2:40pm
Subject:bzr commit into mysql-6.0 branch (dlenev:2670) WL#3726
View as plain text  
#At file:///home/dlenev/src/bzr/mysql-6.0-3726-w2/

 2670 Dmitry Lenev	2008-06-19
      WL#3726 "DDL locking for all metadata objects".
      
      After-review fixes in progress.
      
      Ensure that metadata locking subsystem properly handles
      out-of-memory conditions. Clarified MDL interface by
      separating release of locks and removal of lock requests
      from the context.
modified:
  sql/lock.cc
  sql/mdl.cc
  sql/mdl.h
  sql/sql_base.cc
  sql/sql_delete.cc
  sql/sql_handler.cc
  sql/sql_show.cc
  sql/sql_table.cc

per-file comments:
  sql/lock.cc
    mdl_release_lock(), mdl_acquire_exclusive_locks() and mdl_try_acquire_exclusive_lock() are no longer responsible
    for removal of metadata lock requests from the context.
    One should explicitly call mdl_remove_all_locks() and
    mdl_remove_lock() to do this.
  sql/mdl.cc
    Ensured that metadata locking subsystem properly handles
    out-of-memory conditions.
    Introduced new MDL_INITIALIZED state for metadata lock request
    which is used in all cases when lock is not acquired and we
    have not associated request with object respesenting lock.
    MDL_PENDING is now only used for requests for exclusive locks
    which are added to the MDL_LOCK::waiting_exclusive queue.
    mdl_release_lock(), mdl_acquire_exclusive_locks() and mdl_try_acquire_exclusive_lock() are no longer responsible
    for removal of metadata lock requests from the context.
    One should explicitly call mdl_remove_all_locks() and
    newly introduced mdl_remove_lock() to do this.
    Also renamed mdl_release_all_locks_for_name() to emphasize
    that it also actually removes lock requests from the context.
    Finally mdl_try_acquire_exclusive_lock() is now returs
    information about encountered lock conflict in separate
    out parameter since its return value is used for distinguishing
    between error (e.g. due to OOM) and success.
  sql/mdl.h
    Introduced new MDL_INITIALIZED state for metadata lock request
    which is used in all cases when lock is not acquired and we
    have not associated request with object respesenting lock.
    MDL_PENDING is now only used for requests for exclusive locks
    which are added to the MDL_LOCK::waiting_exclusive queue.
    mdl_release_lock(), mdl_acquire_exclusive_locks() and mdl_try_acquire_exclusive_lock() are no longer responsible
    for removal of metadata lock requests from the context.
    One should explicitly call mdl_remove_all_locks() and
    newly introduced mdl_remove_lock() to do this.
    Also renamed mdl_release_all_locks_for_name() to emphasize
    that it also actually removes lock requests from the context.
    Finally mdl_try_acquire_exclusive_lock() is now returs
    information about encountered lock conflict in separate
    out parameter since its return value is used for distinguishing
    between error (e.g. due to OOM) and success.
  sql/sql_base.cc
    mdl_release_lock(), mdl_acquire_exclusive_locks() and mdl_try_acquire_exclusive_lock() are no longer responsible
    for removal of metadata lock requests from the context.
    One should explicitly call mdl_remove_all_locks() and
    mdl_remove_lock() to do this.
    Also adjusted open_table() to ensure that it releases/removes
    metadata locks in case of error after adding/acquiring them
    (unless keeping these lock requests is required for recovering
    action).
  sql/sql_delete.cc
    mdl_release_lock(), mdl_acquire_exclusive_locks() and mdl_try_acquire_exclusive_lock() are no longer responsible
    for removal of metadata lock requests from the context.
    One should explicitly call mdl_remove_all_locks() and
    mdl_remove_lock() to do this.
  sql/sql_handler.cc
    mdl_release_lock(), mdl_acquire_exclusive_locks() and mdl_try_acquire_exclusive_lock() are no longer responsible
    for removal of metadata lock requests from the context.
    One should explicitly call mdl_remove_all_locks() and
    mdl_remove_lock() to do this.
  sql/sql_show.cc
    mdl_release_lock(), mdl_acquire_exclusive_locks() and mdl_try_acquire_exclusive_lock() are no longer responsible
    for removal of metadata lock requests from the context.
    One should explicitly call mdl_remove_all_locks() and
    mdl_remove_lock() to do this.
  sql/sql_table.cc
    Renamed mdl_release_all_locks_for_name() to emphasize
    that it also actually removes lock requests from the context.
    mdl_release_lock(), mdl_acquire_exclusive_locks() and mdl_try_acquire_exclusive_lock() are no longer responsible
    for removal of metadata lock requests from the context.
    One should explicitly call mdl_remove_all_locks() and
    mdl_remove_lock() to do this.
    Finally mdl_try_acquire_exclusive_lock() is now returs
    information about encountered lock conflict in separate
    out parameter since its return value is used for distinguishing
    between error (e.g. due to OOM) and success.
=== modified file 'sql/lock.cc'
--- a/sql/lock.cc	2008-06-11 11:49:58 +0000
+++ b/sql/lock.cc	2008-06-19 12:39:58 +0000
@@ -950,7 +950,7 @@ bool lock_table_names(THD *thd, TABLE_LI
     lock_table->mdl_lock_data= mdl_lock_data;
   }
   if (mdl_acquire_exclusive_locks(&thd->mdl_context))
-    return 1;
+    goto end;
   return 0;
 
 end:

=== modified file 'sql/mdl.cc'
--- a/sql/mdl.cc	2008-06-10 14:01:56 +0000
+++ b/sql/mdl.cc	2008-06-19 12:39:58 +0000
@@ -257,7 +257,7 @@ void mdl_context_merge(MDL_CONTEXT *dst,
 
    Stores the database name, object name and the type in the key
    buffer. Initializes mdl_el to point to the key.
-   We can't simply initialize mdl_el with type, db and name
+   We can't simply initialize MDL_LOCK_DATA with type, db and name
    by-pointer because of the underlying HASH implementation
    requires the key to be a contiguous buffer.
 
@@ -275,7 +275,7 @@ void mdl_init_lock(MDL_LOCK_DATA *lock_d
   lock_data->key_length= (uint) (strmov(strmov(key+4, db)+1, name)-key)+1;
   lock_data->key= key;
   lock_data->type= MDL_SHARED;
-  lock_data->state= MDL_PENDING;
+  lock_data->state= MDL_INITIALIZED;
 #ifndef DBUG_OFF
   lock_data->ctx= 0;
   lock_data->lock= 0;
@@ -336,7 +336,7 @@ MDL_LOCK_DATA *mdl_alloc_lock(int type, 
 void mdl_add_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data)
 {
   DBUG_ENTER("mdl_add_lock");
-  DBUG_ASSERT(lock_data->state == MDL_PENDING);
+  DBUG_ASSERT(lock_data->state == MDL_INITIALIZED);
   DBUG_ASSERT(!lock_data->ctx);
   lock_data->ctx= context;
   context->locks.push_front(lock_data);
@@ -345,6 +345,36 @@ void mdl_add_lock(MDL_CONTEXT *context, 
 
 
 /**
+   Remove a lock request from the list of lock requests of the context.
+
+   Disassociates a lock request from the given context.
+
+   @param  context    The MDL context to remove the lock from.
+   @param  lock_data  The lock request to be removed.
+
+   @pre The lock request being removed should correspond to lock which
+        was released or was not acquired.
+
+   @note Resets lock request for lock released back to its initial state
+         (i.e. sets type to MDL_SHARED).
+*/
+
+void mdl_remove_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data)
+{
+  DBUG_ENTER("mdl_remove_lock");
+  DBUG_ASSERT(lock_data->state == MDL_INITIALIZED);
+  DBUG_ASSERT(context == lock_data->ctx);
+  /* Reset lock request back to its initial state. */
+  lock_data->type= MDL_SHARED;
+#ifndef DBUG_OFF
+  lock_data->ctx= 0;
+#endif
+  context->locks.remove(lock_data);
+  DBUG_VOID_RETURN;
+}
+
+
+/**
    Clear all lock requests in the context (clear the context).
 
    Disassociates lock requests from the context.
@@ -629,7 +659,7 @@ bool mdl_acquire_shared_lock(MDL_CONTEXT
   MDL_LOCK *lock;
   *retry= FALSE;
 
-  DBUG_ASSERT(is_shared(lock_data) && lock_data->state == MDL_PENDING);
+  DBUG_ASSERT(is_shared(lock_data) && lock_data->state == MDL_INITIALIZED);
 
   DBUG_ASSERT(lock_data->ctx == context);
 
@@ -654,7 +684,11 @@ bool mdl_acquire_shared_lock(MDL_CONTEXT
   if (!(lock= (MDL_LOCK *)hash_search(&mdl_locks, (uchar*)lock_data->key,
                                       lock_data->key_length)))
   {
-    lock= get_lock_object();
+    if (!(lock= get_lock_object()))
+    {
+      pthread_mutex_unlock(&LOCK_mdl);
+      return TRUE;
+    }
     /*
       Before inserting MDL_LOCK object into hash we should add at least one
       MDL_LOCK_DATA to its lists in order to provide key for this element.
@@ -662,7 +696,12 @@ bool mdl_acquire_shared_lock(MDL_CONTEXT
     */
     lock->active_shared.push_front(lock_data);
     lock->lock_data_count= 1;
-    my_hash_insert(&mdl_locks, (uchar*)lock);
+    if (my_hash_insert(&mdl_locks, (uchar*)lock))
+    {
+      release_lock_object(lock);
+      pthread_mutex_unlock(&LOCK_mdl);
+      return TRUE;
+    }
     lock_data->state= MDL_ACQUIRED;
     lock_data->lock= lock;
     if (lock_data->type == MDL_SHARED_UPGRADABLE)
@@ -702,9 +741,6 @@ static void release_lock(MDL_LOCK_DATA *
    @param context  A context containing requests for exclusive locks
                    The context may not have other lock requests.
 
-   @note In case of failure (for example, if our thread was killed)
-         resets lock requests back to their initial state (MDL_SHARED)
-
    @retval FALSE  Success
    @retval TRUE   Failure
 */
@@ -735,25 +771,32 @@ bool mdl_acquire_exclusive_locks(MDL_CON
   while ((lock_data= it++))
   {
     DBUG_ASSERT(lock_data->type == MDL_EXCLUSIVE &&
-                lock_data->state == MDL_PENDING);
+                lock_data->state == MDL_INITIALIZED);
     if (!(lock= (MDL_LOCK *)hash_search(&mdl_locks, (uchar*)lock_data->key,
                                         lock_data->key_length)))
     {
-      lock= get_lock_object();
+      if (!(lock= get_lock_object()))
+        goto err;
       /*
         Again before inserting MDL_LOCK into hash provide key for
         it by adding MDL_LOCK_DATA to one of its lists.
       */
       lock->waiting_exclusive.push_front(lock_data);
       lock->lock_data_count= 1;
-      my_hash_insert(&mdl_locks, (uchar*)lock);
+      if (my_hash_insert(&mdl_locks, (uchar*)lock))
+      {
+        release_lock_object(lock);
+        goto err;
+      }
       lock_data->lock= lock;
+      lock_data->state= MDL_PENDING;
     }
     else
     {
       lock->waiting_exclusive.push_front(lock_data);
       lock->lock_data_count++;
       lock_data->lock= lock;
+      lock_data->state= MDL_PENDING;
     }
   }
 
@@ -806,23 +849,7 @@ bool mdl_acquire_exclusive_locks(MDL_CON
       pthread_cond_timedwait(&COND_mdl, &LOCK_mdl, &abstime);
     }
     if (thd->killed)
-    {
-      /* Remove our pending lock requests from the locks. */
-      it.rewind();
-      while ((lock_data= it++))
-      {
-        DBUG_ASSERT(lock_data->type == MDL_EXCLUSIVE &&
-                    lock_data->state == MDL_PENDING);
-        release_lock(lock_data);
-        /* Return lock request to its initial state. */
-        lock_data->type= MDL_SHARED;
-        context->locks.remove(lock_data);
-      }
-      /* Pending requests for shared locks can be satisfied now. */
-      pthread_cond_broadcast(&COND_mdl);
-      thd->exit_cond(old_msg);
-      return TRUE;
-    }
+      goto err;
   }
   it.rewind();
   while ((lock_data= it++))
@@ -839,6 +866,22 @@ bool mdl_acquire_exclusive_locks(MDL_CON
   /* As a side-effect THD::exit_cond() unlocks LOCK_mdl. */
   thd->exit_cond(old_msg);
   return FALSE;
+
+err:
+  /*
+    Remove our pending lock requests from the locks.
+    Ignore those lock requests which were not made MDL_PENDING.
+  */
+  it.rewind();
+  while ((lock_data= it++) && lock_data->state == MDL_PENDING)
+  {
+    release_lock(lock_data);
+    lock_data->state= MDL_INITIALIZED;
+  }
+  /* May be some pending requests for shared locks can be satisfied now. */
+  pthread_cond_broadcast(&COND_mdl);
+  thd->exit_cond(old_msg);
+  return TRUE;
 }
 
 
@@ -976,50 +1019,56 @@ bool mdl_upgrade_shared_lock_to_exclusiv
 
    @param context  [in]  The context containing the lock request
    @param lock     [in]  The lock request
+   @param conflict [out] Indicates that conflicting lock exists
 
-   @retval FALSE the lock was granted
-   @retval TRUE  there were conflicting locks.
+   @retval TRUE  Failure either conflicting lock exists or some error
+                 occured (probably OOM).
+   @retval FALSE Success, lock was acquired.
 
    FIXME: Compared to lock_table_name_if_not_cached()
           it gives sligthly more false negatives.
 */
 
 bool mdl_try_acquire_exclusive_lock(MDL_CONTEXT *context,
-                                    MDL_LOCK_DATA *lock_data)
+                                    MDL_LOCK_DATA *lock_data,
+                                    bool *conflict)
 {
   MDL_LOCK *lock;
 
   DBUG_ASSERT(lock_data->type == MDL_EXCLUSIVE &&
-              lock_data->state == MDL_PENDING);
+              lock_data->state == MDL_INITIALIZED);
 
   safe_mutex_assert_not_owner(&LOCK_open);
 
+  *conflict= FALSE;
+
   pthread_mutex_lock(&LOCK_mdl);
 
   if (!(lock= (MDL_LOCK *)hash_search(&mdl_locks, (uchar*)lock_data->key,
                                       lock_data->key_length)))
   {
-    lock= get_lock_object();
+    if (!(lock= get_lock_object()))
+      goto err;
     lock->active_exclusive.push_front(lock_data);
     lock->lock_data_count= 1;
-    my_hash_insert(&mdl_locks, (uchar*)lock);
+    if (my_hash_insert(&mdl_locks, (uchar*)lock))
+    {
+      release_lock_object(lock);
+      goto err;
+    }
     lock_data->state= MDL_ACQUIRED;
     lock_data->lock= lock;
-    lock= 0;
     global_lock.active_intention_exclusive++;
+    pthread_mutex_unlock(&LOCK_mdl);
+    return FALSE;
   }
-  pthread_mutex_unlock(&LOCK_mdl);
 
-  /*
-    FIXME: We can't leave pending MDL_EXCLUSIVE lock request in the list since
-           for such locks we assume that they have MDL_LOCK_DATA::lock properly set.
-           Long term we should clearly define relation between lock types,
-           presence in the context lists and MDL_LOCK_DATA::lock values.
-  */
-  if (lock)
-    context->locks.remove(lock_data);
+  /* There is some lock for the object. */
+  *conflict= TRUE;
 
-  return lock;
+err:
+  pthread_mutex_unlock(&LOCK_mdl);
+  return TRUE;
 }
 
 
@@ -1111,11 +1160,12 @@ bool mdl_wait_for_locks(MDL_CONTEXT *con
     it.rewind();
     while ((lock_data= it++))
     {
-      DBUG_ASSERT(lock_data->state == MDL_PENDING);
+      DBUG_ASSERT(lock_data->state == MDL_INITIALIZED);
       if (!can_grant_global_lock(lock_data))
         break;
       /*
-        To avoid starvation we don't wait if we have pending MDL_EXCLUSIVE lock.
+        To avoid starvation we don't wait if we have a conflict against
+        request for MDL_EXCLUSIVE lock.
       */
       if (is_shared(lock_data) &&
           (lock= (MDL_LOCK *)hash_search(&mdl_locks, (uchar*)lock_data->key,
@@ -1149,6 +1199,9 @@ static void release_lock(MDL_LOCK_DATA *
   DBUG_PRINT("enter", ("db=%s name=%s", lock_data->key + 4,
                         lock_data->key + 4 + strlen(lock_data->key + 4) + 1));
 
+  DBUG_ASSERT(lock_data->state == MDL_PENDING ||
+              lock_data->state == MDL_ACQUIRED);
+
   lock= lock_data->lock;
   if (lock->has_one_lock_data())
   {
@@ -1184,7 +1237,6 @@ static void release_lock(MDL_LOCK_DATA *
         }
         break;
       default:
-        /* TODO Really? How about problems during lock upgrade ? */
         DBUG_ASSERT(0);
     }
     lock->lock_data_count--;
@@ -1224,10 +1276,10 @@ void mdl_release_locks(MDL_CONTEXT *cont
       lists. Allows us to avoid problems in open_tables() in case of
       back-off
     */
-    if (!(is_shared(lock_data) && lock_data->state == MDL_PENDING))
+    if (lock_data->state != MDL_INITIALIZED)
     {
       release_lock(lock_data);
-      lock_data->state= MDL_PENDING;
+      lock_data->state= MDL_INITIALIZED;
 #ifndef DBUG_OFF
       lock_data->lock= 0;
 #endif
@@ -1247,13 +1299,10 @@ void mdl_release_locks(MDL_CONTEXT *cont
 
 /**
    Release a lock.
-   Removes the lock from the context.
 
    @param context   Context containing lock in question
    @param lock_data Lock to be released
 
-   @note Resets lock request for lock released back to its initial state
-         (i.e. sets type to MDL_SHARED).
 */
 
 void mdl_release_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data)
@@ -1263,13 +1312,9 @@ void mdl_release_lock(MDL_CONTEXT *conte
   pthread_mutex_lock(&LOCK_mdl);
   release_lock(lock_data);
 #ifndef DBUG_OFF
-  lock_data->ctx= 0;
   lock_data->lock= 0;
 #endif
-  lock_data->state= MDL_PENDING;
-  /* Return lock request to its initial state. */
-  lock_data->type= MDL_SHARED;
-  context->locks.remove(lock_data);
+  lock_data->state= MDL_INITIALIZED;
   pthread_cond_broadcast(&COND_mdl);
   pthread_mutex_unlock(&LOCK_mdl);
 }
@@ -1277,17 +1322,15 @@ void mdl_release_lock(MDL_CONTEXT *conte
 
 /**
    Release all locks in the context which correspond to the same name/
-   object as this lock request.
+   object as this lock request, remove lock requests from the context.
 
    @param context   Context containing locks in question
    @param lock_data One of the locks for the name/object for which all
                     locks should be released.
-
-   @see mdl_release_lock()
 */
 
-void mdl_release_all_locks_for_name(MDL_CONTEXT *context,
-                                    MDL_LOCK_DATA *lock_data)
+void mdl_release_and_remove_all_locks_for_name(MDL_CONTEXT *context,
+                                               MDL_LOCK_DATA *lock_data)
 {
   MDL_LOCK *lock;
   I_P_List_iterator<MDL_LOCK_DATA, MDL_LOCK_DATA_context> it(context->locks);
@@ -1306,7 +1349,10 @@ void mdl_release_all_locks_for_name(MDL_
   {
     DBUG_ASSERT(lock_data->state == MDL_ACQUIRED);
     if (lock_data->lock == lock)
+    {
       mdl_release_lock(context, lock_data);
+      mdl_remove_lock(context, lock_data);
+    }
   }
 }
 
@@ -1418,9 +1464,10 @@ bool mdl_is_lock_owner(MDL_CONTEXT *cont
   int4store(key, type);
   key_length= (uint) (strmov(strmov(key+4, db)+1, name)-key)+1;
 
-  while ((lock_data= it++) && (lock_data->key_length != key_length ||
-                               memcmp(lock_data->key, key, key_length) ||
-                               lock_data->state == MDL_PENDING))
+  while ((lock_data= it++) &&
+         (lock_data->key_length != key_length ||
+          memcmp(lock_data->key, key, key_length) ||
+          lock_data->state != MDL_ACQUIRED))
     continue;
 
   return lock_data;

=== modified file 'sql/mdl.h'
--- a/sql/mdl.h	2008-06-10 14:01:56 +0000
+++ b/sql/mdl.h	2008-06-19 12:39:58 +0000
@@ -44,7 +44,8 @@ enum enum_mdl_type {MDL_SHARED=0, MDL_SH
 
 /** States which metadata lock request can have. */
 
-enum enum_mdl_state {MDL_PENDING=0, MDL_ACQUIRED, MDL_PENDING_UPGRADE};
+enum enum_mdl_state {MDL_INITIALIZED=0, MDL_PENDING,
+                     MDL_ACQUIRED, MDL_PENDING_UPGRADE};
 
 
 /**
@@ -152,6 +153,7 @@ void mdl_init_lock(MDL_LOCK_DATA *lock_d
 MDL_LOCK_DATA *mdl_alloc_lock(int type, const char *db, const char *name,
                               MEM_ROOT *root);
 void mdl_add_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data);
+void mdl_remove_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data);
 void mdl_remove_all_locks(MDL_CONTEXT *context);
 
 /**
@@ -160,7 +162,7 @@ void mdl_remove_all_locks(MDL_CONTEXT *c
 
 inline void mdl_set_lock_type(MDL_LOCK_DATA *lock_data, enum_mdl_type lock_type)
 {
-  DBUG_ASSERT(lock_data->state == MDL_PENDING);
+  DBUG_ASSERT(lock_data->state == MDL_INITIALIZED);
   lock_data->type= lock_type;
 }
 
@@ -170,14 +172,15 @@ bool mdl_acquire_exclusive_locks(MDL_CON
 bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context,
                                           MDL_LOCK_DATA *lock_data);
 bool mdl_try_acquire_exclusive_lock(MDL_CONTEXT *context,
-                                    MDL_LOCK_DATA *lock_data);
+                                    MDL_LOCK_DATA *lock_data,
+                                    bool *conflict);
 bool mdl_acquire_global_shared_lock(MDL_CONTEXT *context);
 
 bool mdl_wait_for_locks(MDL_CONTEXT *context);
 
 void mdl_release_locks(MDL_CONTEXT *context);
-void mdl_release_all_locks_for_name(MDL_CONTEXT *context,
-                                    MDL_LOCK_DATA *lock_data);
+void mdl_release_and_remove_all_locks_for_name(MDL_CONTEXT *context,
+                                               MDL_LOCK_DATA *lock_data);
 void mdl_release_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data);
 void mdl_downgrade_exclusive_lock(MDL_CONTEXT *context,
                                   MDL_LOCK_DATA *lock_data);

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2008-06-12 02:23:08 +0000
+++ b/sql/sql_base.cc	2008-06-19 12:39:58 +0000
@@ -2219,9 +2219,9 @@ void table_share_release_hook(void *shar
 }
 
 
-/*
-  A helper function that acquires an MDL lock for a table
-  being opened.
+/**
+   A helper function that acquires an MDL lock for a table
+   being opened.
 */
 
 static bool
@@ -2245,7 +2245,10 @@ open_table_get_mdl_lock(THD *thd, TABLE_
     */
     mdl_set_lock_type(mdl_lock_data, MDL_EXCLUSIVE);
     if (mdl_acquire_exclusive_locks(&thd->mdl_context))
+    {
+      mdl_remove_lock(&thd->mdl_context, mdl_lock_data);
       return 1;
+    }
   }
   else
   {
@@ -2268,6 +2271,8 @@ open_table_get_mdl_lock(THD *thd, TABLE_
     {
       if (retry)
         *action= OT_BACK_OFF_AND_RETRY;
+      else
+        mdl_remove_lock(&thd->mdl_context, mdl_lock_data);
       return 1;
     }
   }
@@ -2789,7 +2794,11 @@ err_unlock:
   release_table_share(share);
 err_unlock2:
   pthread_mutex_unlock(&LOCK_open);
-  mdl_release_lock(&thd->mdl_context, mdl_lock_data);
+  if (! (flags & MYSQL_OPEN_HAS_MDL_LOCK))
+  {
+    mdl_release_lock(&thd->mdl_context, mdl_lock_data);
+    mdl_remove_lock(&thd->mdl_context, mdl_lock_data);
+  }
   DBUG_RETURN(TRUE);
 }
 
@@ -3445,7 +3454,10 @@ recover_from_failed_open_table_attempt(T
       mdl_set_lock_type(table->mdl_lock_data, MDL_EXCLUSIVE);
       mdl_add_lock(&thd->mdl_context, table->mdl_lock_data);
       if (mdl_acquire_exclusive_locks(&thd->mdl_context))
+      {
+        mdl_remove_lock(&thd->mdl_context, table->mdl_lock_data);
         return TRUE;
+      }
       pthread_mutex_lock(&LOCK_open);
       tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name);
       ha_create_table_from_engine(thd, table->db, table->table_name);
@@ -3454,18 +3466,23 @@ recover_from_failed_open_table_attempt(T
       mysql_reset_errors(thd, 1);         // Clear warnings
       thd->clear_error();                 // Clear error message
       mdl_release_lock(&thd->mdl_context, table->mdl_lock_data);
+      mdl_remove_lock(&thd->mdl_context, table->mdl_lock_data);
       break;
     case OT_REPAIR:
       mdl_set_lock_type(table->mdl_lock_data, MDL_EXCLUSIVE);
       mdl_add_lock(&thd->mdl_context, table->mdl_lock_data);
       if (mdl_acquire_exclusive_locks(&thd->mdl_context))
+      {
+        mdl_remove_lock(&thd->mdl_context, table->mdl_lock_data);
         return TRUE;
+      }
       pthread_mutex_lock(&LOCK_open);
       tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name);
       pthread_mutex_unlock(&LOCK_open);
 
       result= auto_repair_table(thd, table);
       mdl_release_lock(&thd->mdl_context, table->mdl_lock_data);
+      mdl_remove_lock(&thd->mdl_context, table->mdl_lock_data);
       break;
     default:
       DBUG_ASSERT(0);

=== modified file 'sql/sql_delete.cc'
--- a/sql/sql_delete.cc	2008-06-11 04:33:36 +0000
+++ b/sql/sql_delete.cc	2008-06-19 12:39:58 +0000
@@ -1044,7 +1044,10 @@ bool mysql_truncate(THD *thd, TABLE_LIST
     mdl_set_lock_type(mdl_lock_data, MDL_EXCLUSIVE);
     mdl_add_lock(&thd->mdl_context, mdl_lock_data);
     if (mdl_acquire_exclusive_locks(&thd->mdl_context))
+    {
+      mdl_remove_lock(&thd->mdl_context, mdl_lock_data);
       DBUG_RETURN(TRUE);
+    }
     pthread_mutex_lock(&LOCK_open);
     tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table_list->db,
                      table_list->table_name);
@@ -1074,12 +1077,18 @@ end:
       my_ok(thd);		// This should return record count
     }
     if (mdl_lock_data)
+    {
       mdl_release_lock(&thd->mdl_context, mdl_lock_data);
+      mdl_remove_lock(&thd->mdl_context, mdl_lock_data);
+    }
   }
   else if (error)
   {
     if (mdl_lock_data)
+    {
       mdl_release_lock(&thd->mdl_context, mdl_lock_data);
+      mdl_remove_lock(&thd->mdl_context, mdl_lock_data);
+    }
   }
   DBUG_RETURN(error);
 

=== modified file 'sql/sql_handler.cc'
--- a/sql/sql_handler.cc	2008-06-05 06:48:36 +0000
+++ b/sql/sql_handler.cc	2008-06-19 12:39:58 +0000
@@ -150,6 +150,7 @@ static void mysql_ha_close_table(THD *th
     }
     pthread_mutex_unlock(&LOCK_open);
     mdl_release_lock(&thd->handler_mdl_context, mdl_lock_data);
+    mdl_remove_lock(&thd->handler_mdl_context, mdl_lock_data);
   }
   else if (tables->table)
   {

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2008-06-11 11:53:53 +0000
+++ b/sql/sql_show.cc	2008-06-19 12:39:58 +0000
@@ -3250,6 +3250,7 @@ err_unlock:
 
 err:
   mdl_release_lock(&thd->mdl_context, &mdl_lock_data);
+  mdl_remove_lock(&thd->mdl_context, &mdl_lock_data);
   thd->clear_error();
   return res;
 }

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2008-06-11 15:37:09 +0000
+++ b/sql/sql_table.cc	2008-06-19 12:39:58 +0000
@@ -1853,7 +1853,8 @@ err:
           and locked and therefore have to remove several metadata lock
           requests associated with them.
         */
-        mdl_release_all_locks_for_name(&thd->mdl_context, table->mdl_lock_data);
+        mdl_release_and_remove_all_locks_for_name(&thd->mdl_context,
+                                                  table->mdl_lock_data);
       }
     }
   }
@@ -3692,13 +3693,27 @@ static bool lock_table_name_if_not_cache
                                           const char *table_name,
                                           MDL_LOCK_DATA **lock_data)
 {
+  bool conflict;
+
   if (!(*lock_data= mdl_alloc_lock(0, db, table_name, thd->mem_root)))
     return TRUE;
   mdl_set_lock_type(*lock_data, MDL_EXCLUSIVE);
   mdl_add_lock(&thd->mdl_context, *lock_data);
-  if (mdl_try_acquire_exclusive_lock(&thd->mdl_context, *lock_data))
+  if (mdl_try_acquire_exclusive_lock(&thd->mdl_context, *lock_data,
+                                     &conflict))
   {
-    *lock_data= 0;
+    /*
+      To simplify our life under LOCK TABLES we remove unsatisfied
+      lock request from the context.
+    */
+    mdl_remove_lock(&thd->mdl_context, *lock_data);
+    if (!conflict)
+    {
+      /* Probably OOM. */
+      return TRUE;
+    }
+    else
+      *lock_data= 0;
   }
   return FALSE;
 }
@@ -3768,7 +3783,10 @@ bool mysql_create_table(THD *thd, const 
 
 unlock:
   if (target_lock_data)
+  {
     mdl_release_lock(&thd->mdl_context, target_lock_data);
+    mdl_remove_lock(&thd->mdl_context, target_lock_data);
+  }
   pthread_mutex_lock(&LOCK_lock_db);
   if (!--creating_table && creating_database)
     pthread_cond_signal(&COND_refresh);
@@ -3954,7 +3972,10 @@ static int prepare_for_repair(THD *thd, 
     mdl_set_lock_type(mdl_lock_data, MDL_EXCLUSIVE);
     mdl_add_lock(&thd->mdl_context, mdl_lock_data);
     if (mdl_acquire_exclusive_locks(&thd->mdl_context))
+    {
+      mdl_remove_lock(&thd->mdl_context, mdl_lock_data);
       DBUG_RETURN(0);
+    }
 
     pthread_mutex_lock(&LOCK_open);
     if (!(share= (get_table_share(thd, table_list, key, key_length, 0,
@@ -4088,7 +4109,10 @@ end:
   }
   /* In case of a temporary table there will be no metadata lock. */
   if (error && mdl_lock_data)
+  {
     mdl_release_lock(&thd->mdl_context, mdl_lock_data);
+    mdl_remove_lock(&thd->mdl_context, mdl_lock_data);
+  }
   DBUG_RETURN(error);
 }
 
@@ -4942,7 +4966,10 @@ table_exists:
 
 err:
   if (target_lock_data)
+  {
     mdl_release_lock(&thd->mdl_context, target_lock_data);
+    mdl_remove_lock(&thd->mdl_context, target_lock_data);
+  }
   DBUG_RETURN(res);
 }
 
@@ -6648,7 +6675,9 @@ view_err:
       if (new_name != table_name || new_db != db)
       {
         mdl_release_lock(&thd->mdl_context, target_lock_data);
-        mdl_release_all_locks_for_name(&thd->mdl_context, mdl_lock_data);
+        mdl_remove_lock(&thd->mdl_context, target_lock_data);
+        mdl_release_and_remove_all_locks_for_name(&thd->mdl_context,
+                                                  mdl_lock_data);
       }
       else
         mdl_downgrade_exclusive_lock(&thd->mdl_context, mdl_lock_data);
@@ -7061,7 +7090,9 @@ end_online:
     if ((new_name != table_name || new_db != db))
     {
       mdl_release_lock(&thd->mdl_context, target_lock_data);
-      mdl_release_all_locks_for_name(&thd->mdl_context, mdl_lock_data);
+      mdl_remove_lock(&thd->mdl_context, target_lock_data);
+      mdl_release_and_remove_all_locks_for_name(&thd->mdl_context,
+                                                mdl_lock_data);
     }
     else
       mdl_downgrade_exclusive_lock(&thd->mdl_context, mdl_lock_data);
@@ -7118,7 +7149,10 @@ err:
     thd->abort_on_warning= save_abort_on_warning;
   }
   if (target_lock_data)
+  {
     mdl_release_lock(&thd->mdl_context, target_lock_data);
+    mdl_remove_lock(&thd->mdl_context, target_lock_data);
+  }
   DBUG_RETURN(TRUE);
 
 err_with_mdl:
@@ -7130,8 +7164,11 @@ err_with_mdl:
   */
   thd->locked_tables_list.unlink_all_closed_tables();
   if (target_lock_data)
+  {
     mdl_release_lock(&thd->mdl_context, target_lock_data);
-  mdl_release_all_locks_for_name(&thd->mdl_context, mdl_lock_data);
+    mdl_remove_lock(&thd->mdl_context, target_lock_data);
+  }
+  mdl_release_and_remove_all_locks_for_name(&thd->mdl_context, mdl_lock_data);
   DBUG_RETURN(TRUE);
 }
 /* mysql_alter_table */

Thread
bzr commit into mysql-6.0 branch (dlenev:2670) WL#3726Dmitry Lenev19 Jun