My Project
|
Classes | |
class | Ticket_list |
Public Types | |
typedef unsigned short | bitmap_t |
typedef Ticket_list::List::Iterator | Ticket_iterator |
Public Member Functions | |
bool | is_empty () const |
virtual const bitmap_t * | incompatible_granted_types_bitmap () const =0 |
virtual const bitmap_t * | incompatible_waiting_types_bitmap () const =0 |
bool | has_pending_conflicting_lock (enum_mdl_type type) |
bool | can_grant_lock (enum_mdl_type type, MDL_context *requstor_ctx, bool ignore_lock_priority) const |
void | reschedule_waiters () |
void | remove_ticket (Ticket_list MDL_lock::*queue, MDL_ticket *ticket) |
bool | visit_subgraph (MDL_ticket *waiting_ticket, MDL_wait_for_graph_visitor *gvisitor) |
virtual bool | needs_notification (const MDL_ticket *ticket) const =0 |
virtual void | notify_conflicting_locks (MDL_context *ctx)=0 |
virtual bitmap_t | hog_lock_types_bitmap () const =0 |
MDL_lock (const MDL_key *key_arg, MDL_map_partition *map_part) | |
Static Public Member Functions | |
static MDL_lock * | create (const MDL_key *key, MDL_map_partition *map_part) |
static void | destroy (MDL_lock *lock) |
Public Attributes | |
MDL_key | key |
mysql_prlock_t | m_rwlock |
Ticket_list | m_granted |
Ticket_list | m_waiting |
ulong | m_hog_lock_count |
uint | m_ref_usage |
uint | m_ref_release |
bool | m_is_destroyed |
ulonglong | m_version |
MDL_map_partition * | m_map_part |
The lock context. Created internally for an acquired lock. For a given name, there exists only one MDL_lock instance, and it exists only when the lock has been granted. Can be seen as an MDL subsystem's version of TABLE_SHARE.
This is an abstract class which lacks information about compatibility rules for lock types. They should be specified in its descendants.
bool MDL_lock::can_grant_lock | ( | enum_mdl_type | type_arg, |
MDL_context * | requestor_ctx, | ||
bool | ignore_lock_priority | ||
) | const |
Check if request for the metadata lock can be satisfied given its current state.
type_arg | The requested lock type. |
requestor_ctx | The MDL context of the requestor. |
ignore_lock_priority | Ignore lock priority. |
TRUE | Lock request can be satisfied |
FALSE | There is some conflicting lock. |
MDL_lock * MDL_lock::create | ( | const MDL_key * | mdl_key, |
MDL_map_partition * | map_part | ||
) | [inline, static] |
bool MDL_lock::has_pending_conflicting_lock | ( | enum_mdl_type | type | ) |
Check if we have any pending locks which conflict with existing shared lock.
void MDL_lock::remove_ticket | ( | Ticket_list MDL_lock::* | list, |
MDL_ticket * | ticket | ||
) |
Remove a ticket from waiting or pending queue and wakeup up waiters.
void MDL_lock::reschedule_waiters | ( | ) |
Determine waiting contexts which requests for the lock can be satisfied, grant lock to them and wake them up.
bool MDL_lock::visit_subgraph | ( | MDL_ticket * | waiting_ticket, |
MDL_wait_for_graph_visitor * | gvisitor | ||
) |
A fragment of recursive traversal of the wait-for graph in search for deadlocks. Direct the deadlock visitor to all contexts that own the lock the current node in the wait-for graph is waiting for. As long as the initial node is remembered in the visitor, a deadlock is found when the same node is seen twice.
The key of the object (data) being protected.
List of granted tickets for this lock.
Number of times high priority lock requests have been granted while low priority lock requests were waiting.
Partition of MDL_map where the lock is stored.
These three members are used to make it possible to separate the MDL_map_partition::m_mutex mutex and MDL_lock::m_rwlock in MDL_map::find_or_insert() for increased scalability. The 'm_is_destroyed' member is only set by destroyers that have both the MDL_map_partition::m_mutex and MDL_lock::m_rwlock, thus holding any of the mutexes is sufficient to read it. The 'm_ref_usage; is incremented under protection by MDL_map_partition::m_mutex, but when 'm_is_destroyed' is set to TRUE, this member is moved to be protected by the MDL_lock::m_rwlock. This means that the MDL_map::find_or_insert() which only holds the MDL_lock::m_rwlock can compare it to 'm_ref_release' without acquiring MDL_map_partition::m_mutex again and if equal it can also destroy the lock object safely. The 'm_ref_release' is incremented under protection by MDL_lock::m_rwlock. Note since we are only interested in equality of these two counters we don't have to worry about overflows as long as their size is big enough to hold maximum number of concurrent threads on the system.
mysql_prlock_t MDL_lock::m_rwlock |
Read-write lock protecting this lock context.
For example, imagine that we have following waiters graph:
ctxA -> obj1 -> ctxB -> obj1 -| ^ | |----------------------------|
and both ctxA and ctxB start deadlock detection process:
ctxA read-locks obj1 ctxB read-locks obj2 ctxA goes deeper ctxB goes deeper
Now ctxC comes in who wants to start waiting on obj1, also ctxD comes in who wants to start waiting on obj2.
ctxC tries to write-lock obj1 ctxD tries to write-lock obj2 ctxC is blocked ctxD is blocked
Now ctxA and ctxB resume their search:
ctxA tries to read-lock obj2 ctxB tries to read-lock obj1
If m_rwlock prefers writes (or fair) both ctxA and ctxB would be blocked because of pending write locks from ctxD and ctxC correspondingly. Thus we will get a deadlock in deadlock detector. If m_wrlock prefers readers (actually ignoring pending writers is enough) ctxA and ctxB will continue and no deadlock will occur.
ulonglong MDL_lock::m_version |
We use the same idea and an additional version counter to support caching of unused MDL_lock object for further re-use. This counter is incremented while holding both MDL_map_partition::m_mutex and MDL_lock::m_rwlock locks each time when a MDL_lock is moved from the partitioned hash to the paritioned unused objects list (or destroyed). A thread, which has found a MDL_lock object for the key in the hash and then released the MDL_map_partition::m_mutex before acquiring the MDL_lock::m_rwlock, can determine that this object was moved to the unused objects list (or destroyed) while it held no locks by comparing the version value which it read while holding the MDL_map_partition::m_mutex with the value read after acquiring the MDL_lock::m_rwlock. Note that since it takes several years to overflow this counter such theoretically possible overflows should not have any practical effects.
Tickets for contexts waiting to acquire a lock.