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

 3465 Tor Didriksen	2011-01-06
      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
        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
=== modified file 'sql/mdl.cc'
--- a/sql/mdl.cc	2010-11-19 12:34:44 +0000
+++ b/sql/mdl.cc	2011-01-06 13:03:07 +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-06 13:03:07 +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 interface 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 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 +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,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 +717,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 +797,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 +826,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 +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-06 13:03:07 +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
@@ -8662,72 +8662,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	2010-12-17 16:14:15 +0000
+++ b/sql/sql_class.cc	2011-01-06 13:03:07 +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
@@ -1321,6 +1322,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-06 13:03:07 +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 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.
+   */
+  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	2010-12-22 13:23:59 +0000
+++ b/sql/sql_insert.cc	2011-01-06 13:03:07 +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
@@ -2239,7 +2239,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-06 13:03:07 +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-06 13:03:07 +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-06 13:03:07 +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-20110106130307-c5n7eif98dkr0slv.bundle
Thread
bzr commit into mysql-trunk branch (tor.didriksen:3465) Bug#59309Tor Didriksen6 Jan
  • Re: bzr commit into mysql-trunk branch (tor.didriksen:3465) Bug#59309Jon Olav Hauglid6 Jan