relcache.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,134 行 · 第 1/5 页
C
2,134 行
*/ if (relation->rd_rel->relhasrules) RelationBuildRuleLock(relation); else { relation->rd_rules = NULL; relation->rd_rulescxt = NULL; } if (relation->rd_rel->reltriggers > 0) RelationBuildTriggers(relation); else relation->trigdesc = NULL; /* * if it's an index, initialize index-related information */ if (OidIsValid(relation->rd_rel->relam)) RelationInitIndexAccessInfo(relation); /* extract reloptions if any */ RelationParseRelOptions(relation, pg_class_tuple); /* * initialize the relation lock manager information */ RelationInitLockInfo(relation); /* see lmgr.c */ /* * initialize physical addressing information for the relation */ RelationInitPhysicalAddr(relation); /* make sure relation is marked as having no open file yet */ relation->rd_smgr = NULL; /* * now we can free the memory allocated for pg_class_tuple */ heap_freetuple(pg_class_tuple); /* * Insert newly created relation into relcache hash tables. */ oldcxt = MemoryContextSwitchTo(CacheMemoryContext); RelationCacheInsert(relation); MemoryContextSwitchTo(oldcxt); /* It's fully valid */ relation->rd_isvalid = true; return relation;}/* * Initialize the physical addressing info (RelFileNode) for a relcache entry */static voidRelationInitPhysicalAddr(Relation relation){ if (relation->rd_rel->reltablespace) relation->rd_node.spcNode = relation->rd_rel->reltablespace; else relation->rd_node.spcNode = MyDatabaseTableSpace; if (relation->rd_rel->relisshared) relation->rd_node.dbNode = InvalidOid; else relation->rd_node.dbNode = MyDatabaseId; relation->rd_node.relNode = relation->rd_rel->relfilenode;}/* * Initialize index-access-method support data for an index relation */voidRelationInitIndexAccessInfo(Relation relation){ HeapTuple tuple; Form_pg_am aform; Datum indclassDatum; Datum indoptionDatum; bool isnull; oidvector *indclass; int2vector *indoption; MemoryContext indexcxt; MemoryContext oldcontext; int natts; uint16 amstrategies; uint16 amsupport; /* * Make a copy of the pg_index entry for the index. Since pg_index * contains variable-length and possibly-null fields, we have to do this * honestly rather than just treating it as a Form_pg_index struct. */ tuple = SearchSysCache(INDEXRELID, ObjectIdGetDatum(RelationGetRelid(relation)), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for index %u", RelationGetRelid(relation)); oldcontext = MemoryContextSwitchTo(CacheMemoryContext); relation->rd_indextuple = heap_copytuple(tuple); relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple); MemoryContextSwitchTo(oldcontext); ReleaseSysCache(tuple); /* * Make a copy of the pg_am entry for the index's access method */ tuple = SearchSysCache(AMOID, ObjectIdGetDatum(relation->rd_rel->relam), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for access method %u", relation->rd_rel->relam); aform = (Form_pg_am) MemoryContextAlloc(CacheMemoryContext, sizeof *aform); memcpy(aform, GETSTRUCT(tuple), sizeof *aform); ReleaseSysCache(tuple); relation->rd_am = aform; natts = relation->rd_rel->relnatts; if (natts != relation->rd_index->indnatts) elog(ERROR, "relnatts disagrees with indnatts for index %u", RelationGetRelid(relation)); amstrategies = aform->amstrategies; amsupport = aform->amsupport; /* * Make the private context to hold index access info. The reason we need * a context, and not just a couple of pallocs, is so that we won't leak * any subsidiary info attached to fmgr lookup records. * * Context parameters are set on the assumption that it'll probably not * contain much data. */ indexcxt = AllocSetContextCreate(CacheMemoryContext, RelationGetRelationName(relation), ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE); relation->rd_indexcxt = indexcxt; /* * Allocate arrays to hold data */ relation->rd_aminfo = (RelationAmInfo *) MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo)); relation->rd_opfamily = (Oid *) MemoryContextAllocZero(indexcxt, natts * sizeof(Oid)); relation->rd_opcintype = (Oid *) MemoryContextAllocZero(indexcxt, natts * sizeof(Oid)); if (amstrategies > 0) relation->rd_operator = (Oid *) MemoryContextAllocZero(indexcxt, natts * amstrategies * sizeof(Oid)); else relation->rd_operator = NULL; if (amsupport > 0) { int nsupport = natts * amsupport; relation->rd_support = (RegProcedure *) MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure)); relation->rd_supportinfo = (FmgrInfo *) MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo)); } else { relation->rd_support = NULL; relation->rd_supportinfo = NULL; } relation->rd_indoption = (int16 *) MemoryContextAllocZero(indexcxt, natts * sizeof(int16)); /* * indclass cannot be referenced directly through the C struct, because it * comes after the variable-width indkey field. Must extract the datum * the hard way... */ indclassDatum = fastgetattr(relation->rd_indextuple, Anum_pg_index_indclass, GetPgIndexDescriptor(), &isnull); Assert(!isnull); indclass = (oidvector *) DatumGetPointer(indclassDatum); /* * Fill the operator and support procedure OID arrays, as well as the info * about opfamilies and opclass input types. (aminfo and supportinfo are * left as zeroes, and are filled on-the-fly when used) */ IndexSupportInitialize(indclass, relation->rd_operator, relation->rd_support, relation->rd_opfamily, relation->rd_opcintype, amstrategies, amsupport, natts); /* * Similarly extract indoption and copy it to the cache entry */ indoptionDatum = fastgetattr(relation->rd_indextuple, Anum_pg_index_indoption, GetPgIndexDescriptor(), &isnull); Assert(!isnull); indoption = (int2vector *) DatumGetPointer(indoptionDatum); memcpy(relation->rd_indoption, indoption->values, natts * sizeof(int16)); /* * expressions and predicate cache will be filled later */ relation->rd_indexprs = NIL; relation->rd_indpred = NIL; relation->rd_amcache = NULL;}/* * IndexSupportInitialize * Initializes an index's cached opclass information, * given the index's pg_index.indclass entry. * * Data is returned into *indexOperator, *indexSupport, *opFamily, and * *opcInType, 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, Oid *opFamily, Oid *opcInType, 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 */ opFamily[attIndex] = opcentry->opcfamily; opcInType[attIndex] = opcentry->opcintype; 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. * * Note there is no provision for flushing the cache. This is OK at the * moment because there is no way to ALTER any interesting properties of an * existing opclass --- all you can do is drop it, which will result in * a useless but harmless dead entry in the cache. To support altering * opclass membership (not the same as opfamily membership!), we'd need to * be able to flush this cache as well as the contents of relcache entries * for indexes. */static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid, StrategyNumber numStrats, StrategyNumber numSupport){ OpClassCacheEnt *opcentry; bool found; Relation rel; SysScanDesc scan; ScanKeyData skey[3]; 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) { /* Need to allocate memory for 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; } else { Assert(numStrats == opcentry->numStrats); Assert(numSupport == opcentry->numSupport); } /* * When testing for cache-flush hazards, we intentionally disable the * operator class cache and force reloading of the info on each call. * This is helpful because we want to test the case where a cache flush * occurs while we are loading the info, and it's very hard to provoke * that if this happens only once per opclass per backend. */#if defined(CLOBBER_CACHE_ALWAYS) opcentry->valid = false;#endif if (opcentry->valid) return opcentry; /* * Need to fill in new entry. * * 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); /* * We have to fetch the pg_opclass row to determine its opfamily and * opcintype, which are needed to look up the operators and functions. * It'd be convenient to use the syscache here, but that probably doesn't * work while bootstrapping. */ ScanKeyInit(&skey[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(operatorClassOid)); rel = heap_open(OperatorClassRelationId, AccessShareLock); scan = systable_beginscan(rel, OpclassOidIndexId, indexOK, SnapshotNow, 1, skey); if (HeapTupleIsValid(htup = systable_getnext(scan))) { Form_pg_opclass opclassform = (Form_pg_opclass) GETSTRUCT(htup); opcentry->opcfamily = opclassform->opcfamily; opcentry->opcintype = opclassform->opcintype; } else elog(ERROR, "could not find tuple for opclass %u", operatorClassOid); systable_endscan(scan); heap_close(rel, AccessShareLock); /* * Scan pg_amop to obtain operators for the opclass. We only fetch the * default ones (those with lefttype = righttype = opcintype). */ if (numStrats > 0) { ScanKeyInit(&skey[0], Anum_pg_amop_amopfamily, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(opcentry->opcfamily)); ScanKeyInit(&skey[1], Anum_pg_amop_amoplefttype, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(opcentry->opcintype)); ScanKeyInit(&skey[2], Anum_pg_amop_amoprighttype, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(opcentry->opcintype)); rel = heap_open(AccessMethodOperatorRelationId, AccessShareLock); scan = systable_beginscan(rel, AccessMethodStrategyIndexId, indexOK, SnapshotNow, 3, skey);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?