⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 relcache.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
	/*	 * 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.	 */	rd = RelationBuildDesc(relationId, NULL);	if (RelationIsValid(rd))		RelationIncrementReferenceCount(rd);	return rd;}/* ---------------------------------------------------------------- *				cache invalidation support routines * ---------------------------------------------------------------- *//* * RelationIncrementReferenceCount *		Increments relation reference count. * * Note: bootstrap mode has its own weird ideas about relation refcount * behavior; we ought to fix it someday, but for now, just disable * reference count ownership tracking in bootstrap mode. */voidRelationIncrementReferenceCount(Relation rel){	ResourceOwnerEnlargeRelationRefs(CurrentResourceOwner);	rel->rd_refcnt += 1;	if (!IsBootstrapProcessingMode())		ResourceOwnerRememberRelationRef(CurrentResourceOwner, rel);}/* * RelationDecrementReferenceCount *		Decrements relation reference count. */voidRelationDecrementReferenceCount(Relation rel){	Assert(rel->rd_refcnt > 0);	rel->rd_refcnt -= 1;	if (!IsBootstrapProcessingMode())		ResourceOwnerForgetRelationRef(CurrentResourceOwner, rel);}/* * 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_createSubid == InvalidSubTransactionId)		RelationClearRelation(relation, false);#endif}/* * RelationReloadClassinfo - reload the pg_class row (only) * *	This function is used only for indexes.  We currently allow only the *	pg_class row of an existing index to change (to support changes of *	owner, tablespace, or relfilenode), not its pg_index row or other *	subsidiary index schema information.  Therefore it's sufficient to do *	this when we get an SI invalidation.  Furthermore, there are cases *	where it's necessary not to throw away the index information, especially *	for "nailed" indexes which we are unable to rebuild on-the-fly. * *	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_isvalid to false.  This routine is called to fix the entry when it *	is next needed. */static voidRelationReloadClassinfo(Relation relation){	bool		indexOK;	HeapTuple	pg_class_tuple;	Form_pg_class relp;	/* Should be called only for invalidated indexes */	Assert(relation->rd_rel->relkind == RELKIND_INDEX &&		   !relation->rd_isvalid);	/* Should be closed at smgr level */	Assert(relation->rd_smgr == NULL);	/*	 * Read the pg_class row	 *	 * Don't try to use an indexscan of pg_class_oid_index to reload the info	 * for pg_class_oid_index ...	 */	indexOK = (RelationGetRelid(relation) != ClassOidIndexId);	pg_class_tuple = ScanPgRelation(RelationGetRelid(relation), indexOK);	if (!HeapTupleIsValid(pg_class_tuple))		elog(ERROR, "could not find pg_class tuple for index %u",			 RelationGetRelid(relation));	relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);	memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);	heap_freetuple(pg_class_tuple);	/* We must recalculate physical address in case it changed */	RelationInitPhysicalAddr(relation);	/* Make sure targblock is reset in case rel was truncated */	relation->rd_targblock = InvalidBlockNumber;	/* Okay, now it's valid again */	relation->rd_isvalid = true;}/* * 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){	Oid			old_reltype = relation->rd_rel->reltype;	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.	 */	RelationCloseSmgr(relation);	/*	 * Never, never ever blow away a nailed-in system relation, because we'd	 * be unable to recover.  However, we must 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)	{		relation->rd_targblock = InvalidBlockNumber;		if (relation->rd_rel->relkind == RELKIND_INDEX)		{			relation->rd_isvalid = false;		/* needs to be revalidated */			if (relation->rd_refcnt > 1)				RelationReloadClassinfo(relation);		}		return;	}	/*	 * Even non-system indexes should not be blown away if they are open and	 * have valid index support information.  This avoids problems with active	 * use of the index support information.  As with nailed indexes, we	 * re-read the pg_class row to handle possible physical relocation of	 * the index.	 */	if (relation->rd_rel->relkind == RELKIND_INDEX &&		relation->rd_refcnt > 0 &&		relation->rd_indexcxt != NULL)	{		relation->rd_isvalid = false;			/* needs to be revalidated */		RelationReloadClassinfo(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);	list_free(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 */		flush_rowtype_cache(old_reltype);		FreeTupleDesc(relation->rd_att);		if (relation->rd_rulescxt)			MemoryContextDelete(relation->rd_rulescxt);		pfree(relation);	}	else	{		/*		 * When rebuilding an open relcache entry, must preserve ref count and		 * rd_createSubid state.  Also attempt to preserve the tupledesc and		 * rewrite-rule substructures in place.		 *		 * Note that this process does not touch CurrentResourceOwner; which		 * is good because whatever ref counts the entry may have do not		 * necessarily belong to that resource owner.		 */		Oid			save_relid = RelationGetRelid(relation);		int			old_refcnt = relation->rd_refcnt;		SubTransactionId old_createSubid = relation->rd_createSubid;		TupleDesc	old_att = relation->rd_att;		RuleLock   *old_rules = relation->rd_rules;		MemoryContext old_rulescxt = relation->rd_rulescxt;		if (RelationBuildDesc(save_relid, relation) != relation)		{			/* Should only get here if relation was deleted */			flush_rowtype_cache(old_reltype);			FreeTupleDesc(old_att);			if (old_rulescxt)				MemoryContextDelete(old_rulescxt);			pfree(relation);			elog(ERROR, "relation %u deleted while still in use", save_relid);		}		relation->rd_refcnt = old_refcnt;		relation->rd_createSubid = old_createSubid;		if (equalTupleDescs(old_att, relation->rd_att))		{			/* needn't flush typcache here */			FreeTupleDesc(relation->rd_att);			relation->rd_att = old_att;		}		else		{			flush_rowtype_cache(old_reltype);			FreeTupleDesc(old_att);		}		if (equalRuleLocks(old_rules, relation->rd_rules))		{			if (relation->rd_rulescxt)				MemoryContextDelete(relation->rd_rulescxt);			relation->rd_rules = old_rules;			relation->rd_rulescxt = old_rulescxt;		}		else		{			if (old_rulescxt)				MemoryContextDelete(old_rulescxt);		}	}}/* * RelationFlushRelation * *	 Rebuild the relation if it is open (refcount > 0), else blow it away. */static voidRelationFlushRelation(Relation relation){	bool		rebuild;	if (relation->rd_createSubid != InvalidSubTransactionId)	{		/*		 * New relcache entries are always rebuilt, not flushed; else we'd		 * forget the "new" status of the relation, which is a useful		 * optimization to have.		 */		rebuild = true;	}	else	{		/*		 * Pre-existing rels can be dropped from the relcache if not open.		 */		rebuild = !RelationHasReferenceCountZero(relation);	}	RelationClearRelation(relation, rebuild);}/* * RelationForgetRelation - unconditionally remove a relcache entry * *		   External interface for destroying a relcache entry when we *		   drop the relation. */voidRelationForgetRelation(Oid rid){	Relation	relation;	RelationIdCacheLookup(rid, relation);	if (!PointerIsValid(relation))		return;					/* not in cache, nothing to do */	if (!RelationHasReferenceCountZero(relation))		elog(ERROR, "relation %u is still open", rid);	/* Unconditionally destroy the relcache entry */	RelationClearRelation(relation, false);}/* *		RelationCacheInvalidateEntry * *		This routine is invoked for SI cache flush messages. * * Any relcache entry matching the relid must be flushed.  (Note: caller has * already determined that the relid belongs to our database or is a shared * relation.) * * We used to skip local relations, on the grounds that they could * not be targets of cross-backend SI update messages; but it seems * safer to process them, so that our *own* SI update messages will * have the same effects during CommandCounterIncrement for both * local and nonlocal relations. */voidRelationCacheInvalidateEntry(Oid relationId){	Relation	relation;	RelationIdCacheLookup(relationId, relation);	if (PointerIsValid(relation))	{		relcacheInvalsReceived++;		RelationFlushRelation(relation);	}}/* * RelationCacheInvalidate *	 Blow away cached relation descriptors that have zero reference counts, *	 and rebuild those with positive reference counts.	Also reset the smgr *	 relation cache. * *	 This is currently used only to recover from SI message buffer overflow, *	 so we do not touch new-in-transaction relations; they cannot be targets *	 of cross-backend SI updates (and our own updates now go through a *	 separate linked list that isn't limited by the SI message buffer size). * *	 We do this in two phases: the first pass deletes deletable items, and *	 the second one rebuilds the rebuildable items.  This is essential for *	 safety, because hash_seq_search only copes with concurrent deletion of *	 the element it is currently visiting.	If a second SI overflow were to *	 occur while we are walking the table, resulting in recursive entry to *	 this routine, we could crash because the inner invocation blows away *	 the entry next to be visited by the outer scan.  But this way is OK, *	 because (a) during the first pass we won't process any more SI messages, *	 so hash_seq_search will complete safely; (b) during the second pass we *	 only hold onto pointers to nondeletable entries. * *	 The two-phase approach also makes it easy to ensure that we process *	 nailed-in-cache indexes before other nondeletable items, and that we *	 process pg_class_oid_index first of all.  In scenarios where a nailed *	 index has been given a new relfilenode, we have to detect that update *	 before the nailed index is used in reloading any other relcache entry. */voidRelationCacheInvalidate(void){	HASH_SEQ_STATUS status;	RelIdCacheEnt *idhentry;	Relation	relation;	List	   *rebuildFirstList = NIL;	List	   *rebuildList = NIL;	ListCell   *l;	/* Phase 1 */	hash_seq_init(&status, RelationIdCache);	while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)	{		relation = idhentry->reldesc;		/* Must close all smgr references to avoid leaving dangling ptrs */		RelationCloseSmgr(relation);		/* Ignore new relations, since they are never SI targets */		if (relation->rd_createSubid != InvalidSubTransactionId)			continue;		relcacheInvalsReceived++;		if (RelationHasReferenceCountZero(relation))		{			/* Delete this entry immediately */			Assert(!relation->rd_isnailed);			RelationClearRelation(relation, false);		}		else		{			/*			 * Add this entry to list of stuff to rebuild in second pass.			 * pg_class_oid_index goes on the front of rebuildFirstList, other			 * nailed indexes on the back, and everything else into			 * rebuildList (in no particular order).			 */			if (relation->rd_isnailed &&				relation->rd_rel->relkind == RELKIND_INDEX)			{				if (RelationGetRelid(relation) == ClassOidIndexId)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -