系统缓冲管理器
当数据库访问表时,需要表的模式信息,比如表的列属性、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 }
PG高速缓冲区(Cache)——系统表元组缓冲区SysCache初始化
原文:https://www.cnblogs.com/feishujun/p/PostgreSQLSourceAnalysis_cache01.html