PostgreSQL源码 · 元组管理(一)· 页的组织结构
开个新坑,简单写一写PostgreSQL中的元组管理。
对于整个存储架构,各种PostgreSQL的相关书籍已经介绍的很详细了,这里也就不再重复造轮子了。下面我们主要基于面向对象(大雾),来看看元组这个对象,有哪些成员变量
,又有哪些成员函数
元组(Tuple)是PostgreSQL中数据的基本存储单元,Page又是存储元组的基本载体,所以这第一篇我们先来看一下Page的结构
Page的结构
Page的结构可以简单看下图所示
page的默认大小为8k。每个页面的起始位置有大小为24个字节的PageHeader,记录该page相关的元数据信息。PageHeader中的pd_lower和pd_upper分别指向了页面空闲空间的首尾。
这里每一个tuple存储一条数据记录,从数据页底部开始向前依次存储。这些元组在页面中的位置存储在行指针line pointer中,每个行指针指向一个tuple。行指针从前向后依次存储,形成一个简单的数据。行指针中还存放了元组的状态和大小信息,扮演元组在页面中的索引的角色。行指针和tuple中间的部分为页面的空闲空间。
我们首先来看看PageHeader存储了什么元数据
PageHeader
1 | typedef struct PageHeaderData |
-
pd_lsn
,记录了该页面最后一次更改的WAL log的lsn -
pg_checksum
,页面校验和 -
pd_flags
,页面的标记为,包括以下标记PD_HAS_FREE_LINES
,页面中是否有unused line pointer. 这个unused的概念我们之后在看到line pointer时会介绍PD_PAGE_FULL
,页面是否有足够的空闲空间给新的tuplePD_ALL_VISIBLE
,页面中的所有元组是否对当前和之后的所有事务可见
-
pd_lower
,指向空闲空间的起始位置 -
pd_upper
,指向空闲空间的结束位置 -
pd_special
,指向特殊空间的起始位置 -
pd_pagesize_version
,页面布局的版本号 -
pd_prune_xid
,用于页面元组清理时的标记位,记录了最旧的可清理的事务号。没有则为0 -
pg_linp
,页面行指针数组
页面的行指针结构
行指针是一个32位大小的索引结构,如下:
1 | typedef struct ItemIdData |
-
lp_off
,记录了tuple在页面中的offset -
lp_len
,记录了tuple的size -
lp_flags
,是一个tuple状态的简单标记,方便在扫描元组时做一个初步筛选,有以下几个标记LP_UNUSED
,元组未使用,可以立刻被重用LP_NORMAL
,元组状态正常LP_REDIRECT
,元组被重定向了。用于PG的HOT链的头部和中间元组LP_DEAD
,元组已死,但空间可能还没有回收