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

这篇具有很好参考价值的文章主要介绍了postgresql regular lock常规锁 烤的内嫩外焦,入口即化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

postgresql regular lock常规锁 烤的内嫩外焦,入口即化,#  postgresql内核源码分析,postgresql,postgresql,数据库,sql,c语言,linux,数据库架构,架构

专栏内容
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_RELATION LOCKTAG
LOCKTAG_RELATION locktag_field1 = dboid 当relation 为共享表时 dboid = 0
locktag_field2 = reloid
LOCKTAG_RELATION_EXTEND 同上
LOCKTAG_DATABASE_FROZEN_IDS locktag_field1 = dboid
LOCKTAG_PAGE locktag_field1 = dboid
locktag_field2 = reloid
locktag_field3 = blocknum
LOCKTAG_TUPLE locktag_field1 = dboid
locktag_field2 = reloid
locktag_field3 = blocknum
locktag_field4 = offnum
LOCKTAG_TRANSACTION locktag_field1 = xid
locktag_field2 = 0
locktag_field3 = 0
locktag_field4 = 0
LOCKTAG_VIRTUALTRANSACTION locktag_field1 = (vxid).backendId
locktag_field2 = (vxid).localTransactionId
locktag_field3 = 0
locktag_field4 = 0
LOCKTAG_SPECULATIVE_TOKEN locktag_field1 = xid
locktag_field2 = token
locktag_field3 = 0
locktag_field4 = 0
LOCKTAG_OBJECT locktag_field1 = dboid
locktag_field2 = classoid
locktag_field3 = objoid
locktag_field4 = objsubid
LOCKTAG_USERLOCK 用户自定义锁
LOCKTAG_ADVISORY locktag_field1 = id1
locktag_field2 = id2
locktag_field3 = id3
locktag_field4 = id4
LOCKTAG_APPLY_TRANSACTION locktag_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
如有错误或者疏漏欢迎指出,互相学习。

注:未经同意,不得转载!文章来源地址https://www.toymoban.com/news/detail-536861.html

到了这里,关于postgresql regular lock常规锁 烤的内嫩外焦,入口即化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 我的内网渗透-提权大法

     出现这个提示就是切换成功,后面也是可以正常显示的 新版本的kali直接getsystem,可以提权成功(有时候可以,有时候不可以) 提权成功 利用uac(用户账户控制)进行提权。 用户账户控制 在涉及管理员权限的时候会提示你是否要这么做,确定的话就是以管理员的身份去运

    2024年02月08日
    浏览(20)
  • 几款实用的内网穿透工具

    本文以渗透的视角,总结几种个人常用的内网穿透,内网代理工具,介绍其简单原理和使用方法。 nps是一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持tcp、udp流量转发,可支持任何tcp、udp上层协议(访问内网网站、本地支付接口调试、ssh访问、远程桌面,内

    2024年02月05日
    浏览(15)
  • 私有GitLab的内网搭建与维护

            摘要:由于有私有代码保密和开发代码托管需求,将在部门内部网络(与互联网不联通)搭建GitLab代码托管服务器。本次的部署步骤主要是,第一,下载好离线的GitLab安装包和依赖包;第二,部署gitlab到Linux服务器中;第三,调整gitlab配置文件。 目录  一、下载

    2024年02月11日
    浏览(27)
  • 【MySql】表的内连接和外连接

    本篇博客主要介绍的内容是表的连接,在MySql中表的连接分为内连接和外连接,下面,我们直接进入主题把 内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选 ,我们前面学习的查询都是内连接,也是在开发过程中使用的最多的连接查询。 对于内连接,我们还是

    2024年02月10日
    浏览(20)
  • SQL中的内连接(inner join)用法

    一、什么是内连接(inner join) `INNER JOIN`是SQL中的一种连接类型,用于将两个或多个表中的记录根据某个条件进行匹配,并返回匹配的记录。它只返回那些在两个表中都有匹配的记录。 以下是一个示例的`INNER JOIN`查询语句: SELECT table1.column1, table2.column2 FROM table1 INNER JOIN tabl

    2024年02月04日
    浏览(26)
  • 【MySQL系列】表的内连接和外连接学习

    「前言」文章内容大致是对MySQL表的内连接和外连接。 「归属专栏」MySQL 「主页链接」个人主页 「笔者」枫叶先生(fy) 内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选,前面篇章学习的查询都是内连 接,也是在开发过程中使用的最多的连接查询 内连接语法如

    2024年02月11日
    浏览(14)
  • python-网络爬虫.regular

    regular 正则表达式 (regular expression) 正则表达式(regular expression)描述了一种字符串匹配的模式 (pattern), 可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串 中取出符合某个条件的子串等。 正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为

    2024年02月13日
    浏览(17)
  • Regularization

    在图像中的特征处理: 平均亮度的去除 注意 P i P_i P i ​ 对特征向量进行处理的意义, 把特征矩阵的对角线变成1,即把每个特征的重要性相等,让每个特征相互独立 数据归一化: 标准归一化 缩放归一化 PCA/SVD 归一化后,可以更快的搜索到最优值点 梯度变化大,学习太慢,

    2024年02月06日
    浏览(2)
  • 免费开源的内网穿透工具-FRP安装与配置

      FRP是一款内网穿透工具,首先要一台带公网IP的服务器用作服务端(Linux),需要被穿透的内网服务器作为客户端   FRP的Github地址   下载FRP:    FRPS服务端的安装:   需要有一台具备公网IP的机器或云服务器,我用的是阿里云服务器,具有公网IP的机器(云服务

    2024年02月12日
    浏览(21)
  • 利用frp搭建自己的内网穿透服务器

    本教程基于以下环境完成 带有公网IP的云服务器一台,安装centos7.6系统 一个属于自己的域名,可以是二级域名 域名对应的证书文件 一台64位Windows系统的电脑 开源项目frp 证书文件主要是用来配置https访问的,如果没有证书文件可以参考我的这篇文章生成 centos7中申请Let‘s E

    2024年02月02日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包