1 元数据锁的锁请求与锁等待
元数据锁在MySQL Server层,依照锁的状态被细分为两种。一种是已经施加的锁。一种是等待施加的锁即锁请求,这样被区分的原因,如MySQL对“class MDL_request”的代码凝视作了解释:
/**
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 //注意这里给出的原因是从project实践中对锁的实现的角度区分的
controlled
from outside of the MDL subsystem,
while allocation of granted //体现了project与理论的不同
locks
(tickets) is controlled within the MDL
subsystem.
MDL_request
is a C structure, you don't need to call a constructor
or
destructor for it.
*/
class MDL_request{...} //锁请求
所以,元数据锁在使用的过程中又被细分为“lock granted
metadata” (代码中使用“class MDL_ticket”表示。
ticket,入场卷。即要被授予的锁)和“lock request metadata”(代码中使用“class MDL_request”表示加锁的请求)。
这样,MySQL Server分别使用两个类来表示这两种被细分的锁。
当锁请求要求施加锁不成功的时候,则产生锁等待,而锁等待则用MDL_wait表示。
/**A reliable way to wait on an MDL lock. */
class MDL_wait{... //锁等待。在获取锁的过程中,须要为是否获得锁做标志。採用的就是锁等待的状态值
enum enum_wait_status
{ //锁等待的状态,在锁等待在生命周期内因不同操作产生不同结果
EMPTY = 0, //空状态。初始值
GRANTED, //锁被授予的状态
VICTIM, //某个会话被选为了受害者
TIMEOUT,
//超时状态,申请加锁却发生超时
KILLED };
//被killed状态,发起锁请求的会话被killed掉。所以不仅是发起加锁请求的事务应终止,事务的属主会话也被终止
...}
2 元数据锁类对象
保存每一MDL_key相应的全部已经授予的MDL锁信息,由于MDL_key标识了不同的数据库对象类,不同的数据库对象类上所施加的锁之间的兼容性因对象存在区别,所以定义了不同的策略来区分这些区别。请注意,MDL_lock不是一个详细的锁,而是一类锁的集合。
GLOBAL和COMMIT类的锁。是全局唯一的。除此之外的其它类型的锁,能够有多个。
/**
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. //能够被存储层的TABLE_SHARE使用这个锁对象
This is an abstract class which lacks information
aboutcompatibility rules for lock types.
They should
be specifiedin its descendants.
*/
class //当须要施加元数据锁的时候。生成一个MDL_lock锁对象
{...
class Ticket_list{...} //把MDL_ticket封装为一个 List对象,用以存放多个MDL_ticket锁对象(MDL_ticket參见下一小节)
/** //对于锁的操作,又存在两种策略。这是依据被加锁的对象的特定区分的。
每一种策略分别有各自的锁兼容规则
Helper struct which defines how different
types of locks are handledfor a specific MDL_lock.
In practice we use only two strategies:
"scoped"lock
strategy for locks in GLOBAL, COMMIT, TABLESPACE and SCHEMA namespaces //范围锁策略:范围带有空间的意味
and "object"
lock strategy for all other namespaces. //对象锁策略:数据库内部的各种对象
*/
struct MDL_lock_strategy
//锁的施加策略。如上所述,锁被分为两种类型,所以统一用策略数据结构来管理和描写叙述这两类锁的特性
{
/**Compatibility (or rather
"incompatibility") matrices for lock types. //新申请的锁向已经授予的锁进行锁的相容性推断
Array of bitmaps which elements specify which granted locks areincompatible with
the type of lock being requested.*/
bitmap_tm_granted_incompatible[MDL_TYPE_END]; //已经被授予的锁的数组中保存有不兼容的、准备申请此对象的请求锁,位图数组结构
//新申请的锁向已经正在等待的锁进行锁的相容性(优先级)推断。此数组的作用有两个:
//一是通过m_waiting_incompatible[0]。
//二是防止产生锁饥饿现象,
//所以添加了对低优先级锁的申请次数的计数。当计数到一定程度时,唤醒低优先级的尚没获得锁的会话。
//能够关注MDL_lock::reschedule_waiters()函数。查看对等待的锁的处理方式;看其调用者查看唤醒条件。
//另外看此函数中封锁粒度较强的锁释放而封锁粒度较弱的锁得以有机会被授予的时候,
//m_hog_lock_count/m_piglet_lock_count有机会被重置
//(注意强弱是相对的,取决于11.4.1节中第3小节中定义的enum_mdl_type中的锁的粒度值。据这些值比較大小)
/** Arrays
of bitmaps which elements specify which waiting
locks areincompatible with the type of lock being requested.
Basically, eacharray defines priorities
between lock types.
We need
4 separate arrays since in order to prevent starvation for some of lock request
types, we use different priority matrices:
0) in "normal" situation. //正常优先级
1) in situation when the number of
successively granted "piglet" requestsexceeds the
max_write_lock_count limit. //小猪优先级
2) in situation when the number of
successively granted "hog" requestsexceeds the max_write_lock_count
limit. //猪优先级
3) in situation when both "piglet"
and "hog" counters exceed limit.*/
//小猪和猪之和
//这个矩阵是某个锁请求与处于等待状态的锁的优先级比較表
//第一个数组是正常情况,其它三个数组是为解决锁饥饿而设置的
//如m_piglet_lock_count的值大于了max_write_lock_count。则m_waiting_incompatible[1][x]被置位
//如m_hog_lock_count的值大于了max_write_lock_count。则m_waiting_incompatible[2][x]被置位
//在等待的锁的数组中保存有不兼容的、准备申请此对象的请求锁,二维位图数组结构
bitmap_tm_waiting_incompatible[4][MDL_TYPE_END];//piglet,会申请SW锁;hog。会申请X、SNRW、SNW这三者其一
/**Array of increments for
"unobtrusive" types of lock requests for locks.
@sa
MDL_lock::get_unobtrusive_lock_increment().*/
//“unobtrusive”类型相关的锁粒度包含: S、SH、SR 和SW。相应“Fast path”的訪问方式,主要用于DML类操作
//“obtrusive” 类型相关的锁粒度包含:SU、SRO、SNW、SNRW、X。相应“slow path”的訪问方式,主要用于非DML类操作
fast_path_state_tm_unobtrusive_lock_increment[MDL_TYPE_END];
//高速訪问“unobtrusive”类型的锁
/**Indicates that locks of this type are
affected bythe max_write_lock_count limit.*/
bool m_is_affected_by_max_write_lock_count;
/**Pointer to a static method which determines
if the type of lockrequested requires
notification of conflicting locks.
NULL if
thereare no lock types requiring notification.*/
//当有冲突锁的时候,是否要被通知。
“scopedlock”不要求被通知。而“object lock”施加排它锁时才须要被通知
bool (*m_needs_notification)(const MDL_ticket
*ticket);
/**Pointer to a static method which allows
notification of owners ofconflicting locksabout the fact
that a
type of lock requiringnotification was requested.*/
//对于“object lock”,通知持有S、SH类锁的会话线程(可能与待定的X锁冲突。pending lock)
void (*m_notify_conflicting_locks)(MDL_context
*ctx, MDL_lock *lock); //发出通知的函数,含义相似上面
/**Pointer to a static method which converts
information aboutlocks granted using "fast" path
from
fast_path_state_trepresentation to bitmap of lock types.*/
//S、SR、SW粒度的锁能够被使用“fast path”方式高速处理
bitmap_t (*m_fast_path_granted_bitmap)(const MDL_lock &lock);
/**Pointer
to a static method which determines if waiting for the lockshould be aborted
when
connection is lost. NULL if locks ofthis type don't require such aborts.*/ //当连接断开的时候,锁是否应该被撤销。
//LOCKING_SERVICE和USER_LEVEL_LOCK加锁的情况可被撤销,如通过GET_LOCK()施加的锁。
bool (*m_needs_connection_check)(const
MDL_lock *lock);
};
public:
/** The key of the object (data) being
protected. */
MDL_key key; //元数据锁所属的类型(在MDL_key中把元数据这种对象分为了几类,给每类定义一个key在enum_mdl_namespace枚举中)
…
/** List
of granted tickets for this lock. */
Ticket_list m_granted; //对于本锁而言,在系统内部存在的已经被授予的全部锁list
/**
Tickets for contexts waiting to acquire a lock. */
Ticket_list
m_waiting; //对于本锁而言,在系统内部存在的正在等待被授予的全部锁list
//如上两个list,配合使用:
//当要获取一个锁(入通过acquire_lock()函数)不成功时。把新生成的一个MDL_ticket对象放入等待队列。获取成功。则放入m_granted中
//当一个处于等待状态的锁能够被授予的时候(can_grant_lock()推断能否够被授予)。就从m_waiting中remove掉,然后添加到m_granted中,
//这种事情,当获取锁或释放锁时,或因ALTER
TABLE等操作须要降级锁时,通过reschedule_waiters()函数进行
...
/** Pointer to strategy object which defines
how different types of lock
requests should be handled for the namespace
to which this lock belongs.
@sa MDL_lock::m_scoped_lock_strategy and
MDL_lock:m_object_lock_strategy. */
const MDL_lock_strategy *m_strategy;
//注意这是一个指针。运行哪个类型的策略就表示使用被指向的策略对象之策略(指向以下两个策略对象之中的一个)
...
static const MDL_lock_strategy m_scoped_lock_strategy; //范围锁相应的策略
static const MDL_lock_strategy m_object_lock_strategy; //对象锁相应的策略
};