Postgresql源码(123)事务提交时三段资源释放分析ResourceOwnerRelease
0 总结
- 三段释放原因:因为如果先释放锁,没有释放一些共享资源(比如pin住的buffer),别人拿到锁后发现我们仍然持有一些资源,就会有问题。所以三阶段释放主要是以锁为分界线,先释放锁保护的资源,在释放锁,在清理私有资源。这样可以保证别人拿到锁后,一定也能拿到对应的资源。
- 三段:先放pinned buffer、relation、dsm这些共享资源;再放锁;所有放其他会话看不到的私有资源。
1 资源随事务释放
三阶段释放是指ResourceOwnerRelease函数在使用时需要调用三次,按固定顺序调用每次删除特定的资源:
- RESOURCE_RELEASE_BEFORE_LOCKS
- RESOURCE_RELEASE_LOCKS
- 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);......
其他几个事务控制函数资源释放时,也是按照相同的顺序分三阶段释放的:
| 函数名 | phase | isCommit | isTopLevel |
|---|---|---|---|
| CommitTransaction | RESOURCE_RELEASE_BEFORE_LOCKS | true | true |
| CommitTransaction | RESOURCE_RELEASE_LOCKS | true | true |
| CommitTransaction | RESOURCE_RELEASE_AFTER_LOCKS | true | true |
| PrepareTransaction | RESOURCE_RELEASE_BEFORE_LOCKS | true | true |
| PrepareTransaction | RESOURCE_RELEASE_LOCKS | true | true |
| PrepareTransaction | RESOURCE_RELEASE_AFTER_LOCKS | true | true |
| AbortTransaction | RESOURCE_RELEASE_BEFORE_LOCKS | false | true |
| AbortTransaction | RESOURCE_RELEASE_LOCKS | false | true |
| AbortTransaction | RESOURCE_RELEASE_AFTER_LOCKS | false | true |
| CommitSubTransaction | RESOURCE_RELEASE_BEFORE_LOCKS | true | false |
| CommitSubTransaction | RESOURCE_RELEASE_LOCKS | true | false |
| CommitSubTransaction | RESOURCE_RELEASE_AFTER_LOCKS | true | false |
| AbortSubTransaction | RESOURCE_RELEASE_BEFORE_LOCKS | false | false |
| AbortSubTransaction | RESOURCE_RELEASE_LOCKS | false | false |
| AbortSubTransaction | RESOURCE_RELEASE_AFTER_LOCKS | false | false |
2 为什么要分三阶段释放?
结论
因为如果先释放锁,没有释放一些共享资源(比如pin住的buffer),别人拿到锁后发现我们仍然持有一些资源,就会有问题。所以三阶段释放主要是以锁为分界线,先释放锁保护的资源,在释放锁,在清理私有资源。这样可以保证别人拿到锁后,一定也能拿到对应的资源。
- RESOURCE_RELEASE_BEFORE_LOCKS(预锁定阶段):需要释放对其他后端可见的资源(pinned buffers)。为了确保当我们释放另一个后端可能正在等待的锁时,它会看到我们已经完全退出了我们的事务。这是为了防止在释放锁之后,其他后端仍然看到我们持有的资源,从而可能导致数据不一致或其他问题。
- RESOURCE_RELEASE_LOCKS(锁定阶段):释放持有的所有锁。这是为了让其他可能正在等待这些锁的后端能够继续执行。
- 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
- 事务提交时不应该有正在进行中的io了,这里需要把标志位清理干净,避免影响后面事务使用这个buffer。
- 清理pinned的buffer
- 提交时不应该有pinned的了,会告警,回滚时就无所谓了,因为错误不一定出在哪,不一定给机会清理。
- 关闭打开的relation
- 提交时不应该有打开的了,会告警;回滚时同上。
- 关闭dsm段
- 关闭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
- 如果是顶层事务,直接释放所有锁,具体:
- 提交时要保留会话锁,释放事务锁。事务没了会话锁还需要继续生效,生命周期比事务长。
- 回滚时要释放所有锁。
- 会话锁:咨询锁。
- 事务锁:行锁、表锁等。
- 如果是子事务,按提交回滚做出不同行为。
- 提交:转移锁到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
- 释放catcache系统表缓存。
- 释放cached plan。
- 释放tuple desc,注意tuple desc在构造好后,会用IncrTupleDescRefCount函数,在resowner中记录,按引用计数控制删除。引用计数的机制主要是为了处理TupleDesc在多个地方共享使用的情况。例如一个查询的多个部分可能都需要引用同一个TupleDesc。如果在一个部分结束时就直接删除TupleDesc,那么其他部分就无法继续使用这个TupleDesc了。
- 释放快照。
- 释放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;
}
相关文章:
Postgresql源码(123)事务提交时三段资源释放分析ResourceOwnerRelease
0 总结 三段释放原因:因为如果先释放锁,没有释放一些共享资源(比如pin住的buffer),别人拿到锁后发现我们仍然持有一些资源,就会有问题。所以三阶段释放主要是以锁为分界线,先释放锁保护的资源&…...
电脑文件误删除如何恢复?2024最新三种恢复方法
我们在使用电脑的过程中,随着时间的不断推移,渐渐的我们会发现C盘内存空间不足了。这是因为我们很多文件都默认存储在C盘,所以导致C盘空间不足,电脑运行越来越慢。那么电脑哪些文件可以删除,电脑删除的东西怎么恢复&am…...
Netty应用——Google Protobuf强化篇(二十)
Protobuf发送一种实例 客户端可以发送一个 Student PoJo 对象到服务器 (通过 Protobuf 编码)服务端能接收 Student PoJo 对象,并显示信息(通过 Protobuf 解码) Student.proto syntax "proto3"; //版本 option java_outer_classname "StudentPOJO&…...
SpringAMQP开启“可靠性”机制
前言 上一篇介绍了如何在 《SpringBoot 中集成和使用消息队列》,看过这一篇就基本上可以在SpringBoot中使用消息队列了,但是消息队列他归根结底是一个客户端服务器模式的中间件,面对复杂的网络环境和分布式使用环境,难免会出现各…...
戴尔Dell R740服务器开机冒烟亮黄灯故障维修
今天分享的是一台过保修期的DELL PowerEdge R740服务器开机冒烟的维修案例。先上图: 接到用户报修后工程师立即响应,由于用户也是刚开工第一天服务器开机就出现了这种祥龙吐雾的祥兆,导致工厂业务流程无法正常使用,这台机器在东莞…...
【阅读笔记】空域保边降噪《Side Window Filtering》
1、保边滤波背景 保边滤波器的代表包括双边滤波、引导滤波,但是这类滤波器有一个问题,它们均将待处理的像素点放在了方形滤波窗口的中心。但如果待处理的像素位于图像纹理或者边缘,方形滤波核卷积的处理结果会导致这个边缘变模糊。 基于这个…...
vue3前端excel导出;组件表格,自定义表格导出;Vue3 + xlsx + xlsx-style
当画面有自定义的表格或者样式过于复杂的表格时,导出功能可以由前端实现 1. 使用的插件 : sheet.js-xlsx 文档地址:https://docs.sheetjs.com/ 中文地址:https://geekdaxue.co/read/SheetJS-docs-zh/README.md xlsx-style&#…...
npm install一直卡在 sill idealTree buildDeps
当npm install命令在安装过程中卡在sill idealTree buildDeps阶段时,可能的原因包括网络延迟、镜像源问题或缓存问题。以下是一些可能的解决方法: 检查镜像源: 打开命令提示符(cmd)窗口。 输入命令npm config get…...
spring boot rabbitmq常用配置
直接上代码 package com.example.demo;import org.aopalliance.aop.Advice; import org.springframework.amqp.rabbit.annotation.RabbitListenerConfigurer; import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; import org.springframewo…...
MySQL学习记录——십삼 视图及用户、权限管理
文章目录 1、视图2、用户管理3、权限管理 1、视图 视图把查询出来的结果以表结构的形式存储起来,视图和基表有关系,两者的数据变化都会互相影响。 在查询时,假如要经常查询一条记录,select …,那么为了方便ÿ…...
PyCharm 自动添加文件头注释
PyCharm 自动添加文件头注释 1. File and Code Templates2. Python FileReferences 1. File and Code Templates File -> Settings -> Editor -> File and Code Templates -> Python Script Reformat according to style & Enable Live Templates Created by…...
用HTML Canvas和JavaScript创建美丽的花朵动画效果
目录 一、程序代码 二、代码原理 三、运行效果 一、程序代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>炫酷花朵</title><style>* {margin: 0;padding: 0;overflow: hidden;bac…...
java----js常用的api
java----js常用的api 时间函数获取当前时间: DateUtil.today()时间偏移字符换时间格式化 map.computeIfAbsent添加list 时间函数 获取当前时间: DateUtil.today() String todayDateUtil.today()String today “2024-02-01”; 时间偏移 往前退役30天 DateUtil.offsetDay(D…...
unity 使用VS Code 开发,VS Code配置注意事项
vscode 对应的插件(unity开发) 插件:.Net Install Tool,c#,c# Dev Kit,IntelliCode For C# Dev Kit,Unity,Unity Code Snippets 本人现在是用了这些插件 unity需要安装Visual Studio Editor 1、.Net Install Tool 设置 需要在设置里面配置…...
领域驱动设计(Domain Driven Design)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、场景和要求二、领域模型关键词1.领域2.子域3.通用语言4.限界上下文5.领域模型6.实体和值对象7.聚合根8.领域服务9.领域事件 总结 前言 Domain Driven Desi…...
CF778A String Game 题解
文章目录 CF778A String Game 题解题面翻译Input DataOutput DataInput Sample 1Output Sample 1题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 提示算法:二分代码: CF778A String Game 题解 link 题面翻译 …...
【工具插件类教学】Unity运行时监控变量,属性,事件等的值和调用Runtime Monitoring
目录 一、介绍 二、安装方式 三、入门 1.实例化和静态成员...
实际生产中的一次非典型的基于jmeter的接口自动化实践
实际工作中遇到过一次自动化巡检的需求,作为测试人员没法从源代码入手,加之数据库也不熟悉,故采取接口自动化的方式来实现巡检,算是一种歪门邪道吧,应该不是接口自动化的常规使用方式。jmeter在这里的作用实际上也只是…...
新能源汽车软件开发设计规范
新能源汽车 软件开发设计规范 版本: 1.0 编 制: 校 对: 审 核: 会 签: …...
Linux:grep进阶(11)
Linux:shell脚本:基础使用(4)《正则表达式-grep工具》_shell grep 全角字符串-CSDN博客https://blog.csdn.net/w14768855/article/details/132338954?ops_request_misc%257B%2522request%255Fid%2522%253A%252217083360171680022…...
高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
二维FDTD算法仿真
二维FDTD算法仿真,并带完全匹配层,输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...
精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑
精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑 在电子商务领域,转化率与网站性能是决定商业成败的核心指标。今天,我们将深入解析不同类型电商平台的转化率基准,探讨页面加载速度对用户行为的…...
性能优化中,多面体模型基本原理
1)多面体编译技术是一种基于多面体模型的程序分析和优化技术,它将程序 中的语句实例、访问关系、依赖关系和调度等信息映射到多维空间中的几何对 象,通过对这些几何对象进行几何操作和线性代数计算来进行程序的分析和优 化。 其中࿰…...
【JavaEE】万字详解HTTP协议
HTTP是什么?-----互联网的“快递小哥” 想象我们正在网上购物:打开淘宝APP,搜索“蓝牙耳机”,点击商品图片,然后下单付款。这一系列操作背后,其实有一个看不见的“快递小哥”在帮我们传递信息,…...
可下载旧版app屏蔽更新的app市场
软件介绍 手机用久了,app越来越臃肿,老手机卡顿成常态。这里给大家推荐个改善老手机使用体验的方法,还能帮我们卸载不需要的app。 手机现状 如今的app不断更新,看似在优化,实则内存占用越来越大,对手机性…...
uni-app学习笔记三十--request网络请求传参
request用于发起网络请求。 OBJECT 参数说明 参数名类型必填默认值说明平台差异说明urlString是开发者服务器接口地址dataObject/String/ArrayBuffer否请求的参数App 3.3.7 以下不支持 ArrayBuffer 类型headerObject否设置请求的 header,header 中不能设置 Refere…...
Ubantu-Docker配置最新镜像源250605
尝试其他镜像加速器 阿里云镜像加速器:登录阿里云,进入容器镜像服务获取专属加速器地址。毫秒镜像:https://docker.1ms.run。DockerHub镜像加速器:https://docker.xuanyuan.me。Docker Hub 镜像加速服务:https://dock…...
