postgreSQL中的高速缓存

1. 高速缓存简介

​如下图所示,当一个postgreSQL进程读取一个元组时,需要获取表的基本信息(例如:表的oid、索引信息和统计信息等)及元组的模式信息,这些信息被分别记录在多个系统表中。通常一个表的模式信息在设定好后的变化频率很低,因此在对同一个表的多个元组操作时,每次都去读取系统表的元组来构建模式信息显然是没有必要的,这也会降低元组的操作效率。为了减少对系统表的访问,在每个进程本地内存区域设置了两种cache,一种是用来存储系统表的元组,一种是用来存储表的基本信息,从而可以让进程更快的构建出表的基本信息和元组的模式信息。cache在某一个进程对系统表发生更改时其他的 backend 进程要能够感知到,需要有一套维护cache 一致性的机制,也就是 PG 的 InvalidMessage机制。

用户表是如何被管理的,参考:https://zhuanlan.zhihu.com/p/623283855

在这里插入图片描述

2. SysCache

syscache主要用来缓存最近使用过的系统表的元组。从代码实现看,syscache就是一个catcache数组,数组的长度为系统表的个数,每一个系统表唯一的对应catcache数组的一个元素。

  • catcache数据结构
typedef struct catcache
{
	int			id;				/* catcache id */
	int			cc_nbuckets;	/* # of hash buckets in this cache */
	TupleDesc	cc_tupdesc;		/* tuple descriptor (copied from reldesc) */
	dlist_head *cc_bucket;		/* hash buckets */
	CCHashFN	cc_hashfunc[CATCACHE_MAXKEYS];	/* hash function for each key */
	CCFastEqualFN cc_fastequal[CATCACHE_MAXKEYS];	/* fast equal function for
													 * each key */
	int			cc_keyno[CATCACHE_MAXKEYS]; /* AttrNumber of each key */
	dlist_head	cc_lists;		/* list of CatCList structs */
	int			cc_ntup;		/* # of tuples currently in this cache */
	int			cc_nkeys;		/* # of keys (1..CATCACHE_MAXKEYS) */
	const char *cc_relname;		/* name of relation the tuples come from */
	Oid			cc_reloid;		/* OID of relation the tuples come from */
	Oid			cc_indexoid;	/* OID of index matching cache keys */
	bool		cc_relisshared; /* is relation shared across databases? */
	slist_node	cc_next;		/* list link */
	ScanKeyData cc_skey[CATCACHE_MAXKEYS];	/* precomputed key info for heap
											 * scans */

	/*
	 * Keep these at the end, so that compiling catcache.c with CATCACHE_STATS
	 * doesn't break ABI for other modules
	 */
#ifdef CATCACHE_STATS
	long		cc_searches;	/* total # searches against this cache */
	long		cc_hits;		/* # of matches against existing entry */
	long		cc_neg_hits;	/* # of matches against negative entry */
	long		cc_newloads;	/* # of successful loads of new entry */

	/*
	 * cc_searches - (cc_hits + cc_neg_hits + cc_newloads) is number of failed
	 * searches, each of which will result in loading a negative entry
	 */
	long		cc_invals;		/* # of entries invalidated from cache */
	long		cc_lsearches;	/* total # list-searches */
	long		cc_lhits;		/* # of matches against existing lists */
#endif
} CatCache;
2.1 syscache初始化

在对postgres进程初始化时,会对syscache进行初始化,将查找系统表元组的关键信息写入到catcache数组的元素中。

涉及到的数据结构如下:

  • cacheinfo:存储所有系统表的catcache描述信息

    struct cachedesc
    {
    	Oid			reloid;			/* OID of the relation being cached */
    	Oid			indoid;			/* OID of index relation for this cache */
    	int			reloidattr;		/* attr number of rel OID reference, or 0 */
    	int			nkeys;			/* # of keys needed for cache lookup */
    	int			key[4];			/* attribute numbers of key attrs */
    	int			nbuckets;		/* number of hash buckets for this cache */
    };
    
    static const struct cachedesc cacheinfo[] = {
    	{AggregateRelationId,		/* AGGFNOID */
    		AggregateFnoidIndexId,
    		1,
    		{
    			Anum_pg_aggregate_aggfnoid,
    			0,
    			0,
    			0
    		},
    		16
    	},
    	...
    	
    }
    
  • catcacheheader:catcache使用cc_next字段构成一个单向链表,头部使用此结构体记录

    typedef struct catcacheheader
    {
    	slist_head	ch_caches;		/* head of list of CatCache structs */
    	int			ch_ntup;		/* # of tuples in all caches */
    } CatCacheHeader;
    

初始化阶段1:使用cacheinfo初始化catcache数组

typedef struct catcache
{
	...
	TupleDesc	cc_tupdesc;		/* tuple descriptor (copied from reldesc) */
	int			cc_nbuckets;	/* # of hash buckets in this cache */
	dlist_head *cc_bucket;		/* hash buckets */
	int			cc_keyno[CATCACHE_MAXKEYS]; /* AttrNumber of each key */
	int			cc_nkeys;		/* # of keys (1..CATCACHE_MAXKEYS) */
	Oid			cc_reloid;		/* OID of relation the tuples come from */
	Oid			cc_indexoid;	/* OID of index matching cache keys */
	...
}

初始化阶段2:根据对应的系统表填充catcache中元组描述信息(cc_tupdesc)、系统表名(cc_relname)和查找关键字的相关字段

typedef struct catcache
{
	...
	CCHashFN	cc_hashfunc[CATCACHE_MAXKEYS];	/* hash function for each key */
	CCFastEqualFN cc_fastequal[CATCACHE_MAXKEYS];	/* fast equal function for each key */
	const char *cc_relname;		/* name of relation the tuples come from */
	bool		cc_relisshared; /* is relation shared across databases? */
	ScanKeyData cc_skey[CATCACHE_MAXKEYS];	/* precomputed key info for heap scans */
	...
}
2.2 catcache中缓存元组的组织

每个catcache元素中cc_bucket数组是一个Hash桶数组,元组的键值可以通过hash函数映射到cc_bucket数组的下标。每个hash桶都被组织成一个双向链表Dllist,其中的节点为Dlelem类型,Dlelem是一个包装过的缓存元组,其dle_val字段指向一个CatCTup形式的缓存元组。
在这里插入图片描述

CatCache中的缓存元组将先包装成CatCTup形式,然后再包装成Dlelem形式,最后加入到其所在的hash桶链表中。

typedef struct dlist_node dlist_node;
struct dlist_node
{
	dlist_node *prev;
	dlist_node *next;
};
typedef struct catctup
{
	int			ct_magic;		/* for identifying CatCTup entries */
#define CT_MAGIC   0x57261502
	uint32		hash_value;		/* hash value for this tuple's keys */
	Datum		keys[CATCACHE_MAXKEYS];
	dlist_node	cache_elem;		/* list member of per-bucket list */
	int			refcount;		/* number of active references */
	bool		dead;			/* dead but not yet removed? 标记删除*/
	bool		negative;		/* negative cache entry? 表示实际并不存在的元组*/
	HeapTupleData tuple;		/* tuple management header */
	struct catclist *c_list;	/* containing CatCList, or NULL if none */

	CatCache   *my_cache;		/* link to owning catcache */
} CatCTup;
2.3 在catcache中查找元组

在catcache查找元组有两种方式:精确匹配和部分匹配。

  1. 精确匹配

​ 精确匹配由SearchCatCache函数实现:

HeapTuple
SearchCatCache(CatCache *cache,
			   Datum v1,
			   Datum v2,
			   Datum v3,
			   Datum v4);
  • 首先遍历catcacheheader链表,根据系统表名称或者oid查找到系统表对应的catcache元素。
  • 查找元组键值进行hash,根据hash值找到catcache在cc_bucket数组中对应的hash桶下标。
  • 遍历hash桶链表,找到满足需求的Dlelem,并将其结构体中dle_val强制转换为CatCTup类型,CatCTup中的HeapTupleData就是要查找的元组的头部。
  • 将该Dlelem移动到hash桶链表的头部,并将catcache的cc_hits加1。
  • 如果在hash桶链表中没有找到满足条件的元组,需要进一步扫描物理系统表:
    • 如果在物理系统表中查找到元组,将元组包装成Dlelem,添加到hash桶链表的头部;
    • 否则,说明元组不存在,构建一个“负元组”,并将它包装好,添加到hash桶链表的头部。
      在这里插入图片描述

​ 2. 部分匹配

部分匹配由SearchCatCacheList实现:

SearchCatCacheList(CatCache *cache,
				   int nkeys,
				   Datum v1,
				   Datum v2,
				   Datum v3)

该函数返回一个CatCList数据结构,返回的所有结果通过链表的方式管理。

typedef struct catclist
{
	int			cl_magic;		/* for identifying CatCList entries */
#define CL_MAGIC   0x52765103

	uint32		hash_value;		/* hash value for lookup keys */

	dlist_node	cache_elem;		/* list member of per-catcache list */

	/*
	 * Lookup keys for the entry, with the first nkeys elements being valid.
	 * All by-reference are separately allocated.
	 */
	Datum		keys[CATCACHE_MAXKEYS];

	int			refcount;		/* number of active references */
	bool		dead;			/* dead but not yet removed? */
	bool		ordered;		/* members listed in index order? */
	short		nkeys;			/* number of lookup keys specified */
	int			n_members;		/* number of member tuples */
	CatCache   *my_cache;		/* link to owning catcache */
	CatCTup    *members[FLEXIBLE_ARRAY_MEMBER]; /* members */
} CatCList;

查找过程:
在这里插入图片描述

3. RelCache

RelCache存放的不是元组,而是RelationData数据,每一个RelationData结构表示一个表的模式信息,这些信息由系统表元组中的信息构造而来。

typedef struct RelationData
{
	RelFileNode rd_node;		/* relation physical identifier */
	struct SMgrRelationData *rd_smgr;	/* 表的文件句柄 */
。	...
	Form_pg_class rd_rel;		/* 表在pg_class系统表中对应的元组里的信息 */
	TupleDesc	rd_att;			/* 表的元组描述符,描述了表的各个属性 */
	Oid			rd_id;			/* relation's object id */
	List	   *rd_indexlist;	/* list of OIDs of indexes on relation */
	Bitmapset  *rd_indexattr;	/* identifies columns used in indexes */
	Oid			rd_oidindex;	/* OID of unique index on OID, if any */
	...
	Form_pg_index rd_index;		/* pg_index tuple describing this index */
	...
} RelationData;

由于RelationData数据结构是不变的,采用了hash表维持这个结构。这个hash表也是 PG 内部应用最多最广的 hash 数据结构,其性能和稳定性在PostgreSQL 近三十年的生涯中历经磨练。这个 hash表的实现也是非常值得学习的工业级数据结。

动态hash表介绍参考:https://zhmin.github.io/posts/postgresql-dynamic-hash/

3.1 relcache初始化

初始化阶段1:调用RelationCacheInitialize函数进行初始化,创建hash表。

初始化阶段2:将必要的系统表和系统表索引的模式加入到RelCache中,包括pg_class、pg_attribute、pg_proc、pg_type。

3.2 relcache的操作
  1. 插入新打开的表

    当打开新表时,需要把RelationData加入到RelCache中,该操作通过宏RelationCacheInsert来实现。

  2. 查找hash表

    查找hash表通过宏定义RelationIdCacheLookup来实现,调用函数hash_search。

    relation_open
    	RelationIdGetRelation
    		RelationIdCacheLookup(relationId, rd);
    		RelationBuildDesc -- no reldesc in the cache, RelationBuildDesc() build one and add it.
    			RelationBuildTupleDesc
    			....
    			RelationCacheInsert(relation);
    
  3. 从hash表中删除
    从hash表中删除元素通过宏定义RelationCacheDelete实现。

    RelationClearRelation
    		RelationCacheDelete
    

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

果园自主跟随碎枝机器人

开发背景 农业扶贫项目—— 开发一款适用于猕猴桃果园的跟随碎枝机器人。 在猕猴桃的种植培育过程中,一项非常重要的环节便是剪枝,通常有冬剪和夏剪。以往果农剪完枝条后要将散落于地的枝条归拢后统一粉碎还田。这需要专门收集地面上的枝条并将其归拢到…

C语言指针进阶

文章目录 1.字符指针1.1字符1.2字符串 2.数组指针2.2数组名和&数组名2.3数组指针的使用2.3.1一维数组例子2.3.2 二维数组传参2.3.2.1参数是数组的形式2.3.2.2参数是指针的形式 3.指针数组4.数组传参和指针传参4.1 一维数组传参4.1.1参数为数组的形式,参数为指针…

windows系统用于 SDN 的软件负载均衡器 (SLB)

适用于:Azure Stack HCI 版本 22H2 和 21H2;Windows Server 2022、Windows Server 2019、Windows Server 2016 软件负载均衡器包括哪些内容? 软件负载均衡器提供以下功能: 适用于北/南和东/西 TCP/UDP 流量的第 4 层 (L4) 负载均…

制造企业使用设备健康管理平台的好处

智能科技的发展不仅改变了我们的日常生活,也给工业制造领域带来了巨大的变化。在制造业生产线上,每天都在使用各种不同的机器设备来生产我们日常使用的物品。然而,这些设备的维护、维修和状态监测成为了制造企业的一大挑战。随着科技的发展&a…

java学习part02一些特性

17-Java语言概述-Java语言的特点和JVM的功能_哔哩哔哩_bilibili 1.java优点 跨平台性 在jvm上运行 2.jvm 2.1实现跨平台性 不需要对每一种指令集编写编译器,只需要针对jvm编程,jvm会自动转换 2.2内存回收 内存溢出:用的内存太多已经占满了&…

机器视觉系统的组成

图像获取 光学系统采集图像,图像转换成模拟格式并传入计算机存储器。 图像处理和分析 处理器运用不同的算法来提高对结论有重要影响的图像要素并形成数据作为判决依据。 判决和输出 处理器的控制程序根据收到的数据做出结论并输出信息作反馈控制等应用。

初认识vue,v-for,v-if,v-bind,v-model,v-html等指令

vue 一.vue3介绍 1.为什么data是函数而不是对象? 因为vue是组件开发,组件会多次复用,data如果是对象,多次复用是共享,必须函数返回一个新的对象 1. 官网初识 Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS …

11.10 知识总结(数据的增删改查、如何创建表关系、Django框架的请求生命周期流程图)

一、 数据的增删改查 1.1 用户列表的展示 把数据表中得用户数据都给查询出来展示在页面上 添加数据 id username password gender age action 修改 删除 1.2 修…

VB.NET三层之用户查询窗体

目录 前言: 过程: UI层代码展示: BLL层代码展示: DAL层代码展示: 查询用户效果图:​ 总结: 前言: 想要对用户进行查询,需要用到控件DataGrideView,通过代码的形式将数据库表中的数据显示在DataGrideview控件中,不用对DatGridView控件…

WordPress 文档主题模板Red Line -v0.2.2

此主题作为框架,做承载第三方页面之用,例如飞书文档等, 您可以将视频图片等资源放第三方文档上,通过使用此主题做目录用。 此主题使用前后端分离开发,也使用了一些技术尽量不影响正常的SEO,还望注意。 源码…

DevEco Studio开发工具下载、安装(HarmonyOS开发)_For Mac

一、说明 初学HarmonyOS开发,DevEco Studio开发工具的安装和使用是必须的。 (注:不多废话,跟着下面流程操作下载、安装DevEco Studio即可。) 二、下载DevEco Studio 1.官网下载地址: https://developer.…

什么是状态机?

什么是状态机? 定义 我们先来给出状态机的基本定义。一句话: 状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。 先来解释什么是“状态”( State )。现实事物是有不同状态的,例…

Linux高级编程:IPC之管道

一、无名管道 1.1 无名管道的概述 管道(pipe)又称无名管道。 无名管道是一种特殊类型的文件,在应用层体现为两个打开的文件描述符。 任何一个进程在创建的时候,系统都会 给他分配4G的虚拟内存,分为3G的用户空间和1G 的内核空间,内…

wpf devexpress项目中添加GridControl绑定数据

本教程讲解了如何添加GridControl到wpf项目中并且绑定数据 原文地址Lesson 1 - Add a GridControl to a Project and Bind it to Data | WPF Controls | DevExpress Documentation 1、使用 DevExpress Template Gallery创建一个新的空白mvvm应用程序,这个项目包括了…

P6入门:项目初始化9-项目详情之资源 Resource

前言 使用项目详细信息查看和编辑有关所选项目的详细信息,在项目创建完成后,初始化项目是一项非常重要的工作,涉及需要设置的内容包括项目名,ID,责任人,日历,预算,资金,分类码等等&…

DRAM和SRAM

特点 Static Random Access Memory:速度快、存储一位需要元器件更多、功耗较大、集成度低、更贵 Dynamic Random Access Memory:容量大、需刷新、附属电路更复杂、功耗较小、集成度高 存储位元 SRAM DRAM 逻辑结构 SRAM 典型的SRAM芯片有6116&am…

RHCE第四次作业

题目 架设一台NFS服务器,并按照以下要求配置 1、开放/nfs/shared目录,供所有用户查询资料 2、开放/nfs/upload目录,为192.168.100.0/24网段主机可以上传目录, 并将所有用户及所属的组映射为nfs-upload,其UID和GID均为210 3、将…

算法笔记-第七章-队列

算法笔记-第七章-队列 队列的相关知识点c中队列queue用法队列的操作序列求和队列约瑟夫环-队列匹配队列 队列的相关知识点 大佬的讲解 c中队列queue用法 一&#xff1a;queue是一种容器转换器模板&#xff0c;调用#include< queue>即可使用队列类 二&#xff1a;使用q…

TDengine 与煤科院五大系统实现兼容性互认,助力煤矿智能化安全体系搭建

近日&#xff0c;涛思数据与煤炭科学技术研究院&#xff08;以下简称煤科院&#xff09;已完成数个产品兼容互认证工作&#xff0c;经双方共同严格测试&#xff0c;涛思数据旗下物联网、工业大数据平台 TDengine V3.X 与煤炭科学技术研究院旗下煤矿复合灾害监测监控预警系统、煤…

超越任务调度的极致:初探分布式定时任务 XXL-JOB 分片广播

XXL-JOB 是一个分布式任务调度平台&#xff0c;支持分片任务执行。 1. 依赖引入 在项目中引入 XXL-JOB 的相关依赖。通常&#xff0c;你需要在项目的 pom.xml 文件中添加如下依赖&#xff1a; <dependency><groupId>com.xuxueli</groupId><artifactId&…