MySQL 9.1.0
Source Code Documentation
|
The lock context. More...
Classes | |
struct | MDL_lock_strategy |
Helper struct which defines how different types of locks are handled for a specific MDL_lock. More... | |
class | Ticket_list |
Public Types | |
typedef unsigned short | bitmap_t |
typedef Ticket_list::List::Iterator | Ticket_iterator |
typedef longlong | fast_path_state_t |
Public Member Functions | |
const bitmap_t * | incompatible_granted_types_bitmap () const |
const bitmap_t * | incompatible_waiting_types_bitmap () const |
uint | get_incompatible_waiting_types_bitmap_idx () const |
Get index of priority matrice in MDL_lock_strategy::m_waiting_incompatible array which corresponds to current values of the m_piglet_lock_count and m_hog_lock_count counters and the max_write_lock_count threshold. More... | |
bool | switch_incompatible_waiting_types_bitmap_if_needed () |
Switch priority matrice for the MDL_lock object if m_piglet_lock_count or/ and m_hog_lock_count counters have crossed max_write_lock_count threshold. More... | |
bool | has_pending_conflicting_lock (enum_mdl_type type) |
Check if we have any pending locks which conflict with existing shared lock. More... | |
bool | can_grant_lock (enum_mdl_type type, const MDL_context *requestor_ctx) const |
Check if request for the metadata lock can be satisfied given its current state. More... | |
void | reschedule_waiters () |
Determine waiting contexts which requests for the lock can be satisfied, grant lock to them and wake them up. More... | |
void | remove_ticket (MDL_context *ctx, LF_PINS *pins, Ticket_list MDL_lock::*queue, MDL_ticket *ticket) |
Remove a ticket from waiting or pending queue and wakeup up waiters. More... | |
bool | 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. More... | |
bool | needs_notification (const MDL_ticket *ticket) const |
void | notify_conflicting_locks (MDL_context *ctx) |
bool | needs_connection_check () const |
bool | is_affected_by_max_write_lock_count () const |
bool | count_piglets_and_hogs (enum_mdl_type type) |
If we just have granted a lock of "piglet" or "hog" type and there are pending lower priority locks, increase the appropriate counter. More... | |
fast_path_state_t | get_unobtrusive_lock_increment (enum_mdl_type type) const |
bool | is_obtrusive_lock (enum_mdl_type type) const |
Check if type of lock requested is "obtrusive" type of lock. More... | |
bitmap_t | fast_path_granted_bitmap () const |
Return set of types of lock requests which were granted using "fast path" algorithm in the bitmap_t form. More... | |
MDL_lock () | |
Do "expensive" part of MDL_lock object initialization, Called by LF_ALLOCATOR for each newly malloc()'ed MDL_lock object, is not called in cases when LF_ALLOCATOR decides to reuse object which was returned to it earlier. More... | |
void | reinit (const MDL_key *mdl_key) |
Finalize initialization or re-initialize MDL_lock returned from LF_ALLOCATOR's cache to represent object identified by provided key. More... | |
~MDL_lock () | |
MDL_context * | get_lock_owner () const |
Return the first MDL_context which owns the lock. More... | |
bool | fast_path_state_cas (fast_path_state_t *old_state, fast_path_state_t new_state) |
Wrapper for atomic compare-and-swap operation on m_fast_path_state member which enforces locking and other invariants. More... | |
fast_path_state_t | fast_path_state_add (fast_path_state_t value) |
Wrapper for atomic add operation on m_fast_path_state member which enforces locking and other invariants. More... | |
void | fast_path_state_reset () |
Wrapper for resetting m_fast_path_state enforcing locking invariants. More... | |
Static Public Member Functions | |
static bool | needs_hton_notification (MDL_key::enum_mdl_namespace mdl_namespace) |
Indicates whether object belongs to namespace which requires storage engine to be notified before acquiring and after releasing exclusive lock. More... | |
static fast_path_state_t | get_unobtrusive_lock_increment (const MDL_request *request) |
static MDL_lock * | create (const MDL_key *key) |
Auxiliary functions needed for creation/destruction of MDL_lock objects. More... | |
static void | destroy (MDL_lock *lock) |
static const MDL_lock_strategy * | get_strategy (const MDL_key &key) |
Get MDL lock strategy corresponding to MDL key. More... | |
static bitmap_t | scoped_lock_fast_path_granted_bitmap (const MDL_lock &lock) |
Get bitmap of "unobtrusive" locks granted using "fast path" algorithm for scoped locks. More... | |
static bool | object_lock_needs_notification (const MDL_ticket *ticket) |
Check if we are requesting X lock on the object, so threads holding conflicting S/SH metadata locks on it need to be notified. More... | |
static void | object_lock_notify_conflicting_locks (MDL_context *ctx, MDL_lock *lock) |
Notify threads holding S/SH metadata locks on an object, which conflict with a pending X lock. More... | |
static bitmap_t | object_lock_fast_path_granted_bitmap (const MDL_lock &lock) |
Get bitmap of "unobtrusive" locks granted using "fast path" algorithm for per-object locks. More... | |
static bool | object_lock_needs_connection_check (const MDL_lock *lock) |
Check if MDL_lock object represents user-level lock,locking service lock or acl cache lock, so threads waiting for it need to check if connection is lost and abort waiting when it is. More... | |
Public Attributes | |
MDL_key | key |
The key of the object (data) being protected. More... | |
mysql_prlock_t | m_rwlock |
Read-write lock protecting this lock context. More... | |
Ticket_list | m_granted |
List of granted tickets for this lock. More... | |
Ticket_list | m_waiting |
Tickets for contexts waiting to acquire a lock. More... | |
uint | m_obtrusive_locks_granted_waiting_count |
Number of granted or waiting lock requests of "obtrusive" type. More... | |
std::atomic< fast_path_state_t > | m_fast_path_state |
Combination of IS_DESTROYED/HAS_OBTRUSIVE/HAS_SLOW_PATH flags and packed counters of specific types of "unobtrusive" locks which were granted using "fast path". More... | |
const MDL_lock_strategy * | m_strategy |
Pointer to strategy object which defines how different types of lock requests should be handled for the namespace to which this lock belongs. More... | |
Static Public Attributes | |
static const fast_path_state_t | IS_DESTROYED = 1ULL << 62 |
Flag in MDL_lock::m_fast_path_state that indicates that the MDL_lock object was marked for destruction and will be destroyed once all threads referencing to it through hazard pointers have unpinned it. More... | |
static const fast_path_state_t | HAS_OBTRUSIVE = 1ULL << 61 |
Flag in MDL_lock::m_fast_path_state that indicates that there are "obtrusive" locks which are granted, waiting or for which we are about to check if they can be granted. More... | |
static const fast_path_state_t | HAS_SLOW_PATH = 1ULL << 60 |
Flag in MDL_lock::m_fast_path_state that indicates that there are "slow" path locks which are granted, waiting or for which we are about to check if they can be granted. More... | |
static const bitmap_t | MDL_OBJECT_HOG_LOCK_TYPES |
Bitmap with "hog" lock types for object locks. More... | |
static const MDL_lock_strategy | m_scoped_lock_strategy |
Strategy instances to be used with scoped metadata locks (i.e. More... | |
static const MDL_lock_strategy | m_object_lock_strategy |
Strategy instance for per-object locks. More... | |
Private Attributes | |
ulong | m_hog_lock_count |
Number of times high priority, "hog" lock requests (X, SNRW, SNW) have been granted while lower priority lock requests (all other types) were waiting. More... | |
ulong | m_piglet_lock_count |
Number of times high priority, "piglet" lock requests (SW) have been granted while locks requests with lower priority (SRO) were waiting. More... | |
uint | m_current_waiting_incompatible_idx |
Index of one of the MDL_lock_strategy::m_waiting_incompatible arrays which represents the current priority matrice. More... | |
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.
typedef unsigned short MDL_lock::bitmap_t |
typedef longlong MDL_lock::fast_path_state_t |
|
inline |
Do "expensive" part of MDL_lock object initialization, Called by LF_ALLOCATOR for each newly malloc()'ed MDL_lock object, is not called in cases when LF_ALLOCATOR decides to reuse object which was returned to it earlier.
"Full" initialization happens later by calling MDL_lock::reinit(). So
|
inline |
bool MDL_lock::can_grant_lock | ( | enum_mdl_type | type_arg, |
const MDL_context * | requestor_ctx | ||
) | 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. |
true | Lock request can be satisfied |
false | There is some conflicting lock. |
|
inline |
If we just have granted a lock of "piglet" or "hog" type and there are pending lower priority locks, increase the appropriate counter.
If this counter now exceeds the max_write_lock_count threshold, switch priority matrice for the MDL_lock object.
Auxiliary functions needed for creation/destruction of MDL_lock objects.
|
inlinestatic |
|
inline |
Return set of types of lock requests which were granted using "fast path" algorithm in the bitmap_t form.
This method is only called from MDL_lock::can_grant_lock() and its return value is only important when we are trying to figure out if we can grant an obtrusive lock. But this means that the HAS_OBTRUSIVE flag is set so all changes to m_fast_path_state happen under protection of MDL_lock::m_rwlock (see invariant [INV1]). Since can_grant_lock() is called only when MDL_lock::m_rwlock is held, it is safe to do an ordinary read of m_fast_path_state here.
|
inline |
Wrapper for atomic add operation on m_fast_path_state member which enforces locking and other invariants.
|
inline |
Wrapper for atomic compare-and-swap operation on m_fast_path_state member which enforces locking and other invariants.
|
inline |
Wrapper for resetting m_fast_path_state enforcing locking invariants.
|
inline |
Get index of priority matrice in MDL_lock_strategy::m_waiting_incompatible array which corresponds to current values of the m_piglet_lock_count and m_hog_lock_count counters and the max_write_lock_count threshold.
|
inline |
Return the first MDL_context which owns the lock.
|
inlinestatic |
Get MDL lock strategy corresponding to MDL key.
key | Reference to MDL_key object |
|
inlinestatic |
A) "unobtrusive" lock types 1) Each type from this set should be compatible with all other types from the set (including itself). 2) These types should be common for DML operations
Our goal is to optimize acquisition and release of locks of this type by avoiding complex checks and manipulations on m_waiting/ m_granted bitmaps/lists. We replace them with a check of and increment/decrement of integer counters. We call the latter type of acquisition/release "fast path". Use of "fast path" reduces the size of critical section associated with MDL_lock::m_rwlock lock in the common case and thus increases scalability.
The amount by which acquisition/release of specific type "unobtrusive" lock increases/decreases packed counter in MDL_lock::m_fast_path_state is returned by this function.
B) "obtrusive" lock types 1) Granted or pending lock of those type is incompatible with some other types of locks or with itself. 2) Not common for DML operations
These locks have to be always acquired involving manipulations on m_waiting/m_granted bitmaps/lists, i.e. we have to use "slow path" for them. Moreover in the presence of active/pending locks from "obtrusive" set we have to acquire using "slow path" even locks of "unobtrusive" type.
|
inline |
bool MDL_lock::has_pending_conflicting_lock | ( | enum_mdl_type | type | ) |
Check if we have any pending locks which conflict with existing shared lock.
|
inline |
|
inline |
|
inline |
|
inline |
Check if type of lock requested is "obtrusive" type of lock.
|
inline |
|
inlinestatic |
Indicates whether object belongs to namespace which requires storage engine to be notified before acquiring and after releasing exclusive lock.
|
inline |
|
inline |
|
inlinestatic |
Get bitmap of "unobtrusive" locks granted using "fast path" algorithm for per-object locks.
|
inlinestatic |
Check if MDL_lock object represents user-level lock,locking service lock or acl cache lock, so threads waiting for it need to check if connection is lost and abort waiting when it is.
|
inlinestatic |
Check if we are requesting X lock on the object, so threads holding conflicting S/SH metadata locks on it need to be notified.
|
static |
Notify threads holding S/SH metadata locks on an object, which conflict with a pending X lock.
ctx | MDL_context for current thread. |
lock | MDL_lock object representing lock which is to be acquired. |
|
inline |
Finalize initialization or re-initialize MDL_lock returned from LF_ALLOCATOR's cache to represent object identified by provided key.
void MDL_lock::remove_ticket | ( | MDL_context * | ctx, |
LF_PINS * | pins, | ||
Ticket_list MDL_lock::* | queue, | ||
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.
|
inlinestatic |
Get bitmap of "unobtrusive" locks granted using "fast path" algorithm for scoped locks.
|
inline |
Switch priority matrice for the MDL_lock object if m_piglet_lock_count or/ and m_hog_lock_count counters have crossed max_write_lock_count threshold.
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.
|
static |
Flag in MDL_lock::m_fast_path_state that indicates that there are "obtrusive" locks which are granted, waiting or for which we are about to check if they can be granted.
Corresponds to "MDL_lock::m_obtrusive_locks_granted_waiting_count == 0" predicate. Set using atomic compare-and-swap AND under protection of MDL_lock::m_rwlock lock. Thanks to this can be read either by using atomic compare-and-swap OR using ordinary read under protection of MDL_lock::m_rwlock lock.
Invariant [INV1]: When this flag is set all changes to m_fast_path_state member has to be done under protection of m_rwlock lock.
|
static |
Flag in MDL_lock::m_fast_path_state that indicates that there are "slow" path locks which are granted, waiting or for which we are about to check if they can be granted.
Corresponds to MDL_lock::m_granted/m_waiting lists being non-empty (except special case in MDL_context::try_acquire_lock()). Set using atomic compare-and-swap AND under protection of m_rwlock lock. The latter is necessary because value of this flag needs to be synchronized with contents of MDL_lock::m_granted/m_waiting lists.
|
static |
Flag in MDL_lock::m_fast_path_state that indicates that the MDL_lock object was marked for destruction and will be destroyed once all threads referencing to it through hazard pointers have unpinned it.
Set using atomic compare-and-swap AND under protection of MDL_lock::m_rwlock lock. Thanks to this can be read either by using atomic compare-and-swap OR using ordinary read under protection of MDL_lock::m_rwlock lock.
MDL_key MDL_lock::key |
The key of the object (data) being protected.
|
private |
Index of one of the MDL_lock_strategy::m_waiting_incompatible arrays which represents the current priority matrice.
std::atomic<fast_path_state_t> MDL_lock::m_fast_path_state |
Combination of IS_DESTROYED/HAS_OBTRUSIVE/HAS_SLOW_PATH flags and packed counters of specific types of "unobtrusive" locks which were granted using "fast path".
Write and Read-Modify-Write operations are always carried out atomically. This is necessary to avoid lost updates on 32-bit platforms among other things. In some cases Reads can be done non-atomically because we don't really care about value which they will return (for example, if further down the line there will be an atomic compare-and-swap operation, which will validate this value and provide the correct value if the validation will fail). In other cases Reads can be done non-atomically since they happen under protection of MDL_lock::m_rwlock and there is some invariant which ensures that concurrent updates of the m_fast_path_state member can't happen while MDL_lock::m_rwlock is held (
Ticket_list MDL_lock::m_granted |
List of granted tickets for this lock.
|
private |
Number of times high priority, "hog" lock requests (X, SNRW, SNW) have been granted while lower priority lock requests (all other types) were waiting.
Currently used only for object locks. Protected by m_rwlock lock.
|
static |
Strategy instance for per-object locks.
Supports all locked modes except INTENTION EXCLUSIVE locks.
uint MDL_lock::m_obtrusive_locks_granted_waiting_count |
Number of granted or waiting lock requests of "obtrusive" type.
Also includes "obtrusive" lock requests for which we about to check if they can be granted.
|
private |
Number of times high priority, "piglet" lock requests (SW) have been granted while locks requests with lower priority (SRO) were waiting.
Currently used only for object locks. Protected by m_rwlock lock.
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.
|
static |
Strategy instances to be used with scoped metadata locks (i.e.
locks from GLOBAL, COMMIT, TABLESPACE, BACKUP_LOCK and SCHEMA namespaces). The only locking modes which are supported at the moment are SHARED and INTENTION EXCLUSIVE and EXCLUSIVE.
const MDL_lock_strategy* MDL_lock::m_strategy |
Pointer to strategy object which defines how different types of lock requests should be handled for the namespace to which this lock belongs.
Ticket_list MDL_lock::m_waiting |
Tickets for contexts waiting to acquire a lock.
|
static |
Bitmap with "hog" lock types for object locks.
Locks of these types can easily starve out lower priority locks. To prevent this we only grant them max_write_lock_count times in a row while other lock types are waiting.