PostgreSQL VFD机制

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介: PostgreSQL VFD机制

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

VFDfree链表,实际上是数组的下标。

lruMoreRecently

VFD的最近最少使用链表,为双向。实际上也是数组的下标

lruLessRecently

lruLessRecently为正向,每次插入都插入头部

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时的流程


1Open时首先会调用AllocateVfd,从VfdCache数组中找一个空闲的slot,然后返回。该函数流程见AllocateVfd调用。

2)然后会调用ReleaseLruFiles判断是否open了最大限制的fd。如超出限制,则将LRU链表最后一个VFDfd close掉。

3open文件,并将该VFD插入到LRU链表。插入LRU的函数Insert详细流程看下面的函数分析。

4)然后对vfdP成员变量进行赋值。


PathNameOpenFilePerm->
    file = AllocateVd();
    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文件前都会调用AllocateVfdVfdCache中获取一个空闲的vfd

2)首先会判断free链表中是否为空。初始时刻,SizeVfdCache1,则会将VfdCache初始化成大小32的数组,并将其通过nextFree串联起来形成free链表,注意该free链表为循环。

3VfdCache[0]不使用。最开始32个的时候,即第一次扩充后free 链表如下图所示,跳过VfdCache[1]1会返回。也就是说每次取VFD都是 VfdCache[0].nextFree

4)后续再次扩充时,都是翻倍进行扩充



AllocateVfd->
    if (VfdCache[0].nextFree == 0){
        SizenewCacheSize = 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


1nfileopen打开的文件数,numAllocatedDescsfopen打开的文件数,max_safe_fds为操作系统计算得出的值。

2)一旦超出max_safe_fds值,就会调用ReleaseLruFileLRU链表删除一个,注意删除的是VfdCache[0].lruMoreRecently,即链表的尾部,最近最少使用的。

3首先将该fd关闭,然后将之置为VFD_CLOSED。调用Delete函数将VFDLRU链表删除。注意这里只是从LRU链表删除,不会释放回收到free链表,也不会修改vfd数据结构的其他成员变量值。因为后续可能还会用到该物理文件,会重新open并将之重新insertLRU链表。



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->lruLessRecently].lruMoreRecently = vfdP->lruMoreRecently;
            VfdCache[vfdP->lruMoreRecently].lruLessRecently = vfdP->lruLessRecently;

3、Insert


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

LRU链表的形式如下:

Insert一个VFD时:

4、Delete


Delete(file);-->
    vfdP = &VfdCache[file];
    VfdCache[vfdP->lruLessRecently].lruMoreRecently = vfdP->lruMoreRecently;
    VfdCache[vfdP->lruMoreRecently].lruLessRecently = vfdP->lruLessRecently;

例如删除VfdCache[1]


b932a15685a44abc9ac81714279a738a.png

5、回收VFD

1)每次调用FileClose时,会回收vfdfree链表。

2)先调用close函数

3)然后将之从LRU链表删除

4)如果是临时文件,还会将临时文件删除

5)调用FreeVfdvfd回收到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;
相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
7月前
|
存储 关系型数据库 Go
深入理解 PostgreSQL 中的 MVCC(多版本并发控制)机制
深入理解 PostgreSQL 中的 MVCC(多版本并发控制)机制
92 0
|
7月前
|
关系型数据库 数据库 PostgreSQL
PostgreSQL 的事务管理和并发控制机制解析
PostgreSQL 的事务管理和并发控制机制解析
147 0
|
10月前
|
关系型数据库 PostgreSQL
PostgreSQL pg_resetwal处理机制
PostgreSQL pg_resetwal处理机制
88 0
|
存储 算法 安全
SHA-1被攻破了吗? PostgreSQL SCRAM-SHA-256 安全认证机制解救你来了
标签 PostgreSQL , 认证方法 , SCRAM-SHA-256 , scram , scram-sha-256-plus , SASL , Simple Authentication and Security Layer 背景 PostgreSQL的很多设计非常的工业化,比如开放了许多扩展接口(类型、操作符、索引、扫描、采样、数据库编程语言等)。
6727 0
|
存储 SQL Oracle
再谈PostgreSQL的膨胀和vacuum机制及最佳实践
作者介绍 朱贤文,成都文武信息技术有限公司创始人,PostgreSQL中国用户会核心组成员,熟悉数据库,存储和集群技术; 成都文武信息技术有限公司是PostgreSQL和GreenPlum数据库服务的专业厂商,主要产品是ECOX集群管理系统和Hunghu Cloud,专门运行数据库的私有云系统,带高端存储功能。公司总部位于天府软件园。公司网站:w3.ww-it.cn 写本文的原因 这两天有两篇专门介绍PostgreSQL的vacuum机制的技术文章,得到了比较热烈和正面的反馈,让用户可以比较清楚地理解和使用这个特性。 我个人觉得有点小遗憾:这两篇文章没有跳出技术的角度,分析为什么会有这
325 0
|
关系型数据库 数据库 C语言
|
机器学习/深度学习 关系型数据库 PostgreSQL
|
关系型数据库 数据库 PostgreSQL
|
SQL 关系型数据库 PostgreSQL
浅析PostgreSQL事务处理机制
1、Q:PostgreSQL中DDL支不支持事务? A:支持。PostgreSQL中对DDL的处理方式和普通的DML类似,也是支持事务的。
1249 0
|
SQL 监控 关系型数据库
浅析PostgreSQL事务处理机制
前段时间在公司小范围做了一个关于PG事务实现的讲座,最后总结了一个摘要性的东西,分享一下,欢迎拍砖。 背景说明: 以ACID为特征的事务是关系数据库的一项重要的也是基本的功能。
1604 0