Heap Table数据格式

Posted by CCH on November 5, 2021

表和元组的组织形式

HeapTable格式 表和索引由一个或多个表文件组成, 每个表文件被分成固定长度的page(或者叫block), block大小由代码的宏定义BLCKSZ决定, 在单机PG中,该值为8KB(8192);在ADB PG中,该值为32KB(32768). 一个表文件由固定数量的block组成, 数量由宏定义RELSEG_SIZE决定, 该值为32768. 因此,一个表文件最大的size = RELSEG_SIZE * BLCKSZ.

注: BLCKSZ的值最大智能设置为2^15=32768, 原因是用于在block内部寻址的 item pointer中, 用了15位来存一个tuple在block内部的偏移量.

pd_lsn: 表示该页面最近一次修改所对应的WAL日志的位置,该值用于数据库恢复replay WAL时,若page的pd_lsn大于此时replay WAL的lsn, 说明该页面比WAL所对应的操作更新, 无需replay pd_checksum: 页面的checksum值 pd_flags: 这些flag用于在读一个页面时,快速能判断这个页是否有 空余的line_poiner, 是否还有可用空间, 页面中的元组是否全部可见.

#define PD_HAS_FREE_LINES	0x0001		/* are there any unused line pointers? */
#define PD_PAGE_FULL		0x0002		/* not enough free space for new
										 * tuple? */
#define PD_ALL_VISIBLE		0x0004		/* all tuples on page are visible to
										 * everyone */

#define PD_VALID_FLAG_BITS	0x0007		/* OR of all valid pd_flags bits */

pd_lower: 记录block内的偏移量,指向block free space的起始位置, 也即最后一个line pointer的结束位置 pd_upper: 记录block内的偏移量, 指向block free space的结束位置.

pd_special: block内的偏移量, 指向block最后的 special 存储区域的起始位置, 该区域用来存储索引的专用数据. 对于普通表, 该区域为空, 所以pd_special的值就等于页大小.

pd_pagesize_version: 2字节, 记录页面大小和页面版本, 前1个字节表示页面大小, 后1个字节表示版本

pd_prune_xid: 每次页面中的有元组被update/delete时,会设置这个值为当前update/delete事务ID. 之后数据库读取该页面(如调用heapgetpage) 会检查该值是否比此时的oldest min xid 还小, 如果是, 则表明该页面时可以清理的, 那么最终会调用PageRepairFragmentation对该page(block)进行清理. 清理简单讲就是将无用的元组清除(包括HOT链中的无用tuple),将有用的元组移动到页面的最后, 腾出页面中间的free space, 使得页面空间再次变得连续.

pg_linp[]: line pointer数组, 每个数组元素是是一个iitemId结构, 记录一个元组在block内的偏移量, 元组长度, 以及一些flag, 用来表示该line pointer 是否可用

typedef struct ItemIdData
{
	unsigned	lp_off:15,		/* offset to tuple (from start of page) */
				lp_flags:2,		/* state of item pointer, see below */
				lp_len:15;		/* byte length of tuple */
} ItemIdData;