MySQL 源码解读 -- 基础结构之MDL

MDL_context

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class MDL_context {

/**
If our request for a lock is scheduled, or aborted by the deadlock
detector, the result is recorded in this class.
*/
MDL_wait m_wait;

MDL_ticket_store m_ticket_store;

MDL_context_owner *m_owner;

/**
Tell the deadlock detector what metadata lock or table
definition cache entry this session is waiting for.
In principle, this is redundant, as information can be found
by inspecting waiting queues, but we'd very much like it to be
readily available to the wait-for graph iterator.
*/
MDL_wait_for_subgraph *m_waiting_for;
/**
Thread's pins (a.k.a. hazard pointers) to be used by lock-free
implementation of MDL_map::m_locks container. NULL if pins are
not yet allocated from container's pinbox.
*/
LF_PINS *m_pins;
}

MDL_ticket_store

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
Lists of all MDL tickets acquired by this connection.

Lists of MDL tickets:
---------------------
The entire set of locks acquired by a connection can be separated
in three subsets according to their duration: locks released at
the end of statement, at the end of transaction and locks are
released explicitly.

Statement and transactional locks are locks with automatic scope.
They are accumulated in the course of a transaction, and released
either at the end of uppermost statement (for statement locks) or
on COMMIT, ROLLBACK or ROLLBACK TO SAVEPOINT (for transactional
locks). They must not be (and never are) released manually,
i.e. with release_lock() call.

Tickets with explicit duration are taken for locks that span
multiple transactions or savepoints.
These are: HANDLER SQL locks (HANDLER SQL is
transaction-agnostic), LOCK TABLES locks (you can COMMIT/etc
under LOCK TABLES, and the locked tables stay locked), user level
locks (GET_LOCK()/RELEASE_LOCK() functions) and
locks implementing "global read lock".

Statement/transactional locks are always prepended to the
beginning of the appropriate list. In other words, they are
stored in reverse temporal order. Thus, when we rollback to
a savepoint, we start popping and releasing tickets from the
front until we reach the last ticket acquired after the savepoint.

Locks with explicit duration are not stored in any
particular order, and among each other can be split into
four sets:
- LOCK TABLES locks
- User-level locks
- HANDLER locks
- GLOBAL READ LOCK locks
*/
/**
Keep track of MDL_ticket for different durations. Maintains a
hash-based secondary index into the linked lists, to speed up access
by MDL_key.
*/
class MDL_ticket_store {
}

MDL_ticket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class MDL_ticket : public MDL_wait_for_subgraph {
/**
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. Externally accessible.
*/
MDL_ticket *next_in_lock;
MDL_ticket **prev_in_lock;

/** If current thread is worker thread, points to ticket of leader thread,
* NULL otherwise.
*/
MDL_ticket *m_leader_ticket;

// 核心就这几个成员
/** Type of metadata lock. Externally accessible. */
enum enum_mdl_type m_type;
#ifndef DBUG_OFF
/**
Duration of lock represented by this ticket.
Context private. Debug-only.
*/
enum_mdl_duration m_duration;
#endif
/**
Context of the owner of the metadata lock ticket. Externally accessible.
*/
MDL_context *m_ctx;

/**
Pointer to the lock object for this lock ticket. Externally accessible.
*/
MDL_lock *m_lock;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
A pending metadata lock request.

A lock request and a granted metadata lock are represented by
different classes because they have different allocation
sites and hence different lifetimes. The allocation of lock requests is
controlled from outside of the MDL subsystem, while allocation of granted
locks (tickets) is controlled within the MDL subsystem.
*/

class MDL_request {
/** Type of metadata lock. */
enum_mdl_type type{MDL_INTENTION_EXCLUSIVE};
/** Duration for requested lock. */
enum_mdl_duration duration{MDL_STATEMENT};

/**
Pointers for participating in the list of lock requests for this context.
*/
MDL_request *next_in_list{nullptr};
MDL_request **prev_in_list{nullptr};
/**
Pointer to the lock ticket object for this lock request.
Valid only if this lock request is satisfied.
*/
MDL_ticket *ticket{nullptr};

/** A lock is requested based on a fully qualified name and type. */
MDL_key key;

bool m_is_for_delegation{false}; // On if this request is for PQ leader

const char *m_src_file{nullptr};
uint m_src_line{0};
}