共计 1759 个字符,预计需要花费 5 分钟才能阅读完成。
因为每个操作系统限度了一个过程能关上的文件数(例如:ubuntu 为 1024),因而过程能取得的文件描述符是无限的。对于常常须要关上许多文件的数据库过程来说,很容易会超过操作系统对于文件描述符数量的限度。
为解决这个问题,PostgreSQL 中应用了虚构文件描述符 (VFD) 机制,通过 VFD 治理实在的文件描述符,帮忙过程解脱操作系统的限度。
typedef struct vfd
{
int fd;
unsigned short fdstate;
ResourceOwner resowner;
File nextFree;
File lruMoreRecently;
File lruLessRecently;
off_t fileSize;
char *fileName;
int fileFlags;
mode_t fileMode;
} Vfd;
VDF 中各字段含意:
- fd 记录该 VFD 所对应的实在文件描述符,如果以后 VFD 没有关上文件,则其值为 VFD_CLOSED (-1)。
- fdstate 标记位:如 FD_DELETE_AT_CLOSE,表明该文件在敞开时要被删除。
- nextFree:指向下一个闲暇的 VFD,其数据类型 File 示意其在 VFD 数组中的下标。
- lruMoreRecently:指向比该 VFD 最近更罕用的虚构文件描述符。
- lnuLessRecently:指向比该 VFD 最近更不罕用的虚构文件描述符。
- fileSize:以后文件大小。
- fleName:该 VFD 对应文件的文件名,如果是闲暇的 VFD 则 fileName 为空。
- fileFlags:该文件关上时的标记,包含只读、只写、读写等。
- fileMode:文件创建时所指定的模式。
VFD 数组 VfdCache 作为 LRU 池管理文件描述符,并依据须要关上和敞开理论的 OS 文件描述符。LRU 池应用数组实现,数组元素是 VFD 构造体,数组大小会依据须要增长(最大 1024)。
static Vfd *VfdCache;
static Size SizeVfdCache = 0;
当 LRU 池未满时,过程能够申请一个 VFD 用来关上物理文件;而当 LRU 池已满时,过程须要首先敞开一个 VFD。在 LRU 中,应用替换最长工夫未应用 VFD 策略。
过程在 VfdCache 上放弃了两个链表,一个是 LRU 池(双向链表),另一个是 FreeList(闲暇链表,记录了所有可被调配的 VFD)。前者通过 lruMoreRecently 属性和 lruLessRecently 属性来链接,后者则通过 nextFree 属性来链接。
VfdCache [0] 不是可用的 VFD,它仅用来标识 FreeList 和 LRU 池的链表头部。对 LRU 池里的 VFD 的操作次要包含以下三种:
(1) 将 VFD 插入 LRU 池
关上一个新的 VFD 时,会将该 VFD 对应的物理文件关上,并将该 VFD 插入到 VfdCache[O] 之后的地位。例如,咱们要插入的 VFD 为 a,首先要依据 a 中的 fd 字段判断对应的物理文件是否曾经关上。如果没有关上则依据 a 中的 fileName 关上此文件,并插入到 LRU 池中。
插入时要将 a 的 lruMoreRecently 指向 VfdCache[0],VfdCache[0] 的 lruLessRecently 指向 a,而后 a 的 lruLessRecently 指向 V1,V1 的 lruMoreRecently 指向 a。
(2) 从 LRU 池删除 VFD
过程应用完一个文件并敞开它时,将该文件的 VFD 从 LRU 池中删除,并将该 VFD 对应的文件敞开掉。例如,咱们要对 V2 操作,则首先将 V1 的 lrulessRecently 指向 V3,将 V3 的 lruMoreRecently 指向 V1。
这样就将 V2 从 LRU 池中删除了,如果 V2 的 fdstate 被置为 FD_DELETE_AT_CLOSE,则要先将 V2 对应的文件删除,再清掉 FD_DELETE_AT_CLOSE 位,接着将 fileSize 置为 0,将 fd 置为 VFD_CLOSED。这样 V2 就变为闲暇,最初将其退出到闲暇链表中。
(3) 删除 LRU 池尾 VFD
当 LRU 池已满,而此时又要关上新的文件时,就需将池尾的 VFD 删掉,这样新关上的 VFD 就能够插入到 LRU 中。留神,这里被删除的 VFD 仅仅只是从 LRU 池中脱链并敞开其对应的物理文件,VFD 自身并不做其余批改和删除。