编程技术分享

  • 首页
  1. 首页
  2. MySQL
  3. 正文

MySQL源码分析系列4——MDL子系统

2022年8月10日 5247点热度 0人点赞 19条评论

1、MDL

MDL是metadata lock的简写,即元数据锁,该锁是在Server层实现的,用于保证并发操作时元数据的一致性,如DDL和DML并发时,保护表结构数据。接下来本文会从源码角度分析MDL的实现。

2、数据结构

要分析MDL源码,需要了解其中几个重要的数据结构:MDL_request、MDL_lock、MDL_ticket、MDL_key、MDL_context、MDL_map。

2.1 MDL_request

MDL_request表示MDL锁请求,该对象在MDL子系统外部创建,生命周期由外部控制。该结构主要成员如下:

class MDL_request {
    // 请求的MDL锁类型,详情见后文
    enum enum_mdl_type type;
    // 请求的MDL锁周期,详情见后文
    enum enum_mdl_duration duration;
    // 请求获取的ticket,表示访问权限,只有当请求成功后该值才有效,详情见后文
    MDL_ticket *ticket;
    // 请求的MDL锁名称,详情见后文
    MDL_key key;
    // 请求连接列表
    MDL_request *next_in_list;
    MDL_request **prev_in_list;
}

2.2 MDL_lock

MDL_lock表示MDL锁对象,每个MDL_key仅对应一个锁对象。该结构主要成员如下:

class MDL_lock {
    // MDL锁名称,详情见后文
    MDL_key key;
    // 已获取的权限列表
    Ticket_list m_granted;
    // 等待获取的权限列表
    Ticket_list m_waiting;
    // 范围锁策略,包括锁之间的兼容性定义等,详情见后文
    MDL_lock_strategy m_scoped_lock_strategy;
    // 对象锁策略,包括锁之间的兼容性定义等,详情见后文
    MDL_lock_strategy m_object_lock_strategy;
    // 根据锁名称key中的mdl_namespace值判断是范围锁还是对象锁,然后指向对应的锁策略
    MDL_lock_strategy *m_strategy;
    // 用于”fast path”算法快速判断锁冲突,详情见后文
    fast_path_state_t m_fast_path_state;
}

2.3 MDL_ticket

MDL_ticket表示MDL锁的权限,获取权限就是获取一个该对象。该结构主要成员如下:

class MDL_ticket {
    // 用于连接MDL_context上关联的所有MDL_ticket,详情见后文
    MDL_ticket *next_in_context;
    MDL_ticket **prev_in_context;
    // 用于连接MDL_lock上关联的所有MDL_ticket,详情见后文
    MDL_ticket *next_in_lock;
    MDL_ticket **prev_in_lock;
    // MDL锁类型,详情见后文
    enum enum_mdl_type m_type;
    // MDL锁周期,详情见后文
    enum_mdl_duration m_duration;
    // 该权限所属MDL_context
    MDL_context *m_ctx;
    // 该权限所属MDL_lock
    MDL_lock *m_lock;
    // 表示该权限使用"fast path"算法获取
    bool m_is_fast_path;
}

2.4 MDL_key

MDL_key表示锁的名称,由三部分组成:mdl_namespace、database name、object name或table name,格式如下:

该结构主要成员如下:

class MDL_key {
    // 字符串总长度,包括\0
    uint16 m_length;
    // database name长度,不包括\0
    uint16 m_db_name_length;
    // 字符串,格式:<mdl_namespace>+<database name>+\0+<object name/table name>+\0
    char m_ptr[MAX_MDLKEY_LENGTH];
}

2.5 MDL_context

MDL_context表示MDL锁持有者的上下文,每个连接拥有一个上下文。该结构主要成员如下:

class MDL_context {
    // 该连接获取的所有MDL锁权限列表,每个不同周期锁对应一个列表
    Ticket_list m_tickets[MDL_DURATION_END];
}

2.6 MDL_map

MDL_map表示所有MDL锁的集合,该集合是键为MDL_key,值为MDL_lock的哈希表,服务器中仅有一个该结构的单实例。该结构主要成员如下:

class MDL_map {
    // 所有MDL锁的哈希表,锁对象引用都来自于此
    LF_HASH m_locks;
    // 预分配的mdl_namespace=GLOBAL、database name=''、object name=''的MDL锁
    MDL_lock *m_global_lock;
    // 预分配的mdl_namespace=COMMIT、database name=''、object name=''的MDL锁
    MDL_lock *m_commit_lock;
}

2.7 结构关系图

MDL系统中主要结构之间的关系图如下:

MDL_map是一个单例哈希表,键为MDL_key,值为MDL_lock。每个MDL_lock实例包含已获取的权限列表m_granted和等待获取的权限列表m_waiting,每个列表由MDL_ticket中next_in_lock和prev_in_lock指针链接起来,列表中的MDL_ticket包含该锁的不同访问类型enum_mdl_type和锁周期enum_mdl_duration,因此每个访问权限MDL_ticket由MDL_key、enum_mdl_type和enum_mdl_duration唯一确定。

每个客户端连接对应一个上下文信息MDL_context,上下文中包含该连接已获取的不同周期的访问权限列表,由MDL_ticket中next_in_context和prev_in_context指针链接起来。

3、MDL属性

3.1 MDL namespace

MDL锁的命名空间,定义为mdl.h/MDL_key::enum_mdl_namespace,该枚举类型值包括以下几种:

  • GLOBAL:用于全局读锁
  • TABLESPACE:用于tablespace
  • SCHEMA:用于schema
  • TABLE:用于table和view
  • FUNCTION:用于存储函数
  • PROCEDURE:用于存储过程
  • TRIGGER:用于trigger
  • EVENT:用于事件调度器事件
  • COMMIT:用于启用全局读锁以阻塞提交
  • USER_LEVEL_LOCK:用于用户级锁
  • LOCKING_SERVICE:用于名称插件RW-lock服务

3.2 MDL type

MDL锁类型,定义为mdl.h/enum_mdl_type,该枚举类型值包括以下几种:

  • MDL_INTENTION_EXCLUSIVE(IX):意向排他锁,仅用于范围锁,持有该锁可以获取单个对象的可升级排他锁。兼容IX锁,但不兼容S、X锁。
  • MDL_SHARED(S):共享锁,仅用于访问元数据,不访问数据。
  • MDL_SHARED_HIGH_PRIO(SH):高优先级共享锁,仅用于访问元数据,不访问数据。高优先级表示在等待请求中比排他锁优先级高。
  • MDL_SHARED_READ(SR):共享锁,用于读取表元数据和表数据,例如:select,lock table ... read。
  • MDL_SHARED_WRITE(SW):共享锁,用于读取表元数据、读取或修改表数据,例如:insert,update,delete,select ... for update。lock table ... write和DDL不使用该锁。
  • MDL_SHARED_WRITE_LOW_PRIO(SWLP):比MDL_SHARED_READ_ONLY优先级更低的MDL_SHARED_WRITE锁,用于带LOW_PRIORITY的DML语句。
  • MDL_SHARED_UPGRADABLE(SU):可升级共享锁,允许并发update/read表数据。持有该锁能读取表元数据和表数据,但不能修改表数据。能够升级到SNW、SNRW、X锁,一旦升级到X、SNRW锁,即可修改表数据,用于alter table第一阶段。
  • MDL_SHARED_READ_ONLY(SRO):共享锁,用于读取表数据,阻塞所有并发修改表元数据和表数据,例如:lock tables read。
  • MDL_SHARED_NO_WRITE(SNW):可升级共享锁,持有该锁能读取表元数据和表数据,阻塞所有表数据更新操作,只允许读。能升级到X锁,用于alter table第一阶段,在拷贝数据时,允许并发select,不允许update。
  • MDL_SHARED_NO_READ_WRITE(SNRW):可升级共享锁,允许其他连接访问表元数据,不能访问表数据,阻塞所有读取、更新表数据操作,允许information_schema和show查询。持有该锁能读取表元数据、修改和读取表数据,能升级到X锁,用于lock tables write。
  • MDL_EXCLUSIVE(X):排他锁,持有该锁能修改表元数据和表数据。用于create、drop、rename table或DDL的某些执行阶段。

3.3 MDL duration

MDL锁周期,定义为mdl.h/enum_mdl_duration,该枚举类型值包括以下几种:

  • MDL_STATEMENT:语句周期锁,语句或事务结束时自动释放。
  • MDL_TRANSACTION:事务周期锁,事务结束时自动释放。
  • MDL_EXPLICIT:显式周期锁,需要显式调用MDL_context::release_lock()释放。

4、MDL策略

为了处理不同类型的锁策略,MDL系统根据mdl_namespace将锁分为范围锁和对象锁,当mdl_namespace为GLOBAL、TABLESPACE、SCHEMA、COMMIT时定义为范围锁,其他值定义为对象锁。在class MDL_lock中分别定义了两种锁的静态锁策略m_scoped_lock_strategy、m_object_lock_strategy,m_strategy根据mdl_namespace指向其中的某个策略。下面详细介绍它们的兼容性。

4.1 范围锁(scoped lock)

范围锁支持的锁类型为:MDL_INTENTION_EXCLUSIVE(IX)、MDL_SHARED(S)、MDL_EXCLUSIVE(X),它们之间的兼容性如下:

+ 表示请求能兼容

- 表示请求不能兼容,需要等待

(由于意向共享锁IS和其他锁都兼容,因此不需要考虑它)

4.2 对象锁(object lock)

对象锁支持除了MDL_INTENTION_EXCLUSIVE之外的所有锁类型,它们之间的兼容性如下:

+ 表示请求能兼容

- 表示请求不能兼容,需要等待

5、锁权限判断优化

在获取锁权限时,需要通过MDL_lock对象的权限列表m_granted、m_waiting来判断请求权限是否满足,涉及到复杂的bitmap和链表检查操作,由于在大部分场景下都是DML操作,获取的锁都是相互兼容的,如select获取的SR和insert/delete/update获取的SW,为了优化锁权限判断性能,MDL系统引入了unobtrusive、obtrusive两种集合类型,将上文介绍的各种锁类型划分到其中某个集合。这两个集合可以分别理解为兼容性强锁、兼容性弱锁,大部分操作使用兼容性强锁,可以直接通过计数器增减进行判断(“fast path”算法),对于少部分兼容性弱锁,还是通过复杂的bitmap和链表操作进行判断(“slow path”算法)。

5.1 集合类型

集合类型分为unobtrusive、obtrusive,两者的划分原则如下:

unobtrusive集合要求:

  • 该集合中每个锁类型和集合中所有其他类型的锁兼容(包括自身)
  • 该集合中的锁类型对于DML操作是通用的

obtrusive集合要求:

  • 该集合中每个类型的已授予或等待锁和某些其他类型的锁或自身不兼容
  • 该集合中的锁类型对于DML操作不通用

由上面的定义可以看出unobtrusive集合中的锁由于相互兼容,如果当前锁只被授予了unobtrusive类型的权限,请求也是unobtrusive类型时可以快速判断为兼容,这种情况下,MDL_lock对象中无需创建实际的权限对象,只需要记录unobtrusive类型锁的数量,当遇到obtrusive类型请求时,再实际创建对应的unobtrusive类型的权限对象,从而达到快速判断兼容性和真正需要时才构建权限对象。

5.2 集合划分

根据上面的集合划分原则可以将不同的锁类型归属于其中之一,由于不同锁空间对应不同的锁类型,因此需要针对范围锁和对象锁分别划分。

5.2.1 范围锁划分

之前介绍过,范围锁支持的锁类型为:MDL_INTENTION_EXCLUSIVE(IX)、MDL_SHARED(S)、MDL_EXCLUSIVE(X),划分如下:

unobtrusive类型:IX

obtrusive类型:X、S

该划分定义在mdl.cc/MDL_lock::m_scoped_lock_strategy的成员变量m_unobtrusive_lock_increment中,该变量表示:使用"fast path"算法时,每次获取对应集合类型的锁时需要增加计数器m_fast_path_state的值,unobtrusive类型会增加1,obtrusive类型会增加0,该值设定为:

fast_path_state_t m_unobtrusive_lock_increment[MDL_TYPE_END] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }

其中的1对应IX,表示获取IX锁时会将MDL_lock::m_fast_path_state的0-59bit增加1(0-59bit表示IX的数量,m_fast_path_state是8byte的longlong类型,还有高位的4bit另做他用,后文会介绍到)。

5.2.2 对象锁划分

之前介绍过,对象锁支持除了MDL_INTENTION_EXCLUSIVE之外的所有锁类型,划分如下:

unobtrusive类型:S、SH、SR、SW、SWLP

obtrusive类型:SU、SRO、SNW、SNRW、X

该划分定义在mdl.cc/MDL_lock::m_object_lock_strategy的成员变量m_unobtrusive_lock_increment中,该变量表示和范围锁一样,该值设定为:

fast_path_state_t m_unobtrusive_lock_increment[MDL_TYPE_END] = { 0, 1, 1, 1ULL << 20, 1ULL << 40, 1ULL << 40, 0, 0, 0, 0, 0 }

其中非0值按顺序依次对应S、SH、SR、SW、SWLP的增量值,表示获取S、SH锁时会将MDL_lock::m_fast_path_state的0-19bit增加1,获取SR锁时会将MDL_lock::m_fast_path_state的20-39bit增加1,获取SW、SWLP时会将MDL_lock::m_fast_path_state的40-59bit增加1,相当于使用每20bit保存锁的数量,由于MySQL不考虑超高2^20 - 1个并发连接,因此不存在溢出问题。同样m_fast_path_state高位另做他用。

5.3 特殊标志

上面介绍到"fast path"流程时,m_fast_path_state除了记录unobtrusive锁类型的数量外,还有高位4bit未说明,它们主要的作用是作为标志位,作用如下:

60bit:HAS_SLOW_PATH,表示该MDL_lock对象上有已授权、等待或正在检查授权的slow path锁。

61bit:HAS_OBTRUSIVE,表示该MDL_lock对象上有已授权、等待或正在检查授权的obtrusive锁。

62bit:IS_DESTROYED,表示该MDL_lock对象已经标记删除。

63bit:未使用。

这些标志位主要在多线程并发情况下用作"fast path"、"slow path"选择判断。

6、锁操作

锁操作主要包括:获取锁、锁升级、锁降级、释放锁,下面分别介绍各个操作的流程。

6.1 获取锁

获取锁操作的函数为mdl.cc/MDL_context::acquire_lock,该函数执行流程如下:

其中真正获取锁的函数为mdl.cc/MDL_context::try_acquire_lock_impl,其执行流程如下:

6.2 锁升级

锁升级操作的函数为mdl.cc/MDL_context::upgrade_shared_lock,该函数主要用于ALTER TABLE和CREATE TABLE,执行流程如下:

6.3 锁降级

锁降级操作的函数为mdl.cc/MDL_ticket::downgrade_lock,该函数用于将MDL_EXCLUSIVE、MDL_SHARED_NO_WRITE为降为共享锁,执行流程如下:

6.4 释放锁

释放锁操作的函数为mdl.cc/MDL_context::release_lock,该函数执行流程如下:

7、加锁分析

MySQL 5.7加入了MDL锁分析,开启方法如下:

UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME ='global_instrumentation';
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME ='wait/lock/metadata/sql/mdl';

执行语句可以查询当前MDL锁状态:select * from performance_schema.metadata_locks。不过该方式无法查看整个语句执行过程中的加锁流程。下面将会介绍常用语句的锁操作调用链。

8、常用语句加锁流程

以下所有调用链的入口如下:

connection_handler_per_thread.cc/handle_connection()
|--sql_parse.cc/do_command()
   |--sql_parse.cc/dispatch_command()
      |--sql_parse.cc/mysql_parse() //该函数解析出锁请求thd->lex->query_tables->mdl_request
         |--sql_parse.cc/mysql_execute_command()
            |-- ...

8.1 select from ...

执行语句:select * from d1.t1;

锁操作调用链:

//获取锁:mdl_type=MDL_SHARED_READ,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_parse.cc/execute_sqlcom_select()
|--sql_base.cc/open_tables_for_query()
   |--sql_base.cc/open_tables()
      |--sql_base.cc/open_and_process_table()
         |--sql_base.cc/open_table()
            |--sql_base.cc/open_table_get_mdl_lock()
               |--mdl.cc/acquire_lock()

//释放锁:mdl_type=MDL_SHARED_READ,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

8.2 select from ... for update

执行语句:select * from d1.t1 for update;

锁操作调用链:

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
sql_parse.cc/execute_sqlcom_select()
|--sql_base.cc/open_tables_for_query():加MDL锁
   |--sql_base.cc/open_tables()
      |--sql_base.cc/open_and_process_table()
         |--sql_base.cc/open_table()
            |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_SHARED_WRITE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_parse.cc/execute_sqlcom_select()
|--sql_base.cc/open_tables_for_query()
   |--sql_base.cc/open_tables()
      |--sql_base.cc/open_and_process_table()
         |--sql_base.cc/open_table()
            |--sql_base.cc/open_table_get_mdl_lock()
               |--mdl.cc/acquire_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_SHARED_WRITE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

8.3 insert into ...

执行语句:insert into d1.t1 values(1005, "name6", 15, 1);

锁操作调用链:

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
sql_insert.cc/Sql_cmd_insert::execute()
|--sql_insert.cc/Sql_cmd_insert::mysql_insert()
   |--sql_base.cc/open_tables_for_query()
      |--sql_base.cc/open_tables()
         |--sql_base.cc/open_and_process_table()
            |--sql_base.cc/open_table()
               |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_SHARED_WRITE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_insert.cc/Sql_cmd_insert::execute()
|--sql_insert.cc/Sql_cmd_insert::mysql_insert()
   |--sql_base.cc/open_tables_for_query()
      |--sql_base.cc/open_tables()
         |--sql_base.cc/open_and_process_table()
            |--sql_base.cc/open_table()
               |--sql_base.cc/open_table_get_mdl_lock()
                  |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_EXPLICIT,mdl_namespace=COMMIT,db_name='',name=''
transaction.cc/trans_commit_stmt()
|--handler.cc/ha_commit_trans()
   |--mdl.cc/acquire_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_EXPLICIT,mdl_namespace=COMMIT,db_name='',name=''
transaction.cc/trans_commit_stmt()
|--handler.cc/ha_commit_trans()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_SHARED_WRITE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

8.4 update ...

执行语句:update d1.t1 set c1=111;

锁操作调用链:

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
sql_update.cc/Sql_cmd_update::execute()
|--sql_update.cc/Sql_cmd_update::try_single_table_update()
   |--sql_base.cc/open_tables_for_query()
      |--sql_base.cc/open_tables()
         |--sql_base.cc/open_and_process_table()
            |--sql_base.cc/open_table()
               |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_SHARED_WRITE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_update.cc/Sql_cmd_update::execute()
|--sql_update.cc/Sql_cmd_update::try_single_table_update()
   |--sql_base.cc/open_tables_for_query()
      |--sql_base.cc/open_tables()
         |--sql_base.cc/open_and_process_table()
            |--sql_base.cc/open_table()
               |--sql_base.cc/open_table_get_mdl_lock()
                  |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_EXPLICIT,mdl_namespace=COMMIT,db_name='',name=''
transaction.cc/trans_commit_stmt()
|--handler.cc/ha_commit_trans()
   |--mdl.cc/acquire_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_EXPLICIT,mdl_namespace=COMMIT,db_name='',name=''
transaction.cc/trans_commit_stmt()
|--handler.cc/ha_commit_trans()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_SHARED_WRITE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

8.5 delete from ...

执行语句:delete from d1.t1 where id=1005;

锁操作调用链:

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
sql_delete.cc/Sql_cmd_delete::execute()
|--sql_delete.cc/Sql_cmd_delete::mysql_delete()
   |--sql_base.cc/open_tables_for_query()
      |--sql_base.cc/open_tables()
         |--sql_base.cc/open_and_process_table()
            |--sql_base.cc/open_table()
               |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_SHARED_WRITE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_delete.cc/Sql_cmd_delete::execute()
|--sql_delete.cc/Sql_cmd_delete::mysql_delete()
   |--sql_base.cc/open_tables_for_query()
      |--sql_base.cc/open_tables()
         |--sql_base.cc/open_and_process_table()
            |--sql_base.cc/open_table()
               |--sql_base.cc/open_table_get_mdl_lock()
                  |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_EXPLICIT,mdl_namespace=COMMIT,db_name='',name=''
transaction.cc/trans_commit_stmt()
|--handler.cc/ha_commit_trans()
   |--mdl.cc/acquire_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_EXPLICIT,mdl_namespace=COMMIT,db_name='',name=''
transaction.cc/trans_commit_stmt()
|--handler.cc/ha_commit_trans()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_SHARED_WRITE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

8.6 drop table ...

执行语句:drop table d1.t1;

锁操作调用链:

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
sql_table.cc/mysql_rm_table()
|--sql_base.cc/lock_table_names()
   |--mdl.cc/acquire_locks()
      |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=SCHEMA,db_name=d1,name=''
sql_table.cc/mysql_rm_table()
|--sql_base.cc/lock_table_names()
   |--mdl.cc/acquire_locks()
      |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_table.cc/mysql_rm_table()
|--sql_base.cc/lock_table_names()
   |--mdl.cc/acquire_locks()
      |--mdl.cc/acquire_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=SCHEMA,db_name=d1,name=''
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

8.7 create table ...

执行语句:create table d1.t1 (id int(11) not null, name varchar(100), age int(11), primary key(id));

锁操作调用链:

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
sql_table.cc/mysql_create_table()
|--sql_base.cc/open_tables()
   |--sql_base.cc/lock_table_names()
      |--mdl.cc/acquire_locks()
         |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=SCHEMA,db_name=d1,name=''
sql_table.cc/mysql_create_table()
|--sql_base.cc/open_tables()
   |--sql_base.cc/lock_table_names()
      |--mdl.cc/acquire_locks()
         |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_SHARED,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_table.cc/mysql_create_table()
|--sql_base.cc/open_tables()
   |--sql_base.cc/lock_table_names()
      |--mdl.cc/acquire_locks()
         |--mdl.cc/acquire_lock()

//升级锁
// 旧锁:mdl_type=MDL_SHARED,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
// 新锁:mdl_type=MDL_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_table.cc/mysql_create_table()
|--sql_base.cc/open_tables()
   |--sql_base.cc/open_and_process_table()
      |--sql_base.cc/open_table()
         |--mdl.cc/upgrade_shared_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=SCHEMA,db_name=d1,name=''
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

8.8 flush tables with read lock

执行语句:flush tables with read lock;

锁操作调用链:

//获取锁:mdl_type=MDL_SHARED,mdl_duration=MDL_EXPLICIT,mdl_namespace=GLOBAL,db_name='',name=''
sql_reload.cc/reload_acl_and_cache()
|--lock.cc/lock_global_read_lock()
   |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_SHARED,mdl_duration=MDL_EXPLICIT,mdl_namespace=COMMIT,db_name='',name=''
sql_reload.cc/reload_acl_and_cache()
|--lock.cc/make_global_read_lock_block_commit()
   |--mdl.cc/acquire_lock()

//以下释放锁流程需要手动执行:unlock tables
//释放锁:mdl_type=MDL_SHARED,mdl_duration=MDL_EXPLICIT,mdl_namespace=COMMIT,db_name='',name=''
lock.cc/unlock_global_read_lock()
|--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_SHARED,mdl_duration=MDL_EXPLICIT,mdl_namespace=GLOBAL,db_name='',name=''
lock.cc/unlock_global_read_lock()
|--mdl.cc/release_lock()

8.9 desc ...

执行语句:desc d1.t1;

锁操作调用链:

//获取锁:mdl_type=MDL_SHARED_HIGH_PRIO,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_parse.cc/execute_sqlcom_select()
|--sql_select.cc/handle_query()
   |--sql_executor.cc/JOIN::exec()
      |--sql_select.cc/JOIN::prepare_result()
         |--sql_show.cc/get_schema_tables_result()
            |--sql_show.cc/do_fill_table()
               |--sql_show.cc/get_all_tables()
                  |--sql_show.cc/fill_schema_table_by_open()
                     |--sql_base.cc/open_tables_for_query()
                        |--sql_base.cc/open_tables()
                           |--sql_base.cc/open_and_process_table()
                              |--sql_base.cc/open_table()
                                 |--sql_base.cc/open_table_get_mdl_lock()
                                    |--mdl.cc/acquire_lock()

//释放锁:mdl_type=MDL_SHARED_HIGH_PRIO,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_parse.cc/execute_sqlcom_select()
|--sql_select.cc/handle_query()
   |--sql_executor.cc/JOIN::exec()
      |--sql_select.cc/JOIN::prepare_result()
         |--sql_show.cc/get_schema_tables_result()
            |--sql_show.cc/do_fill_table()
               |--sql_show.cc/get_all_tables()
                  |--sql_show.cc/fill_schema_table_by_open()
                     |--mdl.cc/rollback_to_savepoint()
                        |--mdl.cc/release_locks_stored_before()
                           |--mdl.cc/release_lock()

8.10 alter table ... add column ...

执行语句:alter table d1.t1 add column c1 int not null;

锁操作调用链:

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
sql_alter.cc/Sql_cmd_alter_table::execute()
|--sql_table.cc/mysql_alter_table()
   |--sql_base.cc/open_tables()
      |--sql_base.cc/lock_table_names()
         |--mdl.cc/acquire_locks()
            |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=SCHEMA,db_name=d1,name=''
sql_alter.cc/Sql_cmd_alter_table::execute()
|--sql_table.cc/mysql_alter_table()
   |--sql_base.cc/open_tables()
      |--sql_base.cc/lock_table_names()
         |--mdl.cc/acquire_locks()
            |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_SHARED_UPGRADABLE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_alter.cc/Sql_cmd_alter_table::execute()
|--sql_table.cc/mysql_alter_table()
   |--sql_base.cc/open_tables()
      |--sql_base.cc/lock_table_names()
         |--mdl.cc/acquire_locks()
            |--mdl.cc/acquire_lock()

//升级锁
// 旧锁:mdl_type=MDL_SHARED_UPGRADABLE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
// 新锁:mdl_type=MDL_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_alter.cc/Sql_cmd_alter_table::execute()
|--sql_table.cc/mysql_alter_table()
   |--sql_table.cc/mysql_inplace_alter_table()
      |--mdl.cc/upgrade_shared_lock()

//降级锁
// 旧锁:mdl_type=MDL_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
// 新锁:mdl_type=MDL_SHARED_UPGRADABLE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_alter.cc/Sql_cmd_alter_table::execute()
|--sql_table.cc/mysql_alter_table()
   |--sql_table.cc/mysql_inplace_alter_table()
      |--mdl.cc/downgrade_lock()

//升级锁
// 旧锁:mdl_type=MDL_SHARED_UPGRADABLE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
// 新锁:mdl_type=MDL_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_alter.cc/Sql_cmd_alter_table::execute()
|--sql_table.cc/mysql_alter_table()
   |--sql_table.cc/mysql_inplace_alter_table()
      |--sql_base.cc/wait_while_table_is_used()
         |--mdl.cc/upgrade_shared_lock()

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_EXPLICIT,mdl_namespace=COMMIT,db_name='',name=''
transaction.cc/trans_commit_stmt()
|--handler.cc/ha_commit_trans()
   |--mdl.cc/acquire_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_EXPLICIT,mdl_namespace=COMMIT,db_name='',name=''
transaction.cc/trans_commit_stmt()
|--handler.cc/ha_commit_trans()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=SCHEMA,db_name=d1,name=''
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

8.11 alter table ... algorithm=copy

执行语句:alter table d1.t1 algorithm=copy;

锁操作调用链:

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
sql_alter.cc/Sql_cmd_alter_table::execute()
|--sql_table.cc/mysql_alter_table()
   |--sql_base.cc/open_tables()
      |--sql_base.cc/lock_table_names()
         |--mdl.cc/acquire_locks()
            |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=SCHEMA,db_name=d1,name=''
sql_alter.cc/Sql_cmd_alter_table::execute()
|--sql_table.cc/mysql_alter_table()
   |--sql_base.cc/open_tables()
      |--sql_base.cc/lock_table_names()
         |--mdl.cc/acquire_locks()
            |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_SHARED_UPGRADABLE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_alter.cc/Sql_cmd_alter_table::execute()
|--sql_table.cc/mysql_alter_table()
   |--sql_base.cc/open_tables()
      |--sql_base.cc/lock_table_names()
         |--mdl.cc/acquire_locks()
            |--mdl.cc/acquire_lock()

//升级锁
// 旧锁:mdl_type=MDL_SHARED_UPGRADABLE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
// 新锁:mdl_type=MDL_SHARED_NO_WRITE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_alter.cc/Sql_cmd_alter_table::execute()
|--sql_table.cc/mysql_alter_table()
   |--mdl.cc/upgrade_shared_lock()

//升级锁
// 旧锁:mdl_type=MDL_SHARED_NO_WRITE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
// 新锁:mdl_type=MDL_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_alter.cc/Sql_cmd_alter_table::execute()
|--sql_table.cc/mysql_alter_table()
   |--sql_base.cc/wait_while_table_is_used()
      |--mdl.cc/upgrade_shared_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=SCHEMA,db_name=d1,name=''
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

8.12 alter table ... algorithm=inplace

执行语句:alter table d1.t1 algorithm=inplace;

锁操作调用链:

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
sql_alter.cc/Sql_cmd_alter_table::execute()
|--sql_table.cc/mysql_alter_table()
   |--sql_base.cc/open_tables()
      |--sql_base.cc/lock_table_names()
         |--mdl.cc/acquire_locks()
            |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=SCHEMA,db_name=d1,name=''
sql_alter.cc/Sql_cmd_alter_table::execute()
|--sql_table.cc/mysql_alter_table()
   |--sql_base.cc/open_tables()
      |--sql_base.cc/lock_table_names()
         |--mdl.cc/acquire_locks()
            |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_SHARED_UPGRADABLE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_alter.cc/Sql_cmd_alter_table::execute()
|--sql_table.cc/mysql_alter_table()
   |--sql_base.cc/open_tables()
      |--sql_base.cc/lock_table_names()
         |--mdl.cc/acquire_locks()
            |--mdl.cc/acquire_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_SHARED_UPGRADABLE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

//释放锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=SCHEMA,db_name=d1,name=''
mdl.cc/release_transactional_locks()
|--mdl.cc/release_locks_stored_before()
   |--mdl.cc/release_lock()

8.13 lock table ... read

执行语句:lock table d1.t1 read;

锁操作调用链:

//获取锁:mdl_type=MDL_SHARED_READ_ONLY,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_parse.cc/lock_tables_open_and_lock_tables()
|--sql_base.cc/open_tables()
   |--sql_base.cc/lock_table_names()
      |--mdl.cc/acquire_locks()
         |--mdl.cc/acquire_lock()

//释放锁需要手动执行:unlock tables

8.14 lock table ... write

执行语句:lock table d1.t1 write;

锁操作调用链:

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_STATEMENT,mdl_namespace=GLOBAL,db_name='',name=''
sql_parse.cc/lock_tables_open_and_lock_tables()
|--sql_base.cc/open_tables()
   |--sql_base.cc/lock_table_names()
      |--mdl.cc/acquire_locks()
         |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_INTENTION_EXCLUSIVE,mdl_duration=MDL_TRANSACTION,mdl_namespace=SCHEMA,db_name=d1,name=''
sql_parse.cc/lock_tables_open_and_lock_tables()
|--sql_base.cc/open_tables()
   |--sql_base.cc/lock_table_names()
      |--mdl.cc/acquire_locks()
         |--mdl.cc/acquire_lock()

//获取锁:mdl_type=MDL_SHARED_NO_READ_WRITE,mdl_duration=MDL_TRANSACTION,mdl_namespace=TABLE,db_name=d1,name=t1
sql_parse.cc/lock_tables_open_and_lock_tables()
|--sql_base.cc/open_tables()
   |--sql_base.cc/lock_table_names()
      |--mdl.cc/acquire_locks()
         |--mdl.cc/acquire_lock()

//释放锁需要手动执行:unlock tables

 

标签: 暂无
最后更新:2022年8月13日

jemuel

这个人很懒,什么都没留下

点赞
< 上一篇
下一篇 >

文章评论

您需要 登录 之后才可以评论
文章目录
  • 1、MDL
  • 2、数据结构
    • 2.1 MDL_request
    • 2.2 MDL_lock
    • 2.3 MDL_ticket
    • 2.4 MDL_key
    • 2.5 MDL_context
    • 2.6 MDL_map
    • 2.7 结构关系图
  • 3、MDL属性
    • 3.1 MDL namespace
    • 3.2 MDL type
    • 3.3 MDL duration
  • 4、MDL策略
    • 4.1 范围锁(scoped lock)
    • 4.2 对象锁(object lock)
  • 5、锁权限判断优化
    • 5.1 集合类型
    • 5.2 集合划分
      • 5.2.1 范围锁划分
      • 5.2.2 对象锁划分
    • 5.3 特殊标志
  • 6、锁操作
    • 6.1 获取锁
    • 6.2 锁升级
    • 6.3 锁降级
    • 6.4 释放锁
  • 7、加锁分析
  • 8、常用语句加锁流程
    • 8.1 select from ...
    • 8.2 select from ... for update
    • 8.3 insert into ...
    • 8.4 update ...
    • 8.5 delete from ...
    • 8.6 drop table ...
    • 8.7 create table ...
    • 8.8 flush tables with read lock
    • 8.9 desc ...
    • 8.10 alter table ... add column ...
    • 8.11 alter table ... algorithm=copy
    • 8.12 alter table ... algorithm=inplace
    • 8.13 lock table ... read
    • 8.14 lock table ... write
最新 热点 随机
最新 热点 随机
K8S源码分析系列2—远程调试K8S组件 Volcano源码分析系列—调度篇 K8S源码分析系列1—搭建K8S调试集群 K8S Controller开发 6.5840 Lab 1: MapReduce MongoDB源码分析系列1——编译环境搭建
K8S源码分析系列2—远程调试K8S组件
分布式共识算法paxos Volcano源码分析系列—调度篇 GraphQL介绍及使用 Golang优先级调度 K8S源码分析系列1—搭建K8S调试集群 6.5840 Lab 1: MapReduce

COPYRIGHT © 2021 www.miaozhouguang.com. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

粤ICP备2022006024号

粤公网安备 44030602006568号