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

专栏内容
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
如有错误或者疏漏欢迎指出,互相学习。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/41309.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

边缘检测之loG算子

note // 边缘检测之loG算子:对高斯函数求二阶导数 // G(x,y) exp(-1 * (x*x y*y) / 2 / sigma / sigma) // loG(x,y) ((x*x y*y - 2 * sigma * sigma) / (sigma^4)) * exp(-1 * (x*x y*y) / 2 / sigma /sigma) /* [ 0,0,-1,0,0; 0,-1,-2,-1,0; -1,-2,16,-2…

(栈队列堆) 剑指 Offer 09. 用两个栈实现队列 ——【Leetcode每日一题】

❓ 剑指 Offer 09. 用两个栈实现队列 难度:简单 用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead …

Shikra:新一代多模态大语言模型,理解指向,说出坐标

“ Shikra:解锁多模态语言模型参考对话的魔法” Shikra和用户的对话案例 在人类的日常交流中,经常会关注场景中的不同区域或物体,双方都可以通过说话并指向这些区域来进行高效的信息交换。我们将这种对话模式称为参考对话(Referen…

C语言 替换gets函数

目录 替换gets函数gets()用处gets()的危险之处gets()的几种替代方法一、用%c循环输入直到遇到换行结束二、用getchar()循环输入直到遇到换行结束三、scanf的另一种用法四、c中的getline()方法五、解决方案使用fgets代替 替换gets函数 gets()用处 gets从标准输入设备读字符串函…

C# Linq 详解四

目录 概述 二十、SelectMany 二十一、Aggregate 二十二、DistinctBy 二十三、Reverse 二十四、SequenceEqual 二十五、Zip 二十六、SkipWhile 二十七、TakeWhile C# Linq 详解一 1.Where 2.Select 3.GroupBy 4.First / FirstOrDefault 5.Last / LastOrDefault C# Li…

truffle 进行智能合约测试

本方法使用了可视化软件Ganache 前两步与不使用可视化工具的步骤是一样的(有道云笔记),到第三步的时候需要注意: 在truffle插件下找到networks目录,提前打开Ganache软件 在Ganache中选择连接或者新建,我在…

软件测试测试用例

等价类:把输入的数据可以分为有效的数据和无效的数据 被测试的对象输入的数据: 1、有效的数据 2、无效的数据 测试一个产品,需要考虑它的正确场景,也需要考虑它的异常场景 边界值:边界值测试用例是针对等价类测试用例方法的补…

每天一道C语言编程:排队买票

题目描述 有M个小孩到公园玩,门票是1元。其中N个小孩带的钱为1元,K个小孩带的钱为2元。售票员没有零钱,问这些小孩共有多少种排队方法,使得售票员总能找得开零钱。注意:两个拿一元零钱的小孩,他们的位置互…

Thymeleaf + Layui+快速分页模板(含前后端代码)

发现很多模块写法逻辑太多重复的&#xff0c;因此把分页方法抽取出来记录以下&#xff0c;以后想写分页直接拿来用即可&#xff1a; 1. 首先是queryQrEx.html&#xff1a; <!DOCTYPE html> <html xmlns:th"http://www.w3.org/1999/xhtml"> <head>…

zabbix监控自己

目录 一、实验环境准备 二、server端 1、配置阿里云yum源 2、部署lamp环境 3、启动lamp对应服务 4、准备java环境 5、源码安装zabbix 6、mariadb数据库授权 7、创建zabbix程序用户并授权防止权限报错 8、修改zabbix配置文件 9、配置php与apache 10、web安装zabbix …

Qgis3.16ltr+VS2017二次开发环境搭建(保姆级教程)

1.二次开发环境搭建 下载osgeo4w-setup.exeDownload QGIShttps://www.qgis.org/en/site/forusers/download.html 点击OSGeo4W Network Installer 点击下载 OSGeo4W Installer 运行程序 osgeo4w-setup.exe&#xff0c;出现以下界面&#xff0c;点击下一页。 选中install from i…

uniapp中超好用(且免费)的安全类插件推荐!(持续更新中)

前几天写了一篇【干货分享】uniapp做的安卓App如何加固&#xff0c;发现收藏的人蛮多的。所以说&#xff0c;更加证明了我说的第一个问题&#xff1a;现在用uniapp的人是越来越多了。 而通过使用uniapp上自带的插件&#xff0c;也是能够实现事半功倍的效果&#xff0c;让不懂前…

OpenCv之图像形态学(二)

目录 一、形态学梯度 二、顶帽操作 三、黑帽操作 一、形态学梯度 梯度原图 - 腐蚀腐蚀之后原图边缘变小&#xff0c;原图 - 腐蚀 就可以得到腐蚀掉的部分&#xff0c;即边缘 案例代码如下: import cv2 import numpy as np# 导入图片 img cv2.imread(6.jpg)# 注意调节kern…

ubuntu打开usb摄像头

文章目录 前言一、识别 usb 摄像头二、安装应用程序显示摄像头捕捉到的视频1、使用应用程序茄子&#xff08;cheese&#xff09;2、运行 cheese 捕捉视频 前言 记录一下解决在 Linux 下打开 usb 摄像头界面黑屏的问题。 一、识别 usb 摄像头 1、保持在 ubuntu 界面&#xff0…

leetcode 965.单值二叉树

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;单值二叉树 思路&#xff1a; 让当前的根节点与左孩子节点与右孩子节点判断&#xff0c;若相等则继续向下分治&#xff0c;让左孩子与右孩子当作新的根节点继续判断&#xff0c;直到某个节点不相等。 1️⃣ 代码&#x…

相机标定学习笔记

Kalibr 是标定工具中&#xff0c;唯一一个可以标定camToImu的&#xff0c;是vio必不可少的工具&#xff0c;其他的都有替代品。所以学习多种开源算法进行相机标定&#xff0c;并记录学习相机标定的过程。 一、相机标定 1、在场景中放置一个已知的物体 &#xff08;1&#xff…

【DBA课程-笔记】第 3 章:MongoDB数据库核心知识

内容 一、MongoDB 数据库架构 A. MongoDB数据库体系架构 1. 存储引擎&#xff08;MongoDB Storage Engines&#xff09;&#xff1a; 2. MongoDB 数据逻辑架构 二、MongoDB 存储引擎 A. 查看mongodb服务器的状态 B. 查看引擎信息&#xff08;4.2.1 没有这个命令&#xf…

实例019 以图形按钮显示的界面

实例说明 菜单和工具栏虽然能方便用户操作程序的相应功能&#xff0c;但各有缺点。如果采用按钮式功能菜单&#xff0c;不但美观大方&#xff0c;而且操作灵活。当单击按钮时&#xff0c;用户区将显示相应的操作按钮组。下面介绍图形界面式菜单的设计方法。运行本例&#xff0…

ceph集群(二)

ceph 一、资源池 Pool 管理二、创建 CephFS 文件系统 MDS 接口三、创建 Ceph 块存储系统 RBD 接口四、创建 Ceph 对象存储系统 RGW 接口五、OSD 故障模拟与恢复 一、资源池 Pool 管理 上次我们已经完成了 Ceph 集群的部署&#xff0c;但是我们如何向 Ceph 中存储数据呢&#x…

餐饮行业油烟监控管理系统设计与应用

安科瑞 华楠 摘 要&#xff1a;餐饮油烟污染问题已经成为城市环境污染的重要污染源&#xff0c;本研究的油烟在线监测数据管理信息系统是油烟在线监测数据采集仪的配套软件&#xff0c;用于展现现场端数据采集仪采集的数据&#xff0c;对数据采集仪进行远程控制&#xff0c;以…