【PostgreSQL的CLOG解析】

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

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里看到相关定义。

所以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。

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

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

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存放位置的定义和计算方法,如下所示

这四个分别为
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

另开一个session,查看clog

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


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

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

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


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

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

相关文章:
【PostgreSQL的CLOG解析】
同样还是这张图,之前发过shared_buffer和os cache、wal buffer和work mem的文章,今天的主题是图中的clog,即 commit log,PostgreSQL10之前放在数据库目录的pg_clog下面。PostgreSQL10之后修更名为xact,数据目录变更为pg_xact下面&…...
腾讯云国际站代充-阿里云ECS怎么一键迁移到腾讯云cvm?
今天主要来介绍一下如何通过阿里云国际ECS控制台一键迁移至腾讯云国际CVM。腾讯云国际站云服务器CVM提供全面广泛的服务内容。无-需-绑-定PayPal,代-充-值腾讯云国际站、阿里云国际站、AWS亚马逊云、GCP谷歌云,官方授权经销商!靠谱࿰…...
东方晶源亮相第十一届半导体设备年会,共话发展“芯”机遇
8月11日,以“协力同芯抢机遇,集成创新造设备”为主题的第十一届(2023年)中国电子专用设备工业协会半导体设备年会暨产业链合作论坛(CSEAC)在无锡太湖国际博览中心圆满闭幕。为期3天的CSEAC,通过…...
git修改历史commit信息
修改历史提交 commit 的信息 操作步骤: git rebase -i 列出 commit 列表找到需要修改的 commit 记录,把 pick 修改为 edit 或 e,:wq 保存退出修改 commit 的具体信息git commit --amend,保存并继续下一条git 4. 4. rebase --cont…...
基于K8S环境部署Dolphinscheduler及简单应用
一、Dolphinscheduler简介 Apache DolphinScheduler 是一个分布式易扩展的可视化DAG工作流任务调度开源系统。适用于企业级场景,提供了一个可视化操作任务、工作流和全生命周期数据处理过程的解决方案。 Apache DolphinScheduler 旨在解决复杂的大数据任务依赖关系,并为应用…...
Linux的ln命令
ln是link的缩写,在Linux中 ln 命令的功能是为某一个文件在另外一个位置建立一个同步的链接,当我们需要在不同的目录,用到相同的文件时,我们不需要在每一个需要的目录下都放一个必须相同的文件,我们只要在某个固定的目录࿰…...
深入了解Bear Necessities Hackathon黑客松的优胜者们
生态系统中的资深建设者皆知道Moonbeam是大型黑客松狂热爱好者,不论是线上虚拟的还是现场的。然而,很少有黑客松能达到Moonbeam和AWS举办的Bear Necessities黑客松这样的规模和吸引力。本次黑客松共有755人参与,共提交了62份参赛作品。其中22…...
mysql-tokudb使用qa
一、使用前提 安装tokudb引擎的前提条件是物理机要关闭大页,并需要注意物理机所剩内存和配置文件中tokudb_cache_size(内存主要占用部分),innodb_buffer_pool_size的使用,另外tokudb的安装一定要安装libjemalloc依赖&…...
对比学习论文综述总结
第一阶段:百花齐放(18-19中) 有InstDisc(Instance Discrimination)、CPC、CMC代表工作。在这个阶段方法模型都还没有统一,目标函数也没有统一,代理任务也没有统一,所以说是一个百花齐放的时代 1 判别式代理任务---个体判别任务 1.1 Inst Dict---一个编码器+一个memory…...
【BASH】回顾与知识点梳理(二十三)
【BASH】回顾与知识点梳理 二十三 二十三. Linux 账号管理(二)23.1 账号管理新增与移除使用者: useradd, 相关配置文件, passwd, usermod, userdelusermoduserdel 23.2 用户功能(普通用户可使用)idfingerchfnchsh 23.3…...
用 Python 写一个 NoSQL 数据库
NoSQL 这个词在近些年正变得随处可见. 但是到底 “NoSQL” 指的是什么? 它是如何并且为什么这么有用? 在本文, 我们将会通过纯 Python (我比较喜欢叫它, “轻结构化的伪代码”) 写一个 NoSQL 数据库来回答这些问题. OldSQL 很多情况下, SQL 已经成为 “数据库” (database)…...
Spring Security自定义登陆界面和密码验证逻辑
maven依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId> </dependency> 创建配置文件处理跳转拦截等功能以及密码比对功能 package com.example.demo2.demos.web1;…...
Android布局【LinearLayout】
文章目录 常见属性orientation的选择项解释项目结构主要代码 常见属性 orientation:布局中组件的排列方式gravity:控制组件所包含的子元素的对齐方式,可多个组合layout_gravity:控制该组件在父容器里的对齐方式background&#x…...
搭建grafana+loki+promtail日志收集系统
准备工作 下载地址 https://github.com/grafana/loki/releases 安装包放在服务器目录:/opt wget https://github.com/grafana/loki/releases/download/v2.4.2/loki-linux-amd64.zip wget https://github.com/grafana/loki/releases/download/v2.4.2/promtail-lin…...
Electron+vue3项目使用SQLite3数据库
SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意味着与其他数据库不一样,我们不需要在系统中配置。 就像其他数据库,SQLite 引擎不是一个独立的进程&am…...
SpringSpringBoot常用注解
目录 一、核心注解二、Spring Bean 相关2.1 Autowired2.2 Component, Repository, Service, Controller2.3 RestController 与 Controller2.4 Configuration 与 Component2.5 Scope 三、处理常见的 HTTP 请求类型3.1 GET 请求3.2 POST 请求3.3 PUT 请求3.4 DELETE 请求3.5 PATC…...
题目:2566.替换一个数字后的最大差值
题目来源: leetcode题目,网址:2566. 替换一个数字后的最大差值 - 力扣(LeetCode) 解题思路: 将从左到右第一个非 9 数字全部修改为 9 以得到最大值。将从左到右第一个数字全部修改为 0 以得到最小值&a…...
使用 NLP 进行文本摘要
一、说明 文本摘要是为较长的文本文档生成简短、流畅且最重要的是准确摘要的过程。自动文本摘要背后的主要思想是能够从整个集合中找到最重要信息的一小部分,并以人类可读的格式呈现。随着在线文本数据的增长,自动文本摘要方法可能会非常有用,…...
vue3挂载全局方法和组件
话不多说直接上代码 main.js import { createApp } from vue import App from ./App.vueconst app createApp(App)// 注册全局方法和组件 function myMethod(){console.log(Hello, world!); } app.provide("myMethod", myMethod) // provide注册全局方法 inject获取…...
mybatisplus学习笔记
1.踩过的坑 1.MybatisPlus 要与其代码生成器的版本一致; 2.要使用新版代码(3.5.1及以上)生成器则要使用springboot3,如果用springboot2使用新版代码生成器会导致builder.parent(“com.sdfsf”) // 设置父包名》重复!&…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
