relcache.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,282 行 · 第 1/5 页
C
2,282 行
else relation->rd_node.tblNode = MyDatabaseId; relation->rd_node.relNode = relation->rd_rel->relfilenode; /* make sure relation is marked as having no open file yet */ relation->rd_fd = -1; /* * Insert newly created relation into relcache hash tables. */ oldcxt = MemoryContextSwitchTo(CacheMemoryContext); RelationCacheInsert(relation); MemoryContextSwitchTo(oldcxt); /* * If it's a temp rel, RelationGetNumberOfBlocks will assume that * rd_nblocks is correct. Must forcibly update the block count when * creating the relcache entry. But if we are doing a rebuild, don't * do this yet; leave it to RelationClearRelation to do at the end. * (Otherwise, an elog in RelationUpdateNumberOfBlocks would leave us * with inconsistent relcache state.) */ if (relation->rd_istemp && oldrelation == NULL) RelationUpdateNumberOfBlocks(relation); return relation;}/* * Initialize index-access-method support data for an index relation */voidRelationInitIndexAccessInfo(Relation relation){ HeapTuple tuple; Form_pg_am aform; MemoryContext indexcxt; MemoryContext oldcontext; IndexStrategy strategy; Oid *operator; RegProcedure *support; FmgrInfo *supportinfo; 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 */ if (amstrategies > 0) { int noperators = natts * amstrategies; Size stratSize; stratSize = AttributeNumberGetIndexStrategySize(natts, amstrategies); strategy = (IndexStrategy) MemoryContextAlloc(indexcxt, stratSize); MemSet(strategy, 0, stratSize); operator = (Oid *) MemoryContextAlloc(indexcxt, noperators * sizeof(Oid)); MemSet(operator, 0, noperators * sizeof(Oid)); } else { strategy = NULL; operator = NULL; } if (amsupport > 0) { int nsupport = natts * amsupport; support = (RegProcedure *) MemoryContextAlloc(indexcxt, nsupport * sizeof(RegProcedure)); MemSet(support, 0, nsupport * sizeof(RegProcedure)); supportinfo = (FmgrInfo *) MemoryContextAlloc(indexcxt, nsupport * sizeof(FmgrInfo)); MemSet(supportinfo, 0, nsupport * sizeof(FmgrInfo)); } else { support = NULL; supportinfo = NULL; } relation->rd_istrat = strategy; relation->rd_operator = operator; relation->rd_support = support; relation->rd_supportinfo = supportinfo; /* * Fill the strategy map and the support RegProcedure arrays. * (supportinfo is left as zeroes, and is filled on-the-fly when used) */ IndexSupportInitialize(relation->rd_index, strategy, 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 strategy and associated support procedures, * given the index's pg_index tuple. * * Data is returned into *indexStrategy, *indexOperator, and *indexSupport, * all of which are objects 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(Form_pg_index iform, IndexStrategy indexStrategy, Oid *indexOperator, RegProcedure *indexSupport, StrategyNumber maxStrategyNumber, StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber){ int attIndex; maxStrategyNumber = AMStrategies(maxStrategyNumber); /* * XXX note that the following assumes the INDEX tuple is well formed * and that the *key and *class are 0 terminated. */ for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++) { OpClassCacheEnt *opcentry; if (!OidIsValid(iform->indclass[attIndex])) elog(ERROR, "bogus pg_index tuple"); /* look up the info for this opclass, using a cache */ opcentry = LookupOpclassInfo(iform->indclass[attIndex], maxStrategyNumber, maxSupportNumber); /* load the strategy information for the index operators */ if (maxStrategyNumber > 0) { StrategyMap map; Oid *opers; StrategyNumber strategy; map = IndexStrategyGetStrategyMap(indexStrategy, maxStrategyNumber, attIndex + 1); opers = &indexOperator[attIndex * maxStrategyNumber]; for (strategy = 0; strategy < maxStrategyNumber; strategy++) { ScanKey mapentry; mapentry = StrategyMapGetScanKeyEntry(map, strategy + 1); if (RegProcedureIsValid(opcentry->operatorProcs[strategy])) { MemSet(mapentry, 0, sizeof(*mapentry)); mapentry->sk_flags = 0; mapentry->sk_procedure = opcentry->operatorProcs[strategy]; /* * Mark mapentry->sk_func invalid, until and unless * someone sets it up. */ mapentry->sk_func.fn_oid = InvalidOid; } else ScanKeyEntrySetIllegal(mapentry); opers[strategy] = opcentry->operatorOids[strategy]; } } /* if support routines exist for this access method, load them */ if (maxSupportNumber > 0) { RegProcedure *procs; StrategyNumber support; procs = &indexSupport[attIndex * maxSupportNumber]; for (support = 0; support < maxSupportNumber; ++support) procs[support] = opcentry->supportProcs[support]; } }}/* * 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 pg_amop_desc; Relation pg_amproc_desc; SysScanDesc pg_amop_scan; SysScanDesc pg_amproc_scan; ScanKeyData key; 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 = tag_hash; OpClassCache = hash_create("Operator class cache", 64, &ctl, HASH_ELEM | HASH_FUNCTION); } opcentry = (OpClassCacheEnt *) hash_search(OpClassCache, (void *) &operatorClassOid, HASH_ENTER, &found); if (opcentry == NULL) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); 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 *) MemoryContextAlloc(CacheMemoryContext, numStrats * sizeof(Oid)); MemSet(opcentry->operatorOids, 0, numStrats * sizeof(Oid)); opcentry->operatorProcs = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext, numStrats * sizeof(RegProcedure)); MemSet(opcentry->operatorProcs, 0, numStrats * sizeof(RegProcedure)); } else { opcentry->operatorOids = NULL; opcentry->operatorProcs = NULL; } if (numSupport > 0) { opcentry->supportProcs = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext, numSupport * sizeof(RegProcedure)); MemSet(opcentry->supportProcs, 0, numSupport * sizeof(RegProcedure)); } else opcentry->supportProcs = NULL; /* * To avoid infinite recursion during startup, force a heap scan 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 */ if (numStrats > 0) { ScanKeyEntryInitialize(&key, 0, Anum_pg_amop_amopclaid, F_OIDEQ, ObjectIdGetDatum(operatorClassOid)); pg_amop_desc = heap_openr(AccessMethodOperatorRelationName, AccessShareLock); pg_amop_scan = systable_beginscan(pg_amop_desc, AccessMethodStrategyIndex, indexOK, SnapshotNow, 1, &key); while (HeapTupleIsValid(htup = systable_getnext(pg_amop_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; opcentry->operatorProcs[amopform->amopstrategy - 1] = get_opcode(amopform->amopopr); } systable_endscan(pg_amop_scan); heap_close(pg_amop_desc, AccessShareLock); } /* * Scan pg_amproc to obtain support procs for the opclass */ if (numSupport > 0) { ScanKeyEntryInitialize(&key, 0, Anum_pg_amproc_amopclaid, F_OIDEQ, ObjectIdGetDatum(operatorClassOid)); pg_amproc_desc = heap_openr(AccessMethodProcedureRelationName, AccessShareLock); pg_amproc_scan = systable_beginscan(pg_amproc_desc, AccessMethodProcedureIndex, indexOK, SnapshotNow, 1, &key); while (HeapTupleIsValid(htup = systable_getnext(pg_amproc_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(pg_amproc_scan); heap_close(pg_amproc_desc, 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, int natts, FormData_pg_attribute *att){ Relation relation; int i; bool has_not_null; /* * allocate new relation desc clear all fields of reldesc
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?