从mysql源码看GAP LOCK死锁问题

 

环境篇:关于mysql源码开发环境搭建

1.基础开发包安装,一般ubuntu安装完这些就OK了

> sudo apt-get -y install \
 libreadline-dev libreadline6 libncurses5-dev libboost-dev \
 g++ openssl libssl-dev bison make cmake git && \
 apt-get clean

2.容器的选择,大家大可以根据自己的喜好来选择,无论是docker、WSL + xmanage 、

还是 vscode + WSL 都是不错的选择,近年来,微软对开发者的友好度提升的不是一点点,

从 Vscode + Arduino 生产力可以看见,微软正在做软硬通吃的场景

 

好,进入正题了,先看几个死锁现象

第一步,我们先关闭自动mysql自动提交的,不然就看不到效果了

第二步,我在trx1中用for update 锁住一条不存在的数据

第三步,我们在trx2插入一条primary_key 不同于 trx1 中的数据,发现无法插入,一直lock wait中

为什么insert所指的行,发生锁超时了,我明明没有锁8这条数据,为什么会对不存在的key,进行加锁,难道这升级为mysql的表锁,再看下一个现象

第一步:重复上述步骤,继续查找4这条数据,因为索引是有序的,所以到4这条数据应该,不再往下查了,后面的数据都比4要大,所以后面的数据不该被锁,锁已这里不该是表锁,一定发生的是行锁

第二步:在trx2总继续插一条比数据已存在的任意一条都要大的数据,按照刚才的猜想应该不被锁住,但令人意外的是,这条数据还是无法插入

我们在来看我们现在锁4这条数据,明显如果按照mysql遍历,我么大胆猜测应该锁4,或者(6,1,1)这条数据,但是很明显,这里我们(6,2,1) 都是无法插入,所以这个应该不是表锁

思考🤔:为什么箭头锁指的方向没锁,按照道理来讲,我们执行了for update,会去尝试对相对应的数据尝试加锁,因为insert无法插入了,所以锁是一定存在的,为什么for update 表现出来是无锁访问

🤔:老子就锁了一条不存在的数据,然后你就罢工了?我非得揪出来你的小辫子,我先看看,你老爸当初怎么设计你的

 

 

innodb是基于b+tree,为了单页可以加载更多的索引,mysql分离了两种不用的存储方式,分别为叶子,和根节点,这里我们统一讲,infimum存在与逻辑节点的最小值, supremun存在于逻辑节点的最大值,在page创建的时候就被划分,并且不会发生改变(除上下指针)基于这个我们大胆猜测,间隙锁很有可能锁住了他的下一个元素就知道,当前锁是不是存在了

我们来看源码验证下:

确实我们查到在insert的时候,它去检查了锁,但是还是不能证明他就是去看了,他的下一个node,是否存在锁,我们继续往下看

锁代码2:

这里我们终于看到了next_rec,确实它去看了他的下一个元素是不是,找到了锁,这一步已经非常接近真相了,但是离真相还是有点远,拿到锁啥都不干?

原理:对于每条数据产生的时候都有唯一的heap_no与之对应,其实加锁我只知道相应heap_no 和 page_no就知道相应锁存在的hash表中

继续看…

暂停想一下,可能有些小伙伴已经明白了,innodb这货没查到数据,就把supremun这个记录给加锁了,所以怎么查都是锁,怎么查都是超时

源码3:

这里我们看到,如果锁发生锁的兼容性冲突,就是去执行锁队列等待,这里我们都以为我们找到真相,但其实我们还没有看到到底哪里发生了阻塞了,这里就不带大家看了,会涉及到linux的多线程相关,但是还是到这里我们还有一个问题没有解决,就是为什么for update 出现了无锁查询,继续…

代码4:

这段代码是从lock_rec_other_has_conflicting,中截出来的,也就是上面说的检查了锁的兼容性这里如果不是insert锁,会直接过锁队列,直接成功,这里就可以大致明白,innodb为了性能所作所为,和我们之前所说的为什么我查了一条不存在的数据,就简单的死锁了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值