#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