[MySQL 源码]MySQL5.1版本 lock table write与DML操作产生的MySQL层/Innodb层死锁

————————————-

当在set autocommit=0时,执行lock table write操作,如果此时有同一个表上进入Innodb层的DML,可能导致死锁,这种死锁MySQL不做检测,只能等待Innodb层超时,简单的分析如下:

1.

对于lock table write操作,backtrace如下:

SQL :set aucommit = 0 && lock tables t1 write:

mysql_execute_command

    –>open_and_lock_tables_derived

         –>simple_open_n_lock_tables

            –>open_and_lock_tables_derived

                –>lock_tables

                  –>mysql_lock_tables

在mysql_lock_tables函数中:

调用lock_external

            ->handler::ha_external_lock

                  ->ha_innodb::external_lock

                        ->row_lock_table_for_mysql   对innodb表进行加锁(LOCK_X)

随后调用thr_multi_lock

                         ->thr_lock->wait_for_lock   —>等待锁释放  (如果已经有DML进入Innodb层还没完成的话)

2.

对于进入Innodb层的DML,例如一条insert操作,该线程会被suspend:

 row_insert_for_mysql

      –>row_ins_step(thr)

                –>lock_table(0, node->table, LOCK_IX, thr);

 由于lock table操作为该表加了LOCK_X锁,因此这里insert操作在尝试加LOCK_IX锁时失败,返回

DB_LOCK_WAIT,线程被suspend,等待超时。

5.5通过MDL锁解决了MySQL层和Innodb层的死锁问题,但在5.1里,目前唯一的办法就是等待在innodb层超时。

.

.

.

.

.

.

.

.

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

以下为本人自言自语,记录目的为以后调试方便,不保证正确性。。。。。。

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

最近看到参数skip_external_locking,看了官方的解释,该参数看起来只对MyISAM引擎有用,用于在多进程(也就是有多个服务器程序时)对单个表操作时进行锁定,默认值为打开,也就是跳过外部锁定。

之前一直对external lock没啥概念,大概浏览了下,以下只是简略的笔记。

从代码里可以发现,innodb也实现了相应的external_lock函数。那么这个external lock是做什么的呢?

在handler.cc里对应的是:

handler::ha_external_lock(THD *thd, int lock_type)

调用的地方包括

sql_table.cc:

copy_data_between_tables

当alter table,需要拷贝数据时,对目标表上F_WRLCK锁,然后再向其中拷贝数据。

lock.cc:

mysql_lock_tables->lock_external->handler::ha_external_lock

mysql_unlock_tables->unlock_external->handler::ha_external_lock

mysql_lock_tables用于对SQL涉及到的表进行加锁,从lock_external里可以看到

当只对表做读操作时(TL_READ_NO_INSERT>=lock_type >= TL_READ),锁类型为F_RDLCK

否则为F_WRLCK

然后对涉及到的表依次调用(*tables)->file->ha_external_lock

opt_range.cc:

QUICK_RANGE_SELECT::init_ror_merged_scan

QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT

在初始化ROR(RowidOrderedRetrieval) merge scan时调用。

ha_partition.cc:

ha_partition::prepare_new_partition

ha_partition::cleanup_new_partition

在innodb层,调用的是ha_innobase::external_lock,主要做如下工作:

1.update_thd(thd);

2.设置prebuilt->sql_stat_start = TRUE

3.根据lock_type的类型值,设置相应的变量,所谓的external lock,并不是实际上加锁,仅仅是设置某些标记。加锁操作包括:

–当lock_type == F_WRLCK时:

  prebuilt->select_lock_type = LOCK_X;

  prebuilt->stored_select_lock_type = LOCK_X;

–当lock_type不等于F_UNLCK

        (1).innobase_register_trx(ht, thd, trx);

        (2).if (trx->isolation_level == TRX_ISO_SERIALIZABLE          —-隔离级别为SERIALIZABLE

            && prebuilt->select_lock_type == LOCK_NONE

            && thd_test_options(

                thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {

              prebuilt->select_lock_type = LOCK_S;

              prebuilt->stored_select_lock_type = LOCK_S;

        }

        (3).对于LOCK TABLE操作,只有在AUTOCOMMIT = 0时,才会对Innodb表加锁(row_lock_table_for_mysql)

        (4).trx->n_mysql_tables_in_use++;

           prebuilt->mysql_has_locked = TRUE;

           DBUG_RETURN(0);

—以下为解锁逻辑

(1)设置标记

    trx->n_mysql_tables_in_use–;

    prebuilt->mysql_has_locked = FALSE;

(2)innobase_release_stat_resources(trx);

if (trx->n_mysql_tables_in_use == 0)   //表明该SQL语句已经完成,需要重置相关变量和标记

         当设置为自动提交时,则会在innodb层提交事务(innobase_commit),否则如果隔离级别小于等于read commited,则关闭该SQL的read view。

时间: 2024-08-07 20:12:05

[MySQL 源码]MySQL5.1版本 lock table write与DML操作产生的MySQL层/Innodb层死锁的相关文章

Linux下MySQL源码编译安装(eg:mysql-5.6.27.tar.gz )

Linux下MySQL源码安装(eg:mysql-5.6.27.tar.gz ): 1:准备MySQL源码安装包: mysql-5.6.27.tar.gz.cmake-3.3.2.tar.gz.ncurses-6.0.tar.gz 注:centos请安装: yum install -y ncurses-devel yum install -y perl-Module-Install.noarch 网址: https://cmake.org/download/ ftp://invisible-is

MySQL源码安装总结(r12笔记第12天)

作为一个DBA, MySQL源码安装还是要做做的,虽然不是推荐线上批量安装部署,但是自己作为了解MySQL的一个学习过程,还是值得的. 相比商业软件来说,开源的这一点上就让人很羡慕,商业软件我们总是使用各种工具和底层原理去反推,探测,但是离代码还是有一定的距离.当然商业有商业的好,开源有开源的乐,不能一概而论. 值得推荐的安装镜像 对于MySQL的安装部署来说,总是存在各种版本和子版本,其实整理起来非常繁杂,今天看到竟然我狐已经提供了非常的镜像站点 http://mirrors.sohu.com

mysql源码安装

我准备学下mysql的源码,所以编译和调试源码是很重要的一部分. 好了废话不多说. 我的环境是 CentOS-6.9-x86_64-minimal,这个可以在阿里的源中直接下.阿里云CentOS6.9下载地址 然后是安装之前的准备工作 先装好环境 yum update yum -y install cmake yum -y install bison yum -y install library* yum -y install libncurses5-dev yum -y install g++

Linux CentOS6.6系统中安装mysql源码包的方法_Linux

这里以CentOS6.6系统中安装MySQL的源码包,进行讲解. 1. mysql源码包的下载 mysql安装包的官方下载地址为:http://dev.mysql.com/downloads/mysql/5.6.html 打开该下载地址后,在 "Select Version:"处,选择要下载的mysql的版本,我选择的是5.6.34:在"Select Platform:"处,选择适用的操作系统类型,由于是下载源码包,故这里我们要选择Source Code. 之后,会

Linux下mysql源码安装笔记_Mysql

1.假设已经有mysql-5.5.10.tar.gz以及cmake-2.8.4.tar.gz两个源文件 (1)先安装cmake(mysql5.5以后是通过cmake来编译的) [root@ rhel5 local]#tar -zxv -f cmake-2.8.4.tar.gz [root@ rhel5 local]#cd cmake-2.8.4 [root@ rhel5 cmake-2.8.4]#./configure [root@ rhel5 cmake-2.8.4]#make [root@

MYSQL源码编译的变动

Mysql的安装,对于mysql不同版本的mysql源码编译方式不一样 5.6.2的版本开始编译方式已经由 configure 变成了cmake方式 ,相关的新的 编译方式在mysql官网已经提供 http://dev.mysql.com/doc/refman/5.6/en/source-configuration-options.html 源码下载地址如下 http://dev.mysql.com/downloads/mysql/ 网上相关mysql5.6的源码编译方式 http://www.

MySQL源码:Range优化相关的数据结构

1. 背景知识 在开始介绍Range的主要数据结构之前,我们先看Range优化的一些概念和背景.依旧建议先阅读参考文件的[1-8],Sergey Petrunya写的PPT和文档质量都很高,很多图示,非常直观的展示了原理. (1) 什么是Range条件? 参考Range Optimization@MySQL Manual 单列Range和多列Range (2) 给定一个KEY(key1)对应的WHERE条件,如何将其转化成一个Range,下面是"简述",详细参考单列Range: SEL

MySQL源码:索引相关的数据结构(前篇)

1. MySQL如何描述某个数据表的索引 MySQL使用TABLE对象来描述一个数据表,那么数据表的索引是如何描述,索引的统计信息又是如何存储的呢? 例如我们有如下数据表: CREATE TABLE `users` ( `id` int(11) NOT NULL, `nick` varchar(32) DEFAULT NULL, `reg_date` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `IND_NICK` (`nick`), KEY `

MySQL 源码scr.rpm安装的一点注意事项

    rpm安装包通常为二进制包(Binary)以及源代码包(Source)两种形式.在使用源码方式安装MySQL的时候,官方网站上下载的源码包通常为scr.rpm格式,而不是直接的tar包,对此,需要先使用rpm命令先安装源码后在进行编译安装,本文是对该方式的描述.   1.下载源码包  http://mirrors.sohu.com/mysql/MySQL-5.6/  http://dev.mysql.com/downloads/mysql/   2.安装rpm#环境suse11:~ #