|
1、结构体 VFD 机制中由结构体 struct vfd 来维护。其中各个成员变量的意义如下表所示: fd | vfd 实际对应的物理文件文件描述符 | fdstate | FD_DELETE_AT_CLOSE :表示文件在关闭时需删除
FD_TEMP_FILE_LIMIT :标记临时文件
FD_CLOSE_AT_EOXACT :
这几个都针对临时文件 | resowner | owner, for automatic cleanup | nextFree | VFD 的 free 链表,实际上是数组的下标。 | lruMoreRecently | VFD 的最近最少使用链表,为双向。实际上也是数组的下标 | lruLe***ecently | lruLe***ecently 为正向,每次插入都插入头部 | fileSize | 文件大小 | fileName | 文件名 | fileFlags | 打开文件时的标签,比如 O_CREATE 等 | fileMode | 打开文件时的属性,比如读写权限等 |
2、初始化 启动时初始化,使用malloc ,只在本进程中有效,即每个进程都维护各自的 VfdCache 而并非共享内存。初始化时只申请第一个数组,并将其 fd 置为 VFD_CLOSED 。
PostgresMain->BaseInit->InitFileAccess:
VfdCache = (Vfd *) malloc(sizeof(Vfd));
MemSet((char *) &(VfdCache[0]), 0, sizeof(Vfd));
VfdCache->fd = VFD_CLOSED;
SizeVfdCache = 1; 2、open时的流程 1 ) Open 时首先会调用 AllocateVfd ,从 VfdCache 数组中找一个空闲的 slot ,然后返回。该函数流程见 AllocateVfd 调用。
2 )然后会调用 ReleaseLruFiles 判断是否 open 了最大限制的 fd 。如超出限制,则将 LRU 链表最后一个 VFD 的 fd close 掉。
3 ) open 文件,并将该 VFD 插入到 LRU 链表。插入 LRU 的函数 Insert 详细流程看下面的函数分析。
4 )然后对 vfdP 成员变量进行赋值。
PathNameOpenFilePerm->
file = AllocateVfd();
vfdP = &VfdCache[file];
ReleaseLruFiles();
vfdP->fd = BasicOpenFilePerm(fileName, fileFlags, fileMode);
Insert(file);
vfdP->fileName = fnamecopy;
/* Saved flags are adjusted to be OK for re-opening file */
vfdP->fileFlags = fileFlags & ~(O_CREAT | O_TRUNC | O_EXCL);
vfdP->fileMode = fileMode;
vfdP->fileSize = 0;
vfdP->fdstate = 0x0;
vfdP->resowner = NULL; AllocateVfd 1 )每次调用 BasicOpenFilePerm open 文件前都会调用 AllocateVfd 从 VfdCache 中获取一个空闲的 vfd 。
2 )首先会判断 free 链表中是否为空。初始时刻, SizeVfdCache 为 1 ,则会将 VfdCache 初始化成大小 32 的数组,并将其通过 nextFree 串联起来形成 free 链表,注意该 free 链表为循环。
3 ) VfdCache[0] 不使用。最开始 32 个的时候,即第一次扩充后 free 链表如下图所示,跳过 VfdCache[1] , 1 会返回。也就是说每次取 VFD 都是 VfdCache[0].nextFree
4 )后续再次扩充时,都是翻倍进行扩充
AllocateVfd->
if (VfdCache[0].nextFree == 0){
Size newCacheSize = SizeVfdCache * 2;
if (newCacheSize < 32)
newCacheSize = 32;
newVfdCache = (Vfd *) realloc(VfdCache, sizeof(Vfd) * newCacheSize);
VfdCache = newVfdCache;
for (i = SizeVfdCache; i < newCacheSize; i++){
MemSet((char *) &(VfdCache[i]), 0, sizeof(Vfd));
VfdCache[i].nextFree = i + 1;
VfdCache[i].fd = VFD_CLOSED;
}
VfdCache[newCacheSize - 1].nextFree = 0;
VfdCache[0].nextFree = SizeVfdCache;
SizeVfdCache = newCacheSize;
}
file = VfdCache[0].nextFree;
VfdCache[0].nextFree = VfdCache[file].nextFree;
return file;
 ReleaseLruFiles 1 ) nfile 为 open 打开的文件数, numAllocatedDescs 为 fopen 打开的文件数, max_safe_fds 为操作系统计算得出的值。
2 )一旦超出 max_safe_fds 值,就会调用 ReleaseLruFile 从 LRU 链表删除一个,注意删除的是 VfdCache[0].lruMoreRecently ,即链表的尾部,最近最少使用的。
3 ) 首先将该fd 关闭 ,然后将之置为VFD_CLOSED 。调用 Delete 函数将 VFD 从 LRU 链表删除。注意这里只是从 LRU 链表删除,不会释放回收到 free 链表,也不会修改 vfd 数据结构的其他成员变量值。因为后续可能还会用到该物理文件,会重新 open 并将之重新 insert 到 LRU 链表。
ReleaseLruFiles->
while (nfile + numAllocatedDescs >= max_safe_fds){
if (!ReleaseLruFile())
break;
}
ReleaseLruFile->
LruDelete(VfdCache[0].lruMoreRecently);->
vfdP = &VfdCache[file];
close(vfdP->fd);
vfdP->fd = VFD_CLOSED;
--nfile;
Delete(file);-->
vfdP = &VfdCache[file];
VfdCache[vfdP->lruLe***ecently].lruMoreRecently = vfdP->lruMoreRecently;
VfdCache[vfdP->lruMoreRecently].lruLe***ecently = vfdP->lruLe***ecently; 3、Insert Insert->
vfdP = &VfdCache[file];
vfdP->lruMoreRecently = 0;
vfdP->lruLe***ecently = VfdCache[0].lruLe***ecently;
VfdCache[0].lruLe***ecently = file;
VfdCache[vfdP->lruLe***ecently].lruMoreRecently = file;
LRU 链表的形式如下:

Insert 一个 VFD 时:
 4、Delete Delete(file);-->
vfdP = &VfdCache[file];
VfdCache[vfdP->lruLe***ecently].lruMoreRecently = vfdP->lruMoreRecently;
VfdCache[vfdP->lruMoreRecently].lruLe***ecently = vfdP->lruLe***ecently;
例如删除VfdCache[1] :
 5、回收VFD 1 )每次调用 FileClose 时,会回收 vfd 到 free 链表。
2 )先调用 close 函数
3 )然后将之从 LRU 链表删除
4 )如果是临时文件,还会将临时文件删除
5 )调用 FreeVfd 将 vfd 回收到 free 链表
FileClose->
close(vfdP->fd);
--nfile;
vfdP->fd = VFD_CLOSED;
Delete(file);
...
FreeVfd(file);
FreeVfd 调用函数FreeVfd 回收,注意几个成员变量的修改。回收时,将之插入到 free 链表头部。注意每次取时也从头部取
FreeVfd->
free(vfdP->fileName);//注意fileName需要释放,他是另malloc的
vfdP->fileName = NULL;
vfdP->fdstate = 0x0;
vfdP->nextFree = VfdCache[0].nextFree;
VfdCache[0].nextFree = file;
----------------------------
原文链接:https://blog.51cto.com/yanzongshuai/2447763
程序猿的技术大观园:www.javathinker.net
[这个贴子最后由 flybird 在 2020-03-13 11:45:49 重新编辑]
|
|