【PostgreSQL的CLOG解析】

image.png

同样还是这张图,之前发过shared_buffer和os cache、wal buffer和work mem的文章,今天的主题是图中的clog,即 commit log,PostgreSQL10之前放在数据库目录的pg_clog下面。PostgreSQL10之后修更名为xact,数据目录变更为pg_xact下面,表现形式是一些物理文件。

image.png


PostgreSQL为什么要使用clog呢,众所周知,PostgreSQL有着独特的MVCC机制,由于其多版本的特性,
在进行可见性判断时,需要获取事务的状态,即元组中 t_xmin 和 t_xmax 的状态,需要clog来记录事务的状态,从而判断其可见性,内存里的访问远远快于磁盘读写,因此PostgreSQL的很多机制都是运行时候在内存,然后定期持久化到磁盘。因此clog也有一块内存区域便于高效访问,即clog buffers,它也属于共享内存的这部分,平时更新clog是内存中进行的,然后满足条件后会调用pg_fsync刷数据到磁盘上的clog文件,或者等待checkpoint刷数据。数据库启动时会从磁盘的pg_xact目录下读取事务状态加载到clog buffers,并且运行过程中,vacuum会定时将不再使用的clog文件清理。

关于clog buffers 的大小,可以在 src/backend/access/transam/clog.c里看到相关定义。

image.png

所以clog buffers 占用的页的个数是NBuffers / 512,最大为128个页,最小为4个页,这里的NBuffers 在之前wal buffer这篇文章已经说过,它和shared_buffers的关系,两者计算的字节数是一致的,感兴趣可以去看下 (PostgreSQL的wal_buffers - 墨天轮)。
因此,这里clog buffers的大小可以理解为 shared_buffers的1/512。

PostgreSQL中通过clog来存储事务的状态。所以,当在Postgresql中如果想要取消一个执行了很长时间的事务,基本上是瞬间完成的,而不是像Oracle中一样需要等到undo表空间中内容回滚完,因为PostgreSQL里只需要将事务的状态由IN_PROGRESS修改为ABORTED即可。

PG中,事务号最多占用32位,有三个是比较特殊的,在access/xlogdefs.h下可以看到,这里的BootstrapTransactionId是用于“bootstrap”操作的XID,FrozenTransactionId用于非常老的元组。FirstNormalTransactionId是第一个“正常”的事务id。

image.png

一、事务状态

在clog.h里定义了需要提交日志clog来记录事务的状态,从而判断其可见性,在PostgreSQL里总共有四种事务状态。分别是:IN_PROGRESS、COMMITED、ABORTED和SUB_COMMITED。例如事务正在运行中,那么它的状态就是IN_PROGRESS。全部是0是初始状态,SUB_COMMITTED状态表示已提交的子事务,其父事务尚未提交或中止。每个状态只需要两位(2 bit)就可以表示。

image.png

二、clog文件里事务id和状态信息的空间占用

对于上述提到的四种状态,可以用2 bit来表示。因此四个事务的状态就占用了8 bit 即一个字节。
在src/backend/access/transam/clog.c里一样可以找到关于这块空间占用的定义。

image.png

CLOG_BITS_PER_XACT:每个事务占用几个 bit(默认为2,因为4种状态用2bit就可以完全表示)
CLOG_XACTS_PER_BYTE :每个字节可以存几个事务的状态(默认为4,因为1bytes=8bit,1个事务状态需要占用2bit)
CLOG_XACTS_PER_PAGE:每个页可以存几个事务的状态(8KB*4=32K=2^15)
CLOG_XACT_BITMASK:位掩码

三、如何根据事务ID查看在clog日志里的事务的状态

在PostgreSQL中,事务id并不是在事务开始时就会被真正分配,它会先分配一个虚拟事务号,当有数据要发生变化时才会真正分配xid,而当事务提交或回滚时,其事务状态便会被写入clog中。比如你显式开启事务,什么都不做或者只做查询操作,commit之后,是不会消耗xid的。而当你有对数据的变更操作,则会消耗xid。

举个例子如下,当我们执行 select txid_current();的时候,他每次也要使用一个事务号,而当我们显式开启事务,然后什么都不做或者只执行select操作后,commit以后,事务号是不会增加的。我测试中增加了1是因为执行了select txid_current();的原因。而当显示事务里有对数据的变更操作,则下次执行select txid_current();的时候,事务号直接跳了两个,减去一个select txid_current();的,剩下那个增加的事务号则是我这个insert的事务占用的。

postgres=# select txid_current();txid_current 
--------------2119
(1 row)postgres=# select txid_current();txid_current 
--------------2120
(1 row)postgres=# begin;
BEGIN
postgres=*# select 1;?column? 
----------1
(1 row)
postgres=*# commit;
COMMIT
postgres=# select txid_current();txid_current 
--------------2121
(1 row)postgres=# begin;
BEGIN
postgres=*# insert into t1 values(5);
INSERT 0 1
postgres=*# commit;
COMMIT
postgres=# select txid_current();txid_current 
--------------2123
(1 row)

在src/backend/access/transam/clog.c里同同样也存在着事务ID存放位置的定义和计算方法,如下所示

image.png

这四个分别为

TransactionIdToPage (事务id对应在哪个CLOG页)

计算方法为:(xid) / (TransactionId) CLOG_XACTS_PER_PAGE,这个CLOG_XACTS_PER_PAGE是第二部分看到的每个页可以存几个事务的状态,它默认是2^15。因此。事务id/ (2^15)得到的就是事务id对应在哪个CLOG页,当然,是要取整的。从0号页开始。

TransactionIdToPgIndex(事务id对应在上面页中的偏移量)

计算方法为:(xid) % (TransactionId) CLOG_XACTS_PER_PAGE,即事务id%(2^15)得到的是在页里的偏移量。

TransactionIdToByte(事务id对应在上面页中第几个的字节)

计算方法为:TransactionIdToPgIndex(xid) / CLOG_XACTS_PER_BYTE,这里的TransactionIdToPgIndex(xid)是刚才计算的偏移量。而CLOG_XACTS_PER_BYTE是第二部分定义的每个字节可以存几个事务的状态,默认是4,所以事务在页里的偏移量/4得到的是事务id对应在页中第几个的字节。

TransactionIdToBIndex(事务id对应在上面字节中的哪个bit)

计算方法为:(xid) % (TransactionId) CLOG_XACTS_PER_BYTE。这里 CLOG_XACTS_PER_BYTE依旧是每个字节可以存几个事务的状态,默认为4,此处不用偏移量。直接用事务id%4来得到在一个byte里的哪个bit。(1byte=8bit)

这里做一个验证,
开启一个session

image.png

另开一个session,查看clog

image.png

计算四个值,我们该条记录是一个新的bytes里的
事务id对应在哪个CLOG页=2108/(2^15)=0
事务id对应在上面页中的偏移量=2108%(2^15)=2108
事务id对应在上面页中第几个的字节=2108/4=527
事务id对应在上面字节中的哪个bit=2108%4=0(表示这个事务在一bytes的第一组bits)

image.png

image.png

在commit后,原本的值应该变为01,但我们查看对应的clog文件部分是00,但是这可能并不代表事务在进程中,因为所有的状态初始值都是00,clog的数据还没有从内存写到磁盘。而且clog分配于共享内存的clog_buffer中,当申请新的CLOG PAGE时所有的clog_buffer都没有刷出脏页,才需要主动选择一个page并调用pg_fsync刷出对应的pg_clog到磁盘中,除此之外,checkpoint会将clog buffer刷到磁盘。因此我这里为了观察选择使用checkpoint。

image.png

此时clog buffer刷到了磁盘,可以看到此事务的状态是01,对照开头的状态,是已经提交的状态。

image.png

上边的例子是一个TransactionIdToByte计算为整数的,当TransactionIdToByte计算带有小数的时候,我们只看整数取整就可以了,例如如下的例子。

image.png

image.png

15从16进制转换成2进制为 0001 0101 ,而上边这个2110的事务,其计算的TransactionIdToBIndex(事务id对应在上面字节中的哪个bit)=2110%4=2,所以他在第3组bit上(取值是0为第一组),为01。因此在这个bytes里,我们的三个事务都是提交的状态。
 

image.png


等到一个byte的四组事务全部都是commited的时候,hexdump -C 0000 -s 527 -n 1查看到的值应该是55,例如下面这种大量的55,如果不是55则表示这一bytes里的四组事务,不是全部提交的,存在IN PROCESS、ABORTED或者SUB_COMMITTED的事务。

image.png

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

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

相关文章

WPF 本地化的最佳做法

WPF 本地化的最佳做法 资源文件英文资源文件 en-US.xaml中文资源文件 zh-CN.xaml 资源使用App.xaml主界面布局cs代码 App.config辅助类语言切换操作类资源 binding 解析类 实现效果 应用程序本地化有很多种方式,选择合适的才是最好的。这里只讨论一种方式&#xff0…

pytorch单机多卡后台运行

nohup sh ./train_chat.sh > train_chat20230814.log 2>1&参考资料 Pytorch单机多卡后台运行的解决办法

kafka-2.12使用记录

kafka-2.12使用记录 安装kafka 2.12版本 下载安装包 根据你的系统下载rpm /deb /zip包等等, 这里我使用的是rpm包 安装命令 rpm -ivh kafka-2.12-1.nfs.x86_64.rpm启动内置Zookeeper 以下命令要写在同一行上 /opt/kafka-2.12/bin/zookeeper-server-start.sh /opt/kafka-2…

实验二十八、三角波发生电路参数的确认

一、题目 利用 Multisim 确定图1所示电路中各元件的参数,使输出电压的频率为 500 Hz 500\,\textrm{Hz} 500Hz、幅值为 6 V 6\,\textrm{V} 6V 的三角波。 图 1 三角波发生电路 图1\,\,三角波发生电路 图1三角波发生电路 2、仿真电路 A 1 \textrm A_1 A1​ 采用…

sift-1M数据集的读取及ES插入数据

sift是检查ann近邻召回率的标准数据集,ann可以选择faiss,milvus等库或者方法;sift数据分为query和base,以及label(groundtruth)数据。本文采用sift-1M进行解读,且看如下: 1、sift-1m数据集 官方链接地址:Evaluation of Approximate nearest neighbors: large datase…

Java:简单算法:冒泡排序、选择排序、二分查找

冒泡排序 // 1、准备一个数组 int[] arr {5&#xff0c;2&#xff0c;3&#xff0c;1};//2、定义一个循环控制排几轮 for (int i 0; i < arr.length - 1; i) { // i 0 1 2 【5&#xff0c;2&#xff0c;3&#xff0c;1】 次数 // i 0 第一轮 0 1 2 …

「网络」网络安全必须知道的19个知识分享

一、防火墙&#xff08;Firewall&#xff09; 定义&#xff1a;都知道防火墙是干什么用的&#xff0c;但我觉得需要特别提醒一下&#xff0c;防火墙抵御的是外部的攻击&#xff0c;并不能对内部的病毒 ( 如ARP病毒 ) 或攻击没什么太大作用。 功能 : 防火墙的功能主要是两个网…

Vue2-收集表单数据、过滤器、内置指令与自定义指令、Vue生命周期

&#x1f954;&#xff1a;我徒越万重山 千帆过 万木自逢春 更多Vue知识请点击——Vue.js VUE2-Day4 收集表单数据1、不同标签的value属性2、v-model的三个修饰符 过滤器内置指令与自定义指令1、内置指令2、自定义指令定义语法&#xff08;1&#xff09;函数式&#xff08;2&am…

文献综述|NLP领域后门攻击、检测与防御

前言&#xff1a;在信息安全中后门攻击&#xff08;Backdoor Attack&#xff09;是指绕过安全控制而获取对程序或系统访问权的方法。而随着深度学习以及各种神经网络模型的广泛应用&#xff0c;神经网络中存在的后门问题也引起了研究人员的广泛关注。神经网络后门攻击就是使网络…

Android AOSP源码编译——AOSP整编(二)

切换到源码目录下执行下面命令 1、初始化环境 . build/envsetup.sh //清除缓存 make clobber2、选择编译目标 lunchAOSP 预制了很多 Product。这里为了简单我们先不用真机&#xff0c;而是选择模拟器的方式&#xff0c;对于 x86_64 模拟器&#xff0c;我们选择的是 aosp_x86…

深度学习笔记(kaggle课程《Intro to Deep Learning》)

一、什么是深度学习&#xff1f; 深度学习是一种机器学习方法&#xff0c;通过构建和训练深层神经网络来处理和理解数据。它模仿人脑神经系统的工作方式&#xff0c;通过多层次的神经网络结构来学习和提取数据的特征。深度学习在图像识别、语音识别、自然语言处理等领域取得了…

Opencv将数据保存到xml、yaml / 从xml、yaml读取数据

Opencv将数据保存到xml、yaml / 从xml、yaml读取数据 Opencv提供了读写xml、yaml的类实现&#xff1a; 本文重点参考&#xff1a;https://blog.csdn.net/cd_yourheart/article/details/122705776?spm1001.2014.3001.5506&#xff0c;并将给出文件读写的具体使用实例。 1. 官…

C++多线程场景中的变量提前释放导致栈内存异常

多线程场景中的栈内存异常 在子线程中尝试使用当前函数的资源&#xff0c;是非常危险的&#xff0c;但是C支持这么做。因此C这么做可能会造成栈内存异常。 正常代码 #include <iostream> #include <thread> #include <windows.h>// 线程函数&#xff0c;用…

【分布式存储】数据存储和检索~LSM

在数据库领域&#xff0c;B树拥有无可撼动的地位&#xff0c;但是B树的缺点就是在写多读少的场景下&#xff0c;需要进行大量随机的磁盘IO读写&#xff0c;而这个性能是最差的。并且在删除和添加数据的时候&#xff0c;会造成整个树进行递归的合并、分裂&#xff0c;数据在磁盘…

【JVM】类装载的执行过程

文章目录 类装载的执行过程1.加载2.验证3.准备4.解析5.初始化6.使用7.卸载 类装载的执行过程 类装载总共分为7个过程&#xff0c;分别是 加载&#xff0c;验证&#xff0c;准备、解析、初始化、使用、卸载 1.加载 将类的字节码文件加载到内存(元空间&#xff09;中。这一步会…

16.3.1 【Linux】程序的观察

既然程序这么重要&#xff0c;那么我们如何查阅系统上面正在运行当中的程序呢&#xff1f;利用静态的 ps 或者是动态的 top&#xff0c;还能以 pstree 来查阅程序树之间的关系。 ps &#xff1a;将某个时间点的程序运行情况撷取下来 仅观察自己的 bash 相关程序&#xff1a; p…

Keburnetes 存储卷 volumes

K8S 的 存储卷 volumes emptyDir 可实现Pod中的容器之间共享目录数据&#xff0c;但emptyDir存储卷没有持久化数据的能力&#xff0c;存储卷会随着Pod生命周期结束而一起删除 &#xff08;一个pod中创建了docker1 docker2两个容器&#xff0c;他们都挂载这个emptyDir&#xff0…

Gradle依赖管理:编译时和运行时依赖的区别

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

【LeetCode】《LeetCode 101》第十一章:妙用数据结构

文章目录 11.1 C STL11.2 数组448. 找到所有数组中消失的数字&#xff08;简单&#xff09;48. 旋转图像&#xff08;中等&#xff09;74. 搜索二维矩阵&#xff08;中等&#xff09;240. 搜索二维矩阵 II&#xff08;中等&#xff09;769. 最多能完成排序的块&#xff08;中等…

ROSpider机器人评测报告

ROSpider机器人评测报告 最近入手了一款ROSpider六足仿生机器人&#xff0c;ROSpider是一款基于ROS 操作系统开发的智能视觉六足机器人。 外观 外观上ROSpider六足机器人如同名字一样有六只机械腿&#xff0c;整体来看像一只六腿的蜘蛛。腿上的关节处用了明亮的橙黄色很是显…