1. 程式人生 > 實用技巧 >PG高速緩衝區(Cache)——系統表元組緩衝區SysCache初始化

PG高速緩衝區(Cache)——系統表元組緩衝區SysCache初始化

系統緩衝管理器

  當資料庫訪問表時,需要表的模式資訊,比如表的列屬性、OID、統計資訊等。PostgreSQL將表的模式資訊存放在系統表中,因此要訪問表,就需要首先在系統表中取得表的模式資訊。對於一個PostgreSQL系統來說,對於系統表和普通表模式的訪問是非常頻繁的。為了提高這些訪問的效率,PostgreSQL設立了快取記憶體Cache來提高訪問效率。Cache中包括一個系統表元組Cache(SysCache)和一個表模式資訊Cache(RelCache)。SysCache中存放的是最近使用過的系統表的元組,而RelCache中包含所有最近訪問過的表的模式資訊(包含系統表的資訊),RelCache中存放的不是元組,而是RelationData資料結構。兩種Cache都不是所有程序共享的,每個PG程序都維護著自己的SysCache和RelCahce。SysCache機制允許parser、planner、executor快速查詢系統表的內容。src/backend/utils/cache/syscache.c

  SysCache主要用於快取系統表元組。從實現上看SysCache就是一個數組,陣列的長度為預定義的系統表的個數。在PG 8.4.1中實現了54個系統表,因此SysCache陣列具有54個元素。每個元素的資料結構為CatCache,該結構體內使用Hash來儲存被快取的系統表元組,每個系統表唯一地對應一個SysCache陣列中的CatCache結構。在Postgres程序初始化時,將會對SysCache進行初始化,實際上是填充SysCache陣列中元素的CatCache結構體的過程,也就是將查詢系統表元組的關鍵字資訊寫入SysCache陣列元素中。在SysCache.c檔案中將所有系統表的CatCache資訊儲存在一個名為cacheinfo的靜態陣列中。下面先介紹cacheinfo陣列。

  將新快取新增到include/utils/syscache.h中的列表中。將條目新增到下面的cacheinfo[]陣列中。所有快取列表都是按字母順序排列的,因此請將其新增到適當的位置。指定關係OID、索引OID、鍵數、鍵屬性號和雜湊桶數。如果關係包含與特定關係(例如,其屬性、規則、觸發器等)關聯的元組,則指定包含關聯關係的OID的屬性號。CatalogCacheFlushRelation()用於在表刪除或relcache失效事件期間刪除正確的元組。
桶數的冪必須是2的冪。將其設定為中等大小資料庫中特定快取中的條目數是合理的。每個syscache下必須有一個唯一的索引(即,其鍵與快取的鍵相同的索引)。如果還沒有,請為其新增包含/catalog/INDEX.h的定義:您需要為INDEX OID新增DECLARE_UNIQUE_INDEX巨集和#define。(新增索引需要catversion.h更新,而簡單地新增/刪除快取只需要重新編譯。)
  最後,由於heap_*呼叫不更新索引,在關係表得到heap_insert()或heap_update()呼叫的任何位置,請確保存在CatalogUpdateIndexes()或類似呼叫。。

  1 static const struct cachedesc cacheinfo[] = {
  2     {AggregateRelationId, /* AGGFNOID */
  3         AggregateFnoidIndexId, 0, 1,
  4         {
  5             Anum_pg_aggregate_aggfnoid, 0, 0, 0
  6         }, 32 },
  7     {AccessMethodRelationId, /* AMNAME */
  8         AmNameIndexId, 0, 1,
  9         {
 10             Anum_pg_am_amname, 0, 0, 0
 11         }, 4 },
 12     {AccessMethodRelationId, /* AMOID */
 13         AmOidIndexId, 0, 1,
 14         {
 15             ObjectIdAttributeNumber, 0, 0, 0
 16         }, 4 },
 17     {AccessMethodOperatorRelationId, /* AMOPOPID */
 18         AccessMethodOperatorIndexId, 0, 2,
 19         {
 20             Anum_pg_amop_amopopr, 
 21                         Anum_pg_amop_amopfamily, 0, 0
 22         }, 64 },
 23     {AccessMethodOperatorRelationId, /* AMOPSTRATEGY */
 24         AccessMethodStrategyIndexId, 0, 4,
 25         {
 26             Anum_pg_amop_amopfamily,
 27             Anum_pg_amop_amoplefttype,
 28             Anum_pg_amop_amoprighttype,
 29             Anum_pg_amop_amopstrategy
 30         }, 64 },
 31     {AccessMethodProcedureRelationId, /* AMPROCNUM */
 32         AccessMethodProcedureIndexId, 0, 4,
 33         {
 34             Anum_pg_amproc_amprocfamily,
 35             Anum_pg_amproc_amproclefttype,
 36             Anum_pg_amproc_amprocrighttype,
 37             Anum_pg_amproc_amprocnum
 38         }, 64 },
 39     {AttributeRelationId, /* ATTNAME */
 40         AttributeRelidNameIndexId,
 41         Anum_pg_attribute_attrelid, 2,
 42         {
 43             Anum_pg_attribute_attrelid,
 44             Anum_pg_attribute_attname, 0, 0
 45         }, 2048 },
 46     {AttributeRelationId,        /* ATTNUM */
 47         AttributeRelidNumIndexId,
 48         Anum_pg_attribute_attrelid, 2,
 49         {
 50             Anum_pg_attribute_attrelid,
 51             Anum_pg_attribute_attnum, 0, 0
 52         }, 2048 },
 53     {AuthMemRelationId,            /* AUTHMEMMEMROLE */
 54         AuthMemMemRoleIndexId,
 55         0,
 56         2,
 57         {
 58             Anum_pg_auth_members_member,
 59             Anum_pg_auth_members_roleid,
 60             0,
 61             0
 62         },
 63         128
 64     },
 65     {AuthMemRelationId,            /* AUTHMEMROLEMEM */
 66         AuthMemRoleMemIndexId,
 67         0,
 68         2,
 69         {
 70             Anum_pg_auth_members_roleid,
 71             Anum_pg_auth_members_member,
 72             0,
 73             0
 74         },
 75         128
 76     },
 77     {AuthIdRelationId, /* AUTHNAME */
 78         AuthIdRolnameIndexId, 0, 1,
 79         {
 80             Anum_pg_authid_rolname, 0, 0, 0
 81         }, 128 },
 82     {AuthIdRelationId,            /* AUTHOID */
 83         AuthIdOidIndexId,
 84         0,
 85         1,
 86         {
 87             ObjectIdAttributeNumber,
 88             0,
 89             0,
 90             0
 91         },
 92         128
 93     },
 94     {
 95         CastRelationId,            /* CASTSOURCETARGET */
 96         CastSourceTargetIndexId,
 97         0,
 98         2,
 99         {
100             Anum_pg_cast_castsource,
101             Anum_pg_cast_casttarget,
102             0,
103             0
104         },
105         256
106     },
107     {OperatorClassRelationId,    /* CLAAMNAMENSP */
108         OpclassAmNameNspIndexId,
109         0,
110         3,
111         {
112             Anum_pg_opclass_opcmethod,
113             Anum_pg_opclass_opcname,
114             Anum_pg_opclass_opcnamespace,
115             0
116         },
117         64
118     },
119     {OperatorClassRelationId,    /* CLAOID */
120         OpclassOidIndexId,
121         0,
122         1,
123         {
124             ObjectIdAttributeNumber,
125             0,
126             0,
127             0
128         },
129         64
130     },
131     {ConversionRelationId,        /* CONDEFAULT */
132         ConversionDefaultIndexId,
133         0,
134         4,
135         {
136             Anum_pg_conversion_connamespace,
137             Anum_pg_conversion_conforencoding,
138             Anum_pg_conversion_contoencoding,
139             ObjectIdAttributeNumber,
140         },
141         128
142     },
143     {ConversionRelationId,        /* CONNAMENSP */
144         ConversionNameNspIndexId,
145         0,
146         2,
147         {
148             Anum_pg_conversion_conname,
149             Anum_pg_conversion_connamespace,
150             0,
151             0
152         },
153         128
154     },
155     {ConstraintRelationId,        /* CONSTROID */
156         ConstraintOidIndexId,
157         Anum_pg_constraint_conrelid,
158         1,
159         {
160             ObjectIdAttributeNumber,
161             0,
162             0,
163             0
164         },
165         1024
166     },
167     {ConversionRelationId,        /* CONVOID */
168         ConversionOidIndexId,
169         0,
170         1,
171         {
172             ObjectIdAttributeNumber,
173             0,
174             0,
175             0
176         },
177         128
178     },
179     {DatabaseRelationId,        /* DATABASEOID */
180         DatabaseOidIndexId,
181         0,
182         1,
183         {
184             ObjectIdAttributeNumber,
185             0,
186             0,
187             0
188         },
189         4
190     },
191     {EnumRelationId,            /* ENUMOID */
192         EnumOidIndexId,
193         0,
194         1,
195         {
196             ObjectIdAttributeNumber,
197             0,
198             0,
199             0
200         },
201         256
202     },
203     {EnumRelationId,            /* ENUMTYPOIDNAME */
204         EnumTypIdLabelIndexId,
205         0,
206         2,
207         {
208             Anum_pg_enum_enumtypid,
209             Anum_pg_enum_enumlabel,
210             0,
211             0
212         },
213         256
214     },
215     {ForeignDataWrapperRelationId,        /* FOREIGNDATAWRAPPERNAME */
216         ForeignDataWrapperNameIndexId,
217         0,
218         1,
219         {
220             Anum_pg_foreign_data_wrapper_fdwname,
221             0,
222             0,
223             0
224         },
225         8
226     },
227     {ForeignDataWrapperRelationId,        /* FOREIGNDATAWRAPPEROID */
228         ForeignDataWrapperOidIndexId,
229         0,
230         1,
231         {
232             ObjectIdAttributeNumber,
233             0,
234             0,
235             0
236         },
237         8
238     },
239     {ForeignServerRelationId,    /* FOREIGNSERVERNAME */
240         ForeignServerNameIndexId,
241         0,
242         1,
243         {
244             Anum_pg_foreign_server_srvname,
245             0,
246             0,
247             0
248         },
249         32
250     },
251     {ForeignServerRelationId,    /* FOREIGNSERVEROID */
252         ForeignServerOidIndexId,
253         0,
254         1,
255         {
256             ObjectIdAttributeNumber,
257             0,
258             0,
259             0
260         },
261         32
262     },
263     {IndexRelationId,            /* INDEXRELID */
264         IndexRelidIndexId,
265         Anum_pg_index_indrelid,
266         1,
267         {
268             Anum_pg_index_indexrelid,
269             0,
270             0,
271             0
272         },
273         1024
274     },
275     {LanguageRelationId,        /* LANGNAME */
276         LanguageNameIndexId,
277         0,
278         1,
279         {
280             Anum_pg_language_lanname,
281             0,
282             0,
283             0
284         },
285         4
286     },
287     {LanguageRelationId,        /* LANGOID */
288         LanguageOidIndexId,
289         0,
290         1,
291         {
292             ObjectIdAttributeNumber,
293             0,
294             0,
295             0
296         },
297         4
298     },
299     {NamespaceRelationId,        /* NAMESPACENAME */
300         NamespaceNameIndexId,
301         0,
302         1,
303         {
304             Anum_pg_namespace_nspname,
305             0,
306             0,
307             0
308         },
309         256
310     },
311     {NamespaceRelationId,        /* NAMESPACEOID */
312         NamespaceOidIndexId,
313         0,
314         1,
315         {
316             ObjectIdAttributeNumber,
317             0,
318             0,
319             0
320         },
321         256
322     },
323     {OperatorRelationId,        /* OPERNAMENSP */
324         OperatorNameNspIndexId,
325         0,
326         4,
327         {
328             Anum_pg_operator_oprname,
329             Anum_pg_operator_oprleft,
330             Anum_pg_operator_oprright,
331             Anum_pg_operator_oprnamespace
332         },
333         1024
334     },
335     {OperatorRelationId,        /* OPEROID */
336         OperatorOidIndexId,
337         0,
338         1,
339         {
340             ObjectIdAttributeNumber,
341             0,
342             0,
343             0
344         },
345         1024
346     },
347     {OperatorFamilyRelationId,    /* OPFAMILYAMNAMENSP */
348         OpfamilyAmNameNspIndexId,
349         0,
350         3,
351         {
352             Anum_pg_opfamily_opfmethod,
353             Anum_pg_opfamily_opfname,
354             Anum_pg_opfamily_opfnamespace,
355             0
356         },
357         64
358     },
359     {OperatorFamilyRelationId,    /* OPFAMILYOID */
360         OpfamilyOidIndexId,
361         0,
362         1,
363         {
364             ObjectIdAttributeNumber,
365             0,
366             0,
367             0
368         },
369         64
370     },
371     {ProcedureRelationId,        /* PROCNAMEARGSNSP */
372         ProcedureNameArgsNspIndexId,
373         0,
374         3,
375         {
376             Anum_pg_proc_proname,
377             Anum_pg_proc_proargtypes,
378             Anum_pg_proc_pronamespace,
379             0
380         },
381         2048
382     },
383     {ProcedureRelationId,        /* PROCOID */
384         ProcedureOidIndexId,
385         0,
386         1,
387         {
388             ObjectIdAttributeNumber,
389             0,
390             0,
391             0
392         },
393         2048
394     },
395     {RelationRelationId,        /* RELNAMENSP */
396         ClassNameNspIndexId,
397         ObjectIdAttributeNumber, 2,
398         {
399             Anum_pg_class_relname,
400             Anum_pg_class_relnamespace, 0, 0
401         }, 1024 },
402     {RelationRelationId,        /* RELOID */
403         ClassOidIndexId,
404         ObjectIdAttributeNumber,
405         1,
406         {
407             ObjectIdAttributeNumber,
408             0,
409             0,
410             0
411         },
412         1024
413     },
414     {RewriteRelationId,            /* RULERELNAME */
415         RewriteRelRulenameIndexId,
416         Anum_pg_rewrite_ev_class,
417         2,
418         {
419             Anum_pg_rewrite_ev_class,
420             Anum_pg_rewrite_rulename,
421             0,
422             0
423         },
424         1024
425     },
426     {StatisticRelationId,        /* STATRELATT */
427         StatisticRelidAttnumIndexId,
428         Anum_pg_statistic_starelid, 2,
429         {
430             Anum_pg_statistic_starelid,
431             Anum_pg_statistic_staattnum, 0, 0
432         }, 1024 },
433     {TSConfigMapRelationId,        /* TSCONFIGMAP */
434         TSConfigMapIndexId,
435         0,
436         3,
437         {
438             Anum_pg_ts_config_map_mapcfg,
439             Anum_pg_ts_config_map_maptokentype,
440             Anum_pg_ts_config_map_mapseqno,
441             0
442         },
443         4
444     },
445     {TSConfigRelationId,        /* TSCONFIGNAMENSP */
446         TSConfigNameNspIndexId,
447         0,
448         2,
449         {
450             Anum_pg_ts_config_cfgname,
451             Anum_pg_ts_config_cfgnamespace,
452             0,
453             0
454         },
455         16
456     },
457     {TSConfigRelationId,        /* TSCONFIGOID */
458         TSConfigOidIndexId,
459         0,
460         1,
461         {
462             ObjectIdAttributeNumber,
463             0,
464             0,
465             0
466         },
467         16
468     },
469     {TSDictionaryRelationId,    /* TSDICTNAMENSP */
470         TSDictionaryNameNspIndexId,
471         0,
472         2,
473         {
474             Anum_pg_ts_dict_dictname,
475             Anum_pg_ts_dict_dictnamespace,
476             0,
477             0
478         },
479         16
480     },
481     {TSDictionaryRelationId,    /* TSDICTOID */
482         TSDictionaryOidIndexId,
483         0,
484         1,
485         {
486             ObjectIdAttributeNumber,
487             0,
488             0,
489             0
490         },
491         16
492     },
493     {TSParserRelationId,        /* TSPARSERNAMENSP */
494         TSParserNameNspIndexId,
495         0,
496         2,
497         {
498             Anum_pg_ts_parser_prsname,
499             Anum_pg_ts_parser_prsnamespace,
500             0,
501             0
502         },
503         4
504     },
505     {TSParserRelationId, /* TSPARSEROID */
506         TSParserOidIndexId, 0, 1,
507         {
508             ObjectIdAttributeNumber, 0, 0, 0
509         }, 4 },
510     {TSTemplateRelationId, /* TSTEMPLATENAMENSP */
511         TSTemplateNameNspIndexId, 0, 2,
512         {
513             Anum_pg_ts_template_tmplname,
514             Anum_pg_ts_template_tmplnamespace, 0, 0
515         }, 16 },
516     {TSTemplateRelationId,        /* TSTEMPLATEOID */
517         TSTemplateOidIndexId, 0, 1,
518         {
519             ObjectIdAttributeNumber, 0, 0, 0
520         }, 16 },
521     {TypeRelationId, /* TYPENAMENSP */
522         TypeNameNspIndexId, Anum_pg_type_typrelid, 2,
523         {
524             Anum_pg_type_typname,
525             Anum_pg_type_typnamespace, 0, 0
526         }, 1024 },
527     {TypeRelationId, /* TYPEOID */
528         TypeOidIndexId, Anum_pg_type_typrelid, 1,
529         {
530             ObjectIdAttributeNumber, 0, 0, 0
531         }, 1024 },
532     {UserMappingRelationId, /* USERMAPPINGOID */
533         UserMappingOidIndexId, 0, 1,
534         {
535             ObjectIdAttributeNumber, 0, 0, 0
536         }, 128 },
537     {UserMappingRelationId, /* USERMAPPINGUSERSERVER */
538         UserMappingUserServerIndexId, 0, 2,
539         {
540             Anum_pg_user_mapping_umuser,
541             Anum_pg_user_mapping_umserver, 0, 0
542         }, 128 }
543 };

  看了靜態陣列cacheinfo,我們下一步看一下SysCache的廬山真面目。SysCache其實是一個由CatCache結構體指標組成的陣列。CatCache結構體使用Hash來儲存被快取的系統表元組,每個系統表唯一地對應一個SysCache陣列中的CatCache結構。每個CatCache都有若干個(不超過4個)查詢關鍵字,這些關鍵字及其組合可以用來在CatCache中查詢系統表元組,在初始化資料集簇時會在這些關鍵字上為系統表建立索引。為了便於查詢,Catcache通過其cc_next欄位構成一個單向連結串列,連結串列頭使用全域性變數CachHdr記錄(資料結構為catcacheheader)。cc_lists是由CatClist結構構成的Dllist連結串列,用於快取部分匹配的元組,每個CatClist結構儲存一次部分匹配的結果元組。()CatCache中的cc_bucket陣列中的每個元素都表示一個Hash桶,元組的鍵值通過Hash函式可以對映到cc_bucket陣列的下標。每個桶都被組織成一個雙向連結串列,節點為Dlelem型別。Dlelem是一個包裝過的快取元組,其dle_val欄位指向一個CatCTup形式的快取元組。

  在PG程序初始化時,會呼叫InitCatalogCache函式對SysCache陣列進行初始化,並建立由CacheHdr記錄的CatCache連結串列。InitCatalogCache函式中對SysCache的初始化主要分為以下幾個步驟:

1) 根據cacheinfo為SysCache陣列分配空間

2) 迴圈呼叫InitCatcache函式根據cacheinfo中的每個元素生成CatCache結構並放入SysCache陣列的對應位置中。InitCatcache每呼叫一次將處理一個cachedesc結構,InitCatcache將首先確保CacheMemoryContext存在(如不存在會建立),然後切換到CacheMemoryContext中。接下來將檢查CacheHdr是否存在,不存在則先建立CacheHdr。然後該函式根據cachedesc中要求的Hash桶的數量為即將建立的CatCache結構分配記憶體,並根據cachedesc結構中的資訊填充CatCache的各個欄位。最後將生成的CatCache連結在CacheHdr所指向的連結串列的頭部。

 1 void InitCatalogCache(void) {
 2     int            cacheId;
 3     Assert(!CacheInitialized);
 4     MemSet(SysCache, 0, sizeof(SysCache));
 5     for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
 6     {
 7         SysCache[cacheId] = InitCatCache(cacheId,                                 
 8                   cacheinfo[cacheId].reloid,                                         
 9                   cacheinfo[cacheId].indoid,                                         
10                   cacheinfo[cacheId].reloidattr,                                         
11                   cacheinfo[cacheId].nkeys,                                         
12                   cacheinfo[cacheId].key,                                         
13                   cacheinfo[cacheId].nbuckets);
14         if (!PointerIsValid(SysCache[cacheId]))
15             elog(ERROR, "could not initialize cache %u (%d)",
16                  cacheinfo[cacheId].reloid, cacheId);
17     }
18     CacheInitialized = true;
19 }

InitCatCache函式,nbuckets是hash桶的數量,必須是2的次方。首先需要建立MemoryContext記憶體上下文,並轉換為CacheMemoryContext型別。如果第一次進入該函式,需要建立CacheHdr結構體。為CatCache結構體申請記憶體,大小為sizeof(CatCache) + nbuckets * sizeof(Dllist)位元組。最後將生成的CatCache結構體插入CacheHdr連結串列。

 1 CatCache * InitCatCache(int id, Oid reloid, Oid indexoid,
 2              int reloidattr, int nkeys, const int *key,
 3              int nbuckets) {
 4     CatCache   *cp;
 5     MemoryContext oldcxt;
 6     int            i;
 7 
 8     Assert(nbuckets > 0 && (nbuckets & -nbuckets) == nbuckets);
 9     if (!CacheMemoryContext)
10         CreateCacheMemoryContext();
11 
12     oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
13     if (CacheHdr == NULL)
14     {
15         CacheHdr = (CatCacheHeader *) palloc(sizeof(CatCacheHeader));
16         CacheHdr->ch_caches = NULL;
17         CacheHdr->ch_ntup = 0;
18 #ifdef CATCACHE_STATS
19         /* set up to dump stats at backend exit */
20         on_proc_exit(CatCachePrintStats, 0);
21 #endif
22     }
23     cp = (CatCache *) palloc0(sizeof(CatCache) + nbuckets * sizeof(Dllist));
24     cp->id = id;
25     cp->cc_relname = "(not known yet)";
26     cp->cc_reloid = reloid;
27     cp->cc_indexoid = indexoid;
28     cp->cc_relisshared = false; /* temporary */
29     cp->cc_tupdesc = (TupleDesc) NULL;
30     cp->cc_reloidattr = reloidattr;
31     cp->cc_ntup = 0;
32     cp->cc_nbuckets = nbuckets;
33     cp->cc_nkeys = nkeys;
34     for (i = 0; i < nkeys; ++i)
35         cp->cc_key[i] = key[i];
36     cp->cc_next = CacheHdr->ch_caches;
37     CacheHdr->ch_caches = cp;
38     MemoryContextSwitchTo(oldcxt);
39     return cp;
40 }

  在InitCatalogCache函式中實際只完成了SysCache初始化的第一個階段,在稍後被呼叫的函式RelationCacheInitializePhase2(負責RelCache的初始化)還將呼叫InitCatcachePhase2進行第二階段也是最後的SysCache初始化工作。InitCatcachePhase2將依次完善SysCacche陣列中的CatCache結構,主要是根據對應的系統表填充CatCache結構中的元組描述符(cc_tupledesc)、系統表名(cc_relname)、查詢關鍵字的相關欄位(cc_hashfunc、cc_isname、cc_skey)等。SysCache陣列初始化後,CatCache內是沒有任何元組的,但是隨著系統執行,對於系統表元組的訪問,其中的系統表元組也會逐漸增多。

1 void InitCatalogCachePhase2(void) {
2     int            cacheId;
3     Assert(CacheInitialized);
4     for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
5         InitCatCachePhase2(SysCache[cacheId], true);
6 }

InitCatCachePhase2每呼叫一次將處理一個SysCache元素指向的結構,如果對應的系統表元組描述符為NULL,則先呼叫CatalogCacheInitialize函式。對除了AMOID和AMNAME之外的系統表都嘗試開啟其引用的索引。

1 void InitCatCachePhase2(CatCache *cache, bool touch_index) {
2     if (cache->cc_tupdesc == NULL)
3         CatalogCacheInitializeCache(cache);
4     if (touch_index && cache->id != AMOID && cache->id != AMNAME) {
5         Relation    idesc;
6         idesc = index_open(cache->cc_indexoid, AccessShareLock);
7         index_close(idesc, AccessShareLock);
8     }
9 }

CatalogCacheInitialize函式是靜態函式,先通過向heap_open傳入相應系統表的OID獲取RelationData結構體。將TupleDesc開唄到臨時緩衝區中。初始化cache鍵相關資訊。

 1 static void CatalogCacheInitializeCache(CatCache *cache) {
 2     Relation    relation;
 3     MemoryContext oldcxt;
 4     TupleDesc    tupdesc;
 5     int            i;
 6 
 7     relation = heap_open(cache->cc_reloid, AccessShareLock);
 8     Assert(CacheMemoryContext != NULL);
 9     oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
10 
11     /* copy the relcache's tuple descriptor to permanent cache storage */
12     tupdesc = CreateTupleDescCopyConstr(RelationGetDescr(relation));
13 
14     cache->cc_relname = pstrdup(RelationGetRelationName(relation));
15     cache->cc_relisshared = RelationGetForm(relation)->relisshared;
16 
17     MemoryContextSwitchTo(oldcxt);
18     heap_close(relation, AccessShareLock);
19 
20     CACHE3_elog(DEBUG2, "CatalogCacheInitializeCache: %s, %d keys",
21                 cache->cc_relname, cache->cc_nkeys);
22 
23     /* initialize cache's key information */
24     for (i = 0; i < cache->cc_nkeys; ++i)
25     {
26         Oid            keytype;
27         RegProcedure eqfunc;
28 
29         if (cache->cc_key[i] > 0)
30             keytype = tupdesc->attrs[cache->cc_key[i] - 1]->atttypid;
31         else
32         {
33             if (cache->cc_key[i] != ObjectIdAttributeNumber)
34                 elog(FATAL, "only sys attr supported in caches is OID");
35             keytype = OIDOID;
36         }
37 
38         GetCCHashEqFuncs(keytype,
39                          &cache->cc_hashfunc[i],
40                          &eqfunc);
41 
42         cache->cc_isname[i] = (keytype == NAMEOID);
43 
44         fmgr_info_cxt(eqfunc,
45                       &cache->cc_skey[i].sk_func,
46                       CacheMemoryContext);
47 
48         /* Initialize sk_attno suitably for HeapKeyTest() and heap scans */
49         cache->cc_skey[i].sk_attno = cache->cc_key[i];
50 
51         /* Fill in sk_strategy as well --- always standard equality */
52         cache->cc_skey[i].sk_strategy = BTEqualStrategyNumber;
53         cache->cc_skey[i].sk_subtype = InvalidOid;
54 
55         CACHE4_elog(DEBUG2, "CatalogCacheInitializeCache %s %d %p",
56                     cache->cc_relname,
57                     i,
58                     cache);
59     }
60 
61     /*
62      * mark this cache fully initialized
63      */
64     cache->cc_tupdesc = tupdesc;
65 }