PostgreSQL 数据库存储 t_infomask
1 背景知识
本文主要介绍 t_infomask 的数据结构和底层原理。
2 t_infomask 信息
使用 pageinspect 扩展插件函数 heap_page_items
,可以看到 t_infomask
值,这个 t_infomask
是个两字节的值,含有的信息量非常大,每个 bit
都有特定的含义,包括了 锁信息、xmin and xmax
信息、xidfrozen
信息等。以下对这些具体结构的详细说明。
t_infomask
是个16
位的值,每bit
都有具体的含义:
#define HEAP_HASNULL 0x0001 /* has null attribute(s) */
#define HEAP_HASVARWIDTH 0x0002 /* has variable-width attribute(s) */
#define HEAP_HASEXTERNAL 0x0004 /* has external stored attribute(s) */
#define HEAP_HASOID 0x0008 /* has an object-id field */
#define HEAP_XMAX_KEYSHR_LOCK 0x0010 /* xmax is a key-shared locker */
#define HEAP_COMBOCID 0x0020 /* t_cid is a combo cid */
**#define HEAP_XMAX_EXCL_LOCK 0x0040 /* xmax is exclusive locker */**
#define HEAP_XMAX_LOCK_ONLY 0x0080 /* xmax, if valid, is only a locker */
#define HEAP_XMAX_SHR_LOCK (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)
#define HEAP_LOCK_MASK (HEAP_XMAX_SHR_LOCK | HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)
#define HEAP_XMIN_COMMITTED 0x0100 /* t_xmin committed */
#define HEAP_XMIN_INVALID 0x0200 /* t_xmin invalid/aborted */
**#define HEAP_XMIN_FROZEN (HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID) --两个位都为1**
#define HEAP_XMAX_COMMITTED 0x0400 /* t_xmax committed */
#define HEAP_XMAX_INVALID 0x0800 /* t_xmax invalid/aborted */
#define HEAP_XMAX_IS_MULTI 0x1000 /* t_xmax is a MultiXactId */
#define HEAP_UPDATED 0x2000 /* this is UPDATEd version of row */
#define HEAP_MOVED_OFF 0x4000 /* moved to another place by pre-9.0 * VACUUM FULL; kept for binary * upgrade support */
#define HEAP_MOVED_IN 0x8000 /* moved from another place by pre-9.0 * VACUUM FULL; kept for binary * upgrade support */
#define HEAP_MOVED (HEAP_MOVED_OFF | HEAP_MOVED_IN)
#define HEAP_XACT_MASK 0xFFF0 /* visibility-related bits */
3 xmin & xmax 状态指示位
3.1 新增记录
CREATE TABLE t01(id integer,name text);
INSERT INTO t01 values(1,'a');
SELECT T_INFOMASK FROM heap_page_items(get_raw_page('t1',0)) ;
//屏幕输出:
t_infomask
------------
2050
第1次访问之前:2050 转二进制 1000 0000 0010,其中黑体部分 1 对应:HEAP_XMAX_INVALID ,其他黑体部分 0 是没有信息的。读者可能会奇怪,事务不是已提交了吗,HEAP_XMIN_COMMITTED 对应的bit 怎么还是 0 ?
test=# select id,xmin,xmax from t1;
id | xmin | xmax
----+------+------
1 | 3288 | 0
test=# select t_infomask from heap_page_items(get_raw_page('t1',0)) ;
t_infomask
------------
2306
第1次访问之后:2036转二进制 1001 0000 0010,其中黑体部分 1 对应:HEAP_XMAX_INVALID and HEAP_XMIN_COMMITTED ,变化点是 HEAP_XMIN_COMMITTED 有值了,这也意味着后续读取该记录时,无需通过clog判断事务是否状态。
3.1.1 删除记录
test=# delete from t1 where id=1;
DELETE 1
test=# select t_infomask from heap_page_items(get_raw_page('t1',0)) ;
t_infomask
------------
258
(1 row)
删除记录后,第1次访问之前:258 转二进制 0001 0000 0010,其中黑体部分 1 对应:HEAP_XMIN_COMMITTED 。同样问题,事务已提交,为什么 HEAP_XMAX_INVALID 还是 0 ?
test=# select id,xmin,xmax from t1;
id | xmin | xmax
----+------+------
(0 rows)
test=# select t_infomask from heap_page_items(get_raw_page('t1',0)) ;
t_infomask
------------
1282
(1 row)
删除记录后,第1次访问之后:1282 转二进制 0101 0000 0010,其中黑体部分 1 对应:HEAP_XMAX_COMMITTED and HEAP_XMIN_COMMITTED ,变化点是 HEAP_XMAX_COMMITTED 有值了,这也意味着后续读取该记录时,无需通过clog判断事务是否状态。
PS:以上的测试有 HEAP_HASVARWIDTH 标志位,这代表什么意思?实际有时同样测试,却没有 HEAP_HASVARWIDTH 标志位。
4 xmax 锁标志位
会话1:
test=# create table t1(id integer);
CREATE TABLE
test=# insert into t1 values(1);
INSERT 0 1
test=# begin;
BEGIN
test=# select * from t1 where id=1 for update;
id
----
1
(1 row)
test=# select id,xmin,xmax from t1;
id | xmin | xmax
----+------+------
1 | 3296 | **3297**
会话2:
test=# select t_infomask from heap_page_items(get_raw_page('t1',0)) ;
t_infomask
------------
448
(1 row)
448 转二进制 0001 1100 0000,黑体部分 HEAP_XMAX_EXCL_LOCK and HEAP_XMAX_LOCK_ONLY ,也就是说这里的xmax 只是表示在该记录上有exclusive lock
5 xidfrozen 标志位
test=# create table t1(id integer);
CREATE TABLE
test=# insert into t1 values(1);
INSERT 0 1
test=# select * from t1;
id
----
1
(1 row)
test=# select t_infomask from heap_page_items( get_raw_page('t1',0) ) ;
t_infomask
------------
2304
(1 row)
test=# vacuum freeze t1;
VACUUM
test=# select t_infomask from heap_page_items(get_raw_page('t1',0)) ;
t_infomask
------------
2816
(1 row)
test=# select id, xmin,xmax from t1;
id | xmin | xmax
----+------+------
1 | 3300 | 0
(1 row)
2816 转二进制 1011 0000 0000,黑体部分三个1 分别表示:HEAP_XMAX_INVALID 、HEAP_XMIN_INVALID、HEAP_XMIN_COMMITTED,其中 11 表示HEAP_XMIN_FROZEN ,也就是 xidfrozen。