List:Commits« Previous MessageNext Message »
From:Tor Didriksen Date:January 5 2011 2:51pm
Subject:bzr commit into mysql-trunk branch (tor.didriksen:3462) Bug#59309
View as plain text  
#At file:///export/home/didrik/repo/trunk-bug59309-gtest-thd/ based on revid:georgi.kodinov@stripped

 3462 Tor Didriksen	2011-01-05
      Bug #59309  Cleanup MDL - THD interface 
      
      Define an abstract interface MDL_context_owner
      which is implemented by THD and the unit test classes.
     @ 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
        Remove note about broken interface.
     @ sql/sql_class.h
        THD now implements the MDL_context_owner interface.
     @ 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.h
      unittest/gunit/mdl-t.cc
      unittest/gunit/mdl_mytap-t.cc
=== modified file 'sql/mdl.cc'
--- a/sql/mdl.cc	2010-11-19 12:34:44 +0000
+++ b/sql/mdl.cc	2011-01-05 14:51: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;
 }
@@ -1690,15 +1691,16 @@ void MDL_object_lock::notify_conflicting
 
     {
       MDL_context *conflicting_ctx= conflicting_ticket->get_ctx();
+      MDL_context_owner *conflicting_owner= conflicting_ctx->get_owner();
 
       /*
         If thread which holds conflicting lock is waiting on table-level
         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_owner,
+                           conflicting_ctx->get_needs_thr_lock_abort());
     }
   }
 }
@@ -1722,15 +1724,16 @@ void MDL_scoped_lock::notify_conflicting
 
     {
       MDL_context *conflicting_ctx= conflicting_ticket->get_ctx();
+      MDL_context_owner *conflicting_owner= conflicting_ctx->get_owner();
 
       /*
         Thread which holds global IX lock can be a handler thread for
         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_owner,
+                           conflicting_ctx->get_needs_thr_lock_abort());
     }
   }
 }
@@ -1797,7 +1800,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 +1813,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 +1825,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-05 14:51: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,37 @@ class MDL_context;
 class MDL_lock;
 class MDL_ticket;
 
+
+/**
+   An iterface to separate the MDL classes from the THD,
+   so that we can do unit testing.
+ */
+
+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;
+
+  virtual THD* get_thd() = 0;
+
+  /**
+     @see mysql_notify_thread_having_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 +624,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 +704,8 @@ public:
   void release_transactional_locks();
   void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint);
 
-  inline THD *get_thd() const { return m_thd; }
+  THD *get_thd() const { return m_owner->get_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 +718,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 +798,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
@@ -839,16 +872,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	2010-12-29 00:38:59 +0000
+++ b/sql/sql_base.cc	2011-01-05 14:51:18 +0000
@@ -8684,9 +8684,6 @@ void tdc_flush_unused_tables()
 
    @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,

=== 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-05 14:51: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
@@ -1468,6 +1468,8 @@ private:
 
 extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
 
+extern bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
+                                                   bool needs_thr_lock_abort);
 /**
   @class THD
   For each client connection we create a separate thread with THD serving as
@@ -1475,7 +1477,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;
@@ -2091,6 +2094,8 @@ public:
   };
   killed_state volatile killed;
 
+  int is_killed() { return killed; }
+
   /* scramble - random string sent to client on handshake */
   char	     scramble[SCRAMBLE_LENGTH+1];
 
@@ -2318,6 +2323,16 @@ public:
     mysql_mutex_unlock(&mysys_var->mutex);
     return;
   }
+  THD* get_thd() { return this; }
+  bool notify_shared_lock(MDL_context_owner *in_use,
+                          bool needs_thr_lock_abort)
+  {
+    return
+      mysql_notify_thread_having_shared_lock(get_thd(),
+                                             in_use->get_thd(),
+                                             needs_thr_lock_abort);
+  }
+
   inline time_t query_start() { query_start_used=1; return start_time; }
   inline void set_time()
   {

=== 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-05 14:51: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-05 14:51: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-05 14:51: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


Attachment: [text/bzr-bundle] bzr/tor.didriksen@oracle.com-20110105145118-888336cpz8o9j5xv.bundle
Thread
bzr commit into mysql-trunk branch (tor.didriksen:3462) Bug#59309Tor Didriksen5 Jan
  • Re: bzr commit into mysql-trunk branch (tor.didriksen:3462) Bug#59309Jon Olav Hauglid6 Jan
    • Re: bzr commit into mysql-trunk branch (tor.didriksen:3462) Bug#59309Tor Didriksen6 Jan