List:Commits« Previous MessageNext Message »
From:Konstantin Osipov Date:January 28 2010 9:35am
Subject:bzr commit into mysql-5.6-next-mr branch (kostja:3068) Bug#46272
View as plain text  
#At file:///opt/local/work/next-4284-stage/ based on revid:kostja@stripped

 3068 Konstantin Osipov	2010-01-28
      Bug#46272, review fixes.

    modified:
      sql/mdl.cc
      sql/mdl.h
=== modified file 'sql/mdl.cc'
--- a/sql/mdl.cc	2010-01-27 21:44:28 +0000
+++ b/sql/mdl.cc	2010-01-28 09:35:54 +0000
@@ -630,8 +630,6 @@ void MDL_lock::destroy(MDL_lock *lock)
 }
 
 
-
-
 /**
   Auxiliary functions needed for creation/destruction of MDL_ticket
   objects.
@@ -938,6 +936,7 @@ const uchar MDL_object_lock::m_granted_i
     MDL_BIT(MDL_SHARED)
 };
 
+
 const uchar MDL_object_lock::m_waiting_incompatible[MDL_TYPE_END] =
 {
   0,
@@ -1211,22 +1210,42 @@ MDL_context::acquire_lock(MDL_request *m
 /**
   Try to acquire one lock.
 
+  Unlike exclusive locks, shared locks are acquired one by
+  one. This is interface is chosen to simplify introduction of
+  the new locking API to the system. MDL_context::try_acquire_lock()
+  is currently used from open_table(), and there we have only one
+  table to work with.
+
+  This function may also be used to try to acquire an exclusive
+  lock on a destination table, by ALTER TABLE ... RENAME.
+
+  Returns immediately without any side effect if encounters a lock
+  conflict. Otherwise takes the lock.
+
+  FIXME: Compared to lock_table_name_if_not_cached() (from 5.1)
+         it gives slightly more false negatives.
+
   @param mdl_request [in/out] Lock request object for lock to be acquired
 
   @retval  FALSE   Success. The lock may have not been acquired.
                    Check the ticket, if it's NULL, a conflicting lock
-                   exists.
+                   exists and another attempt should be made after releasing
+                   all current locks and waiting for conflicting lock go
+                   away (using MDL_context::wait_for_lock()).
   @retval  TRUE    Out of resources, an error has been reported.
 */
 
 bool
-MDL_context::try_acquire_lock_impl(MDL_request *mdl_request)
+MDL_context::try_acquire_lock(MDL_request *mdl_request)
 {
   MDL_lock *lock;
   MDL_key *key= &mdl_request->key;
   MDL_ticket *ticket;
   bool is_transactional;
 
+  DBUG_ASSERT(mdl_request->type < MDL_SHARED_NO_WRITE ||
+              (is_lock_owner(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE)
+               && ! is_lock_owner(MDL_key::GLOBAL, "", "", MDL_SHARED)));
   DBUG_ASSERT(mdl_request->ticket == NULL);
 
   /* Don't take chances in production. */
@@ -1302,45 +1321,6 @@ MDL_context::try_acquire_lock_impl(MDL_r
 
 
 /**
-  Try to acquire one lock.
-
-  Unlike exclusive locks, shared locks are acquired one by
-  one. This is interface is chosen to simplify introduction of
-  the new locking API to the system. MDL_context::try_acquire_lock()
-  is currently used from open_table(), and there we have only one
-  table to work with.
-
-  This function may also be used to try to acquire an exclusive
-  lock on a destination table, by ALTER TABLE ... RENAME.
-
-  Returns immediately without any side effect if encounters a lock
-  conflict. Otherwise takes the lock.
-
-  FIXME: Compared to lock_table_name_if_not_cached() (from 5.1)
-         it gives slightly more false negatives.
-
-  @param mdl_request [in/out] Lock request object for lock to be acquired
-
-  @retval  FALSE   Success. The lock may have not been acquired.
-                   Check the ticket, if it's NULL, a conflicting lock
-                   exists and another attempt should be made after releasing
-                   all current locks and waiting for conflicting lock go
-                   away (using MDL_context::wait_for_lock()).
-  @retval  TRUE    Out of resources, an error has been reported.
-*/
-
-bool
-MDL_context::try_acquire_lock(MDL_request *mdl_request)
-{
-  DBUG_ASSERT(mdl_request->type < MDL_SHARED_NO_WRITE ||
-              (is_lock_owner(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE)
-               && ! is_lock_owner(MDL_key::GLOBAL, "", "", MDL_SHARED)));
-
-  return try_acquire_lock_impl(mdl_request);
-}
-
-
-/**
   Create a copy of a granted ticket.
   This is used to make sure that HANDLER ticket
   is never shared with a ticket that belongs to
@@ -1382,6 +1362,7 @@ MDL_context::clone_ticket(MDL_request *m
   return FALSE;
 }
 
+
 /**
   Notify a thread holding a shared metadata lock which
   conflicts with a pending exclusive lock.
@@ -1418,6 +1399,8 @@ void notify_shared_lock(THD *thd, MDL_ti
   Auxiliary method for acquiring an exclusive lock.
 
   @param mdl_request  Request for the lock to be acqured.
+  @param is_upgrade   Are we trying to upgrade a shared
+                      lock to exclusive?
 
   @note Should not be used outside of MDL subsystem. Instead one should
         call acquire_exclusive_lock() or acquire_exclusive_locks() methods
@@ -1428,7 +1411,8 @@ void notify_shared_lock(THD *thd, MDL_ti
   @retval TRUE   Failure
 */
 
-bool MDL_context::acquire_exclusive_lock_impl(MDL_request *mdl_request)
+bool MDL_context::acquire_exclusive_lock_impl(MDL_request *mdl_request,
+                                              bool is_upgrade)
 {
   MDL_lock *lock;
   const char *old_msg;
@@ -1477,9 +1461,9 @@ bool MDL_context::acquire_exclusive_lock
   old_msg= MDL_ENTER_COND(m_thd, mysys_var, &m_ctx_wakeup_cond,
                           &lock->m_mutex);
 
-  while (!lock->can_grant_lock(mdl_request->type, FALSE))
+  while (!lock->can_grant_lock(mdl_request->type, is_upgrade))
   {
-    if (m_trans_sentinel)
+    if (m_trans_sentinel && ! is_upgrade)
     {
       /*
         We're about to start waiting. Don't do it if we have
@@ -1543,7 +1527,7 @@ bool MDL_context::acquire_exclusive_lock
       MDL_EXIT_COND(m_thd, mysys_var, &lock->m_mutex, old_msg);
 
       pthread_mutex_lock(&lock->m_mutex);
-      /* Get rid of pending ticket. */
+      /* Get rid of the pending ticket. */
       lock->remove_pending(ticket);
       if (lock->is_empty())
         mdl_locks.remove(lock);
@@ -1598,7 +1582,7 @@ bool MDL_context::acquire_exclusive_lock
               m_tickets.front()->m_lock->key.mdl_namespace() == MDL_key::GLOBAL &&
               ++Ticket_list::Iterator(m_tickets) == m_trans_sentinel);
 
-  return acquire_exclusive_lock_impl(mdl_request);
+  return acquire_exclusive_lock_impl(mdl_request, FALSE);
 }
 
 
@@ -1658,7 +1642,7 @@ bool MDL_context::acquire_exclusive_lock
 
   for (i= 0; i < mdl_requests->elements(); i++)
   {
-    if (acquire_exclusive_lock_impl(sort_buf[i]))
+    if (acquire_exclusive_lock_impl(sort_buf[i], FALSE))
       goto err;
   }
   my_free(sort_buf, MYF(0));
@@ -1699,16 +1683,12 @@ err:
 bool
 MDL_context::upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket)
 {
-  const char *old_msg;
-  st_my_thread_var *mysys_var= my_thread_var;
-  THD *thd= get_thd();
-  MDL_lock *mdl_lock= mdl_ticket->m_lock;
-  MDL_ticket *pending_ticket;
+  MDL_request mdl_xlock_request;
+  MDL_ticket *mdl_svp= mdl_savepoint();
+  bool is_new_ticket;
 
   DBUG_ENTER("MDL_ticket::upgrade_shared_lock_to_exclusive");
-  DEBUG_SYNC(thd, "mdl_upgrade_shared_lock_to_exclusive");
-
-  safe_mutex_assert_not_owner(&LOCK_open);
+  DEBUG_SYNC(get_thd(), "mdl_upgrade_shared_lock_to_exclusive");
 
   /*
     Do nothing if already upgraded. Used when we FLUSH TABLE under
@@ -1721,90 +1701,33 @@ MDL_context::upgrade_shared_lock_to_excl
   DBUG_ASSERT(mdl_ticket->m_type == MDL_SHARED_NO_WRITE ||
               mdl_ticket->m_type == MDL_SHARED_NO_READ_WRITE);
 
-  /*
-    Since we should have already acquired an intention exclusive
-    global lock this call is only enforcing asserts.
-  */
-  DBUG_ASSERT(is_lock_owner(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE)
-              && ! is_lock_owner(MDL_key::GLOBAL, "", "", MDL_SHARED));
+  mdl_xlock_request.init(&mdl_ticket->m_lock->key, MDL_EXCLUSIVE);
 
-  /*
-    Create an auxiliary ticket to represent a pending exclusive
-    lock and add it to the 'waiting' queue for the duration
-    of upgrade. During upgrade we abort waits of connections
-    that own conflicting locks. A pending request is used
-    to signal such connections that upon waking up they
-    must back off, rather than fall into sleep again.
-  */
-  if (! (pending_ticket= MDL_ticket::create(this, MDL_EXCLUSIVE)))
+  if (acquire_exclusive_lock_impl(&mdl_xlock_request, TRUE))
     DBUG_RETURN(TRUE);
 
-  pthread_mutex_lock(&mdl_lock->m_mutex);
-
-  mdl_lock->add_pending(pending_ticket);
-
-  old_msg= MDL_ENTER_COND(thd, mysys_var, &m_ctx_wakeup_cond,
-                          &mdl_lock->m_mutex);
-
-  while (1)
-  {
-    if (mdl_lock->can_grant_lock(MDL_EXCLUSIVE, TRUE))
-      break;
-
-    mdl_lock->notify_shared_locks(this);
-
-    /* There is a shared or exclusive lock on the object. */
-    DEBUG_SYNC(thd, "mdl_upgrade_shared_lock_to_exclusive_wait");
-
-    /*
-      Another thread might have obtained a shared MDL lock on some table
-      but has not yet opened it and/or tried to obtain data lock on it.
-      Also invocation of acquire_exclusive_lock() method and consequently
-      first call to notify_shared_lock() might have happened right after
-      thread holding shared metadata lock in wait_for_locks() method
-      checked that there are no pending conflicting locks but before
-      it has started waiting.
-      In both these cases we need to sleep until these threads will start
-      waiting and try to abort them once again.
-    */
-    struct timespec abstime;
-    set_timespec(abstime, 1);
-    pthread_cond_timedwait(&m_ctx_wakeup_cond, &mdl_lock->m_mutex,
-                           &abstime);
-
-    if (mysys_var->abort)
-    {
-      mdl_lock->remove_pending(pending_ticket);
-      /*
-        If there are no other pending requests for exclusive locks
-        we need to wake up threads waiting for a chance to acquire
-        shared lock.
-      */
-      mdl_lock->wake_up_waiters();
-      MDL_EXIT_COND(thd, mysys_var, &mdl_lock->m_mutex, old_msg);
-      MDL_ticket::destroy(pending_ticket);
-      DBUG_RETURN(TRUE);
-    }
-  }
+  is_new_ticket= ! has_lock(mdl_svp, mdl_xlock_request.ticket);
 
+  /* Merge the acquired and the original lock. @todo: move to a method. */
+  pthread_mutex_lock(&mdl_ticket->m_lock->m_mutex);
+  if (is_new_ticket)
+    mdl_ticket->m_lock->remove_granted(mdl_xlock_request.ticket);
   /*
-    Set the new type of lock in the ticket. To update state of MDL_lock object
-    correctly we need to temporarily exclude ticket from the granted queue and
-    then include it back.
+    Set the new type of lock in the ticket. To update state of
+    MDL_lock object correctly we need to temporarily exclude
+    ticket from the granted queue and then include it back.
   */
-  mdl_lock->remove_granted(mdl_ticket);
+  mdl_ticket->m_lock->remove_granted(mdl_ticket);
   mdl_ticket->m_type= MDL_EXCLUSIVE;
-  mdl_lock->add_granted(mdl_ticket);
-
-  mdl_lock->remove_pending(pending_ticket);
-
-  if (mdl_lock->cached_object)
-    (*mdl_lock->cached_object_release_hook)(mdl_lock->cached_object);
-  mdl_lock->cached_object= 0;
+  mdl_ticket->m_lock->add_granted(mdl_ticket);
 
-  MDL_EXIT_COND(thd, mysys_var, &mdl_lock->m_mutex, old_msg);
+  pthread_mutex_unlock(&mdl_ticket->m_lock->m_mutex);
 
-  MDL_ticket::destroy(pending_ticket);
+  if (is_new_ticket)
+  {
+    m_tickets.remove(mdl_xlock_request.ticket);
+    MDL_ticket::destroy(mdl_xlock_request.ticket);
+  }
 
   DBUG_RETURN(FALSE);
 }
@@ -2248,18 +2171,27 @@ void MDL_context::release_transactional_
 bool MDL_context::has_lock(MDL_ticket *mdl_savepoint,
                            MDL_ticket *mdl_ticket)
 {
-  /* Adjust the savepoint to take into account m_trans_sentinel. */
-  MDL_context::Ticket_iterator it(m_tickets, mdl_savepoint ?
-                                  mdl_savepoint : m_trans_sentinel);
   MDL_ticket *ticket;
+  /* Start from the beginning, most likely mdl_ticket's been just acquired. */
+  MDL_context::Ticket_iterator it(m_tickets);
+  bool found_savepoint= FALSE;
 
-  /* Start iteration from the savepoint. */
   while ((ticket= it++) && ticket != m_trans_sentinel)
   {
+    /*
+      First met the savepoint. The ticket must be
+      somewhere after it.
+    */
+    if (ticket == mdl_savepoint)
+      found_savepoint= TRUE;
+    /*
+      Met the ticket. If we haven't yet met the savepoint,
+      the ticket is newer than the savepoint.
+    */
     if (ticket == mdl_ticket)
-      return TRUE;
+      return found_savepoint;
   }
-  /* The ticket is either before the savepoint or LT, HA or GRL ticket. */
+  /* Reached m_trans_sentinel. The ticket must be LT, HA or GRL ticket. */
   return FALSE;
 }
 

=== modified file 'sql/mdl.h'
--- a/sql/mdl.h	2010-01-27 21:44:28 +0000
+++ b/sql/mdl.h	2010-01-28 09:35:54 +0000
@@ -616,9 +616,7 @@ private:
   MDL_ticket *find_ticket(MDL_request *mdl_req,
                           bool *is_transactional);
   void release_locks_stored_before(MDL_ticket *sentinel);
-
-  bool try_acquire_lock_impl(MDL_request *mdl_request);
-  bool acquire_exclusive_lock_impl(MDL_request *mdl_request);
+  bool acquire_exclusive_lock_impl(MDL_request *mdl_request, bool is_upgrade);
 private:
   MDL_context(const MDL_context &rhs);          /* not implemented */
   MDL_context &operator=(MDL_context &rhs);     /* not implemented */


Attachment: [text/bzr-bundle] bzr/kostja@sun.com-20100128093554-nq59oqiha8gjvkb3.bundle
Thread
bzr commit into mysql-5.6-next-mr branch (kostja:3068) Bug#46272Konstantin Osipov28 Jan