4.2 数据的内部格式
4.2.1 页的存储数据结构
在操作系统层面,数据存储,只是一些二进制信息,这个层次,是不知道文件内容的含义的。文件的逻辑含义,取决于应用层面。
数据库系统的文件组织,也如此。在外存存储,以二进制格式存放,读写文件,以块(8k)为单位,读入的数据,存放与数据缓冲区,所以,数据的逻辑含义,始于数据缓冲区。
在bufpage.h文件中,有如下定义:
typedef struct PageHeaderData
{
/* XXX LSN is member of *any* block, not only page-organized ones */
XLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog
* record for last change to this page */
uint16 pd_tli; /* least significant bits of the TimeLineID
* containing the LSN */
uint16 pd_flags; /* flag bits, see below */
LocationIndex pd_lower; /* offset to start of free space */
LocationIndex pd_upper; /* offset to end of free space */
LocationIndex pd_special; /* offset to start of special space */
uint16 pd_pagesize_version;
TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */
ItemIdData pd_linp[1]; /* beginning of line pointer array */
} PageHeaderData;
这个结构,描述了数据页的页头信息。一个数据页,是一个块大小,即8k。这个页的初始部分,完全由PageHeaderData这个结构定义。
结构成员名称 | 类型 | 功能 |
pd_lsn | XLogRecPtr | 写到redo日志中的记录的结束位置的位置标识,用以把数据页和redo日志关联,用于恢复数据时校验日志文件和数据文件的一致性 |
pd_tli | uint16 | 与redo日志相关,上一个记录了redo日志的文件id和偏移,本标志记载了redo日志的“timeline”时间线。在redo日志中,完整标识一个日志文件,是靠时间线和日志id;完整标识一个日志位置,是靠时间线和日志id和日志文件中的偏移值 |
pd_flags | uint16 | 标识本页面的数据存储情况,是半满页、满页、、还是有冗余数据(数据对于一些用户是否可见,与事务相关,与PG实现的MVCC相关) |
pd_lower | LocationIndex | 指向空闲空间的开始位置 |
pd_upper | LocationIndex | 指向空闲空间的结束位置 |
pd_special | LocationIndex | 指向页面尾部的一个特殊块的位置处,通过PageInit函数可以了解不同调用函数通常有不同的特殊块存在。如gin索引对应的页面、hash页面、BTree索引页面都有特殊的块标识特别的信息 |
pd_pagesize_version | uint16 | 标识数据页的页面版本,不同PG的版本,数据页格式可能发生变化,用以标识变化的。这样,就存在根据页面版本号读取不同信息的可能 |
pd_prune_xid | TransactionId | 记载本页面上最老的事务ID值,在做vacuum操作时使用 |
pd_linp[1] | ItemIdData | 指向页面上存在的tuple(记录)的指针 相关代码: src/include/storage/itemid.h |