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 + -
显示快捷键?