postgresql regular lock常规锁申请与释放 以及fastpath快速申请优化的取舍

news/2024/10/19 18:26:06/

专栏内容
postgresql内核源码分析
手写数据库toadb
并发编程
个人主页:我的主页
座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物.

==================================

定义

每种常规锁都需要定义几个要素,它由结构体 LockMethodData 定义;

typedef struct LockMethodData
{int			numLockModes;const LOCKMASK *conflictTab;const char *const *lockModeNames;const bool *trace_flag;
} LockMethodData;typedef const LockMethodData *LockMethod;

这几个要素分别是:

  • 锁的模式类型,也就是锁分了几种加锁方式,比如这里表锁是8种,也就是8级表锁;
  • 锁的冲突矩阵,它是一个按bit的二维表,也就是各级锁方式之间的冲突关系,比如读写互斥,读读不冲突等;
  • 锁的名字,主要是为了查找调试;

postgresql 已经定义了一种默认锁 default_lockmethod, 也可以自定义用户锁

存储

regular lock是多进程间共享的,所以存储在共享内存中。
由这几个结构组织存储:

  • LockMethodLockHash ,以locktag为hash存储使用的锁
  • LockMethodProcLockHash , 存储锁的引用关系,由lock-proc对来存储,proc是每个backend信息
  • FastPathStrongRelationLocks ,
  • LockMethodLocalHash , 存储本进程持有的所,相同锁的话,只是引用计数递增

以上hash表,在初始化时就已经分配

申请

常规锁的申请主要在接口 LockAcquire 和 LockAcquireExtended中实现。

LockAcquireResult
LockAcquire(const LOCKTAG *locktag,LOCKMODE lockmode,bool sessionLock,bool dontWait)
{return LockAcquireExtended(locktag, lockmode, sessionLock, dontWait,true, NULL);
}LockAcquireResult
LockAcquireExtended(const LOCKTAG *locktag,LOCKMODE lockmode,bool sessionLock,bool dontWait,bool reportMemoryError,LOCALLOCK **locallockp);

可以看到最终是在 LockAcquireExtended实现 ,前者只是简单调用关系;

申请流程

下面我们来看LockAcquireExtended中的实现流程

  • 从本地锁记录中查找;如果找到则返回;如果没找到创建本地新记录;
  • 在standby模式时特殊处理;只能获取只读锁,此时需要先获取事务ID,以便锁与事务关锁;
  • fastpath 处理;

fastpath 只用在表锁模式下;当获取的锁小于4级ShareUpdateExclusiveLock时启用;
fastpath 可以记录FP_LOCK_SLOTS_PER_BACKEND 16个锁记录,根据locktag hash值取模,对应位置如果没有被占用count=0时,就进行fastpath;
通过 FastPathGrantRelationLock 进行获取锁 ;当对应bit位为0时,就直接获得锁,并将bit为置1,同时reloid数组中记录对应的reloid; 如果上次获取过4级以下的锁,那么也将直接获得;
这里有两个变量(proc)->fpLockBits和 (proc)->fpRelId[FP_LOCK_SLOTS_PER_BACKEND],前者记录锁模式,后者记录对应的reloid;前者是一个64位整型,每4bit为一组,可以记录16个锁;

  • 创建或查找锁,并创建锁proclock

当申请的是表锁且锁级别大于4时,先检查与 fastpath锁的冲突; 先在FastPathStrongRelationLocks->count[fasthashcode]对应+1,占位; 然后通过ProcGlobal来遍历所有进程中的fastpath信息;如果发现有backend已经通过fastpath占有4级以下锁,那么就创建lock和lockproc,在对应的hash中加入,这样在后面锁冲突判断时就会发现;

  • 检查锁冲突

从 LockMethodLockHash 查找锁的locktag,如果有说明已经有持有者;再从 LockMethodProcLockHash 创建持有者关系;

  • 先检查与锁等待者的冲突情况,根据lock->waitMask 来检查冲突;如果有冲突,则进行锁排队等待;
  • 再检查与已经持有的锁冲突情况,避免死锁等待; 这一步比较复杂,先检查持有锁,再检查锁组冲突;
    经过以上两步,没有冲突,则获得锁;有冲突测进行锁排队等待;
  • 锁冲突等待 ,至到有人唤醒为止

释放

在使用结束后释放锁,如果有等待者需要唤醒, 在LockRelease中进行处理。

bool 
LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock);

主要流程如下:

  • 检查本地是否记录锁的持有 LockMethodLocalHash ;

本地持有,那么先对锁持有计数 -1 ,如果不为零,那就释放完成,返回true;

如果锁计数为零时,先将本地持有锁数量-1,从资源管理中取消持有记录;

  • 处理fastpath申请的情况

如果持的有为fastpath申请的锁,从fastpath信息中清除;并清除本地锁记录,返回true;

  • 当然锁完全释放,从LockMethodLockHash和LockMethodProcLockHash中删除
  • 检查当前是否持有锁,如果已经不持有,清除本地锁记录,返回false;
  • 释放锁;
    锁授予和已请求计数分别 -1; 如果当前锁模式授予为0时,将grantMask的锁模式位置0;
    检查是否有等待者,也就是看waitMask是否有冲突,如果有则需要唤醒;
    在proclock中将持有锁holdMask中将当前锁模式置为0;
  • 清理锁并唤醒等待者;
    如果当前不再持有锁,则将lockproc从hash表中删除;
    如果当前锁的请求者为0时,将lock从hash表中删除;
    如果有请求者,也就是锁等待者,则需要唤醒;

遍历所有等待者,检查是否可以被唤醒,唤醒时,先授予锁,再唤醒,避够再次竞争;
等待者可以被唤醒的条件是:

  1. 等待者申请的锁模式与之前的等待者(没唤醒的),不会有锁冲突;
  2. 与已经持有锁者 不会产生锁冲突;
    如果产生冲突,都不会唤醒;
  • 清除本地锁记录并返回true;

结尾

非常感谢大家的支持,在浏览的同时别忘了留下您宝贵的评论,如果觉得值得鼓励,请点赞,收藏,我会更加努力!

作者邮箱:study@senllang.onaliyun.com
如有错误或者疏漏欢迎指出,互相学习。

注:未经同意,不得转载!


http://www.ppmy.cn/news/902122.html

相关文章

茅台的市场价值及消耗量计算

如何监测茅台的流通性和被喝了(瓶盖被毁机制),计算茅台的被珍藏年限及被消耗情况,自己被珍藏后的市场价值? 要监测茅台的流通性和被喝的情况(包括瓶盖被毁机制),可以通过以下步骤实现: 1. 采集数据:对于茅台来说,可以通过扫描二维码或条形码等方式,记录茅台的生产…

多少钱才算财富自由?

昨天说到蚂蚁即将上市,上市后之后将会有很多人实现财务自由,评论区就有不少读者问我,赚多少钱才能财务自由?这是个有意思的话题,今天跟大家聊聊。 首先咱们来看看财务自由的定义:财务自由是指你无需为生活开…

纽约金与伦敦金价的关系

目前美国是全球的黄金期货交易中心,纽约商品交易所旗下COMEX交易所的黄金期货常被称为“纽约金”。伦敦则是历史最悠久的黄金交易中心,是世界上最大的黄金市场,其特点是没有一个固定的交易所,即没有实际的交易场所,整个…

人,越朴素,越高贵

庄子说:“朴素而天下莫能与之争美。” 朴素,是极致的美。譬如一枝白莲,清清净净立于水中,不染一丝纤尘,素雅而高贵,胜过万千姹紫嫣红,所以古人说:“淡极始知花更艳,花到…

GuidUtil

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace LXYD.WebGame.Util.MiscHelpers {public class GuidUtil {/// /// 获取一个GUID /// /// public static string GuidKey => Guid.New…

价差 量差

这两个概念属于成本控制的范畴 成本控制有广义和狭义之分; 广义:生产经营各个环节和各个方面全过程的限制 狭义:生产阶段产品成本控制 标准成本就是通过一些方法制定的在有效的经营条件下应该实现的成本,根据产品的耗费标准和耗费…

价格的真相:用户嫌贵,并不是真的贵了

作者:康熙师爷 全文共 2906 字 10 图,阅读需要 7 分钟 ———— / BEGIN / ———— 99%的marketing,都很可能遇到过这些问题: “客户说我们产品太贵了,怎么办?” “A公司又开始降价促销了,怎么…

回归与度量

回归与度量 什么是回归 ​ 回归用于预测输入变量和输出变量之间的关系,当输入变量发生变化的时候,输出变量也随之发生变化。回归模型是输入到输出的一种映射函数。回归问题等价于函数拟合:选择一条函数曲线使其尽可能拟合当前数据的变化趋势&#xff0…