📄 relcache.c
字号:
/* -------------------------------- * RelationIdCacheGetRelation * * only try to get the reldesc by looking up the cache * do not go to the disk. this is used by BlockPrepareFile() * and RelationIdGetRelation below. * -------------------------------- */RelationRelationIdCacheGetRelation(Oid relationId){ Relation rd; RelationIdCacheLookup(relationId, rd); if (RelationIsValid(rd)) { if (rd->rd_fd == -1) { rd->rd_fd = smgropen(DEFAULT_SMGR, rd); Assert(rd->rd_fd != -1); } RelationIncrementReferenceCount(rd); } return rd;}/* -------------------------------- * RelationNameCacheGetRelation * -------------------------------- */static RelationRelationNameCacheGetRelation(char *relationName){ Relation rd; NameData name; /* * make sure that the name key used for hash lookup is properly * null-padded */ namestrcpy(&name, relationName); RelationNameCacheLookup(name.data, rd); if (RelationIsValid(rd)) { if (rd->rd_fd == -1) { rd->rd_fd = smgropen(DEFAULT_SMGR, rd); Assert(rd->rd_fd != -1); } RelationIncrementReferenceCount(rd); } return rd;}/* -------------------------------- * RelationIdGetRelation * * return a relation descriptor based on its id. * return a cached value if possible * -------------------------------- */RelationRelationIdGetRelation(Oid relationId){ Relation rd; RelationBuildDescInfo buildinfo; /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_RelationIdGetRelation); IncrHeapAccessStat(global_RelationIdGetRelation); /* ---------------- * first try and get a reldesc from the cache * ---------------- */ rd = RelationIdCacheGetRelation(relationId); if (RelationIsValid(rd)) return rd; /* ---------------- * no reldesc in the cache, so have RelationBuildDesc() * build one and add it. * ---------------- */ buildinfo.infotype = INFO_RELID; buildinfo.i.info_id = relationId; rd = RelationBuildDesc(buildinfo); return rd;}/* -------------------------------- * RelationNameGetRelation * * return a relation descriptor based on its name. * return a cached value if possible * -------------------------------- */RelationRelationNameGetRelation(char *relationName){ Relation rd; RelationBuildDescInfo buildinfo; /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_RelationNameGetRelation); IncrHeapAccessStat(global_RelationNameGetRelation); /* ---------------- * first try and get a reldesc from the cache * ---------------- */ rd = RelationNameCacheGetRelation(relationName); if (RelationIsValid(rd)) return rd; /* ---------------- * no reldesc in the cache, so have RelationBuildDesc() * build one and add it. * ---------------- */ buildinfo.infotype = INFO_RELNAME; buildinfo.i.info_name = relationName; rd = RelationBuildDesc(buildinfo); return rd;}/* ---------------- * old "getreldesc" interface. * ---------------- */#ifdef NOT_USEDRelationgetreldesc(char *relationName){ /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_getreldesc); IncrHeapAccessStat(global_getreldesc); return RelationNameGetRelation(relationName);}#endif/* ---------------------------------------------------------------- * cache invalidation support routines * ---------------------------------------------------------------- *//* -------------------------------- * RelationClose - close an open relation * -------------------------------- */voidRelationClose(Relation relation){ /* Note: no locking manipulations needed */ RelationDecrementReferenceCount(relation);}/* -------------------------------- * RelationFlushRelation * * Actually blows away a relation... RelationFree doesn't do * anything anymore. * -------------------------------- */static voidRelationFlushRelation(Relation *relationPtr, bool onlyFlushReferenceCountZero){ MemoryContext oldcxt; Relation relation = *relationPtr; if (relation->rd_isnailed) { /* this is a nailed special relation for bootstraping */ return; } if (!onlyFlushReferenceCountZero || RelationHasReferenceCountZero(relation)) { oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); /* make sure smgr and lower levels close the relation's files, * if they weren't closed already */ smgrclose(DEFAULT_SMGR, relation); RelationCacheDelete(relation); FreeTupleDesc(relation->rd_att); SystemCacheRelationFlushed(RelationGetRelid(relation)); FreeTriggerDesc(relation);#ifdef NOT_USED if (relation->rd_rules) { int j; for (j = 0; j < relation->rd_rules->numLocks; j++) pfree(relation->rd_rules->rules[j]); pfree(relation->rd_rules->rules); pfree(relation->rd_rules); }#endif pfree(RelationGetLockInfo(relation)); pfree(RelationGetForm(relation)); pfree(relation); MemoryContextSwitchTo(oldcxt); }}/* -------------------------------- * RelationForgetRelation - * RelationFlushRelation + if the relation is myxactonly then * get rid of the relation descriptor from the newly created * relation list. * -------------------------------- */voidRelationForgetRelation(Oid rid){ Relation relation; RelationIdCacheLookup(rid, relation); if (PointerIsValid(relation)) { if (relation->rd_myxactonly) { MemoryContext oldcxt; List *curr; List *prev = NIL; oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); foreach(curr, newlyCreatedRelns) { Relation reln = lfirst(curr); Assert(reln != NULL && reln->rd_myxactonly); if (RelationGetRelid(reln) == rid) break; prev = curr; } if (curr == NIL) elog(FATAL, "Local relation %s not found in list", (RelationGetRelationName(relation))->data); if (prev == NIL) newlyCreatedRelns = lnext(newlyCreatedRelns); else lnext(prev) = lnext(curr); pfree(curr); MemoryContextSwitchTo(oldcxt); } RelationFlushRelation(&relation, false); }}/* -------------------------------- * RelationIdInvalidateRelationCacheByRelationId * -------------------------------- */voidRelationIdInvalidateRelationCacheByRelationId(Oid relationId){ Relation relation; RelationIdCacheLookup(relationId, relation); /* * "local" relations are invalidated by RelationPurgeLocalRelation. * (This is to make LocalBufferSync's life easier: want the descriptor * to hang around for a while. In fact, won't we want this for * BufferSync also? But I'll leave it for now since I don't want to * break anything.) - ay 3/95 */ if (PointerIsValid(relation) && !relation->rd_myxactonly) { /* * The boolean onlyFlushReferenceCountZero in RelationFlushReln() * should be set to true when we are incrementing the command * counter and to false when we are starting a new xaction. This * can be determined by checking the current xaction status. */ RelationFlushRelation(&relation, CurrentXactInProgress()); }}#if NOT_USED /* See comments at line 1304 *//* -------------------------------- * RelationIdInvalidateRelationCacheByAccessMethodId * * RelationFlushIndexes is needed for use with HashTableWalk.. * -------------------------------- */static voidRelationFlushIndexes(Relation *r, Oid accessMethodId){ Relation relation = *r; if (!RelationIsValid(relation)) { elog(NOTICE, "inval call to RFI"); return; } if (relation->rd_rel->relkind == RELKIND_INDEX && /* XXX style */ (!OidIsValid(accessMethodId) || relation->rd_rel->relam == accessMethodId)) RelationFlushRelation(&relation, false);}#endifvoidRelationIdInvalidateRelationCacheByAccessMethodId(Oid accessMethodId){#ifdef NOT_USED /* * 25 aug 1992: mao commented out the ht walk below. it should be * doing the right thing, in theory, but flushing reldescs for index * relations apparently doesn't work. we want to cut 4.0.1, and i * don't want to introduce new bugs. this code never executed before, * so i'm turning it off for now. after the release is cut, i'll fix * this up. */ HashTableWalk(RelationNameCache, (HashtFunc) RelationFlushIndexes, accessMethodId);#else return;#endif}/* * RelationCacheInvalidate * * Will blow away either all the cached relation descriptors or * those that have a zero reference count. * */voidRelationCacheInvalidate(bool onlyFlushReferenceCountZero){ HashTableWalk(RelationNameCache, (HashtFunc) RelationFlushRelation, onlyFlushReferenceCountZero); /* * nailed-in reldescs will still be in the cache... 7 hardwired heaps * + 3 hardwired indices == 10 total. */ if (!onlyFlushReferenceCountZero) { Assert(RelationNameCache->hctl->nkeys == 10); Assert(RelationIdCache->hctl->nkeys == 10); }}/* -------------------------------- * RelationRegisterRelation - * register the Relation descriptor of a newly created relation * with the relation descriptor Cache. * -------------------------------- */voidRelationRegisterRelation(Relation relation){ MemoryContext oldcxt; oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); if (oldcxt != (MemoryContext) CacheCxt) elog(NOIND, "RelationRegisterRelation: WARNING: Context != CacheCxt"); RelationCacheInsert(relation); RelationInitLockInfo(relation); /* * we've just created the relation. It is invisible to anyone else * before the transaction is committed. Setting rd_myxactonly allows * us to use the local buffer manager for select/insert/etc before the * end of transaction. (We also need to keep track of relations * created during a transaction and does the necessary clean up at the * end of the transaction.) - ay 3/95 */ relation->rd_myxactonly = TRUE; newlyCreatedRelns = lcons(relation, newlyCreatedRelns); MemoryContextSwitchTo(oldcxt);}/* * RelationPurgeLocalRelation - * find all the Relation descriptors marked rd_myxactonly and reset them. * This should be called at the end of a transaction (commit/abort) when * the "local" relations will become visible to others and the multi-user * buffer pool should be used. */voidRelationPurgeLocalRelation(bool xactCommitted){ MemoryContext oldcxt; if (newlyCreatedRelns == NULL) return; oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); while (newlyCreatedRelns) { List *l = newlyCreatedRelns; Relation reln = lfirst(l); Assert(reln != NULL && reln->rd_myxactonly); if (!xactCommitted) { /* * remove the file if we abort. This is so that files for * tables created inside a transaction block get removed. */ if (reln->rd_isnoname) { if (!(reln->rd_nonameunlinked)) { smgrunlink(DEFAULT_SMGR, reln); reln->rd_nonameunlinked = TRUE; } } else smgrunlink(DEFAULT_SMGR, reln); } reln->rd_myxactonly = FALSE; if (!IsBootstrapProcessingMode()) RelationFlushRelation(&reln, FALSE); newlyCreatedRelns = lnext(newlyCreatedRelns); pfree(l); } MemoryContextSwitchTo(oldcxt);}/* -------------------------------- * RelationInitialize * * This initializes the relation descriptor cache. * -------------------------------- */#define INITRELCACHESIZE 400voidRelationInitialize(void){ MemoryContext oldcxt; HASHCTL ctl; /* ---------------- * switch to cache memory context * ---------------- */ if (!CacheCxt) CacheCxt = CreateGlobalMemory("Cache"); oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); /* ---------------- * create global caches * ---------------- */ MemSet(&ctl, 0, (int) sizeof(ctl)); ctl.keysize = sizeof(NameData); ctl.datasize = sizeof(Relation); RelationNameCache = hash_create(INITRELCACHESIZE, &ctl, HASH_ELEM); ctl.keysize = sizeof(Oid); ctl.hash = tag_hash; RelationIdCache = hash_create(INITRELCACHESIZE, &ctl, HASH_ELEM | HASH_FUNCTION); /* ---------------- * initialize the cache with pre-made relation descriptors * for some of the more important system relations. These * relations should always be in the cache. * ---------------- */ formrdesc(RelationRelationName, Natts_pg_class, Desc_pg_class); formrdesc(AttributeRelationName, Natts_pg_attribute, Desc_pg_attribute); formrdesc(ProcedureRelationName, Natts_pg_proc, Desc_pg_proc); formrdesc(TypeRelationName, Natts_pg_type, Desc_pg_type); formrdesc(VariableRelationName, Natts_pg_variable, Desc_pg_variable); formrdesc(LogRelationName, Natts_pg_log, Desc_pg_log);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -