postgresql regular lock常规锁 烤的内嫩外焦,入口即化

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

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

介绍

常规锁,主要用于数据库对象的加锁,如表,根据用户请求来加锁 。

它有死锁检测,在事务结束时会自动释放。

regular lock原理

regular lock像lwlock一样会预先在共享内存中分配,对于每一类型需要加锁的数据库对象都会分配一个锁对象。

为了标识具体的数据库对象,所以locktag唯一标识了每个锁,它的内容与加锁对象关联起来。 这里就有个问题,数据库对象可以非常多,锁的数量也很庞大,如何确定锁的数量呢?

regular lock 结构

typedef struct LOCK
{/* hash key */LOCKTAG		tag;			/* unique identifier of lockable object *//* data */LOCKMASK	grantMask;		/* bitmask for lock types already granted */LOCKMASK	waitMask;		/* bitmask for lock types awaited */dlist_head	procLocks;		/* list of PROCLOCK objects assoc. with lock */dclist_head waitProcs;		/* list of PGPROC objects waiting on lock */int			requested[MAX_LOCKMODES];	/* counts of requested locks */int			nRequested;		/* total of requested[] array */int			granted[MAX_LOCKMODES]; /* counts of granted locks */int			nGranted;		/* total of granted[] array */
} LOCK;

锁标识 LOCKTAG

锁标识的定义如下

typedef struct LOCKTAG
{uint32		locktag_field1; /* a 32-bit ID field */uint32		locktag_field2; /* a 32-bit ID field */uint32		locktag_field3; /* a 32-bit ID field */uint16		locktag_field4; /* a 16-bit ID field */uint8		locktag_type;	/* see enum LockTagType */uint8		locktag_lockmethodid;	/* lockmethod indicator */
} LOCKTAG;

locktag 唯一标识一个常规锁,它由6个成员组成, 前四个成员,在不同类型的锁中对应不同的数据

最后一个lockmethodid是定义锁的操作及冲突矩阵,一般采用默认的定义

LOCKTAG_RELATIONLOCKTAG
LOCKTAG_RELATIONlocktag_field1 = dboid 当relation 为共享表时 dboid = 0
locktag_field2 = reloid
LOCKTAG_RELATION_EXTEND同上
LOCKTAG_DATABASE_FROZEN_IDSlocktag_field1 = dboid
LOCKTAG_PAGElocktag_field1 = dboid
locktag_field2 = reloid
locktag_field3 = blocknum
LOCKTAG_TUPLElocktag_field1 = dboid
locktag_field2 = reloid
locktag_field3 = blocknum
locktag_field4 = offnum
LOCKTAG_TRANSACTIONlocktag_field1 = xid
locktag_field2 = 0
locktag_field3 = 0
locktag_field4 = 0
LOCKTAG_VIRTUALTRANSACTIONlocktag_field1 = (vxid).backendId
locktag_field2 = (vxid).localTransactionId
locktag_field3 = 0
locktag_field4 = 0
LOCKTAG_SPECULATIVE_TOKENlocktag_field1 = xid
locktag_field2 = token
locktag_field3 = 0
locktag_field4 = 0
LOCKTAG_OBJECTlocktag_field1 = dboid
locktag_field2 = classoid
locktag_field3 = objoid
locktag_field4 = objsubid
LOCKTAG_USERLOCK用户自定义锁
LOCKTAG_ADVISORYlocktag_field1 = id1
locktag_field2 = id2
locktag_field3 = id3
locktag_field4 = id4
LOCKTAG_APPLY_TRANSACTIONlocktag_field1 = dboid
locktag_field2 = suboid
locktag_field3 = xid
locktag_field4 = objid

锁流程

初始化

初始化主要获取锁的共享内存区域指针,并且创建本地记录已持有锁的hash空间。
另外还有一个全局hash记录锁持有者,在共享内存中存储。

锁的初始化接口如下

void InitLocks(void);
  • 获取锁的数量
  #define NLOCKENTS() \mul_size(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))max_table_size = NLOCKENTS();init_table_size = max_table_size / 2;

每个backend可以最大持有锁的数量由GUC参数决定,最小10,最大为int上限

  • 在共享内存中分配锁的内存空间
  LockMethodLockHash = ShmemInitHash("LOCK hash",init_table_size,max_table_size,&info,HASH_ELEM | HASH_BLOBS | HASH_PARTITION);

常规锁在hash中存储,LockMethodLockHash的大小分配初始大小,不够时会再扩展,直到最大值。

  • 锁持有者记录的内存空间

锁持有者,按每个锁平均有两个持有者来计算,所以空间大小为

	max_table_size *= 2;init_table_size *= 2;

也是用hash链表来记录,在共享内存中分配

	LockMethodProcLockHash = ShmemInitHash("PROCLOCK hash",init_table_size,max_table_size,&info,HASH_ELEM | HASH_FUNCTION | HASH_PARTITION);
  • fastpath 信息记录的内存空间分配
	FastPathStrongRelationLocks =ShmemInitStruct("Fast Path Strong Relation Lock Data",sizeof(FastPathStrongRelationLockData), &found);
  • 每个backend自己也会记录自己持有锁信息
	LockMethodLocalHash = hash_create("LOCALLOCK hash",16,&info,HASH_ELEM | HASH_BLOBS);

这里也是使用hash,内存是在当前本地内存分配,大小指定为16,这里对于重复持有锁只累积计数。

锁种类

typedef enum LockTagType
{LOCKTAG_RELATION,			/* whole relation */LOCKTAG_RELATION_EXTEND,	/* the right to extend a relation */LOCKTAG_DATABASE_FROZEN_IDS,	/* pg_database.datfrozenxid */LOCKTAG_PAGE,				/* one page of a relation */LOCKTAG_TUPLE,				/* one physical tuple */LOCKTAG_TRANSACTION,		/* transaction (for waiting for xact done) */LOCKTAG_VIRTUALTRANSACTION, /* virtual transaction (ditto) */LOCKTAG_SPECULATIVE_TOKEN,	/* speculative insertion Xid and token */LOCKTAG_OBJECT,				/* non-relation database object */LOCKTAG_USERLOCK,			/* reserved for old contrib/userlock code */LOCKTAG_ADVISORY,			/* advisory user locks */LOCKTAG_APPLY_TRANSACTION	/* transaction being applied on a logical* replication subscriber */
} LockTagType;

当前使用regular lock 加锁的数据库对象,由LockTagType定义,每一种对象都有对应的加锁、解锁接口

常规锁接口

表锁相关接口

表锁被分为8级,每级定义了使用范围,同时按等级递增规定了冲突矩阵。

在open表时,使用OID或relid来对表进行加锁,也可以尝试加锁,不进行等待

extern void LockRelationOid(Oid relid, LOCKMODE lockmode);
extern void LockRelationId(LockRelId *relid, LOCKMODE lockmode);
extern bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode);
extern void UnlockRelationId(LockRelId *relid, LOCKMODE lockmode);
extern void UnlockRelationOid(Oid relid, LOCKMODE lockmode);

以下接口是open之后,进一步对表加锁时调用

此时relation结构可用,直接使用此结构就可以对表加锁

extern void LockRelation(Relation relation, LOCKMODE lockmode);
extern bool ConditionalLockRelation(Relation relation, LOCKMODE lockmode);
extern void UnlockRelation(Relation relation, LOCKMODE lockmode);
extern bool CheckRelationLockedByMe(Relation relation, LOCKMODE lockmode,bool orstronger);
extern bool LockHasWaitersRelation(Relation relation, LOCKMODE lockmode);extern void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode);
extern void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode);

表扩展时相关锁接口

extern void LockRelationForExtension(Relation relation, LOCKMODE lockmode);
extern void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode);
extern bool ConditionalLockRelationForExtension(Relation relation,LOCKMODE lockmode);
extern int	RelationExtensionLockWaiterCount(Relation relation);

计算database frozenxid时的锁接口

extern void LockDatabaseFrozenIds(LOCKMODE lockmode);

每个数据库会计算 frozenxid,然后计算所有库的最小值作为集群的frozenxid;
每个database的值在 pg_database.datfrozenxid 字段中存储

锁定page 时的接口

extern void LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
extern bool ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
extern void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);

当前只在索引中使用

行锁接口

extern void LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode);
extern bool ConditionalLockTuple(Relation relation, ItemPointer tid,LOCKMODE lockmode);
extern void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode);

事务等待锁接口

extern void XactLockTableInsert(TransactionId xid);
extern void XactLockTableDelete(TransactionId xid);
extern void XactLockTableWait(TransactionId xid, Relation rel,ItemPointer ctid, XLTW_Oper oper);
extern bool ConditionalXactLockTableWait(TransactionId xid);

主要用于事务隔离冲突时,等待某个事务xid结束时使用

VXID锁接口

extern void WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode, bool progress);
extern void WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress);

用于 VXID冲突时进行等待

行插入锁接口

extern uint32 SpeculativeInsertionLockAcquire(TransactionId xid);
extern void SpeculativeInsertionLockRelease(TransactionId xid);
extern void SpeculativeInsertionWait(TransactionId xid, uint32 token);

其它数据库对象(除表外)

extern void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,LOCKMODE lockmode);
extern void UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,LOCKMODE lockmode);

跨库数据库对角

extern void LockSharedObject(Oid classid, Oid objid, uint16 objsubid,LOCKMODE lockmode);
extern void UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,LOCKMODE lockmode);extern void LockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,LOCKMODE lockmode);
extern void UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,LOCKMODE lockmode);extern void LockApplyTransactionForSession(Oid suboid, TransactionId xid, uint16 objid,LOCKMODE lockmode);
extern void UnlockApplyTransactionForSession(Oid suboid, TransactionId xid, uint16 objid,LOCKMODE lockmode);										 

结尾

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux命令与shell编程

文章目录 一、概念linux内存嵌入式嵌入式层次图判断小端和大端 二、linux系统操作命令ls查看cd 命令pwd命令touch 创建文件mkdir 创建目录chmod 修改权限man命令cp 拷贝mv 移动rm命令cat命令echo 命令tty命令->查看当前终端号clear 命令ldd命令 ->查看文件依赖哪些库prin…

阿里云ECS云服务器的云盘使用

在我阿里云控制台上,可以看到有额外的磁盘(2个实例,3个磁盘) 找到对应云服务实例,看到了云盘信息 状态显示的挂接点是:/dev/xvdb 进入服务器却无法找到,也无法挂载 执行命令:fdisk …

spring 自带的校验框架使用

引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>编写规则 开启校验

Ai数字人——为写实而生

在当今数字化时代&#xff0c;人工智能技术正成为推动各行各业发展的重要驱动力。企业需要创新的解决方案&#xff0c;以提高效率、降低成本、增强客户体验并应对市场竞争。Ai数字人作为数字化转型的关键组成部分&#xff0c;具备强大的潜力和多样化的应用场景。 根据市场研究…

如果在SOLIDWORKS中修改导入的实体?

一、导入的供应商文件 在本例子中&#xff0c;供应商提供了所需部件的版本&#xff0c;它被作为IGES文件导入。我们的目的是在Solidworks中修改这个零件而不是重建它。为此&#xff0c;我们将直接从现有几何体创建一个与新零件规格匹配的模型版本。 打开供应商文件 红色箭头…

【Spring】项目创建和使用

一、Spring 的概念 Spring : 包含众多工具方法的 IoC 容器。 Spring 的核心 &#xff1a;IoC &#xff08;控制反转&#xff09;&#xff0c; DI (依赖注入)。 loC &#xff08;Inversion of Control&#xff09;翻译成中文就是 “控制反转” 的意思&#xff0c;控制反转一种…

【C语言】指针进化:传参与函数(2)

莫道君行早&#xff0c;更有早行人。— 出自《增广贤文上集》 解释&#xff1a;别说你出发的早&#xff0c;还有比你更早的人。 这篇博客我们将会深入的理解数组传参和函数指针等指针&#xff0c;是非常重要的内容&#xff0c;学好这部分才能算真正学懂C语言。 目录 一维数组传…

vscode maven开发

安装jdk 安装maven 安装vscode 安装vscode插件 Extension Pack for JavaSpring Boot Extension PackLombok Annotations Support for VS CodeLanguage Support for Java™ by Red Hat jdk和maven配置 {"workbench.colorTheme": "One Dark Pro","…

Unity经营类美食小摊小游戏

Unity经营类美食小摊小游戏 挺有意思的小游戏 关卡页面 游戏主页面 有顾客上门 需要给顾客搭配他们想要的美食 会不断地有顾客过来&#xff0c;这个时候就考验手速的时候了&#xff0c;真实模拟经营 服务到位立马有钱 项目地址&#xff1a; https://download.csdn.net/downl…

4 款非常好用的AI生成图片软件

AI生成图片最近是越来越火了&#xff0c;越来越多的AI生成图片工具上线。 本文就给你推荐4款非常好用的AI生成图片工具&#xff0c;避免你碰雷。 即时灵感 「即时灵感」是通过文字描述等方式生成精致图像的AI绘图工具。输入文字&#xff0c;即可将创意变为现实&#xff01; …

C#轻松读写NDEF智能海报

NDEF 全称 NFC data exchange format 即 nfc 数据交换格式&#xff0c;是一种标准化的数据格式&#xff0c;可用于在任何兼容的NFC设备与另一个NFC设备或标签之间交换信息。数据格式由NDEF消息和NDEF记录组成。 NDEF信息可以写到不同类型的NFC芯片中&#xff0c;如Ntag系列芯片…

【Java基础教程】(十一)面向对象篇 · 第五讲:透彻讲解Java中的static关键字及代码块——静态属性、静态方法和普通代码块、构造块、静态块的使用~

Java基础教程之面向对象 第五讲 本节学习目标1️⃣ static 关键字1.1 static定义静态属性1.2 static定义静态方法1.3 主方法1.4 实际应用功能一&#xff1a;实现类实例化对象个数的统计功能二&#xff1a; 实现属性的自动设置 2️⃣ 代码块2.1 普通代码块2.2 构造块2.3 静态块…