📄 relcache.c
字号:
/* * If this isn't initdb time, then we want to initialize some index * relation descriptors, as well. The descriptors are for * pg_attnumind (to make building relation descriptors fast) and * possibly others, as they're added. */ if (!IsBootstrapProcessingMode()) init_irels(); MemoryContextSwitchTo(oldcxt);}static voidAttrDefaultFetch(Relation relation){ AttrDefault *attrdef = relation->rd_att->constr->defval; int ndef = relation->rd_att->constr->num_defval; Relation adrel; Relation irel; ScanKeyData skey; HeapTupleData tuple; Form_pg_attrdef adform; IndexScanDesc sd; RetrieveIndexResult indexRes; struct varlena *val; bool isnull; int found; int i; ScanKeyEntryInitialize(&skey, (bits16) 0x0, (AttrNumber) 1, (RegProcedure) F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(relation))); adrel = heap_openr(AttrDefaultRelationName); irel = index_openr(AttrDefaultIndex); sd = index_beginscan(irel, false, 1, &skey); tuple.t_data = NULL; for (found = 0;;) { Buffer buffer; indexRes = index_getnext(sd, ForwardScanDirection); if (!indexRes) break; tuple.t_self = indexRes->heap_iptr; heap_fetch(adrel, SnapshotNow, &tuple, &buffer); pfree(indexRes); if (tuple.t_data == NULL) continue; found++; adform = (Form_pg_attrdef) GETSTRUCT(&tuple); for (i = 0; i < ndef; i++) { if (adform->adnum != attrdef[i].adnum) continue; if (attrdef[i].adsrc != NULL) elog(ERROR, "AttrDefaultFetch: second record found for attr %s in rel %s", relation->rd_att->attrs[adform->adnum - 1]->attname.data, relation->rd_rel->relname.data); val = (struct varlena *) fastgetattr(&tuple, Anum_pg_attrdef_adbin, adrel->rd_att, &isnull); if (isnull) elog(ERROR, "AttrDefaultFetch: adbin IS NULL for attr %s in rel %s", relation->rd_att->attrs[adform->adnum - 1]->attname.data, relation->rd_rel->relname.data); attrdef[i].adbin = textout(val); val = (struct varlena *) fastgetattr(&tuple, Anum_pg_attrdef_adsrc, adrel->rd_att, &isnull); if (isnull) elog(ERROR, "AttrDefaultFetch: adsrc IS NULL for attr %s in rel %s", relation->rd_att->attrs[adform->adnum - 1]->attname.data, relation->rd_rel->relname.data); attrdef[i].adsrc = textout(val); break; } ReleaseBuffer(buffer); if (i >= ndef) elog(ERROR, "AttrDefaultFetch: unexpected record found for attr %d in rel %s", adform->adnum, relation->rd_rel->relname.data); } if (found < ndef) elog(ERROR, "AttrDefaultFetch: %d record not found for rel %s", ndef - found, relation->rd_rel->relname.data); index_endscan(sd); pfree(sd); index_close(irel); heap_close(adrel);}static voidRelCheckFetch(Relation relation){ ConstrCheck *check = relation->rd_att->constr->check; int ncheck = relation->rd_att->constr->num_check; Relation rcrel; Relation irel; ScanKeyData skey; HeapTupleData tuple; IndexScanDesc sd; RetrieveIndexResult indexRes; Name rcname; struct varlena *val; bool isnull; int found; ScanKeyEntryInitialize(&skey, (bits16) 0x0, (AttrNumber) 1, (RegProcedure) F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(relation))); rcrel = heap_openr(RelCheckRelationName); irel = index_openr(RelCheckIndex); sd = index_beginscan(irel, false, 1, &skey); tuple.t_data = NULL; for (found = 0;;) { Buffer buffer; indexRes = index_getnext(sd, ForwardScanDirection); if (!indexRes) break; tuple.t_self = indexRes->heap_iptr; heap_fetch(rcrel, SnapshotNow, &tuple, &buffer); pfree(indexRes); if (tuple.t_data == NULL) continue; if (found == ncheck) elog(ERROR, "RelCheckFetch: unexpected record found for rel %s", relation->rd_rel->relname.data); rcname = (Name) fastgetattr(&tuple, Anum_pg_relcheck_rcname, rcrel->rd_att, &isnull); if (isnull) elog(ERROR, "RelCheckFetch: rcname IS NULL for rel %s", relation->rd_rel->relname.data); check[found].ccname = nameout(rcname); val = (struct varlena *) fastgetattr(&tuple, Anum_pg_relcheck_rcbin, rcrel->rd_att, &isnull); if (isnull) elog(ERROR, "RelCheckFetch: rcbin IS NULL for rel %s", relation->rd_rel->relname.data); check[found].ccbin = textout(val); val = (struct varlena *) fastgetattr(&tuple, Anum_pg_relcheck_rcsrc, rcrel->rd_att, &isnull); if (isnull) elog(ERROR, "RelCheckFetch: rcsrc IS NULL for rel %s", relation->rd_rel->relname.data); check[found].ccsrc = textout(val); found++; ReleaseBuffer(buffer); } if (found < ncheck) elog(ERROR, "RelCheckFetch: %d record not found for rel %s", ncheck - found, relation->rd_rel->relname.data); index_endscan(sd); pfree(sd); index_close(irel); heap_close(rcrel);}/* * init_irels(), write_irels() -- handle special-case initialization of * index relation descriptors. * * In late 1992, we started regularly having databases with more than * a thousand classes in them. With this number of classes, it became * critical to do indexed lookups on the system catalogs. * * Bootstrapping these lookups is very hard. We want to be able to * use an index on pg_attribute, for example, but in order to do so, * we must have read pg_attribute for the attributes in the index, * which implies that we need to use the index. * * In order to get around the problem, we do the following: * * + When the database system is initialized (at initdb time), we * don't use indices on pg_attribute. We do sequential scans. * * + When the backend is started up in normal mode, we load an image * of the appropriate relation descriptors, in internal format, * from an initialization file in the data/base/... directory. * * + If the initialization file isn't there, then we create the * relation descriptors using sequential scans and write 'em to * the initialization file for use by subsequent backends. * * We could dispense with the initialization file and just build the * critical reldescs the hard way on every backend startup, but that * slows down backend startup noticeably if pg_class is large. * * As of v6.5, vacuum.c deletes the initialization file at completion * of a VACUUM, so that it will be rebuilt at the next backend startup. * This ensures that vacuum-collected stats for the system indexes * will eventually get used by the optimizer --- otherwise the relcache * entries for these indexes will show zero sizes forever, since the * relcache entries are pinned in memory and will never be reloaded * from pg_class. *//* pg_attnumind, pg_classnameind, pg_classoidind */#define Num_indices_bootstrap 3static voidinit_irels(void){ Size len; int nread; File fd; Relation irel[Num_indices_bootstrap]; Relation ird; Form_pg_am am; Form_pg_class relform; IndexStrategy strat; RegProcedure *support; int i; int relno;#ifndef __CYGWIN32__ if ((fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_RDONLY, 0600)) < 0)#else if ((fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_RDONLY | O_BINARY, 0600)) < 0)#endif { write_irels(); return; } FileSeek(fd, 0L, SEEK_SET); for (relno = 0; relno < Num_indices_bootstrap; relno++) { /* first read the relation descriptor length */ if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len)) { write_irels(); return; } ird = irel[relno] = (Relation) palloc(len); MemSet(ird, 0, len); /* then, read the Relation structure */ if ((nread = FileRead(fd, (char *) ird, len)) != len) { write_irels(); return; } /* the file descriptor is not yet opened */ ird->rd_fd = -1; /* lock info is not initialized */ ird->lockInfo = (char *) NULL; /* next, read the access method tuple form */ if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len)) { write_irels(); return; } am = (Form_pg_am) palloc(len); if ((nread = FileRead(fd, (char *) am, len)) != len) { write_irels(); return; } ird->rd_am = am; /* next read the relation tuple form */ if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len)) { write_irels(); return; } relform = (Form_pg_class) palloc(len); if ((nread = FileRead(fd, (char *) relform, len)) != len) { write_irels(); return; } ird->rd_rel = relform; /* initialize attribute tuple forms */ ird->rd_att = CreateTemplateTupleDesc(relform->relnatts); /* next read all the attribute tuple form data entries */ len = ATTRIBUTE_TUPLE_SIZE; for (i = 0; i < relform->relnatts; i++) { if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len)) { write_irels(); return; } ird->rd_att->attrs[i] = (Form_pg_attribute) palloc(len); if ((nread = FileRead(fd, (char *) ird->rd_att->attrs[i], len)) != len) { write_irels(); return; } } /* next, read the index strategy map */ if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len)) { write_irels(); return; } strat = (IndexStrategy) palloc(len); if ((nread = FileRead(fd, (char *) strat, len)) != len) { write_irels(); return; } /* oh, for god's sake... */#define SMD(i) strat[0].strategyMapData[i].entry[0] /* have to reinit the function pointers in the strategy maps */ for (i = 0; i < am->amstrategies * relform->relnatts; i++) { fmgr_info(SMD(i).sk_procedure, &(SMD(i).sk_func)); SMD(i).sk_nargs = SMD(i).sk_func.fn_nargs; } /* * use a real field called rd_istrat instead of the bogosity of * hanging invisible fields off the end of a structure - jolly */ ird->rd_istrat = strat; /* finally, read the vector of support procedures */ if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len)) { write_irels(); return; } support = (RegProcedure *) palloc(len); if ((nread = FileRead(fd, (char *) support, len)) != len) { write_irels(); return; } /* * p += sizeof(IndexStrategy); ((RegProcedure **) p) = support; */ ird->rd_support = support; RelationCacheInsert(ird); RelationInitLockInfo(ird); }}static voidwrite_irels(void){ Size len; int nwritten; File fd; Relation irel[Num_indices_bootstrap]; Relation ird; Form_pg_am am; Form_pg_class relform; IndexStrategy strat; RegProcedure *support; ProcessingMode oldmode; int i; int relno; RelationBuildDescInfo bi;#ifndef __CYGWIN32__ fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_WRONLY | O_CREAT | O_TRUNC, 0600);#else fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600);#endif if (fd < 0) elog(FATAL, "cannot create init file %s", RELCACHE_INIT_FILENAME); FileSeek(fd, 0L, SEEK_SET); /* * Build a relation descriptor for pg_attnumind without resort to the * descriptor cache. In order to do this, we set ProcessingMode to * Bootstrap. The effect of this is to disable indexed relation * searches -- a necessary step, since we're trying to instantiate the * index relation descriptors here. */ oldmode = GetProcessingMode(); SetProcessingMode(BootstrapProcessing); bi.infotype = INFO_RELNAME; bi.i.info_name = AttributeNumIndex; irel[0] = RelationBuildDesc(bi); irel[0]->rd_isnailed = true; bi.i.info_name = ClassNameIndex; irel[1] = RelationBuildDesc(bi); irel[1]->rd_isnailed = true; bi.i.info_name = ClassOidIndex; irel[2] = RelationBuildDesc(bi); irel[2]->rd_isnailed = true; SetProcessingMode(oldmode); /* nail the descriptor in the cache */ for (relno = 0; relno < Num_indices_bootstrap; relno++) { ird = irel[relno]; /* save the volatile fields in the relation descriptor */ am = ird->rd_am; ird->rd_am = (Form_pg_am) NULL; relform = ird->rd_rel; ird->rd_rel = (Form_pg_class) NULL; strat = ird->rd_istrat; support = ird->rd_support; /* * first write the relation descriptor , excluding strategy and * support */ len = sizeof(RelationData); /* first, write the relation descriptor length */ if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len))) != sizeof(len)) elog(FATAL, "cannot write init file -- descriptor length"); /* next, write out the Relation structure */ if ((nwritten = FileWrite(fd, (char *) ird, len)) != len) elog(FATAL, "cannot write init file -- reldesc"); /* next, write the access method tuple form */ len = sizeof(FormData_pg_am); if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len))) != sizeof(len)) elog(FATAL, "cannot write init file -- am tuple form length"); if ((nwritten = FileWrite(fd, (char *) am, len)) != len) elog(FATAL, "cannot write init file -- am tuple form"); /* next write the relation tuple form */ len = sizeof(FormData_pg_class); if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len))) != sizeof(len)) elog(FATAL, "cannot write init file -- relation tuple form length"); if ((nwritten = FileWrite(fd, (char *) relform, len)) != len) elog(FATAL, "cannot write init file -- relation tuple form"); /* next, do all the attribute tuple form data entries */ len = ATTRIBUTE_TUPLE_SIZE; for (i = 0; i < relform->relnatts; i++) { if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len))) != sizeof(len)) elog(FATAL, "cannot write init file -- length of attdesc %d", i); if ((nwritten = FileWrite(fd, (char *) ird->rd_att->attrs[i], len)) != len) elog(FATAL, "cannot write init file -- attdesc %d", i); } /* next, write the index strategy map */ len = AttributeNumberGetIndexStrategySize(relform->relnatts, am->amstrategies); if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len))) != sizeof(len)) elog(FATAL, "cannot write init file -- strategy map length"); if ((nwritten = FileWrite(fd, (char *) strat, len)) != len) elog(FATAL, "cannot write init file -- strategy map"); /* finally, write the vector of support procedures */ len = relform->relnatts * (am->amsupport * sizeof(RegProcedure)); if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len))) != sizeof(len)) elog(FATAL, "cannot write init file -- support vector length"); if ((nwritten = FileWrite(fd, (char *) support, len)) != len) elog(FATAL, "cannot write init file -- support vector"); /* restore volatile fields */ ird->rd_am = am; ird->rd_rel = relform; } FileClose(fd);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -