文章来源地址https://www.toymoban.com/news/detail-406757.html
- 专栏内容:postgresql内核源码分析
- 个人主页:我的主页
- 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物.
目录
前言
概述
接口介绍
调用场景分析
详细分解
结尾
前言
本文是基于postgresql 15的代码进行分析解读,演示是在centos8系统上进行。
概述
在postgresql中,SQL引擎使用表文件中的数据时,先读入共享缓冲区,修改时也先在缓冲区进行修改,而后通过缓冲区替换算法,定时脏页落盘等机制将数据写入磁盘。共享缓冲区是由buffer数组构成,每一个buffer对应数据文件中的一个page,默认配置时就是8K。
前面介绍过缓冲区替换算法及查找流程,本文对查找接口进行分享介绍。
接口介绍
在postgresql 主要有六种查找buffer的接口,分别在不同场景下,以提升性能。
extern PrefetchBufferResult PrefetchSharedBuffer(struct SMgrRelationData *smgr_reln,
ForkNumber forkNum,
BlockNumber blockNum);
extern PrefetchBufferResult PrefetchBuffer(Relation reln, ForkNumber forkNum,
BlockNumber blockNum);
extern bool ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum,
BlockNumber blockNum, Buffer recent_buffer);
extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum);
extern Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum,
BlockNumber blockNum, ReadBufferMode mode,
BufferAccessStrategy strategy);
extern Buffer ReadBufferWithoutRelcache(RelFileLocator rlocator,
ForkNumber forkNum, BlockNumber blockNum,
ReadBufferMode mode, BufferAccessStrategy strategy,
bool permanent);
调用场景分析
ReadBuffer |
最简单的调用,对于普通表常用,因为只能MAIN_FORKNUM,默认访问策略,也就是NULL |
ReadBufferExtended |
比较灵活,可以指定forknum, mode, strategy,ReadBuffer内部也是调用此接口 |
ReadBufferWithoutRelcache |
一般在拷贝database或table,replay wal时调用 |
ReadRecentBuffer |
主要在replay wal时调用,与ReadBuffer相比,此接口不会去查buffer mapping hash |
PrefetchBuffer |
在lazyvacuum时调用,扫描表的尾部的pages |
PrefetchSharedBuffer |
在PrefetchBuffer会调用;此外在replay wal时调用,提前加载WAL涉及的buffer来加速 |
详细分解
查找buffer会有以下几种情况:
(1) 在BufferMapping hash中找到,说明当前查找的tag已经有buffer存在,直接使用buffer id再查看buffer的有效性;查找到后,需要在第一时间加pin,再释放buffermapping hash段锁;
当前buffer可能有三种情况:
一种是buffer数据已经加载成功,也就是BM_VALID,此时加pin使用即可;
另一种是当前buffer只是tag设置成功了,数据还没有加载成功,有其它backend正在加载,那么此时就等待IO完成;
还有一种情况是,tag设置成功了,数据还没有加载成功,而且没有其它backend设置IO_IN_PROGRESS,那么当前进程负责加载数据;
(2)如果hash中没有找到,说明当前的tag没有buffer,需要使用替换算法找到一个buffer,第一时间进行增加引用计数,加pin;再看此buffer是否需要刷盘或者不符合替换;找到待替换的buffer时,需要持有描述符锁,直到加pin完成才释放,避免其它backend争抢;
对于替换算法找到的buffer会存在几种情况:
一是当前buffer为脏,需要刷盘;先加内容锁,如果加上再进行判断,如果buffer对应的WAL还没有落盘时,需要重新找替换块;不符合当前替换策略时,会将当前块从查找环中踢除,然后重新查找替换块;如果加不上内容锁,说明有backend正在修改,也会放弃重新找替换块;
二是当前buffer已经有tag的,可能是非脏块,需要对替换块对应的buffermapping 段加锁;此处要对新旧tag都要加锁,注意加锁顺序,避够死锁;
三是buffer当前是无效的,可能是没有被用过,就直接替换;
四是在替换过程中,其它backend又加pin使用甚至修改变脏页,此时也需要重新查找替换块;
(3)在新旧tag替换时,先加入buffermapping中,此时有可能此它backend已经加进入去了,那么加pin,等待加载磁盘;如果是新加入buffermapping中,那么修改buffer tag,然后修改buffer 描述符的state;然后启动Io加载磁盘;
结尾
作者邮箱:study@senllang.onaliyun.com
如有错误或者疏漏欢迎指出,互相学习。
注:未经同意,不得转载!文章来源:https://www.toymoban.com/news/detail-406757.html
到了这里,关于postgresql15 内核源码分析-buffer查找接口的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!