PostgreSQL中commit log有什么作用

63次阅读
没有评论

共计 3775 个字符,预计需要花费 10 分钟才能阅读完成。

本篇内容主要讲解“PostgreSQL 中 commit log 有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让丸趣 TV 小编来带大家学习“PostgreSQL 中 commit log 有什么作用”吧!

Concurrency Control 并发控制是一种机制,在并发进行多个事务时维护一致性 (Consistency) 和隔离性 (Isolation),一致性和隔离性是数据库事务 ACID(Atomicity, Consistency, Isolation, Durability) 属性中的 C 和 I。
多版本并发控制 (MVCC) 是广泛使用的并发控制技术, 其主要优势是读不会阻塞写,而写也不会阻塞读。MVCC 有很多种变体,PostgreSQL 使用一种称为快照隔离 Snapshot Isolation (SI)的 MVCC 变体实现并发控制。
在 MVCC 中,每个 DML 操作创建一个数据(包括 Index)的新版本,同时保留之前的旧版本。当事务读取数据时,选择其中一个“正确”的版本,以确保各个事务之间的隔离。

Multi Version Heap Tuple
这一章节中提到事务回滚后, 新写入的数据仍存储在 heap 中,PostgreSQL 如何识别产生这些数据的事务的状态 (提交 / 回滚 / 进行中), 从而确定哪些 tuple 可见不可见?PG 通过 clog(commit log) 存储每个事务的状态, 在数据库启动时,clog 文件会加载到共享内存中,checkpoint 时会把共享内存中的事务状态信息刷新到磁盘上.

一、基本概念

事务 ID
当一个事务开启时,PostgreSQL 事务管理器会为该事务分配一个唯一的事务 ID(txid, 无符号 32bit 整型).
通过 txid_current()函数可获取当前事务号.

testdb=# begin;
BEGIN
testdb=# select txid_current();
 txid_current 
--------------
 2308
(1 row)
testdb=#

在 PG 中, 以下为系统保留使用的 txid:
txid = 0, 表示 Invalid txid,用于判断 txid 的有效性
txid = 1, 表示 Bootstrap txid,在 intidb 初始化数据库时使用
txid = 2, 表示 Frozen txid,在事务 ID 回卷时, 通过 vacuum 进程处理时使用

事务状态
PostgreSQL 定义了四种事务状态, 分别是 IN_PROGRESS(进行中), COMMITTED(已提交), ABORTED(已回滚), 和 SUB_COMMITTED(子事务已提交).

/*
 * Possible transaction statuses --- note that all-zeroes is the initial
 * state.
 *  可能的事务状态  ---  注意初始状态全部为 ASCII 0
 *
 * A  subcommitted  transaction is a committed subtransaction whose parent
 * hasn t committed or aborted yet.
 *  subcommitted 事务是指已提交的子事务, 而该子事务所在的父事务尚未提交或者回滚.
 */
typedef int XidStatus;
#define TRANSACTION_STATUS_IN_PROGRESS 0x00
#define TRANSACTION_STATUS_COMMITTED 0x01
#define TRANSACTION_STATUS_ABORTED 0x02
#define TRANSACTION_STATUS_SUB_COMMITTED 0x03

二、clog 文件

物理文件
clog 文件存储在 $PGDATA/pg_xact 目录中

[xdb@localhost pg_xact]$ ll
total 8
-rw-------. 1 xdb xdb 8192 Jan 8 15:55 0000
[xdb@localhost pg_xact]$

clog segment
如前所述, 事务号是无符号的 32bit 整型,PG 通过以下公式逻辑上把 clog 划分为 N 个 segment:
N = 0xFFFFFFFF/CLOG_XACTS_PER_PAGE/SLRU_PAGES_PER_SEGMENT
其中:
CLOG_XACTS_PER_PAGE 定义为

/* We need two bits per xact, so four xacts fit in a byte */
#define CLOG_BITS_PER_XACT 2 -- 每个事务状态使用 2bits 表示
#define CLOG_XACTS_PER_BYTE 4 -- 每个 Byte 可存储 4 个事务状态
#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE) -- 每个 page 可存储 8192* 4 个事务状态

即 CLOG_XACTS_PER_PAGE = 8192*4
SLRU_PAGES_PER_SEGMENT 定义为

#define SLRU_PAGES_PER_SEGMENT 32

代入公式中:
N = 0xFFFFFFFF/CLOG_XACTS_PER_PAGE/SLRU_PAGES_PER_SEGMENT
 = 0xFFFFFFFF/(8192*4)/32
 = 4096

物理上, 每个 segment 有 32 个 Pages(SLRU_PAGES_PER_SEGMENT = 32), 则每个 segment file 大小为 8K*32=256K.

三、txid clog

给定一个事务号, 如何获取该事务对应的状态?
PG 首先通过该事务号获得该事务状态存储在 clog 中哪个 page 中(即 pageno), 然后再定位存储事务状态的 Byte 在该 page 中的偏移以及在该 Byte 中的偏移.

 #define TransactionIdToPage(xid) ((xid) / (TransactionId) CLOG_XACTS_PER_PAGE)
 #define TransactionIdToPgIndex(xid) ((xid) % (TransactionId) CLOG_XACTS_PER_PAGE)
 #define TransactionIdToByte(xid) (TransactionIdToPgIndex(xid) / CLOG_XACTS_PER_BYTE)
 #define TransactionIdToBIndex(xid) ((xid) % (TransactionId) CLOG_XACTS_PER_BYTE)

如给定事务号 2308, 根据上述公式可得到:
Page = 2308 / (8192*4) = 0 — 第 0 号 page
PageIndex = 2308 % (8192*4) = 2308 — Page 内偏移
ByteInPage = 2308 / 4 = 577 — 该 Page 内的第 577 个 Byte
ByteIndex = 2304 % 4 = 0 — 该字节中的首 2bits
下面通过实际案例验证
开启事务

testdb=# begin;
BEGIN
testdb=# select txid_current();
 txid_current 
--------------
 2308
(1 row)

查看 clog

[xdb@localhost pg_xact]$ hexdump -C ./0000 -s 577 -n 1
00000241 00 |.|
00000242

0x00 — TRANSACTION_STATUS_IN_PROGRESS

提交事务
执行 checkpoint, 刷新到磁盘上

testdb=# commit;
COMMIT
testdb=# checkpoint;
CHECKPOINT

查看 clog

[xdb@localhost pg_xact]$ hexdump -C ./0000 -s 577 -n 1
00000241 01 |.|
00000242

值为 0x01 — TRANSACTION_STATUS_COMMITTED

重新开启一个事务 2309, 回滚该事务,clog 中的值应为 0x09(二进制值为:0000 1001)

testdb=# begin;
BEGIN
testdb=# select txid_current();
 txid_current 
--------------
 2309
(1 row)
testdb=# select 2308%4;
 ?column? 
----------
 0
(1 row)
testdb=# rollback;
ROLLBACK
testdb=# checkpoint;
CHECKPOINT
testdb=#

clog 文件中的内容 0x09, 与预期中的一致.

[xdb@localhost pg_xact]$ hexdump -C ./0000 -s 577 -n 1
00000241 09 |.|
00000242
[xdb@localhost pg_xact]$

到此,相信大家对“PostgreSQL 中 commit log 有什么作用”有了更深的了解,不妨来实际操作一番吧!这里是丸趣 TV 网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-24发表,共计3775字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)