4.1.2 “relation”如何与外部文件对应
对于数据库系统的用户而言,一个二维的表,是一个逻辑的概念,其包含两部分东西,一是表的结构信息(表定义,create table…语句);另外一个是表数据,即通过insert into插入到表中的数据。
表的定义,是展示用户逻辑的,表的定义需要被数据库系统保存,存放地点,则是系统表空间;表的数据,物理上,是以文件形式存储于操作系统,可以存放与系统的表空间,也可以存放于用户自定义的表空间;存放在表空间的数据,是以数据文件的形式存储的。数据文件是表空间的物理外在形式,表空间是数据文件在数据库中的逻辑名称。
所以,表定义,可以是看作逻辑概念,数据文件的存储,是物理形式,如何把两者通过数据库管理系统统一(衔接点),则是我们本节讨论的内容。
从数据结构看,如下结构是逻辑概念和物理存储衔接的纽带:
typedef struct RelFileNode
{
Oid spcNode; /* tablespace */ //表空间的标识符号
Oid dbNode; /* database */ //具体数据库的标识符号
Oid relNode; /* relation */ //具体表的标识符号
} RelFileNode;
从代码季度分析,可以从relpathbackend函数入手,查看逻辑概念和物理存储之间的关系。
1. 本函数,根据数据库对象的RelFileNode指定的关系,找出外存对应的文件(文件位置)
2. 人口参数包括:RelFileNode rnode, BackendId backend, ForkNumber forknum
3. 第一个参数rnode,指出一个数据库中逻辑对象对应的外存文件信息,根据这个信息,可以拼接出外存文件的路径和文件名称(pg以数据库对象的ID值作为路径名称和对象名称,拼接规则,依赖于本函数中对“path”变量的赋值方式)
4. 根据rnode结构中的spcNode的值,判断要在物理存储的哪个表空间上操作dbNode指定数据库的relNode文件。这时,就有如下逻辑判断:
if (rnode.spcNode == GLOBALTABLESPACE_OID) {
/* Shared system relations live in {datadir}/global */
}
else if (rnode.spcNode == DEFAULTTABLESPACE_OID) {
/* The default tablespace is {datadir}/base */
if (backend == InvalidBackendId) {
}
else {
/* OIDCHARS will suffice for an integer, too */
}
}
else {
/* All other tablespaces are accessed via symlinks */
if (backend == InvalidBackendId) {
}
else {
/* OIDCHARS will suffice for an integer, too */
}
}
5. 最后得出文件的具体存放位置,注意在snprintf函数中对于文件路径的拼接方式,有所不同