diff options
author | Dmitry Lenev <dlenev@mysql.com> | 2010-01-21 23:43:03 +0300 |
---|---|---|
committer | Dmitry Lenev <dlenev@mysql.com> | 2010-01-21 23:43:03 +0300 |
commit | 6ddd01c27ab55242f8643e7efdd5f7bc9230a908 (patch) | |
tree | a808065b1c90ad675cd5e9f6c5dee65eedae7a56 /sql/mdl.h | |
parent | 661fd506a3bf3d195db6dc0b718821ea1ca41e3a (diff) | |
download | mariadb-git-6ddd01c27ab55242f8643e7efdd5f7bc9230a908.tar.gz |
Patch that changes metadata locking subsystem to use mutex per lock and
condition variable per context instead of one mutex and one conditional
variable for the whole subsystem.
This should increase concurrency in this subsystem.
It also opens the way for further changes which are necessary to solve
such bugs as bug #46272 "MySQL 5.4.4, new MDL: unnecessary deadlock"
and bug #37346 "innodb does not detect deadlock between update and alter
table".
Two other notable changes done by this patch:
- MDL subsystem no longer implicitly acquires global intention exclusive
metadata lock when per-object metadata lock is acquired. Now this has
to be done by explicit calls outside of MDL subsystem.
- Instead of using separate MDL_context for opening system tables/tables
for purposes of I_S we now create MDL savepoint in the main context
before opening tables and rollback to this savepoint after closing
them. This means that it is now possible to get ER_LOCK_DEADLOCK error
even not inside a transaction. This might happen in unlikely case when
one runs DDL on one of system tables while also running DDL on some
other tables. Cases when this ER_LOCK_DEADLOCK error is not justified
will be addressed by advanced deadlock detector for MDL subsystem which
we plan to implement.
mysql-test/include/handler.inc:
Adjusted handler_myisam.test and handler_innodb.test to the fact that
exclusive metadata locks on tables are now acquired according to
alphabetical order of fully qualified table names instead of order
in which tables are mentioned in statement.
mysql-test/r/handler_innodb.result:
Adjusted handler_myisam.test and handler_innodb.test to the fact that
exclusive metadata locks on tables are now acquired according to
alphabetical order of fully qualified table names instead of order
in which tables are mentioned in statement.
mysql-test/r/handler_myisam.result:
Adjusted handler_myisam.test and handler_innodb.test to the fact that
exclusive metadata locks on tables are now acquired according to
alphabetical order of fully qualified table names instead of order
in which tables are mentioned in statement.
mysql-test/r/mdl_sync.result:
Adjusted mdl_sync.test to the fact that exclusive metadata locks on
tables are now acquired according to alphabetical order of fully
qualified table names instead of order in which tables are mentioned
in statement.
mysql-test/t/mdl_sync.test:
Adjusted mdl_sync.test to the fact that exclusive metadata locks on
tables are now acquired according to alphabetical order of fully
qualified table names instead of order in which tables are mentioned
in statement.
sql/events.cc:
Instead of using separate MDL_context for opening system tables we now
create MDL savepoint in the main context before opening such tables
and rollback to this savepoint after closing them. To support this
change methods of THD responsible for saving/restoring open table
state were changed to use Open_tables_backup class which in addition
to Open_table_state has a member for this savepoint. As result code
opening/closing system tables was changed to use Open_tables_backup
instead of Open_table_state class as well.
sql/ha_ndbcluster.cc:
Since manipulations with open table state no longer install proxy
MDL_context it does not make sense to perform them in order to
satisfy assert in mysql_rm_tables_part2(). Removed them per agreement
with Cluster team. This has not broken test suite since scenario in
which deadlock can occur and assertion fails is not covered by tests.
sql/lock.cc:
MDL subsystem no longer implicitly acquires global intention exclusive
metadata lock when per-object exclusive metadata lock is acquired.
Now this has to be done by explicit calls outside of MDL subsystem.
sql/log.cc:
Instead of using separate MDL_context for opening system tables we now
create MDL savepoint in the main context before opening such tables
and rollback to this savepoint after closing them. To support this
change methods of THD responsible for saving/restoring open table
state were changed to use Open_tables_backup class which in addition
to Open_table_state has a member for this savepoint. As result code
opening/closing system tables was changed to use Open_tables_backup
instead of Open_table_state class as well.
sql/mdl.cc:
Changed metadata locking subsystem to use mutex per lock and condition
variable per context instead of one mutex and one conditional variable
for the whole subsystem.
Changed approach to handling of global metadata locks. Instead of
implicitly acquiring intention exclusive locks when user requests
per-object upgradeable or exclusive locks now we require them to be
acquired explicitly in the same way as ordinary metadata locks.
In fact global lock are now ordinary metadata locks in new GLOBAL
namespace.
To implement these changes:
- Removed LOCK_mdl mutex and COND_mdl condition variable.
- Introduced MDL_lock::m_mutex mutexes which protect individual lock
objects.
- Replaced mdl_locks hash with MDL_map class, which has hash for
MDL_lock objects as a member and separate mutex which protects this
hash. Methods of this class allow to find(), find_or_create() or
remove() MDL_lock objects in concurrency-friendly fashion (i.e.
for most common operation, find_or_create(), we don't acquire
MDL_lock::m_mutex while holding MDL_map::m_mutex. Thanks to MikaelR
for this idea and benchmarks!). Added three auxiliary members to
MDL_lock class (m_is_destroyed, m_ref_usage, m_ref_release) to
support this concurrency-friendly behavior.
- Introduced MDL_context::m_ctx_wakeup_cond condition variable to be
used for waiting until this context's pending request can be
satisfied or its thread has to perform actions to resolve potential
deadlock. Context which want to wait add ticket corresponding to the
request to an appropriate queue of waiters in MDL_lock object so
they can be noticed when other contexts change state of lock and be
awaken by them by signalling on MDL_context::m_ctx_wakeup_cond.
As consequence MDL_ticket objects has to be used for any waiting
in metadata locking subsystem including one which happens in
MDL_context::wait_for_locks() method.
Another consequence is that MDL_context is no longer copyable and
can't be saved/restored when working with system tables.
- Made MDL_lock an abstract class, which delegates specifying exact
compatibility matrix to its descendants. Added MDL_global_lock child
class for global lock (The old is_lock_type_compatible() method
became can_grant_lock() method of this class). Added MDL_object_lock
class to represent per-object lock (The old MDL_lock::can_grant_lock()
became its method). Choice between two classes happens based on MDL
namespace in MDL_lock::create() method.
- Got rid of MDL_lock::type member as its meaning became ambigous for
global locks.
- To simplify waking up of contexts waiting for lock split waiting queue
in MDL_lock class in two queues. One for pending requests for exclusive
(including intention exclusive) locks and another for requests for
shared locks.
- Added virtual wake_up_waiters() method to MDL_lock, MDL_global_lock and
MDL_object_lock classes which allows to wake up waiting contexts after
state of lock changes. Replaced old duplicated code with calls to this
method.
- Adjusted MDL_context::try_acquire_shared_lock()/exclusive_lock()/
global_shared_lock(), MDL_ticket::upgrade_shared_lock_to_exclusive_lock()
and MDL_context::release_ticket() methods to use MDL_map and
MDL_lock::m_mutex instead of single LOCK_mdl mutex and wake up
waiters according to the approach described above. The latter method
also was renamed to MDL_context::release_lock().
- Changed MDL_context::try_acquire_shared_lock()/exclusive_lock() and
release_lock() not to handle global locks. They are now supposed to
be taken explicitly like ordinary metadata locks.
- Added helper MDL_context::try_acquire_global_intention_exclusive_lock()
and acquire_global_intention_exclusive_lock() methods.
- Moved common code from MDL_context::acquire_global_shared_lock() and
acquire_global_intention_exclusive_lock() to new method -
MDL_context::acquire_lock_impl().
- Moved common code from MDL_context::try_acquire_shared_lock(),
try_acquire_global_intention_exclusive_lock()/exclusive_lock()
to MDL_context::try_acquire_lock_impl().
- Since acquiring of several exclusive locks can no longer happen under
single LOCK_mdl mutex the approach to it had to be changed. Now we do
it in one by one fashion. This is done in alphabetical order to avoid
deadlocks. Changed MDL_context::acquire_exclusive_locks() accordingly
(as part of this change moved code responsible for acquiring single
exclusive lock to new MDL_context::acquire_exclusive_lock_impl()
method).
- Since we no longer have single LOCK_mdl mutex which protects all
MDL_context::m_is_waiting_in_mdl members using these members to
determine if we have really awaken context holding conflicting
shared lock became inconvinient. Got rid of this member and changed
notify_shared_lock() helper function and process of acquiring
of/upgrading to exclusive lock not to rely on such information.
Now in MDL_context::acquire_exclusive_lock_impl() and
MDL_ticket::upgrade_shared_lock_to_exclusive_lock() we simply
re-try to wake up threads holding conflicting shared locks after
small time out.
- Adjusted MDL_context::can_wait_lead_to_deadlock() and
MDL_ticket::has_pending_conflicting_lock() to use per-lock
mutexes instead of LOCK_mdl. To do this introduced
MDL_lock::has_pending_exclusive_lock() method.
sql/mdl.h:
Changed metadata locking subsystem to use mutex per lock and condition
variable per context instead of one mutex and one conditional variable
for the whole subsystem. In order to implement this change:
- Added MDL_key::cmp() method to be able to sort MDL_key objects
alphabetically. Changed length fields in MDL_key class to uint16
as 16-bit is enough for length of any key.
- Changed MDL_ticket::get_ctx() to return pointer to non-const
object in order to be able to use MDL_context::awake() method
for such contexts.
- Got rid of unlocked versions of can_wait_lead_to_deadlock()/
has_pending_conflicting_lock() methods in MDL_context and
MDL_ticket. We no longer has single mutex which protects all
locks. Thus one always has to use versions of these methods
which acquire per-lock mutexes.
- MDL_request_list type of list now counts its elements.
- Added MDL_context::m_ctx_wakeup_cond condition variable to be used
for waiting until this context's pending request can be satisfied
or its thread has to perform actions to resolve potential deadlock.
Added awake() method to wake up context from such wait.
Addition of condition variable made MDL_context uncopyable.
As result we no longer can save/restore MDL_context when working
with system tables. Instead we create MDL savepoint before opening
those tables and rollback to it once they are closed.
- MDL_context::release_ticket() became release_lock() method.
- Added auxiliary MDL_context::acquire_exclusive_lock_impl() method
which does all necessary work to acquire exclusive lock on one object
but should not be used directly as it does not enforce any asserts
ensuring that no deadlocks are possible.
- Since we no longer need to know if thread trying to acquire exclusive
lock managed to wake up any threads having conflicting shared locks
(as, anyway, we will try to wake up such threads again shortly)
- MDL_context::m_is_waiting_in_mdl member became unnecessary and
notify_shared_lock() no longer needs to be friend of MDL_context.
Changed approach to handling of global metadata locks. Instead of
implicitly acquiring intention exclusive locks when user requests
per-object upgradeable or exclusive locks now we require them to be
acquired explicitly in the same way as ordinary metadata locks.
- Added new GLOBAL namespace for such locks.
- Added new type of lock to be requested MDL_INTENTION_EXCLISIVE.
- Added MDL_context::try_acquire_global_intention_exclusive_lock()
and acquire_global_intention_exclusive_lock() methods.
- Moved common code from MDL_context::acquire_global_shared_lock()
and acquire_global_intention_exclusive_lock() to new method -
MDL_context::acquire_lock_impl().
- Moved common code from MDL_context::try_acquire_shared_lock(),
try_acquire_global_intention_exclusive_lock()/exclusive_lock()
to MDL_context::try_acquire_lock_impl().
- Added helper MDL_context::is_global_lock_owner() method to be
able easily to find what kind of global lock this context holds.
- MDL_context::m_has_global_shared_lock became unnecessary as
global read lock is now represented by ordinary ticket.
- Removed assert in MDL_context::set_lt_or_ha_sentinel() which became
false for cases when we execute LOCK TABLES under global read lock
mode.
sql/mysql_priv.h:
Instead of using separate MDL_context for opening system tables we now
create MDL savepoint in the main context before opening such tables
and rollback to this savepoint after closing them. To support this
change methods of THD responsible for saving/restoring open table
state were changed to use Open_tables_backup class which in addition
to Open_table_state has a member for this savepoint. As result calls
opening/closing system tables were changed to use Open_tables_backup
instead of Open_table_state class as well.
sql/sp.cc:
Instead of using separate MDL_context for opening system tables we now
create MDL savepoint in the main context before opening such tables
and rollback to this savepoint after closing them. To support this
change methods of THD responsible for saving/restoring open table
state were changed to use Open_tables_backup class which in addition
to Open_table_state has a member for this savepoint. As result code
opening/closing system tables was changed to use Open_tables_backup
instead of Open_table_state class as well.
sql/sp.h:
Instead of using separate MDL_context for opening system tables we now
create MDL savepoint in the main context before opening such tables
and rollback to this savepoint after closing them. To support this
change methods of THD responsible for saving/restoring open table
state were changed to use Open_tables_backup class which in addition
to Open_table_state has a member for this savepoint. As result code
opening/closing system tables was changed to use Open_tables_backup
instead of Open_table_state class as well.
sql/sql_base.cc:
close_thread_tables():
Since we no longer use separate MDL_context for opening system
tables we need to avoid releasing all transaction locks when
closing system table. Releasing metadata lock on system table
is now responsibility of THD::restore_backup_open_tables_state().
open_table_get_mdl_lock(),
Open_table_context::recover_from_failed_open():
MDL subsystem no longer implicitly acquires global intention exclusive
metadata lock when per-object upgradable or exclusive metadata lock is
acquired. So this have to be done explicitly from these calls.
Changed Open_table_context class to store MDL_request object for
global intention exclusive lock acquired when opening tables.
open_table():
Do not release metadata lock if we have failed to open table as
this lock might have been acquired by one of previous statements
in transaction, and therefore should not be released.
open_system_tables_for_read()/close_system_tables()/
open_performance_schema_table():
Instead of using separate MDL_context for opening system tables we now
create MDL savepoint in the main context before opening such tables
and rollback to this savepoint after closing them. To support this
change methods of THD responsible for saving/restoring open table
state were changed to use Open_tables_backup class which in addition
to Open_table_state has a member for this savepoint. As result code
opening/closing system tables was changed to use Open_tables_backup
instead of Open_table_state class as well.
close_performance_schema_table():
Got rid of duplicated code.
sql/sql_class.cc:
Instead of using separate MDL_context for opening system tables we now
create MDL savepoint in the main context before opening such tables
and rollback to this savepoint after closing them. To support this
change methods of THD responsible for saving/restoring open table
state were changed to use Open_tables_backup class which in addition
to Open_table_state has a member for this savepoint. Also releasing
metadata lock on system table is now responsibility of
THD::restore_backup_open_tables_state().
Adjusted assert in THD::cleanup() to take into account fact that now
we also use MDL sentinel for global read lock.
sql/sql_class.h:
Instead of using separate MDL_context for opening system tables we now
create MDL savepoint in the main context before opening such tables
and rollback to this savepoint after closing them. As result:
- 'mdl_context' member was moved out of Open_tables_state to THD class.
enter_locked_tables_mode()/leave_locked_tables_mode() had to follow.
- Methods of THD responsible for saving/restoring open table state were
changed to use Open_tables_backup class which in addition to
Open_table_state has a member for this savepoint.
Changed Open_table_context class to store MDL_request object for
global intention exclusive lock acquired when opening tables.
sql/sql_delete.cc:
MDL subsystem no longer implicitly acquires global intention exclusive
metadata lock when per-object exclusive metadata lock is acquired.
Now this has to be done by explicit calls outside of MDL subsystem.
sql/sql_help.cc:
Instead of using separate MDL_context for opening system tables we now
create MDL savepoint in the main context before opening such tables
and rollback to this savepoint after closing them. To support this
change methods of THD responsible for saving/restoring open table
state were changed to use Open_tables_backup class which in addition
to Open_table_state has a member for this savepoint. As result code
opening/closing system tables was changed to use Open_tables_backup
instead of Open_table_state class as well.
sql/sql_parse.cc:
Adjusted assert reload_acl_and_cache() to the fact that global read
lock now takes full-blown metadata lock.
sql/sql_plist.h:
Added support for element counting to I_P_List list template.
One can use policy classes to specify if such counting is needed
or not needed for particular list.
sql/sql_show.cc:
Instead of using separate MDL_context for opening tables for I_S
purposes we now create MDL savepoint in the main context before
opening tables and rollback to this savepoint after closing them.
To support this and similar change for system tables methods of
THD responsible for saving/restoring open table state were changed
to use Open_tables_backup class which in addition to Open_table_state
has a member for this savepoint. As result code opening/closing tables
for I_S purposes was changed to use Open_tables_backup instead of
Open_table_state class as well.
sql/sql_table.cc:
mysql_rm_tables_part2():
Since now global intention exclusive metadata lock is ordinary
metadata lock we no longer can rely that by releasing MDL locks
on all tables we will release all locks acquired by this routine.
So in non-LOCK-TABLES mode we have to release all locks acquired
explicitly.
prepare_for_repair(), mysql_alter_table():
MDL subsystem no longer implicitly acquires global intention
exclusive metadata lock when per-object exclusive metadata lock
is acquired. Now this has to be done by explicit calls outside of
MDL subsystem.
sql/tztime.cc:
Instead of using separate MDL_context for opening system tables we now
create MDL savepoint in the main context before opening such tables
and rollback to this savepoint after closing them. To support this
change methods of THD responsible for saving/restoring open table
state were changed to use Open_tables_backup class which in addition
to Open_table_state has a member for this savepoint. As result code
opening/closing system tables was changed to use Open_tables_backup
instead of Open_table_state class as well.
Also changed code not to use special mechanism for open system tables
when it is not really necessary.
Diffstat (limited to 'sql/mdl.h')
-rw-r--r-- | sql/mdl.h | 136 |
1 files changed, 100 insertions, 36 deletions
diff --git a/sql/mdl.h b/sql/mdl.h index 8edbfbc0777..3ae7cdc743d 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -36,11 +36,13 @@ class MDL_ticket; (because of that their acquisition involves implicit acquisition of global intention-exclusive lock). - @see Comments for can_grant_lock() and can_grant_global_lock() for details. + @sa Comments for MDL_object_lock::can_grant_lock() and + MDL_global_lock::can_grant_lock() for details. */ enum enum_mdl_type {MDL_SHARED=0, MDL_SHARED_HIGH_PRIO, - MDL_SHARED_UPGRADABLE, MDL_EXCLUSIVE}; + MDL_SHARED_UPGRADABLE, MDL_INTENTION_EXCLUSIVE, + MDL_EXCLUSIVE}; /** States which a metadata lock ticket can have. */ @@ -78,7 +80,8 @@ public: enum enum_mdl_namespace { TABLE=0, FUNCTION, PROCEDURE, - TRIGGER }; + TRIGGER, + GLOBAL }; const uchar *ptr() const { return (uchar*) m_ptr; } uint length() const { return m_length; } @@ -93,7 +96,8 @@ public: { return (enum_mdl_namespace)(m_ptr[0]); } /** - Construct a metadata lock key from a triplet (mdl_namespace, database and name). + Construct a metadata lock key from a triplet (mdl_namespace, + database and name). @remark The key for a table is <mdl_namespace>+<database name>+<table name> @@ -102,11 +106,12 @@ public: @param name Name of of the object @param key Where to store the the MDL key. */ - void mdl_key_init(enum_mdl_namespace mdl_namespace, const char *db, const char *name) + void mdl_key_init(enum_mdl_namespace mdl_namespace, + const char *db, const char *name) { m_ptr[0]= (char) mdl_namespace; - m_db_name_length= (uint) (strmov(m_ptr + 1, db) - m_ptr - 1); - m_length= (uint) (strmov(m_ptr + m_db_name_length + 2, name) - m_ptr + 1); + m_db_name_length= (uint16) (strmov(m_ptr + 1, db) - m_ptr - 1); + m_length= (uint16) (strmov(m_ptr + m_db_name_length + 2, name) - m_ptr + 1); } void mdl_key_init(const MDL_key *rhs) { @@ -119,20 +124,34 @@ public: return (m_length == rhs->m_length && memcmp(m_ptr, rhs->m_ptr, m_length) == 0); } + /** + Compare two MDL keys lexicographically. + */ + int cmp(const MDL_key *rhs) const + { + /* + The key buffer is always '\0'-terminated. Since key + character set is utf-8, we can safely assume that no + character starts with a zero byte. + */ + return memcmp(m_ptr, rhs->m_ptr, min(m_length, rhs->m_length)+1); + } + MDL_key(const MDL_key *rhs) { mdl_key_init(rhs); } - MDL_key(enum_mdl_namespace namespace_arg, const char *db_arg, const char *name_arg) + MDL_key(enum_mdl_namespace namespace_arg, + const char *db_arg, const char *name_arg) { mdl_key_init(namespace_arg, db_arg, name_arg); } MDL_key() {} /* To use when part of MDL_request. */ private: + uint16 m_length; + uint16 m_db_name_length; char m_ptr[MAX_MDLKEY_LENGTH]; - uint m_length; - uint m_db_name_length; private: MDL_key(const MDL_key &); /* not implemented */ MDL_key &operator=(const MDL_key &); /* not implemented */ @@ -198,7 +217,7 @@ public: DBUG_ASSERT(ticket == NULL); type= type_arg; } - bool is_shared() const { return type < MDL_EXCLUSIVE; } + bool is_shared() const { return type < MDL_INTENTION_EXCLUSIVE; } static MDL_request *create(MDL_key::enum_mdl_namespace mdl_namespace, const char *db, const char *name, @@ -243,6 +262,17 @@ typedef void (*mdl_cached_object_release_hook)(void *); @note Multiple shared locks on a same object are represented by a single ticket. The same does not apply for other lock types. + + @note There are two groups of MDL_ticket members: + - "Externally accessible". These members can be accessed from + threads/contexts different than ticket owner in cases when + ticket participates in some list of granted or waiting tickets + for a lock. Therefore one should change these members before + including then to waiting/granted lists or while holding lock + protecting those lists. + - "Context private". Such members are private to thread/context + owning this ticket. I.e. they should not be accessed from other + threads/contexts. */ class MDL_ticket @@ -250,12 +280,13 @@ class MDL_ticket public: /** Pointers for participating in the list of lock requests for this context. + Context private. */ MDL_ticket *next_in_context; MDL_ticket **prev_in_context; /** Pointers for participating in the list of satisfied/pending requests - for the lock. + for the lock. Externally accessible. */ MDL_ticket *next_in_lock; MDL_ticket **prev_in_lock; @@ -265,8 +296,8 @@ public: void *get_cached_object(); void set_cached_object(void *cached_object, mdl_cached_object_release_hook release_hook); - const MDL_context *get_ctx() const { return m_ctx; } - bool is_shared() const { return m_type < MDL_EXCLUSIVE; } + MDL_context *get_ctx() const { return m_ctx; } + bool is_shared() const { return m_type < MDL_INTENTION_EXCLUSIVE; } bool is_upgradable_or_exclusive() const { return m_type == MDL_SHARED_UPGRADABLE || m_type == MDL_EXCLUSIVE; @@ -275,6 +306,8 @@ public: void downgrade_exclusive_lock(); private: friend class MDL_context; + friend class MDL_global_lock; + friend class MDL_object_lock; MDL_ticket(MDL_context *ctx_arg, enum_mdl_type type_arg) : m_type(type_arg), @@ -283,31 +316,31 @@ private: m_lock(NULL) {} - static MDL_ticket *create(MDL_context *ctx_arg, enum_mdl_type type_arg); static void destroy(MDL_ticket *ticket); private: - /** Type of metadata lock. */ + /** Type of metadata lock. Externally accessible. */ enum enum_mdl_type m_type; - /** State of the metadata lock ticket. */ + /** State of the metadata lock ticket. Context private. */ enum enum_mdl_state m_state; - /** Context of the owner of the metadata lock ticket. */ + /** + Context of the owner of the metadata lock ticket. Externally accessible. + */ MDL_context *m_ctx; - /** Pointer to the lock object for this lock ticket. */ + /** Pointer to the lock object for this lock ticket. Context private. */ MDL_lock *m_lock; private: MDL_ticket(const MDL_ticket &); /* not implemented */ MDL_ticket &operator=(const MDL_ticket &); /* not implemented */ - - bool has_pending_conflicting_lock_impl() const; }; typedef I_P_List<MDL_request, I_P_List_adapter<MDL_request, &MDL_request::next_in_list, - &MDL_request::prev_in_list> > + &MDL_request::prev_in_list>, + I_P_List_counter> MDL_request_list; /** @@ -326,21 +359,19 @@ public: typedef Ticket_list::Iterator Ticket_iterator; - void init(THD *thd); + MDL_context(); void destroy(); bool try_acquire_shared_lock(MDL_request *mdl_request); bool acquire_exclusive_lock(MDL_request *mdl_request); bool acquire_exclusive_locks(MDL_request_list *requests); bool try_acquire_exclusive_lock(MDL_request *mdl_request); - bool acquire_global_shared_lock(); bool clone_ticket(MDL_request *mdl_request); bool wait_for_locks(MDL_request_list *requests); void release_all_locks_for_name(MDL_ticket *ticket); void release_lock(MDL_ticket *ticket); - void release_global_shared_lock(); bool is_exclusive_lock_owner(MDL_key::enum_mdl_namespace mdl_namespace, const char *db, @@ -368,7 +399,6 @@ public: void set_lt_or_ha_sentinel() { - DBUG_ASSERT(m_lt_or_ha_sentinel == NULL); m_lt_or_ha_sentinel= mdl_savepoint(); } MDL_ticket *lt_or_ha_sentinel() const { return m_lt_or_ha_sentinel; } @@ -385,16 +415,35 @@ public: bool can_wait_lead_to_deadlock() const; inline THD *get_thd() const { return m_thd; } - - bool is_waiting_in_mdl() const { return m_is_waiting_in_mdl; } -private: - Ticket_list m_tickets; - bool m_has_global_shared_lock; + /** - Indicates that the owner of this context is waiting in - wait_for_locks() method. + Wake up context which is waiting for a change of MDL_lock state. */ - bool m_is_waiting_in_mdl; + void awake() + { + pthread_cond_signal(&m_ctx_wakeup_cond); + } + + bool try_acquire_global_intention_exclusive_lock(MDL_request *mdl_request); + bool acquire_global_intention_exclusive_lock(MDL_request *mdl_request); + + bool acquire_global_shared_lock(); + void release_global_shared_lock(); + + /** + Check if this context owns global lock of particular type. + */ + bool is_global_lock_owner(enum_mdl_type type_arg) + { + MDL_request mdl_request; + bool not_used; + mdl_request.init(MDL_key::GLOBAL, "", "", type_arg); + return find_ticket(&mdl_request, ¬_used); + } + + void init(THD *thd_arg) { m_thd= thd_arg; } +private: + Ticket_list m_tickets; /** This member has two uses: 1) When entering LOCK TABLES mode, remember the last taken @@ -406,12 +455,27 @@ private: */ MDL_ticket *m_lt_or_ha_sentinel; THD *m_thd; + /** + Condvar which is used for waiting until this context's pending + request can be satisfied or this thread has to perform actions + to resolve potential deadlock (we subscribe for such notification + by adding ticket corresponding to the request to an appropriate + queue of waiters). + */ + pthread_cond_t m_ctx_wakeup_cond; private: - void release_ticket(MDL_ticket *ticket); - bool can_wait_lead_to_deadlock_impl() const; MDL_ticket *find_ticket(MDL_request *mdl_req, bool *is_lt_or_ha); void release_locks_stored_before(MDL_ticket *sentinel); + + bool try_acquire_lock_impl(MDL_request *mdl_request); + bool acquire_lock_impl(MDL_request *mdl_request); + bool acquire_exclusive_lock_impl(MDL_request *mdl_request); + + friend bool MDL_ticket::upgrade_shared_lock_to_exclusive(); +private: + MDL_context(const MDL_context &rhs); /* not implemented */ + MDL_context &operator=(MDL_context &rhs); /* not implemented */ }; |