relcache.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,282 行 · 第 1/5 页
C
2,282 行
*/ relation = (Relation) palloc0(sizeof(RelationData)); relation->rd_targblock = InvalidBlockNumber; /* make sure relation is marked as having no open file yet */ relation->rd_fd = -1; /* * initialize reference count */ RelationSetReferenceCount(relation, 1); /* * all entries built with this routine are nailed-in-cache; none are * for new or temp relations. */ relation->rd_isnailed = 1; relation->rd_isnew = false; 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; /* * 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 = true; 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, relation->rd_rel->relhasoids); /* * initialize tuple desc info */ has_not_null = false; for (i = 0; i < natts; i++) { relation->rd_att->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); memcpy((char *) relation->rd_att->attrs[i], (char *) &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; /* * initialize the relation's lock manager and RelFileNode information */ RelationInitLockInfo(relation); /* see lmgr.c */ if (relation->rd_rel->relisshared) relation->rd_node.tblNode = InvalidOid; else relation->rd_node.tblNode = MyDatabaseId; relation->rd_node.relNode = relation->rd_rel->relfilenode = RelationGetRelid(relation); /* * initialize the rel-has-index flag, using hardwired knowledge */ relation->rd_rel->relhasindex = false; /* In bootstrap mode, we have no indexes */ if (!IsBootstrapProcessingMode()) { /* Otherwise, all the rels formrdesc is used for have indexes */ relation->rd_rel->relhasindex = true; } /* * add new reldesc to relcache */ RelationCacheInsert(relation);}/* ---------------------------------------------------------------- * 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_isnailed == 2) RelationReloadClassinfo(rd); } return rd;}/* * RelationSysNameCacheGetRelation * * As above, but lookup by name; only works for system catalogs. */static RelationRelationSysNameCacheGetRelation(const char *relationName){ Relation rd; NameData name; /* * make sure that the name key used for hash lookup is properly * null-padded */ namestrcpy(&name, relationName); RelationSysNameCacheLookup(NameStr(name), rd); if (RelationIsValid(rd)) { RelationIncrementReferenceCount(rd); /* revalidate nailed index if necessary */ if (rd->rd_isnailed == 2) RelationReloadClassinfo(rd); } return rd;}/* * RelationNodeCacheGetRelation * * As above, but lookup by relfilenode. * * NOTE: this must NOT try to revalidate invalidated nailed indexes, since * that could cause us to return an entry with a different relfilenode than * the caller asked for. Currently this is used only by the buffer manager. * Really the bufmgr's idea of relations should be separated out from the * relcache ... */RelationRelationNodeCacheGetRelation(RelFileNode rnode){ Relation rd; RelationNodeCacheLookup(rnode, rd); if (RelationIsValid(rd)) RelationIncrementReferenceCount(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; RelationBuildDescInfo buildinfo; /* * 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, NULL); return rd;}/* * RelationSysNameGetRelation * * As above, but lookup by name; only works for system catalogs. */RelationRelationSysNameGetRelation(const char *relationName){ Relation rd; RelationBuildDescInfo buildinfo; /* * first try and get a reldesc from the cache */ rd = RelationSysNameCacheGetRelation(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 = (char *) relationName; rd = RelationBuildDesc(buildinfo, NULL); return rd;}/* ---------------------------------------------------------------- * cache invalidation support routines * ---------------------------------------------------------------- *//* * RelationClose - close an open relation * * Actually, we just decrement the refcount. * * NOTE: if compiled with -DRELCACHE_FORCE_RELEASE then relcache entries * will be freed as soon as their refcount goes to zero. In combination * with aset.c's CLOBBER_FREED_MEMORY option, this provides a good test * to catch references to already-released relcache entries. It slows * things down quite a bit, however. */voidRelationClose(Relation relation){ /* Note: no locking manipulations needed */ RelationDecrementReferenceCount(relation);#ifdef RELCACHE_FORCE_RELEASE if (RelationHasReferenceCountZero(relation) && !relation->rd_isnew) RelationClearRelation(relation, false);#endif}/* * RelationReloadClassinfo - reload the pg_class row (only) * * This function is used only for nailed indexes. Since a REINDEX can * change the relfilenode value for a nailed index, we have to reread * the pg_class row anytime we get an SI invalidation on a nailed index * (without throwing away the whole relcache entry, since we'd be unable * to rebuild it). * * We can't necessarily reread the pg_class row right away; we might be * in a failed transaction when we receive the SI notification. If so, * RelationClearRelation just marks the entry as invalid by setting * rd_isnailed to 2. This routine is called to fix the entry when it * is next needed. */static voidRelationReloadClassinfo(Relation relation){ RelationBuildDescInfo buildinfo; bool indexOK; HeapTuple pg_class_tuple; Form_pg_class relp; /* Should be called only for invalidated nailed indexes */ Assert(relation->rd_isnailed == 2 && relation->rd_rel->relkind == RELKIND_INDEX); /* Read the pg_class row */ buildinfo.infotype = INFO_RELID; buildinfo.i.info_id = relation->rd_id; /* * Don't try to use an indexscan of pg_class_oid_index to reload the * info for pg_class_oid_index ... */ indexOK = strcmp(RelationGetRelationName(relation), ClassOidIndex) != 0; pg_class_tuple = ScanPgRelation(buildinfo, indexOK); if (!HeapTupleIsValid(pg_class_tuple)) elog(ERROR, "could not find tuple for system relation %u", relation->rd_id); relp = (Form_pg_class) GETSTRUCT(pg_class_tuple); if (relation->rd_node.relNode != relp->relfilenode) { /* We have to re-insert the entry into the relcache indexes */ RelationCacheDelete(relation); memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE); relation->rd_node.relNode = relp->relfilenode; RelationCacheInsert(relation); } heap_freetuple(pg_class_tuple); /* Must adjust number of blocks after we know the new relfilenode */ relation->rd_targblock = InvalidBlockNumber; RelationUpdateNumberOfBlocks(relation); /* Okay, now it's valid again */ relation->rd_isnailed = 1;}/* * RelationClearRelation * * Physically blow away a relation cache entry, or reset it and rebuild * it from scratch (that is, from catalog entries). The latter path is * usually used when we are notified of a change to an open relation * (one with refcount > 0). However, this routine just does whichever * it's told to do; callers must determine which they want. */static voidRelationClearRelation(Relation relation, bool rebuild){ MemoryContext oldcxt; /* * Make sure smgr and lower levels close the relation's files, if they * weren't closed already. If the relation is not getting deleted, * the next smgr access should reopen the files automatically. This * ensures that the low-level file access state is updated after, say, * a vacuum truncation. */ if (relation->rd_fd >= 0) { smgrclose(DEFAULT_SMGR, relation); relation->rd_fd = -1; } /* * Never, never ever blow away a nailed-in system relation, because * we'd be unable to recover. However, we must update rd_nblocks and * reset rd_targblock, in case we got called because of a relation * cache flush that was triggered by VACUUM. If it's a nailed index, * then we need to re-read the pg_class row to see if its relfilenode * changed. We can't necessarily do that here, because we might be in * a failed transaction. We assume it's okay to do it if there are open * references to the relcache entry (cf notes for AtEOXact_RelationCache). * Otherwise just mark the entry as possibly invalid, and it'll be fixed * when next opened. */ if (relation->rd_isnailed) { if (relation->rd_rel->relkind == RELKIND_INDEX) { relation->rd_isnailed = 2; /* needs to be revalidated */ if (relation->rd_refcnt > 1) RelationReloadClassinfo(relation); } else { relation->rd_targblock = InvalidBlockNumber; RelationUpdateNumberOfBlocks(relation); } return; } /* * Remove relation from hash tables * * Note: we might be reinserting it momentarily, but we must not have it * visible in the hash tables until it's valid again, so don't try to * optimize this away... */ oldcxt = MemoryContextSwitchTo(CacheMemoryContext); RelationCacheDelete(relation); MemoryContextSwitchTo(oldcxt); /* Clear out catcache's entries for this relation */ CatalogCacheFlushRelation(RelationGetRelid(relation)); /* * Free all the subsidiary data structures of the relcache entry. We * cannot free rd_att if we are trying to rebuild the entry, however, * because pointers to it may be cached in various places. The rule * manager might also have pointers into the rewrite rules. So to * begin with, we can only get rid of these fields: */ FreeTriggerDesc(relation->trigdesc); if (relation->rd_indextuple) pfree(relation->rd_indextuple); if (relation->rd_am) pfree(relation->rd_am); if (relation->rd_rel) pfree(relation->rd_rel); freeList(relation->rd_indexlist); if (relation->rd_indexcxt) MemoryContextDelete(relation->rd_indexcxt); /* * If we're really done with the relcache entry, blow it away. But if * someone is still using it, reconstruct the whole deal without * moving the physical RelationData record (so that the someone's * pointer is still valid). */ if (!rebuild) { /* ok to zap remaining substructure */ FreeTupleDesc(relation->rd_att); if (relation->rd_rulescxt) MemoryContextDelete(relation->rd_rulescxt); pfree(relation); } else { /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?