虚拟文件描述符VFD

news2024/11/25 22:49:38

瀚高数据库
目录
环境
文档用途
详细信息

环境
系统平台:Linux x86-64 Red Hat Enterprise Linux 7
版本:14
文档用途
了解VFD

详细信息

1.相关数据类型

typedef struct vfd

{

    int            fd;                /* current FD, or VFD_CLOSED if none */ OS文件描述符

    unsigned short fdstate;        /* bitflags for VFD's state */ vfd状态

    ResourceOwner resowner;        /* owner, for automatic cleanup */ 拥有者,自动清理用

    File        nextFree;        /* link to next free VFD, if in freelist */  File为int类型,表示下标

    File        lruMoreRecently;    /* doubly linked recency-of-use list */

    File        lruLessRecently;

    off_t        fileSize;        /* current size of file (0 if not temporary) */  

    char       *fileName;        /* name of file, or NULL for unused VFD */

    /* NB: fileName is malloc'd, and must be free'd when closing the VFD */

    int            fileFlags;        /* open(2) flags for (re)opening the file */ 

    mode_t        fileMode;        /* mode to pass to open(2) */  读、 写、 执行等flag

} Vfd;

2. VfdCache初始化

注意:VfdCache[0]不是一个有效的vfd,仅仅是为了减少链表增加、删除时的判断而引入的头结点。

Assert(SizeVfdCache == 0);    /* call me only once */

/* initialize cache header entry */

VfdCache = (Vfd *) malloc(sizeof(Vfd));

MemSet((char *) &(VfdCache[0]), 0, sizeof(Vfd));

VfdCache->fd = VFD_CLOSED; // 全局的VfdCache指向新建的表头节点

SizeVfdCache = 1;  // 记录vfd的数量

初始化完成之后,VfdCache指向内存空间的某一块:

在这里插入图片描述

3.AllocateVfd

Assert(SizeVfdCache > 0);    /* InitFileAccess not called? */



// 空闲链表上没有可用的vfd

if (VfdCache[0].nextFree == 0)

{

/*

* The free list is empty so it is time to increase the size of the

* array.  We choose to double it each time this happens. However,

* there's not much point in starting *real* small.

*/

Size        newCacheSize = SizeVfdCache * 2; // 原有容量*2

Vfd           *newVfdCache;



if (newCacheSize < 32) // 32个起步,考虑初始化就直接分配,这样的话vfd只有头结点,算作一个,这样分配才2个,太少了。

newCacheSize = 32;



/*

* Be careful not to clobber VfdCache ptr if realloc fails.

*/

newVfdCache = (Vfd *) realloc(VfdCache, sizeof(Vfd) * newCacheSize);

if (newVfdCache == NULL)

ereport(ERROR,

(errcode(ERRCODE_OUT_OF_MEMORY),

errmsg("out of memory")));

VfdCache = newVfdCache; // 新内存片的起始地址



/*

* Initialize the new entries and link them into the free list.

*/

// 之前的vfd已经通过realloc拷贝,只需初始化刚刚分配的vfd,从SizeVfdCache开始,一直到末尾

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;



/*

* Record the new size

*/

SizeVfdCache = newCacheSize; // SizeVfdCache记录现在的vfd数组大小

}

// 返回下标并修改指向下一个free节点的指针

file = VfdCache[0].nextFree;

VfdCache[0].nextFree = VfdCache[file].nextFree;

return file;

}

如图所示(依据环境为vfd初始化后第一次分配的情况):
AllocateVfd (1).png

4.释放内核维护的文件描述符

注意:vfd结构本身没有被释放,因为分配的时候是连续分配。只是更改了其中的fd为VFD_CLOSED,并对计数-1。

1.判断是否超过了max_safe_fds,值为一个固定的数字,pg14是48

/*

* Release kernel FDs as needed to get under the max_safe_fds limit.

* After calling this, it's OK to try to open another file.

*/

// nfile是经由fd.c通过open打开的, numAllocatedDescs是经由fd.c通过fopen打开的, numExternalFDs是系统或者没有通过fd.c打开的文件描述符

static void

ReleaseLruFiles(void)

{

while (nfile + numAllocatedDescs + numExternalFDs >= max_safe_fds)

{

    if (!ReleaseLruFile())

    break;

}

}

2.nfile > 0 表示当前有打开的文件,关闭掉最近最少使用的文件描述符(就是最早打开的那个)。

/*

* Release one kernel FD by closing the least-recently-used VFD.

*/

// 最近最少使用的fd关闭掉,直接关闭掉第一个节点

static bool

ReleaseLruFile(void)

{

if (nfile > 0)

{

    /*

    * There are opened files and so there should be at least one used vfd

    * in the ring.

    */

     Assert(VfdCache[0].lruMoreRecently != 0); // 最早打开的文件描述符在表尾,通过VfdCache[0].lruMoreRecently索引

     LruDelete(VfdCache[0].lruMoreRecently);

     return true;            /* freed a file */

}

return false;                /* no files available to free */

}

3.调用close关闭文件描述符,修改vfd结构相关成员变量。

static void

LruDelete(File file)

{

Vfd           *vfdP;

Assert(file != 0); // 不删头结点

        vfdP = &VfdCache[file];

        close(vfdP->fd); // 关闭系统文件描述符

vfdP->fd = VFD_CLOSED;  // fd设置为无效状态

--nfile; // 计数减一



/* delete the vfd record from the LRU ring */

Delete(file);

}

4.调整VfdCache指向的数组结构

static void

Delete(File file)

{

Vfd           *vfdP;



Assert(file != 0);

vfdP = &VfdCache[file];

VfdCache[vfdP->lruLessRecently].lruMoreRecently = vfdP->lruMoreRecently;

VfdCache[vfdP->lruMoreRecently].lruLessRecently = vfdP->lruLessRecently;

}

如图所示:

在这里插入图片描述

  1. 给定文件路径,打开文件, 获取kernel fd
/*

* Open a file with BasicOpenFilePerm() and pass default file mode for the

* fileMode parameter.

*/

// fileFlags : 文件读、写、执行、截断、创建等

// int pg_file_create_mode = PG_FILE_MODE_OWNER = S_IRUSR |  S_IWUSR , 用户读写,受到进程mask的影响

int

BasicOpenFile(const char *fileName, int fileFlags)

{

return BasicOpenFilePerm(fileName, fileFlags, pg_file_create_mode);

}

进入到BasicOpenFilePerm:

int

BasicOpenFilePerm(const char *fileName, int fileFlags, mode_t fileMode)

{

int            fd;

tryAgain:

// pg自定义PG_O_DIRECT不要和系统存在的flag相冲突

// PG_O_DIRECT_USE_F_NOCACHE这个宏主要用于做系统兼容,macOS中open()系统调用没有O_DIRECT,所以只能用fcntl()去修改File status flags,然而大部分类unix系统都可以在open时指定O_DIRECT。

//指定O_DIRECT会在文件读写时绕过操作系统缓存,这个标志只是建议,不一定有效。

#ifdef PG_O_DIRECT_USE_F_NOCACHE



/*

* The value we defined to stand in for O_DIRECT when simulating it with

* F_NOCACHE had better not collide with any of the standard flags.

*/

StaticAssertStmt((PG_O_DIRECT &

(O_APPEND |

O_CREAT |

O_EXCL |

O_RDWR |

O_RDONLY |

O_SYNC |

O_TRUNC |

O_WRONLY)) == 0,

"PG_O_DIRECT value collides with standard flag");



#if defined(O_CLOEXEC)

StaticAssertStmt((PG_O_DIRECT & O_CLOEXEC) == 0,

"PG_O_DIRECT value collides with O_CLOEXEC");

#endif

#if defined(O_DSYNC)

StaticAssertStmt((PG_O_DIRECT & O_DSYNC) == 0,

"PG_O_DIRECT value collides with O_DSYNC");

#endif

      //没有O_DIRECT标志,只能用fcntl在open之后获取到fd之后再修改,所以这个表达式把PG_O_DIRECT拿掉,fileFlags本身没有变化

fd = open(fileName, fileFlags & ~PG_O_DIRECT, fileMode);

#else

fd = open(fileName, fileFlags, fileMode);

#endif



if (fd >= 0)

{

#ifdef PG_O_DIRECT_USE_F_NOCACHE

if (fileFlags & PG_O_DIRECT)

{

     if (fcntl(fd, F_NOCACHE, 1) < 0)

    {

         // errno是全局的,close()也会设置errno,所以这里在进入close之前先保存一下

         int            save_errno = errno;

         close(fd);

         errno = save_errno;

         return -1;

    }

}

#endif

return fd;                /* success! */

}

      // open调用失败,设置errno,判断errno的值:

      // EMFILE:每个进程能打开的文件描述符有限制,意味着超过了限制;

      // ENFILE:超出了当前系统文件描述符的限制,统计了所有进程打开的

      // 当是上面两种错误时,利用lru算法,关闭最近最少使用的文件描述符,重新再打开一次,如果不是,返回-1表示失败。

if (errno == EMFILE || errno == ENFILE)

{

    int            save_errno = errno;

     ereport(LOG,

     (errcode(ERRCODE_INSUFFICIENT_RESOURCES),

     errmsg("out of file descriptors: %m; release and retry")));

     errno = 0;

     if (ReleaseLruFile())

          goto tryAgain;

     errno = save_errno;

}



return -1;                    /* failure */

}

6.FreeVfd

fileName要释放,它是单独申请的一块内存

把该vfd挂到free列表上,这块空间没法free

static void

FreeVfd(File file)

{

Vfd           *vfdP = &VfdCache[file];

if (vfdP->fileName != NULL)

{

free(vfdP->fileName);

vfdP->fileName = NULL;

}

vfdP->fdstate = 0x0;

vfdP->nextFree = VfdCache[0].nextFree;

VfdCache[0].nextFree = file;

}

7.Insert

static void

Insert(File file)

{

Vfd           *vfdP;



Assert(file != 0);

vfdP = &VfdCache[file];



vfdP->lruMoreRecently = 0;

vfdP->lruLessRecently = VfdCache[0].lruLessRecently;

VfdCache[0].lruLessRecently = file;

VfdCache[vfdP->lruLessRecently].lruMoreRecently = file;

}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/785083.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

23 自定义控件

案例&#xff1a;组合Spin Box和Horizontal Slider实现联动 新建Qt设计师界面&#xff1a; 选择Widget&#xff1a; 选择类名&#xff08;生成.h、.cpp、.ui文件&#xff09; 在smallWidget.ui中使用Spin Box和Horizontal Slider控件 可以自定义数字区间&#xff1a; 在主窗口w…

第17章 常见函数

创建函数 第一种格式采用关键字function&#xff0c;后跟分配给该代码块的函数名。 function name {commands }第二种 name() { commands }你也必须注意函数名。记住&#xff0c;函数名必须是唯一的&#xff0c;否则也会有问题。如果你重定义了函数&#xff0c;新定义会覆…

【时间复杂度】

旋转数组 题目 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 /* 解题思路&#xff1a;使用三次逆转法&#xff0c;让数组旋转k次 1. 先整体逆转 // 1,2,3,4,5,6,7 // 7 6 5 4 3 2 1 2. 逆转子数组[0, k - 1] // 5 6 7 4 3…

C语言基本结构:顺序、选择和循环

文章目录 前言顺序结构代码讲解 选择结构代码讲解 循环结构总结 前言 在计算机编程中&#xff0c;掌握基本的编程结构是非常重要的。C语言作为一种广泛应用的编程语言&#xff0c;具有丰富的基本结构&#xff0c;包括顺序结构、选择结构和循环结构。这些基本结构为开发人员提供…

RocketMQ主从集群broker无法启动,日志报错

使用vmWare安装的centOS7.9虚拟机&#xff0c;RocketMQ5.1.3 在rocketMQ的bin目录里使用相对路径的方式启动broker&#xff0c;jps查询显示没有启动&#xff0c;日志报错如下 排查配置文件没有问题&#xff0c;nameServer也已经正常启动 更换绝对路径&#xff0c;启动broker&…

flutter:animate_do(flutter中的Animate.css)

简介 做过web开发的应该大部分人都知道Animate.css&#xff0c;它为开发者提供了一系列预定义的动画效果&#xff0c;可以通过简单的CSS类来实现各种动画效果。而animate_do 相当于flutter中的Animate.css,它提供了很多定义好的动画效果 基本使用 官方地址 https://pub-web.…

一文学会redis在springBoot中的使用

“收藏从未停止&#xff0c;练习从未开始”&#xff0c;或许有那么一些好题好方法&#xff0c;在被你选中收藏后却遗忘在收藏夹里积起了灰&#xff1f;今天请务必打开你沉甸甸的收藏重新回顾&#xff0c;分享一下那些曾让你拍案叫绝的好东西吧&#xff01; 一、什么是redis缓存…

【深度学习】【三维重建】windows10环境配置PyTorch3d详细教程

【深度学习】【三维重建】windows10环境配置PyTorch3d详细教程 文章目录 【深度学习】【三维重建】windows10环境配置PyTorch3d详细教程Anaconda31.安装Anaconda32.卸载Anaconda33.修改Anaconda3安装虚拟环境的默认位置 安装PyTorch3d确定版本对应关系源码编译安装Pytorch3d 总…

Day 65: 集成学习之 AdaBoosting (3. 集成器)

代码&#xff1a; package dl;import java.io.FileReader; import weka.core.Instance; import weka.core.Instances;/*** The booster which ensembles base classifiers.*/ public class Booster {/*** Classifiers.*/SimpleClassifier[] classifiers;/*** Number of classi…

解决报错:Can‘t connect to HTTPS URL because the SSL module is not available.

本人今天准备打开安装一个label-studio包&#xff0c;试了很多次&#xff0c;接连报如下错误&#xff0c;因此我就去找了一些解决方案&#xff0c;现在总结如下&#xff1a; 1、报错信息如下 2、解决方案如下&#xff1a; github上有对应的解决方案&#xff0c;链接&#xff…

教师ChatGPT的23种用法

火爆全网的ChatGPT&#xff0c;作为教师应该如何正确使用&#xff1f;本文梳理了教师ChatGPT的23种用法&#xff0c;一起来看看吧&#xff01; 1、回答问题 ChatGPT可用于实时回答问题&#xff0c;使其成为需要快速获取信息的学生的有用工具。 从这个意义上说&#xff0c;Cha…

安卓开发后台应用周期循环获取位置信息上报服务器

问题背景 最近有需求&#xff0c;在APP启动后&#xff0c;退到后台&#xff0c;还要能实现周期获取位置信息上报服务器&#xff0c;研究了一下实现方案。 问题分析 一、APP退到后台后网络请求实现 APP退到后台后&#xff0c;实现周期循环发送网络请求。目前尝试了两种方案是…

Sui Builder House巴黎站精彩集锦

Sui Builder House巴黎站于7月19日圆满结束&#xff0c;Mysten Labs联合创始人兼CTO的Sam Blackshear在活动上发表了主题演讲。两天的Builder House活动还邀请了Mysten Labs的其他杰出成员分享Sui的发展情况和近期进展&#xff0c;社区成员展示了自己项目并提供见解&#xff0c…

C++继承体系中,基类析构函数请加上virtual,设置为虚函数

为什么建议在存在继承体系时刻我们的类的析构函数加上virtual呢&#xff1f; 大家看段代码。 咋一看&#xff0c;没什么毛病这段代码&#xff0c;让我们画图理解下。 紫框中的前4个字节指向new开辟的空间。 我们知道&#xff0c;当基类A指针指向基类B时候会发生切片 当我们del…

小程序如何修改商品

​商家可能会遇到需要修改产品信息的情况。无论是价格调整、库存更新还是商品描述的修改&#xff0c;小程序提供了简便的方式来帮助你们完成这些操作。下面是一些简单的步骤和注意事项&#xff0c;帮助你们顺利地修改商品。 一、进入商品管理页面 在个人中心点击管理入口&…

工厂电力监控解决方案

1、概述 电力监控系统实现对变压器、柴油发电机、断路器以及其它重要设备进行监视、测量、记录、报警等功能&#xff0c;并与保护设备和远方控制中心及其他设备通信&#xff0c;实时掌握供电系统运行状况和可能存在的隐患&#xff0c;快速排除故障&#xff0c;提高工厂供电可靠…

2023年Q2京东环境电器市场数据分析(京东数据产品)

今年Q2&#xff0c;环境电器市场中不少类目表现亮眼&#xff0c;尤其是以净水器、空气净化器、除湿机等为代表的环境健康电器。此外&#xff0c;像冷风扇这类具有强季节性特征的电器也呈现出比较好的增长态势。 接下来&#xff0c;结合具体数据我们一起来分析Q2环境电器市场中…

承接箱体透明拼接屏项目时,需要注意哪些事项?

承接箱体透明拼接屏项目时&#xff0c;需要注意以下事项&#xff1a; 确定需求&#xff1a;在承接箱体透明拼接屏项目之前&#xff0c;需要明确客户的需求&#xff0c;包括屏幕的大小、分辨率、亮度、色彩等参数&#xff0c;以及使用的环境、观看距离和观看角度等。 材料选择&…

图文教程:如何在 3DS Max 中创建3D迷你卡通房屋

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 在本教程中&#xff0c;我们将学习如何创建一个有趣的、低多边形的迷你动画房子&#xff0c;你可以在自己的插图或视频游戏项目中使用它。您将学习的一些技能将包括创建基本的3D形状和基本的建模技术。让我…

最简单的固定表格列实现

ref: https://dev.to/nicolaserny/table-with-a-fixed-first-column-2c5b 假设我们现在有这样一个表格 <table><thead><tr><th>姓名</th><th>性别</th><th>民族</th><th>年龄</th><th>籍贯</th>…