List:Commits« Previous MessageNext Message »
From:Tor Didriksen Date:January 27 2011 3:31pm
Subject:bzr push into mysql-trunk branch (tor.didriksen:3561 to 3562) Bug#59309
View as plain text  
 3562 Tor Didriksen	2011-01-27
      Bug #59309  Cleanup MDL - THD interface 
      
      Define an abstract interface MDL_context_owner
      which is implemented by THD and the unit test classes.
      
      This allows us to separate MDL from the THD and the rest of the server code,
      and do standalone unit testing of the MDL module.
     @ sql/mdl.cc
        Use m_owner rather than thd when notifying about waiting events.
     @ sql/mdl.h
        Introduce a new interface (abstract class) MDL_context_owner.
        Remove declaration of the free functions used previously.
     @ sql/sql_base.cc
        Rename mysql_notify_thread_having_shared_lock to THD::notify_shared_lock
        and move it to sql_class.cc
     @ sql/sql_class.cc
        Rename mysql_notify_thread_having_shared_lock to THD::notify_shared_lock
        and move it here.
     @ sql/sql_class.h
        THD now implements the MDL_context_owner interface.
     @ sql/sql_insert.cc
        Update comment about notify_shared_lock
     @ unittest/gunit/mdl-t.cc
        Remove mock free-functions.
        Let the test fixture class and the test thread class implement MDL_context_owner
     @ unittest/gunit/mdl_mytap-t.cc
        Remove mock free-functions.
        Let the test fixture class and the test thread class implement MDL_context_owner
     @ unittest/gunit/test_mdl_context_owner.h
        Common implementation of MDL_context_owner for the two MDL unit tests.

    added:
      unittest/gunit/test_mdl_context_owner.h
    modified:
      sql/mdl.cc
      sql/mdl.h
      sql/sql_base.cc
      sql/sql_class.cc
      sql/sql_class.h
      sql/sql_insert.cc
      unittest/gunit/mdl-t.cc
      unittest/gunit/mdl_mytap-t.cc
 3561 Tor Didriksen	2011-01-27 [merge]
      merge 5.5 => trunk

    modified:
      sql/sql_class.cc
=== modified file 'sql/mdl.cc'
--- a/sql/mdl.cc	2010-11-19 12:34:44 +0000
+++ b/sql/mdl.cc	2011-01-27 15:31:18 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -731,7 +731,8 @@ void MDL_map::remove(MDL_lock *lock)
 */
 
 MDL_context::MDL_context()
-  : m_thd(NULL),
+  :
+  m_owner(NULL),
   m_needs_thr_lock_abort(FALSE),
   m_waiting_for(NULL)
 {
@@ -950,6 +951,7 @@ void MDL_wait::reset_status()
 /**
   Wait for the status to be assigned to this wait slot.
 
+  @param owner           MDL context owner.
   @param abs_timeout     Absolute time after which waiting should stop.
   @param set_status_on_timeout TRUE  - If in case of timeout waiting
                                        context should close the wait slot by
@@ -961,7 +963,7 @@ void MDL_wait::reset_status()
 */
 
 MDL_wait::enum_wait_status
-MDL_wait::timed_wait(THD *thd, struct timespec *abs_timeout,
+MDL_wait::timed_wait(MDL_context_owner *owner, struct timespec *abs_timeout,
                      bool set_status_on_timeout, const char *wait_state_name)
 {
   const char *old_msg;
@@ -970,10 +972,9 @@ MDL_wait::timed_wait(THD *thd, struct ti
 
   mysql_mutex_lock(&m_LOCK_wait_status);
 
-  old_msg= thd_enter_cond(thd, &m_COND_wait_status, &m_LOCK_wait_status,
-                          wait_state_name);
-
-  while (!m_wait_status && !thd_killed(thd) &&
+  old_msg= owner->enter_cond(&m_COND_wait_status, &m_LOCK_wait_status,
+                             wait_state_name);
+  while (!m_wait_status && !owner->is_killed() &&
          wait_result != ETIMEDOUT && wait_result != ETIME)
     wait_result= mysql_cond_timedwait(&m_COND_wait_status, &m_LOCK_wait_status,
                                       abs_timeout);
@@ -992,14 +993,14 @@ MDL_wait::timed_wait(THD *thd, struct ti
       false, which means that the caller intends to restart the
       wait.
     */
-    if (thd_killed(thd))
+    if (owner->is_killed())
       m_wait_status= KILLED;
     else if (set_status_on_timeout)
       m_wait_status= TIMEOUT;
   }
   result= m_wait_status;
 
-  thd_exit_cond(thd, old_msg);
+  owner->exit_cond(old_msg);
 
   return result;
 }
@@ -1696,9 +1697,9 @@ void MDL_object_lock::notify_conflicting
         lock or some other non-MDL resource we might need to wake it up
         by calling code outside of MDL.
       */
-      mysql_notify_thread_having_shared_lock(ctx->get_thd(),
-                                 conflicting_ctx->get_thd(),
-                                 conflicting_ctx->get_needs_thr_lock_abort());
+      ctx->get_owner()->
+        notify_shared_lock(conflicting_ctx->get_owner(),
+                           conflicting_ctx->get_needs_thr_lock_abort());
     }
   }
 }
@@ -1728,9 +1729,9 @@ void MDL_scoped_lock::notify_conflicting
         insert delayed. We need to kill such threads in order to get
         global shared lock. We do this my calling code outside of MDL.
       */
-      mysql_notify_thread_having_shared_lock(ctx->get_thd(),
-                                 conflicting_ctx->get_thd(),
-                                 conflicting_ctx->get_needs_thr_lock_abort());
+      ctx->get_owner()->
+        notify_shared_lock(conflicting_ctx->get_owner(),
+                           conflicting_ctx->get_needs_thr_lock_abort());
     }
   }
 }
@@ -1797,7 +1798,7 @@ MDL_context::acquire_lock(MDL_request *m
   will_wait_for(ticket);
 
   /* There is a shared or exclusive lock on the object. */
-  DEBUG_SYNC(m_thd, "mdl_acquire_lock_wait");
+  DEBUG_SYNC(get_thd(), "mdl_acquire_lock_wait");
 
   find_deadlock();
 
@@ -1810,7 +1811,7 @@ MDL_context::acquire_lock(MDL_request *m
     while (cmp_timespec(abs_shortwait, abs_timeout) <= 0)
     {
       /* abs_timeout is far away. Wait a short while and notify locks. */
-      wait_status= m_wait.timed_wait(m_thd, &abs_shortwait, FALSE,
+      wait_status= m_wait.timed_wait(m_owner, &abs_shortwait, FALSE,
                                      mdl_request->key.get_wait_state_name());
 
       if (wait_status != MDL_wait::EMPTY)
@@ -1822,11 +1823,11 @@ MDL_context::acquire_lock(MDL_request *m
       set_timespec(abs_shortwait, 1);
     }
     if (wait_status == MDL_wait::EMPTY)
-      wait_status= m_wait.timed_wait(m_thd, &abs_timeout, TRUE,
+      wait_status= m_wait.timed_wait(m_owner, &abs_timeout, TRUE,
                                      mdl_request->key.get_wait_state_name());
   }
   else
-    wait_status= m_wait.timed_wait(m_thd, &abs_timeout, TRUE,
+    wait_status= m_wait.timed_wait(m_owner, &abs_timeout, TRUE,
                                    mdl_request->key.get_wait_state_name());
 
   done_waiting_for();

=== modified file 'sql/mdl.h'
--- a/sql/mdl.h	2010-11-22 11:20:49 +0000
+++ b/sql/mdl.h	2011-01-27 15:31:18 +0000
@@ -1,6 +1,6 @@
 #ifndef MDL_H
 #define MDL_H
-/* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -35,6 +35,41 @@ class MDL_context;
 class MDL_lock;
 class MDL_ticket;
 
+
+/**
+   An interface to separate the MDL module from the THD, and the rest of the
+   server code.
+ */
+
+class MDL_context_owner
+{
+public:
+  virtual ~MDL_context_owner() {}
+
+  /**
+     @see THD::enter_cond() and THD::exit_cond()
+   */
+  virtual const char* enter_cond(mysql_cond_t *cond, mysql_mutex_t* mutex,
+                                 const char* msg) = 0;
+  virtual void exit_cond(const char* old_msg) = 0;
+  /**
+     Has the owner thread been killed?
+   */
+  virtual int  is_killed() = 0;
+
+  /**
+     This one is only used for DEBUG_SYNC.
+     (Do not use it to peek/poke into other parts of THD.)
+   */
+  virtual THD* get_thd() = 0;
+
+  /**
+     @see THD::notify_shared_lock()
+   */
+  virtual bool notify_shared_lock(MDL_context_owner *in_use,
+                                  bool needs_thr_lock_abort) = 0;
+};
+
 /**
   Type of metadata lock request.
 
@@ -593,7 +628,8 @@ public:
   bool set_status(enum_wait_status result_arg);
   enum_wait_status get_status();
   void reset_status();
-  enum_wait_status timed_wait(THD *thd, struct timespec *abs_timeout,
+  enum_wait_status timed_wait(MDL_context_owner *owner,
+                              struct timespec *abs_timeout,
                               bool signal_timeout, const char *wait_state_name);
 private:
   /**
@@ -672,7 +708,7 @@ public:
   void release_transactional_locks();
   void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint);
 
-  inline THD *get_thd() const { return m_thd; }
+  MDL_context_owner *get_owner() { return m_owner; }
 
   /** @pre Only valid if we started waiting for lock. */
   inline uint get_deadlock_weight() const
@@ -685,7 +721,7 @@ public:
                     already has received some signal or closed
                     signal slot.
   */
-  void init(THD *thd_arg) { m_thd= thd_arg; }
+  void init(MDL_context_owner *arg) { m_owner= arg; }
 
   void set_needs_thr_lock_abort(bool needs_thr_lock_abort)
   {
@@ -765,7 +801,7 @@ private:
       involved schemas and global intention exclusive lock.
   */
   Ticket_list m_tickets[MDL_DURATION_END];
-  THD *m_thd;
+  MDL_context_owner *m_owner;
   /**
     TRUE -  if for this context we will break protocol and try to
             acquire table-level locks while having only S lock on
@@ -794,6 +830,7 @@ private:
    */
   MDL_wait_for_subgraph *m_waiting_for;
 private:
+  THD *get_thd() const { return m_owner->get_thd(); }
   MDL_ticket *find_ticket(MDL_request *mdl_req,
                           enum_mdl_duration *duration);
   void release_locks_stored_before(enum_mdl_duration duration, MDL_ticket *sentinel);
@@ -839,16 +876,6 @@ void mdl_init();
 void mdl_destroy();
 
 
-/*
-  Functions in the server's kernel used by metadata locking subsystem.
-*/
-
-extern bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
-                                                   bool needs_thr_lock_abort);
-extern "C" const char* thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond,
-                                      mysql_mutex_t *mutex, const char *msg);
-extern "C" void thd_exit_cond(MYSQL_THD thd, const char *old_msg);
-
 #ifndef DBUG_OFF
 extern mysql_mutex_t LOCK_open;
 #endif

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2011-01-11 11:45:02 +0000
+++ b/sql/sql_base.cc	2011-01-27 15:31:18 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -8667,72 +8667,6 @@ void tdc_flush_unused_tables()
 
 
 /**
-   A callback to the server internals that is used to address
-   special cases of the locking protocol.
-   Invoked when acquiring an exclusive lock, for each thread that
-   has a conflicting shared metadata lock.
-
-   This function:
-     - aborts waiting of the thread on a data lock, to make it notice
-       the pending exclusive lock and back off.
-     - if the thread is an INSERT DELAYED thread, sends it a KILL
-       signal to terminate it.
-
-   @note This function does not wait for the thread to give away its
-         locks. Waiting is done outside for all threads at once.
-
-   @param thd    Current thread context
-   @param in_use The thread to wake up
-   @param needs_thr_lock_abort Indicates that to wake up thread
-                               this call needs to abort its waiting
-                               on table-level lock.
-
-   @retval  TRUE  if the thread was woken up
-   @retval  FALSE otherwise.
-
-   @note It is one of two places where border between MDL and the
-         rest of the server is broken.
-*/
-
-bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
-                                            bool needs_thr_lock_abort)
-{
-  bool signalled= FALSE;
-  if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
-      !in_use->killed)
-  {
-    in_use->killed= THD::KILL_CONNECTION;
-    mysql_mutex_lock(&in_use->mysys_var->mutex);
-    if (in_use->mysys_var->current_cond)
-      mysql_cond_broadcast(in_use->mysys_var->current_cond);
-    mysql_mutex_unlock(&in_use->mysys_var->mutex);
-    signalled= TRUE;
-  }
-
-  if (needs_thr_lock_abort)
-  {
-    mysql_mutex_lock(&in_use->LOCK_thd_data);
-    for (TABLE *thd_table= in_use->open_tables;
-         thd_table ;
-         thd_table= thd_table->next)
-    {
-      /*
-        Check for TABLE::needs_reopen() is needed since in some places we call
-        handler::close() for table instance (and set TABLE::db_stat to 0)
-        and do not remove such instances from the THD::open_tables
-        for some time, during which other thread can see those instances
-        (e.g. see partitioning code).
-      */
-      if (!thd_table->needs_reopen())
-        signalled|= mysql_lock_abort_for_thread(thd, thd_table);
-    }
-    mysql_mutex_unlock(&in_use->LOCK_thd_data);
-  }
-  return signalled;
-}
-
-
-/**
    Remove all or some (depending on parameter) instances of TABLE and
    TABLE_SHARE from the table definition cache.
 

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2011-01-27 13:46:28 +0000
+++ b/sql/sql_class.cc	2011-01-27 15:31:18 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -58,6 +58,7 @@
 #include "debug_sync.h"
 #include "sql_parse.h"                          // is_update_query
 #include "sql_callback.h"
+#include "lock.h"
 
 /*
   The following is used to initialise Table_ident with a internal
@@ -1322,6 +1323,45 @@ void THD::disconnect()
 }
 
 
+bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use,
+                             bool needs_thr_lock_abort)
+{
+  THD *in_use= ctx_in_use->get_thd();
+  bool signalled= FALSE;
+  if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
+      !in_use->killed)
+  {
+    in_use->killed= THD::KILL_CONNECTION;
+    mysql_mutex_lock(&in_use->mysys_var->mutex);
+    if (in_use->mysys_var->current_cond)
+      mysql_cond_broadcast(in_use->mysys_var->current_cond);
+    mysql_mutex_unlock(&in_use->mysys_var->mutex);
+    signalled= TRUE;
+  }
+
+  if (needs_thr_lock_abort)
+  {
+    mysql_mutex_lock(&in_use->LOCK_thd_data);
+    for (TABLE *thd_table= in_use->open_tables;
+         thd_table ;
+         thd_table= thd_table->next)
+    {
+      /*
+        Check for TABLE::needs_reopen() is needed since in some places we call
+        handler::close() for table instance (and set TABLE::db_stat to 0)
+        and do not remove such instances from the THD::open_tables
+        for some time, during which other thread can see those instances
+        (e.g. see partitioning code).
+      */
+      if (!thd_table->needs_reopen())
+        signalled|= mysql_lock_abort_for_thread(this, thd_table);
+    }
+    mysql_mutex_unlock(&in_use->LOCK_thd_data);
+  }
+  return signalled;
+}
+
+
 /*
   Remember the location of thread info, the structure needed for
   sql_alloc() and the structure for the net buffer

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2010-12-29 00:38:59 +0000
+++ b/sql/sql_class.h	2011-01-27 15:31:18 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -1475,7 +1475,8 @@ extern "C" void my_message_sql(uint erro
 */
 
 class THD :public Statement,
-           public Open_tables_state
+           public Open_tables_state,
+           public MDL_context_owner
 {
 public:
   MDL_context mdl_context;
@@ -2287,6 +2288,8 @@ public:
                    int errcode);
 #endif
 
+  // Begin implementation of MDL_context_owner interface.
+
   /*
     For enter_cond() / exit_cond() to work the mutex must be got before
     enter_cond(); this mutex is then released by exit_cond().
@@ -2318,6 +2321,39 @@ public:
     mysql_mutex_unlock(&mysys_var->mutex);
     return;
   }
+
+  virtual int is_killed() { return killed; }
+  virtual THD* get_thd() { return this; }
+
+  /**
+    A callback to the server internals that is used to address
+    special cases of the locking protocol.
+    Invoked when acquiring an exclusive lock, for each thread that
+    has a conflicting shared metadata lock.
+
+    This function:
+    - aborts waiting of the thread on a data lock, to make it notice
+      the pending exclusive lock and back off.
+    - if the thread is an INSERT DELAYED thread, sends it a KILL
+      signal to terminate it.
+
+    @note This function does not wait for the thread to give away its
+          locks. Waiting is done outside for all threads at once.
+
+    @param ctx_in_use           The MDL context owner (thread) to wake up.
+    @param needs_thr_lock_abort Indicates that to wake up thread
+                                this call needs to abort its waiting
+                                on table-level lock.
+
+    @retval  TRUE  if the thread was woken up
+    @retval  FALSE otherwise.
+   */
+  virtual bool notify_shared_lock(MDL_context_owner *ctx_in_use,
+                                  bool needs_thr_lock_abort);
+
+  // End implementation of MDL_context_owner interface.
+
+
   inline time_t query_start() { query_start_used=1; return start_time; }
   inline void set_time()
   {

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2011-01-21 11:30:47 +0000
+++ b/sql/sql_insert.cc	2011-01-27 15:31:18 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -2242,7 +2242,7 @@ TABLE *Delayed_insert::get_local_table(T
         The thread could be killed with an error message if
         di->handle_inserts() or di->open_and_lock_table() fails.
         The thread could be killed without an error message if
-        killed using mysql_notify_thread_having_shared_lock() or
+        killed using THD::notify_shared_lock() or
         kill_delayed_threads_for_table().
       */
       if (!thd.is_error() || thd.stmt_da->sql_errno() == ER_SERVER_SHUTDOWN)

=== modified file 'unittest/gunit/mdl-t.cc'
--- a/unittest/gunit/mdl-t.cc	2010-12-23 11:03:09 +0000
+++ b/unittest/gunit/mdl-t.cc	2011-01-27 15:31:18 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009 Sun Microsystems, Inc.
+/* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -15,9 +15,9 @@
 
 /**
    This is a unit test for the 'meta data locking' classes.
-   It is written to illustrate how we can use googletest for unit testing
+   It is written to illustrate how we can use Google Test for unit testing
    of MySQL code.
-   For documentation on googletest, see http://code.google.com/p/googletest/
+   For documentation on Google Test, see http://code.google.com/p/googletest/
    and the contained wiki pages GoogleTestPrimer and GoogleTestAdvancedGuide.
    The code below should hopefully be (mostly) self-explanatory.
  */
@@ -32,32 +32,13 @@
 
 #include "thr_malloc.h"
 #include "thread_utils.h"
+#include "test_mdl_context_owner.h"
 
 pthread_key(MEM_ROOT**,THR_MALLOC);
 pthread_key(THD*, THR_THD);
 mysql_mutex_t LOCK_open;
 uint    opt_debug_sync_timeout= 0;
 
-static mysql_mutex_t *current_mutex= NULL;
-extern "C"
-const char* thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond,
-                           mysql_mutex_t *mutex, const char *msg)
-{
-  current_mutex= mutex;
-  return NULL;
-}
-
-extern "C"
-void thd_exit_cond(MYSQL_THD thd, const char *old_msg)
-{
-  mysql_mutex_unlock(current_mutex);
-}
-
-extern "C" int thd_killed(const MYSQL_THD thd)
-{
-  return 0;
-}
-
 /*
   A mock error handler.
 */
@@ -76,50 +57,6 @@ extern "C" void sql_alloc_error_handler(
   ADD_FAILURE();
 }
 
-namespace {
-bool notify_thread(THD*);
-}
-
-/*
-  We need to mock away this global function, because the real version
-  pulls in a lot of dependencies.
-  (The @note for the real version of this function indicates that the
-  coupling between THD and MDL is too tight.)
-   @retval  TRUE  if the thread was woken up
-   @retval  FALSE otherwise.
-*/
-bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
-                                            bool needs_thr_lock_abort)
-{
-  if (in_use != NULL)
-    return notify_thread(in_use);
-  return FALSE;
-}
-
-/*
-  Mock away this function as well, with an empty function.
-  @todo didrik: Consider verifying that the MDL module actually calls
-  this with correct arguments.
-*/
-void mysql_ha_flush(THD *)
-{
-  DBUG_PRINT("mysql_ha_flush", ("mock version"));
-}
-
-/*
-  We need to mock away this global function, the real version pulls in
-  too many dependencies.
- */
-extern "C" const char *set_thd_proc_info(void *thd, const char *info,
-                                         const char *calling_function,
-                                         const char *calling_file,
-                                         const unsigned int calling_line)
-{
-  DBUG_PRINT("proc_info", ("%s:%d  %s", calling_file, calling_line,
-                           (info != NULL) ? info : "(null)"));
-  return info;
-}
-
 /*
   Mock away this global function.
   We don't need DEBUG_SYNC functionality in a unit test.
@@ -148,12 +85,11 @@ const ulong zero_timeout= 0;
 const ulong long_timeout= (ulong) 3600L*24L*365L;
 
 
-class MDLTest : public ::testing::Test
+class MDLTest : public ::testing::Test, public Test_MDL_context_owner
 {
 protected:
   MDLTest()
-  : m_thd(NULL),
-    m_null_ticket(NULL),
+  : m_null_ticket(NULL),
     m_null_request(NULL)
   {
   }
@@ -167,7 +103,7 @@ protected:
   {
     expected_error= 0;
     mdl_init();
-    m_mdl_context.init(m_thd);
+    m_mdl_context.init(this);
     EXPECT_FALSE(m_mdl_context.has_locks());
     m_global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
                           MDL_TRANSACTION);
@@ -179,10 +115,15 @@ protected:
     mdl_destroy();
   }
 
+  virtual bool notify_shared_lock(MDL_context_owner *in_use,
+                                  bool needs_thr_lock_abort)
+  {
+    return in_use->notify_shared_lock(NULL, needs_thr_lock_abort);
+  }
+
   // A utility member for testing single lock requests.
   void test_one_simple_shared_lock(enum_mdl_type lock_type);
 
-  THD               *m_thd;
   const MDL_ticket  *m_null_ticket;
   const MDL_request *m_null_request;
   MDL_context        m_mdl_context;
@@ -199,7 +140,7 @@ private:
   The two notifications are for synchronizing with the main thread.
   Does *not* take ownership of the notifications.
 */
-class MDL_thread : public Thread
+class MDL_thread : public Thread, public Test_MDL_context_owner
 {
 public:
   MDL_thread(const char   *table_name,
@@ -212,8 +153,7 @@ public:
     m_release_locks(release_locks),
     m_ignore_notify(false)
   {
-    m_thd= reinterpret_cast<THD*>(this);    // See notify_thread below.
-    m_mdl_context.init(m_thd);
+    m_mdl_context.init(this);
   }
 
   ~MDL_thread()
@@ -224,8 +164,12 @@ public:
   virtual void run();
   void ignore_notify() { m_ignore_notify= true; }
 
-  bool notify()
+  virtual bool notify_shared_lock(MDL_context_owner *in_use,
+                                  bool needs_thr_lock_abort)
   {
+    if (in_use)
+      return in_use->notify_shared_lock(NULL, needs_thr_lock_abort);
+
     if (m_ignore_notify)
       return false;
     m_release_locks->notify();
@@ -238,19 +182,10 @@ private:
   Notification  *m_lock_grabbed;
   Notification  *m_release_locks;
   bool           m_ignore_notify;
-  THD           *m_thd;
   MDL_context    m_mdl_context;
 };
 
 
-// Admittedly an ugly hack, to avoid pulling in the THD in this unit test.
-bool notify_thread(THD *thd)
-{
-  MDL_thread *thread = (MDL_thread*) thd;
-  return thread->notify();
-}
-
-
 void MDL_thread::run()
 {
   MDL_request request;
@@ -277,7 +212,7 @@ void MDL_thread::run()
   m_mdl_context.release_transactional_locks();
 }
 
-// googletest recommends DeathTest suffix for classes use in death tests.
+// Google Test recommends DeathTest suffix for classes use in death tests.
 typedef MDLTest MDLDeathTest;
 
 
@@ -438,9 +373,8 @@ TEST_F(MDLTest, TwoShared)
  */
 TEST_F(MDLTest, SharedLocksBetweenContexts)
 {
-  THD         *thd2= (THD*) this;
   MDL_context  mdl_context2;
-  mdl_context2.init(thd2);
+  mdl_context2.init(this);
   MDL_request request_2;
   m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED,
                  MDL_TRANSACTION);

=== modified file 'unittest/gunit/mdl_mytap-t.cc'
--- a/unittest/gunit/mdl_mytap-t.cc	2010-12-23 11:03:09 +0000
+++ b/unittest/gunit/mdl_mytap-t.cc	2011-01-27 15:31:18 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009 Sun Microsystems, Inc.
+/* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -14,9 +14,9 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
 /**
-   This is a port of the corresponding mdl_test.cc (written for googletest)
+   This is a port of the corresponding mdl_test.cc (written for Google Test)
    to mytap. Do a 'tkdiff mdl-t.cc mdl_mytap-t.cc' to see the differences.
-   In order to illustrate (some of) the features of googletest, I have
+   In order to illustrate (some of) the features of Google Test, I have
    added some extensions below, notably support for reporting of line
    numbers in case of failures.
  */
@@ -35,34 +35,14 @@
 
 #include "thr_malloc.h"
 #include "thread_utils.h"
+#include "test_mdl_context_owner.h"
 
 pthread_key(MEM_ROOT**,THR_MALLOC);
 pthread_key(THD*, THR_THD);
 mysql_mutex_t LOCK_open;
 uint    opt_debug_sync_timeout= 0;
 
-static mysql_mutex_t *current_mutex= NULL;
-extern "C"
-const char* thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond,
-                           mysql_mutex_t *mutex, const char *msg)
-{
-  current_mutex= mutex;
-  return NULL;
-}
-
-extern "C"
-void thd_exit_cond(MYSQL_THD thd, const char *old_msg)
-{
-  mysql_mutex_unlock(current_mutex);
-}
-
-extern "C" int thd_killed(const MYSQL_THD thd)
-{
-  return 0;
-}
-
-
-// Reimplemented some macros from googletest, so that the tests below
+// Reimplemented some macros from Google Test, so that the tests below
 // could be kept unchanged.  No support for streaming of user messages
 // in this simplified version.
 void print_message(const char* file, int line, const char* message)
@@ -132,50 +112,6 @@ extern "C" void sql_alloc_error_handler(
   FAIL();
 }
 
-namespace {
-bool notify_thread(THD*);
-}
-
-/*
-  We need to mock away this global function, because the real version
-  pulls in a lot of dependencies.
-  (The @note for the real version of this function indicates that the
-  coupling between THD and MDL is too tight.)
-   @retval  TRUE  if the thread was woken up
-   @retval  FALSE otherwise.
-*/
-bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
-                                            bool needs_thr_lock_abort)
-{
-  if (in_use != NULL)
-    return notify_thread(in_use);
-  return FALSE;
-}
-
-/*
-  Mock away this function as well, with an empty function.
-  @todo didrik: Consider verifying that the MDL module actually calls
-  this with correct arguments.
-*/
-void mysql_ha_flush(THD *)
-{
-  DBUG_PRINT("mysql_ha_flush", ("mock version"));
-}
-
-/*
-  We need to mock away this global function, the real version pulls in
-  too many dependencies.
- */
-extern "C" const char *set_thd_proc_info(void *thd, const char *info,
-                                         const char *calling_function,
-                                         const char *calling_file,
-                                         const unsigned int calling_line)
-{
-  DBUG_PRINT("proc_info", ("%s:%d  %s", calling_file, calling_line,
-                           (info != NULL) ? info : "(null)"));
-  return info;
-}
-
 /*
   Mock away this global function.
   We don't need DEBUG_SYNC functionality in a unit test.
@@ -204,7 +140,7 @@ const ulong zero_timeout= 0;
 const ulong long_timeout= (ulong) 3600L*24L*365L;
 
 
-class MDLTest
+class MDLTest : public Test_MDL_context_owner
 {
 public:
   // Utility function to run one test case.
@@ -216,8 +152,7 @@ public:
 
 protected:
   MDLTest()
-  : m_thd(NULL),
-    m_null_ticket(NULL),
+  : m_null_ticket(NULL),
     m_null_request(NULL)
   {
   }
@@ -231,7 +166,7 @@ protected:
   {
     expected_error= 0;
     mdl_init();
-    m_mdl_context.init(m_thd);
+    m_mdl_context.init(this);
     EXPECT_FALSE(m_mdl_context.has_locks());
     m_global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
                           MDL_TRANSACTION);
@@ -243,6 +178,12 @@ protected:
     mdl_destroy();
   }
 
+  virtual bool notify_shared_lock(MDL_context_owner *in_use,
+                                  bool needs_thr_lock_abort)
+  {
+    return in_use->notify_shared_lock(NULL, needs_thr_lock_abort);
+  }
+
   // A utility member for testing single lock requests.
   void test_one_simple_shared_lock(enum_mdl_type lock_type);
 
@@ -265,7 +206,6 @@ protected:
   void ConcurrentExclusiveShared();
   void ConcurrentUpgrade();
 
-  THD               *m_thd;
   const MDL_ticket  *m_null_ticket;
   const MDL_request *m_null_request;
   MDL_context        m_mdl_context;
@@ -282,7 +222,7 @@ private:
   The two notifications are for synchronizing with the main thread.
   Does *not* take ownership of the notifications.
 */
-class MDL_thread : public Thread
+class MDL_thread : public Thread, public Test_MDL_context_owner
 {
 public:
   MDL_thread(const char   *table_name,
@@ -295,8 +235,7 @@ public:
     m_release_locks(release_locks),
     m_ignore_notify(false)
   {
-    m_thd= reinterpret_cast<THD*>(this);    // See notify_thread below.
-    m_mdl_context.init(m_thd);
+    m_mdl_context.init(this);
   }
 
   ~MDL_thread()
@@ -307,8 +246,12 @@ public:
   virtual void run();
   void ignore_notify() { m_ignore_notify= true; }
 
-  bool notify()
+  virtual bool notify_shared_lock(MDL_context_owner *in_use,
+                                  bool needs_thr_lock_abort)
   {
+    if (in_use)
+      return in_use->notify_shared_lock(NULL, needs_thr_lock_abort);
+
     if (m_ignore_notify)
       return false;
     m_release_locks->notify();
@@ -321,19 +264,10 @@ private:
   Notification  *m_lock_grabbed;
   Notification  *m_release_locks;
   bool           m_ignore_notify;
-  THD           *m_thd;
   MDL_context    m_mdl_context;
 };
 
 
-// Admittedly an ugly hack, to avoid pulling in the THD in this unit test.
-bool notify_thread(THD *thd)
-{
-  MDL_thread *thread = (MDL_thread*) thd;
-  return thread->notify();
-}
-
-
 void MDL_thread::run()
 {
   MDL_request request;
@@ -360,7 +294,7 @@ void MDL_thread::run()
   m_mdl_context.release_transactional_locks();
 }
 
-// googletest recommends DeathTest suffix for classes use in death tests.
+// Google Test recommends DeathTest suffix for classes use in death tests.
 typedef MDLTest MDLDeathTest;
 
 // Our own (simplified) version of the TEST_F macro.
@@ -506,9 +440,8 @@ TEST_F(MDLTest, TwoShared)
  */
 TEST_F(MDLTest, SharedLocksBetweenContexts)
 {
-  THD         *thd2= (THD*) this;
   MDL_context  mdl_context2;
-  mdl_context2.init(thd2);
+  mdl_context2.init(this);
   MDL_request request_2;
   m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED,
                  MDL_TRANSACTION);

=== added file 'unittest/gunit/test_mdl_context_owner.h'
--- a/unittest/gunit/test_mdl_context_owner.h	1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/test_mdl_context_owner.h	2011-01-27 15:31:18 +0000
@@ -0,0 +1,48 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef TEST_MDL_CONTEXT_OWNER_INCLUDED
+#define TEST_MDL_CONTEXT_OWNER_INCLUDED
+
+#include <mdl.h>
+#include <my_pthread.h>
+
+class Test_MDL_context_owner : public MDL_context_owner
+{
+public:
+  Test_MDL_context_owner()
+    : m_current_mutex(NULL)
+  {}
+  virtual const char* enter_cond(mysql_cond_t *cond,
+                                 mysql_mutex_t* mutex,
+                                 const char* msg)
+  {
+    m_current_mutex= mutex;
+    return NULL;
+  }
+
+  virtual void exit_cond(const char* old_msg)
+  {
+    mysql_mutex_unlock(m_current_mutex);
+  }
+
+  virtual int  is_killed() { return 0; }
+  virtual THD* get_thd()   { return NULL; }
+
+private:
+  mysql_mutex_t *m_current_mutex;
+};
+
+#endif  // TEST_MDL_CONTEXT_OWNER_INCLUDED

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (tor.didriksen:3561 to 3562) Bug#59309Tor Didriksen27 Jan