1. 程式人生 > >MDL--元資料鎖的鎖請求與鎖等待+元資料鎖類物件

MDL--元資料鎖的鎖請求與鎖等待+元資料鎖類物件

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//注意這裡給出的原因是從工程實踐中對鎖的實現的角度區分的

controlled from outside of the MDL subsystem, while allocation of granted//體現了工程與理論的不同

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不是一個具體的鎖,而是一類鎖的集合GLOBALCOMMIT類的鎖,是全域性唯一的,除此之外的其他型別的鎖,可以有多個。

/**

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.

*/

當需要施加元資料鎖的時候,生成一個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,會申請XSNRWSNW這三者其一

/**Array of increments for "unobtrusive" types of lock requests for locks.

@sa MDL_lock::get_unobtrusive_lock_increment().*/

//“unobtrusive”型別相關的鎖粒度包括: SSHSR SW,對應“Fast path”的訪問方式,主要用於DML類操作

//obtrusive” 型別相關的鎖粒度包括:SUSROSNWSNRWX,對應“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”,通知持有SSH類鎖的會話執行緒(可能與待定的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.*/

//SSRSW粒度的鎖可以被使用“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_SERVICEUSER_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中把元資料這樣的物件分為了幾類,給每類定義一個keyenum_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_waitingremove掉,然後加入到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; //物件鎖對應的策略

};