Postgresql源码(123)事务提交时三段资源释放分析ResourceOwnerRelease

0 总结

  1. 三段释放原因:因为如果先释放锁,没有释放一些共享资源(比如pin住的buffer),别人拿到锁后发现我们仍然持有一些资源,就会有问题。所以三阶段释放主要是以锁为分界线,先释放锁保护的资源,在释放锁,在清理私有资源。这样可以保证别人拿到锁后,一定也能拿到对应的资源。
  2. 三段:先放pinned buffer、relation、dsm这些共享资源;再放锁;再放其他会话看不到的私有资源。

1 资源随事务释放

三阶段释放是指ResourceOwnerRelease函数在使用时需要调用三次,按固定顺序调用每次删除特定的资源:

  1. RESOURCE_RELEASE_BEFORE_LOCKS
  2. RESOURCE_RELEASE_LOCKS
  3. RESOURCE_RELEASE_AFTER_LOCKS
typedef enum
{RESOURCE_RELEASE_BEFORE_LOCKS = 1,RESOURCE_RELEASE_LOCKS,RESOURCE_RELEASE_AFTER_LOCKS,
} ResourceReleasePhase;

例如事务提交时CommitTransaction:

static void
CommitTransaction(void).........ResourceOwnerRelease(TopTransactionResourceOwner,RESOURCE_RELEASE_BEFORE_LOCKS,true, true);/* Check we've released all buffer pins */AtEOXact_Buffers(true);/* Clean up the relation cache */AtEOXact_RelationCache(true);/** Make catalog changes visible to all backends.  This has to happen after* relcache references are dropped (see comments for* AtEOXact_RelationCache), but before locks are released (if anyone is* waiting for lock on a relation we've modified, we want them to know* about the catalog change before they start using the relation).*/AtEOXact_Inval(true);AtEOXact_MultiXact();ResourceOwnerRelease(TopTransactionResourceOwner,RESOURCE_RELEASE_LOCKS,true, true);ResourceOwnerRelease(TopTransactionResourceOwner,RESOURCE_RELEASE_AFTER_LOCKS,true, true);......

其他几个事务控制函数资源释放时,也是按照相同的顺序分三阶段释放的:

函数名phaseisCommitisTopLevel
CommitTransactionRESOURCE_RELEASE_BEFORE_LOCKStruetrue
CommitTransactionRESOURCE_RELEASE_LOCKStruetrue
CommitTransactionRESOURCE_RELEASE_AFTER_LOCKStruetrue
PrepareTransactionRESOURCE_RELEASE_BEFORE_LOCKStruetrue
PrepareTransactionRESOURCE_RELEASE_LOCKStruetrue
PrepareTransactionRESOURCE_RELEASE_AFTER_LOCKStruetrue
AbortTransactionRESOURCE_RELEASE_BEFORE_LOCKSfalsetrue
AbortTransactionRESOURCE_RELEASE_LOCKSfalsetrue
AbortTransactionRESOURCE_RELEASE_AFTER_LOCKSfalsetrue
CommitSubTransactionRESOURCE_RELEASE_BEFORE_LOCKStruefalse
CommitSubTransactionRESOURCE_RELEASE_LOCKStruefalse
CommitSubTransactionRESOURCE_RELEASE_AFTER_LOCKStruefalse
AbortSubTransactionRESOURCE_RELEASE_BEFORE_LOCKSfalsefalse
AbortSubTransactionRESOURCE_RELEASE_LOCKSfalsefalse
AbortSubTransactionRESOURCE_RELEASE_AFTER_LOCKSfalsefalse

2 为什么要分三阶段释放?

结论

因为如果先释放锁,没有释放一些共享资源(比如pin住的buffer),别人拿到锁后发现我们仍然持有一些资源,就会有问题。所以三阶段释放主要是以锁为分界线,先释放锁保护的资源,在释放锁,在清理私有资源。这样可以保证别人拿到锁后,一定也能拿到对应的资源。

  1. RESOURCE_RELEASE_BEFORE_LOCKS(预锁定阶段):需要释放对其他后端可见的资源(pinned buffers)。为了确保当我们释放另一个后端可能正在等待的锁时,它会看到我们已经完全退出了我们的事务。这是为了防止在释放锁之后,其他后端仍然看到我们持有的资源,从而可能导致数据不一致或其他问题。
  2. RESOURCE_RELEASE_LOCKS(锁定阶段):释放持有的所有锁。这是为了让其他可能正在等待这些锁的后端能够继续执行。
  3. RESOURCE_RELEASE_AFTER_LOCKS(后锁定阶段):后端内部的清理工作。释放那些只有后端自己知道的、不会影响其他后端的资源。

3 代码分析

下面这次提交后对resowner做了扩展性增强,代码逻辑没变但可读性有点差(PG17dev分支)

commit b8bff07daa85c837a2747b4d35cd5a27e73fb7b2
Author: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date:   Wed Nov 8 13:30:50 2023 +0200Make ResourceOwners more easily extensible.

围绕本篇主题,后面分析这次提交前代码(PG17前的逻辑)

static void
ResourceOwnerReleaseInternal(ResourceOwner owner,ResourceReleasePhase phase,bool isCommit,bool isTopLevel)
{ResourceOwner child;ResourceOwner save;ResourceReleaseCallbackItem *item;ResourceReleaseCallbackItem *next;Datum		foundres;

resowner维护树形结构,递归释放自己的child资源。

	for (child = owner->firstchild; child != NULL; child = child->nextchild)ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel);...

3.1 第一阶段:RESOURCE_RELEASE_BEFORE_LOCKS

  1. 事务提交时不应该有正在进行中的io了,这里需要把标志位清理干净,避免影响后面事务使用这个buffer。
  2. 清理pinned的buffer
    • 提交时不应该有pinned的了,会告警,回滚时就无所谓了,因为错误不一定出在哪,不一定给机会清理。
  3. 关闭打开的relation
    • 提交时不应该有打开的了,会告警;回滚时同上。
  4. 关闭dsm段
  5. 关闭jit context
	if (phase == RESOURCE_RELEASE_BEFORE_LOCKS){while (ResourceArrayGetAny(&(owner->bufferioarr), &foundres)){Buffer		res = DatumGetBuffer(foundres);if (isCommit)elog(PANIC, "lost track of buffer IO on buffer %d", res);AbortBufferIO(res);}while (ResourceArrayGetAny(&(owner->bufferarr), &foundres)){Buffer		res = DatumGetBuffer(foundres);if (isCommit)PrintBufferLeakWarning(res);ReleaseBuffer(res);}while (ResourceArrayGetAny(&(owner->relrefarr), &foundres)){Relation	res = (Relation) DatumGetPointer(foundres);if (isCommit)PrintRelCacheLeakWarning(res);RelationClose(res);}while (ResourceArrayGetAny(&(owner->dsmarr), &foundres)){dsm_segment *res = (dsm_segment *) DatumGetPointer(foundres);if (isCommit)PrintDSMLeakWarning(res);dsm_detach(res);}while (ResourceArrayGetAny(&(owner->jitarr), &foundres)){JitContext *context = (JitContext *) DatumGetPointer(foundres);jit_release_context(context);}......}}

3.2 第二阶段:RESOURCE_RELEASE_LOCKS

  1. 如果是顶层事务,直接释放所有锁,具体:
    • 提交时要保留会话锁,释放事务锁。事务没了会话锁还需要继续生效,生命周期比事务长。
    • 回滚时要释放所有锁。
    • 会话锁:咨询锁。
    • 事务锁:行锁、表锁等。
  2. 如果是子事务,按提交回滚做出不同行为。
    • 提交:转移锁到parent resowner。
    • 回滚:释放锁。
	else if (phase == RESOURCE_RELEASE_LOCKS){if (isTopLevel){if (owner == TopTransactionResourceOwner){ProcReleaseLocks(isCommit);ReleasePredicateLocks(isCommit, false);}}else{LOCALLOCK **locks;int			nlocks;...if (isCommit)LockReassignCurrentOwner(locks, nlocks);elseLockReleaseCurrentOwner(locks, nlocks);}}

3.3 第三阶段:RESOURCE_RELEASE_AFTER_LOCKS

  1. 释放catcache系统表缓存。
  2. 释放cached plan。
  3. 释放tuple desc,注意tuple desc在构造好后,会用IncrTupleDescRefCount函数,在resowner中记录,按引用计数控制删除。引用计数的机制主要是为了处理TupleDesc在多个地方共享使用的情况。例如一个查询的多个部分可能都需要引用同一个TupleDesc。如果在一个部分结束时就直接删除TupleDesc,那么其他部分就无法继续使用这个TupleDesc了。
  4. 释放快照。
  5. 释放fd。
	else if (phase == RESOURCE_RELEASE_AFTER_LOCKS){while (ResourceArrayGetAny(&(owner->catrefarr), &foundres)){HeapTuple	res = (HeapTuple) DatumGetPointer(foundres);if (isCommit)PrintCatCacheLeakWarning(res);ReleaseCatCache(res);}while (ResourceArrayGetAny(&(owner->catlistrefarr), &foundres)){CatCList   *res = (CatCList *) DatumGetPointer(foundres);if (isCommit)PrintCatCacheListLeakWarning(res);ReleaseCatCacheList(res);}while (ResourceArrayGetAny(&(owner->planrefarr), &foundres)){CachedPlan *res = (CachedPlan *) DatumGetPointer(foundres);if (isCommit)PrintPlanCacheLeakWarning(res);ReleaseCachedPlan(res, owner);}while (ResourceArrayGetAny(&(owner->tupdescarr), &foundres)){TupleDesc	res = (TupleDesc) DatumGetPointer(foundres);if (isCommit)PrintTupleDescLeakWarning(res);DecrTupleDescRefCount(res);}while (ResourceArrayGetAny(&(owner->snapshotarr), &foundres)){Snapshot	res = (Snapshot) DatumGetPointer(foundres);if (isCommit)PrintSnapshotLeakWarning(res);UnregisterSnapshot(res);}/* Ditto for temporary files */while (ResourceArrayGetAny(&(owner->filearr), &foundres)){File		res = DatumGetFile(foundres);if (isCommit)PrintFileLeakWarning(res);FileClose(res);}}for (item = ResourceRelease_callbacks; item; item = next){next = item->next;item->callback(phase, isCommit, isTopLevel, item->arg);}CurrentResourceOwner = save;
}

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

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

相关文章

智慧未来:人工智能驱动下的创新与发展

智慧未来&#xff1a;人工智能驱动下的创新与发展 随着人工智能技术的迅猛发展和广泛应用&#xff0c;我们正迎来一个智慧未来的时代。人工智能作为驱动力推动着创新与发展&#xff0c;改变着我们的生活、工作和社会。让我们一起探讨人工智能驱动下的创新与发展所带来的影响和…

酷开科技丨新年新玩法!酷开系统壁纸模式给客厅“换”新

甲辰龙年即将到来&#xff0c;新年新家新气象&#xff0c;快到酷开系统壁纸模式中挑选一款喜欢的壁纸&#xff0c;为新的一年增添一份美好和喜悦吧&#xff01; 酷开科技将更多的电视新玩法带给你&#xff0c;让你的电视成为家庭中的焦点&#xff01;酷开系统壁纸模式&#xf…

LabVIEW高效核磁测井仪器多线程优化

LabVIEW高效核磁测井仪器多线程优化 为提高核磁测井仪器的测试效率与性能&#xff0c;开发了基于LabVIEW的多线程优化模型。该研究针对传统的核磁测井仪器软件&#xff0c;在多任务调度测试和并行技术需求上存在的效率不高和资源利用率低的问题&#xff0c;提出了一个多线程优…

智能家居现状分析及未来展望

当前现状 家居行业经过多年发展&#xff0c;顺利完成了从无到有的进化历程&#xff0c;现正在智能化的道路上奋力驰骋&#xff0c;虽发展迅速但也面临一些问题。主要有&#xff1a; APP操作复杂、UI不统一 传统硬件厂家的优势在设备制造领域&#xff0c;让设备“上网”不是其…

SQL注入工具之SQLmap入门操作

了解SQLmap 基础操作 SQLmap是一款自动化的SQL注入工具&#xff0c;可以用于检测和利用SQL注入漏洞。 以下是SQLmap的入门操作步骤&#xff1a; 1.下载SQLmap&#xff1a;可以从官方网站&#xff08;https://sqlmap.org/&#xff09;下载最新版本的SQLmap。 2.打开终端&#…

修改单据转换规则后保存报错提示

文章目录 修改单据转换规则后保存报错提示 修改单据转换规则后保存报错提示

Neo4j导入数据之JAVA JDBC

目录结构 前言设置neo4j外部访问代码整理maven 依赖java 代码 参考链接 前言 公司需要获取neo4j数据库内容进行数据筛查&#xff0c;neo4j数据库咱也是头一次基础&#xff0c;辛辛苦苦安装好整理了安装neo4j的步骤&#xff0c;如今又遇到数据不知道怎么创建&#xff0c;关关难…

VegaPrime 2013 VP2013

Vega Prime 2013 VegaPrime 2013 VP2013

基于springboot+vue实现的大学竞赛报名管理系统

一、系统架构 前端&#xff1a;vue2 | echarts 后端&#xff1a;springboot | mybatis 环境&#xff1a;jdk1.8 | mysql | maven 二、代码及数据库 三、功能介绍 01. 登录页 02. 教师端-统计分析 03. 教师端-竞赛通知管理 04. 教师端-获奖通告管理 05. 教师端…

学生成绩管理系统(C语言课设 )

这个学生成绩管理系统使用C语言编写&#xff0c;具有多项功能以方便管理学生信息和成绩。首先从文件中读取数据到系统中&#xff0c;并提供了多种功能&#xff08;增删改查等&#xff09;选项以满足不同的需求。 学生成绩管理系统功能: 显示学生信息增加学生信息删除学生信息…

《论文阅读》通过识别对话中的情绪原因来提高共情回复的产生 EMNLP 2021

《论文阅读》通过识别对话中的情绪原因来提高共情回复的产生 EMNLP 2021 前言简介方法实现Emotion ReasonerResponse Generator实验结果示例总结前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯手工敲击键盘~ 今天为大家带来的是《Improv…

chatGPT 使用随想

一年前 chatGPT 刚出的时候&#xff0c;我就火速注册试用了。 因为自己就是 AI 行业的&#xff0c;所以想看看国际上最牛的 AI 到底发展到什么程度了. 自从一年前 chatGPT 火出圈之后&#xff0c;国际上的 AI 就一直被 OpenAI 这家公司引领潮流&#xff0c;一直到现在&#x…

《VitePress 简易速速上手小册》第9章 VitePress 的扩展与插件(2024 最新版)

文章目录 9.1 插件生态系统概述9.1.1 基础知识点解析9.1.2 重点案例:SEO 优化插件9.1.3 拓展案例 1:社交分享插件9.1.4 拓展案例 2:内容搜索插件9.2 常用插件介绍与应用9.2.1 基础知识点解析9.2.2 重点案例:使用 SEO 插件9.2.3 拓展案例 1:集成社交分享功能9.2.4 拓展案例…

24-2-22学习总结

练习题 P8637 [蓝桥杯 2016 省 B] 交换瓶子 # [蓝桥杯 2016 省 B] 交换瓶子 ## 题目描述 有 $N$ 个瓶子&#xff0c;编号 $1 \sim N$&#xff0c;放在架子上。 比如有 $5$ 个瓶子&#xff1a; $$2,1,3,5,4$$ 要求每次拿起 $2$ 个瓶子&#xff0c;交换它们的位置。 经过…

RisingWave最佳实践-利用Dynamic filters 和 Temporal filters 实现监控告警

心得的体会 刚过了年刚开工&#xff0c;闲暇之余调研了分布式SQL流处理数据库–RisingWave&#xff0c;本人是Flink&#xff08;包括FlinkSQL和Flink DataStream API&#xff09;的资深用户&#xff0c;但接触到RisingWave令我眼前一亮&#xff0c;并且拿我们生产上的监控告警…

sql server想要小数点后向下取整怎么搞

select FORMAT(3.169, N2) as 四舍五入1, CAST(3.169 AS decimal(9,2)) as 四舍五入2, ROUND(3.169, 2) as 四舍五入3, CAST(FLOOR(3.169 * 100) / 100 AS decimal(9,2)) as 向下取整1, FLOOR(3.169 * 100) / 100 as 向下取整2, ceiling(3.169 * 100) / 100 as 向上取整—…

python 几种常见的音频数据读取、保存方式

1. soundfile 库的使用 soundfile库是一个Python库&#xff0c;主要用于读取和写入音频文件。它支持多种音频格式&#xff0c;包括WAV、AIFF、FLAC和OGG等。通过soundfile库&#xff0c;用户可以方便地将numpy数组存储到音频文件或者将音频文件加载到numpy数组中。此外&#x…

AI 视频 | Stable Video 开放公测了,免部署,免费使用!谁说 4 秒的 AI 视频不香?!

谁说 4 秒的视频不香&#xff1f;2.21 日&#xff0c;Stable Video 开放公测了&#xff0c;不需要自己部署了&#xff0c;直接在网页上就可以生成视频了。 下面这些视频&#xff0c;都是通过 Stable Video Diffusion 生成的&#xff0c;可以先来感受一下&#xff1a; Stable V…

IPsec、安全关联、网络层安全协议

网络层安全协议 IP 几乎不具备任何安全性&#xff0c;不能保证&#xff1a; 1.数据机密性 2.数据完整性 3.数据来源认证 由于其在设计和实现上存在安全漏洞&#xff0c;使各种攻击有机可乘。例如&#xff1a;攻击者很容易构造一个包含虚假地址的 IP 数据报。 IPsec 提供了标…

【PCL】(十三)使用KdTree查找点

【PCL】&#xff08;十三&#xff09;使用KdTree查找点 以下代码实现使用KdTree来查找特定点的K个最近邻点&#xff0c;以及查找指定的某个半径内的所有邻点。 kdtree_search.cpp&#xff1a; #include <pcl/point_cloud.h> #include <pcl/kdtree/kdtree_flann.h&g…