再说Postgres中的高速缓存(cache)

表的模式信息存放在系统表中,因此要访问表,就需要首先在系统表中取得表的模式信息。对于一个PostgreSQL系统来说,对于系统表和普通表模式的访问是非常频繁的。为了提高这些访问的效率,PostgreSQL设立了高速缓存(Cache)来提高访问效率。

Cache中包括一个系统表元组Cache(SysCache)和一个表模式信息Cache(RelCache)。其中:

SysCache中存放的是最近使用过的系统表的元组

RelCache中包含所有最近访问过的表的模式信息(包含系统表的信息)。RelCache中存放的不是元组,而是RelationData数据结构,每一个RelationData结构表示一个表的模式信息,这些信息都由系统表元组中的信息构造而来。

值得注意的是,两种Cache都不是所有进程共享的。每一个PostgreSQL的进程都维护着自己的SysCache和RelCache。

1.SysCache

SysCache主要用于缓存系统表元组。从实现上看SysCache就是一个数组,数组的长度为预定义的系统表的个数。在PostgreSQL9.5.6中实现了55个系统表,因此SysCache数组具有55个元素,每个元素的数据结构为CatCache,该结构体内使用Hash来存储被缓存的系统表元组,每一个系统表唯一地对应一个SysCache数组中的CatCache结构。每个CatCache都有若干个(不超过4个)査找关键字,这些关键字及其组合可以用来在CatCache中查找系统表元组,在初始化数据集簇时会在这些关键字上为系统表创建索引。

其中涉及到的数据类型的简要意义如下,我们先有个印象,以免后面遇到了感到奇怪和陌生:

/* * struct catctup: individual tuple in the cache. * struct catclist: list of tuples matching a partial key. * struct catcache: information for managing a cache. * struct catcacheheader: information for managing all the caches. */ 1.1 SysCache初始化

在Postgres进程初始化时(在InitProgres中),将会对SysCache进行初始化。SysCache的初始化实际上是填充SysCache数组中每个元素的CatCache结构的过程,主要任务是将査找系统表元组的关键字信息写入SysCache数组元素中。这样通过指定的关键字可以快速定位到系统表元组的存储位置。
CatCache的数据结构如下:

typedef struct catcache { int id; /* cache identifier --- see syscache.h */ slist_node cc_next; /* list link */ 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? */ TupleDesc cc_tupdesc; /* tuple descriptor (copied from reldesc) */ int cc_ntup; /* # of tuples currently in this cache */ int cc_nbuckets; /* # of hash buckets in this cache */ int cc_nkeys; /* # of keys (1..CATCACHE_MAXKEYS) */ int cc_key[CATCACHE_MAXKEYS]; /* AttrNumber of each key */ PGFunction cc_hashfunc[CATCACHE_MAXKEYS]; /* hash function for each key */ ScanKeyData cc_skey[CATCACHE_MAXKEYS]; /* precomputed key info for * heap scans */ bool cc_isname[CATCACHE_MAXKEYS]; /* flag "name" key columns */ dlist_head cc_lists; /* list of CatCList structs */ #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 dlist_head *cc_bucket; /* hash buckets */ } CatCache;

在SysCache.c文件中已经将所有系统表的CatCache信息存储在一个名为cacheinfo的静态数组
中,每个系统表的CatCache信息用一个数组元素来描述,其数据类型为cachedesc:

struct cachedesc { Oid reloid; /* OID of the relation being cached */ Oid indoid; /* OID of index relation for this cache */ 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 */ };

在Postgres进程初始化时,会调用InitCatalogCache函数对SysCache数组进行初始化,并建立由CacheHdr记录的CatCache链表。

InitCatalogCache函数中对SysCache的初始化主要分为以下儿个步骤:

1)根据cacheinfo为SysCache数组分配空间,这里将SysCache的长度设置为和cacheinfo数组相同。

2)循环调用InitCatcache函数根据cacheinfo中的每一个元素生成CatCache结构并放人SysCache数组的对应位置中。InitCatcache每调用一次将处理一个cachedesc结构。该函数根据cachedesc中要求的Hash桶的数量
为即将建立的CatCache结构分配内存,并根据cachedesc结构中的信息填充CatCache的各个字段。
最后将生成的CatCache链接在CacheHdr所指向的链表的头部。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppsfg.html