海山数据库(He3DB)源码详解:海山PG 管理大型缓冲临时文件

Buffile.c 文件是 PostgreSQL 存储系统中的一个组成部分,专注于管理和优化临时文件的读写操作。它提供了一种对虚拟文件(由 fd.c 管理)的缓冲输入/输出(I/O)支持,以提高性能并减少资源消耗。

一、BufFile结构

BufFile被创建时,数据结构被存储在palloc中。BufFile同样支持超过OS文件大小限制的临时文件。BufFile还支持临时文件,当相应文件需要在整个事务中存活并多次打开和关闭时,单个后端可以使用这些临时文件。此类文件需要作为 FileSet 的成员。另外无论RELSEG_SIZE大小如何,都会将BufFile分成千兆字节大小的段。原因是希望大的BufFile在可用的情况下分散到多个表空间。

二、功能

1、缓冲I/O

  • BufFile 提供了一种类似标准 C 库中 stdio 的缓冲 I/O 功能。这意味着读写操作首先会在内存中的缓冲区进行,直到缓冲区满或空时,才会对底层文件进行实际的读写操作。这减少了直接对底层文件的访问次数,特别是对于虚拟文件(由 fd.c 管理),可以减少文件描述符的打开和关闭次数,从而提高性能。

2、大文件支持

  • BufFile 支持处理超过操作系统文件大小限制的大文件。这是通过打开多个 fd.c 管理的临时文件来实现的,当一个文件达到其大小限制时,会自动切换到另一个文件继续写入。这对于处理大量数据的排序和哈希连接操作特别重要。

3、资源共享

  • BufFile 支持创建可以与其他后端进程共享的临时文件。这是通过将文件作为共享文件集(SharedFileSet)的成员来实现的,使得参与并行执行的不同进程可以访问相同的文件。

4、跨事务生存能力

  • 对于需要在单个后端中跨事务持久化并且需要多次打开和关闭的临时文件,BufFile 支持将这些文件作为文件集(FileSet)的成员来创建。这样,即使在事务之间,这些文件也可以保持打开状态或根据需要重新打开。

三、源码解读

1、BufFile结构体

BufFile是PostgreSQL中用于表示一个缓冲文件的数据结构,这个缓冲文件可能由一个或多个物理文件组成,每个物理文件都通过一个由fd.c管理的虚拟文件描述符进行访问。这个结构体主要用于管理临时文件,特别是那些需要频繁读写且数据量可能超过单个文件大小限制的场景。

struct BufFile
{
	int        numFiles;       /* 文件集中物理文件的数量 */
	File	   *files;         /* 指向 File 类型的动态分配(使用 palloc)数组的指针 */

	bool		isInterXact;	/* 锁,是否保持事务打开 */
	bool		dirty;		/* 缓冲是否需要被写入,是否脏块 */
	bool		readOnly;	/* 文件是否设置为只读 */

	FileSet    *fileset;		/* 指向 FileSet 结构体的指针 */
	const char *name;		/* 指向字符数组的指针,表示基于文件集的 BufFile 的名称 */

	ResourceOwner resowner;         /* 用于管理底层临时文件的资源所有者 */

	int			curFile;		/* 文件起始位置的索引 */
	off_t		        curOffset;		/* 起始位置的偏移 */
	int			pos;			/* 下一个缓冲区读/写位置 */
	int			nbytes;			/* 缓冲区总有效字节数,数据总数 */
	PGAlignedBlock buffer;
};

2、创建BufFile实例

static BufFile * makeBufFileCommon(int nfiles)
{
	BufFile    *file = (BufFile *) palloc(sizeof(BufFile));   /* 动态分配内存,并讲分配的内存地址转换为`BufFile*`类型,并赋值给`file`指针 */

	file->numFiles = nfiles;
	file->isInterXact = false;
	file->dirty = false;
	file->resowner = CurrentResourceOwner;
	file->curFile = 0;
	file->curOffset = 0L;
	file->pos = 0;
	file->nbytes = 0;

	return file;
}
  • 首先使用palloc函数动态分配BufFile结构体所需的内存
  • 初始化BufFile结构体的各个成员

3、根据第一个底层物理文件构造BufFile

static BufFile * makeBufFile(File firstfile)
{
	BufFile    *file = makeBufFileCommon(1);

	file->files = (File *) palloc(sizeof(File));
	file->files[0] = firstfile;
	file->readOnly = false;
	file->fileset = NULL;
	file->name = NULL;

	return file;
}
  • 使用makeBufFileCommon函数构造只包含一个文件file的BufFile
  • 为file分配空间,BufFile指针指向file
  • 设置结构体中其他成员

4、添加另一个组件临时文件

static void extendBufFile(BufFile *file)
{
	File		pfile;
	ResourceOwner oldowner;

	oldowner = CurrentResourceOwner;
	CurrentResourceOwner = file->resowner;

	if (file->fileset == NULL)
		pfile = OpenTemporaryFile(file->isInterXact);  /* 打开临时文件,关闭后文件消失 */
	else
		pfile = MakeNewFileSetSegment(file, file->numFiles);  /* 创建一个新的段文件,支持基于BufFile的文件集 */

	Assert(pfile >= 0);

	CurrentResourceOwner = oldowner;

	file->files = (File *) repalloc(file->files, (file->numFiles + 1) * sizeof(File));  /* 重新分配内存块,更改所指向的内存块的大小。 */
	file->files[file->numFiles] = pfile;
	file->numFiles++;
}
  1. 资源所有者切换

    • 首先,函数保存当前的活动资源所有者(CurrentResourceOwner),并将它设置为 BufFile 结构体中指定的资源所有者(file->resowner)。这是为了确保与 BufFile 相关联的临时文件能够正确地与特定的资源所有者(如事务或会话)相关联,从而能够在需要时正确地清理这些文件。
  2. 打开新文件

    • 如果 file->fileset 为 NULL,表示这是第一次扩展文件集合,那么它将调用 OpenTemporaryFile 函数来创建一个新的临时文件,并根据 file->isInterXact 的值(指示是否跨事务)来设置文件的属性。
    • 如果 file->fileset 不为 NULL,则表示已经有一个文件集合存在,此时将调用 MakeNewFileSetSegment 函数来为该集合添加一个新的文件段。
  3. 断言文件句柄有效

    • 使用 Assert(pfile >= 0); 来确保返回的文件句柄是有效的(在 Unix-like 系统中,有效的文件句柄是非负的)。
  4. 恢复资源所有者

    • 将当前的活动资源所有者恢复为之前保存的值,以确保后续操作不受此函数的影响。
  5. 扩展文件句柄数组

    • 使用 repalloc 函数重新分配 file->files 数组,以便能够存储更多的文件句柄。新的数组大小为 file->numFiles + 1,即当前文件数量加一。
    • 将新打开的文件句柄添加到数组的新位置。
    • 更新 file->numFiles 以反映文件数量的增加。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值