📄 relcache.c
字号:
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo)); if (amstrategies > 0) operator = (Oid *) MemoryContextAllocZero(indexcxt, natts * amstrategies * sizeof(Oid)); else operator = NULL; if (amsupport > 0) { int nsupport = natts * amsupport; support = (RegProcedure *) MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure)); supportinfo = (FmgrInfo *) MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo)); } else { support = NULL; supportinfo = NULL; } relation->rd_operator = operator; relation->rd_support = support; relation->rd_supportinfo = supportinfo; /* * Fill the operator and support procedure OID arrays. (aminfo and * supportinfo are left as zeroes, and are filled on-the-fly when used) */ IndexSupportInitialize(relation->rd_indclass, operator, support, amstrategies, amsupport, natts); /* * expressions and predicate cache will be filled later */ relation->rd_indexprs = NIL; relation->rd_indpred = NIL;}/* * IndexSupportInitialize * Initializes an index's cached opclass information, * given the index's pg_index.indclass entry. * * Data is returned into *indexOperator and *indexSupport, which are arrays * allocated by the caller. * * The caller also passes maxStrategyNumber, maxSupportNumber, and * maxAttributeNumber, since these indicate the size of the arrays * it has allocated --- but in practice these numbers must always match * those obtainable from the system catalog entries for the index and * access method. */static voidIndexSupportInitialize(oidvector *indclass, Oid *indexOperator, RegProcedure *indexSupport, StrategyNumber maxStrategyNumber, StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber){ int attIndex; for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++) { OpClassCacheEnt *opcentry; if (!OidIsValid(indclass->values[attIndex])) elog(ERROR, "bogus pg_index tuple"); /* look up the info for this opclass, using a cache */ opcentry = LookupOpclassInfo(indclass->values[attIndex], maxStrategyNumber, maxSupportNumber); /* copy cached data into relcache entry */ if (maxStrategyNumber > 0) memcpy(&indexOperator[attIndex * maxStrategyNumber], opcentry->operatorOids, maxStrategyNumber * sizeof(Oid)); if (maxSupportNumber > 0) memcpy(&indexSupport[attIndex * maxSupportNumber], opcentry->supportProcs, maxSupportNumber * sizeof(RegProcedure)); }}/* * LookupOpclassInfo * * This routine maintains a per-opclass cache of the information needed * by IndexSupportInitialize(). This is more efficient than relying on * the catalog cache, because we can load all the info about a particular * opclass in a single indexscan of pg_amproc or pg_amop. * * The information from pg_am about expected range of strategy and support * numbers is passed in, rather than being looked up, mainly because the * caller will have it already. * * XXX There isn't any provision for flushing the cache. However, there * isn't any provision for flushing relcache entries when opclass info * changes, either :-( */static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid, StrategyNumber numStrats, StrategyNumber numSupport){ OpClassCacheEnt *opcentry; bool found; Relation rel; SysScanDesc scan; ScanKeyData skey[2]; HeapTuple htup; bool indexOK; if (OpClassCache == NULL) { /* First time through: initialize the opclass cache */ HASHCTL ctl; if (!CacheMemoryContext) CreateCacheMemoryContext(); MemSet(&ctl, 0, sizeof(ctl)); ctl.keysize = sizeof(Oid); ctl.entrysize = sizeof(OpClassCacheEnt); ctl.hash = oid_hash; OpClassCache = hash_create("Operator class cache", 64, &ctl, HASH_ELEM | HASH_FUNCTION); } opcentry = (OpClassCacheEnt *) hash_search(OpClassCache, (void *) &operatorClassOid, HASH_ENTER, &found); if (found && opcentry->valid) { /* Already made an entry for it */ Assert(numStrats == opcentry->numStrats); Assert(numSupport == opcentry->numSupport); return opcentry; } /* Need to fill in new entry */ opcentry->valid = false; /* until known OK */ opcentry->numStrats = numStrats; opcentry->numSupport = numSupport; if (numStrats > 0) opcentry->operatorOids = (Oid *) MemoryContextAllocZero(CacheMemoryContext, numStrats * sizeof(Oid)); else opcentry->operatorOids = NULL; if (numSupport > 0) opcentry->supportProcs = (RegProcedure *) MemoryContextAllocZero(CacheMemoryContext, numSupport * sizeof(RegProcedure)); else opcentry->supportProcs = NULL; /* * To avoid infinite recursion during startup, force heap scans if we're * looking up info for the opclasses used by the indexes we would like to * reference here. */ indexOK = criticalRelcachesBuilt || (operatorClassOid != OID_BTREE_OPS_OID && operatorClassOid != INT2_BTREE_OPS_OID); /* * Scan pg_amop to obtain operators for the opclass. We only fetch the * default ones (those with subtype zero). */ if (numStrats > 0) { ScanKeyInit(&skey[0], Anum_pg_amop_amopclaid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(operatorClassOid)); ScanKeyInit(&skey[1], Anum_pg_amop_amopsubtype, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(InvalidOid)); rel = heap_open(AccessMethodOperatorRelationId, AccessShareLock); scan = systable_beginscan(rel, AccessMethodStrategyIndexId, indexOK, SnapshotNow, 2, skey); while (HeapTupleIsValid(htup = systable_getnext(scan))) { Form_pg_amop amopform = (Form_pg_amop) GETSTRUCT(htup); if (amopform->amopstrategy <= 0 || (StrategyNumber) amopform->amopstrategy > numStrats) elog(ERROR, "invalid amopstrategy number %d for opclass %u", amopform->amopstrategy, operatorClassOid); opcentry->operatorOids[amopform->amopstrategy - 1] = amopform->amopopr; } systable_endscan(scan); heap_close(rel, AccessShareLock); } /* * Scan pg_amproc to obtain support procs for the opclass. We only fetch * the default ones (those with subtype zero). */ if (numSupport > 0) { ScanKeyInit(&skey[0], Anum_pg_amproc_amopclaid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(operatorClassOid)); ScanKeyInit(&skey[1], Anum_pg_amproc_amprocsubtype, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(InvalidOid)); rel = heap_open(AccessMethodProcedureRelationId, AccessShareLock); scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK, SnapshotNow, 2, skey); while (HeapTupleIsValid(htup = systable_getnext(scan))) { Form_pg_amproc amprocform = (Form_pg_amproc) GETSTRUCT(htup); if (amprocform->amprocnum <= 0 || (StrategyNumber) amprocform->amprocnum > numSupport) elog(ERROR, "invalid amproc number %d for opclass %u", amprocform->amprocnum, operatorClassOid); opcentry->supportProcs[amprocform->amprocnum - 1] = amprocform->amproc; } systable_endscan(scan); heap_close(rel, AccessShareLock); } opcentry->valid = true; return opcentry;}/* * formrdesc * * This is a special cut-down version of RelationBuildDesc() * used by RelationCacheInitialize() in initializing the relcache. * The relation descriptor is built just from the supplied parameters, * without actually looking at any system table entries. We cheat * quite a lot since we only need to work for a few basic system * catalogs. * * formrdesc is currently used for: pg_class, pg_attribute, pg_proc, * and pg_type (see RelationCacheInitialize). * * Note that these catalogs can't have constraints (except attnotnull), * default values, rules, or triggers, since we don't cope with any of that. * * NOTE: we assume we are already switched into CacheMemoryContext. */static voidformrdesc(const char *relationName, Oid relationReltype, bool hasoids, int natts, FormData_pg_attribute *att){ Relation relation; int i; bool has_not_null; /* * allocate new relation desc, clear all fields of reldesc */ relation = (Relation) palloc0(sizeof(RelationData)); relation->rd_targblock = InvalidBlockNumber; /* make sure relation is marked as having no open file yet */ relation->rd_smgr = NULL; /* * initialize reference count: 1 because it is nailed in cache */ relation->rd_refcnt = 1; /* * all entries built with this routine are nailed-in-cache; none are for * new or temp relations. */ relation->rd_isnailed = true; relation->rd_createSubid = InvalidSubTransactionId; relation->rd_istemp = false; /* * initialize relation tuple form * * The data we insert here is pretty incomplete/bogus, but it'll serve to * get us launched. RelationCacheInitializePhase2() will read the real * data from pg_class and replace what we've done here. */ relation->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE); namestrcpy(&relation->rd_rel->relname, relationName); relation->rd_rel->relnamespace = PG_CATALOG_NAMESPACE; relation->rd_rel->reltype = relationReltype; /* * It's important to distinguish between shared and non-shared relations, * even at bootstrap time, to make sure we know where they are stored. At * present, all relations that formrdesc is used for are not shared. */ relation->rd_rel->relisshared = false; relation->rd_rel->relpages = 1; relation->rd_rel->reltuples = 1; relation->rd_rel->relkind = RELKIND_RELATION; relation->rd_rel->relhasoids = hasoids; relation->rd_rel->relnatts = (int16) natts; /* * initialize attribute tuple form * * Unlike the case with the relation tuple, this data had better be right * because it will never be replaced. The input values must be correctly * defined by macros in src/include/catalog/ headers. */ relation->rd_att = CreateTemplateTupleDesc(natts, hasoids); relation->rd_att->tdtypeid = relationReltype; relation->rd_att->tdtypmod = -1; /* unnecessary, but... */ /* * initialize tuple desc info */ has_not_null = false; for (i = 0; i < natts; i++) { memcpy(relation->rd_att->attrs[i], &att[i], ATTRIBUTE_TUPLE_SIZE); has_not_null |= att[i].attnotnull; /* make sure attcacheoff is valid */ relation->rd_att->attrs[i]->attcacheoff = -1; } /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */ relation->rd_att->attrs[0]->attcacheoff = 0; /* mark not-null status */ if (has_not_null) { TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr)); constr->has_not_null = true; relation->rd_att->constr = constr; } /* * initialize relation id from info in att array (my, this is ugly) */ RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid; relation->rd_rel->relfilenode = RelationGetRelid(relation); /* * initialize the relation lock manager information */ RelationInitLockInfo(relation); /* see lmgr.c */ /* * initialize physical addressing information for the relation */ RelationInitPhysicalAddr(relation); /* * initialize the rel-has-index flag, using hardwired knowledge */ if (IsBootstrapProcessingMode()) { /* In bootstrap mode, we have no indexes */ relation->rd_rel->relhasindex = false; } else { /* Otherwise, all the rels formrdesc is used for have indexes */ relation->rd_rel->relhasindex = true; } /* * add new reldesc to relcache */ RelationCacheInsert(relation); /* It's fully valid */ relation->rd_isvalid = true;}/* ---------------------------------------------------------------- * Relation Descriptor Lookup Interface * ---------------------------------------------------------------- *//* * RelationIdCacheGetRelation * * Lookup an existing reldesc by OID. * * Only try to get the reldesc by looking in the cache, * do not go to the disk if it's not present. * * NB: relation ref count is incremented if successful. * Caller should eventually decrement count. (Usually, * that happens by calling RelationClose().) */RelationRelationIdCacheGetRelation(Oid relationId){ Relation rd; RelationIdCacheLookup(relationId, rd); if (RelationIsValid(rd)) { RelationIncrementReferenceCount(rd); /* revalidate nailed index if necessary */ if (!rd->rd_isvalid) RelationReloadClassinfo(rd); } return rd;}/* * RelationIdGetRelation * * Lookup a reldesc by OID; make one if not already in cache. * * NB: relation ref count is incremented, or set to 1 if new entry. * Caller should eventually decrement count. (Usually, * that happens by calling RelationClose().) */RelationRelationIdGetRelation(Oid relationId){ Relation rd;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -