#At file:///export/home/didrik/repo/trunk-bug59309-gtest-thd/ based on revid:vasil.dimov@stripped
3471 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 14:30:37 +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 14:30:37 +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 14:30:37 +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 14:30:37 +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 14:30:37 +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 2010-12-22 13:23:59 +0000
+++ b/sql/sql_insert.cc 2011-01-06 14:30:37 +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 14:30:37 +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 14:30:37 +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 14:30:37 +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-20110106143037-p7olr0btbt9zmnu3.bundle
| Thread |
|---|
| • bzr commit into mysql-trunk branch (tor.didriksen:3471) Bug#59309 | Tor Didriksen | 10 Jan |