relcache.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,134 行 · 第 1/5 页

C
2,134
字号
		while (HeapTupleIsValid(htup = systable_getnext(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;		}		systable_endscan(scan);		heap_close(rel, AccessShareLock);	}	/*	 * Scan pg_amproc to obtain support procs for the opclass.	We only fetch	 * the default ones (those with lefttype = righttype = opcintype).	 */	if (numSupport > 0)	{		ScanKeyInit(&skey[0],					Anum_pg_amproc_amprocfamily,					BTEqualStrategyNumber, F_OIDEQ,					ObjectIdGetDatum(opcentry->opcfamily));		ScanKeyInit(&skey[1],					Anum_pg_amproc_amproclefttype,					BTEqualStrategyNumber, F_OIDEQ,					ObjectIdGetDatum(opcentry->opcintype));		ScanKeyInit(&skey[2],					Anum_pg_amproc_amprocrighttype,					BTEqualStrategyNumber, F_OIDEQ,					ObjectIdGetDatum(opcentry->opcintype));		rel = heap_open(AccessMethodProcedureRelationId, AccessShareLock);		scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK,								  SnapshotNow, 3, skey);		while (HeapTupleIsValid(htup = systable_getnext(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(scan);		heap_close(rel, AccessShareLock);	}	opcentry->valid = true;	return opcentry;}/* *		formrdesc * *		This is a special cut-down version of RelationBuildDesc() *		used by RelationCacheInitializePhase2() 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 RelationCacheInitializePhase2). * * 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, Oid relationReltype,		  bool hasoids, int natts, FormData_pg_attribute *att){	Relation	relation;	int			i;	bool		has_not_null;	/*	 * allocate new relation desc, clear all fields of reldesc	 */	relation = (Relation) palloc0(sizeof(RelationData));	relation->rd_targblock = InvalidBlockNumber;	/* make sure relation is marked as having no open file yet */	relation->rd_smgr = NULL;	/*	 * initialize reference count: 1 because it is nailed in cache	 */	relation->rd_refcnt = 1;	/*	 * all entries built with this routine are nailed-in-cache; none are for	 * new or temp relations.	 */	relation->rd_isnailed = true;	relation->rd_createSubid = InvalidSubTransactionId;	relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;	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;	relation->rd_rel->reltype = relationReltype;	/*	 * 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 = hasoids;	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, hasoids);	relation->rd_att->tdrefcount = 1;	/* mark as refcounted */	relation->rd_att->tdtypeid = relationReltype;	relation->rd_att->tdtypmod = -1;	/* unnecessary, but... */	/*	 * initialize tuple desc info	 */	has_not_null = false;	for (i = 0; i < natts; i++)	{		memcpy(relation->rd_att->attrs[i],			   &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;	relation->rd_rel->relfilenode = RelationGetRelid(relation);	/*	 * initialize the relation lock manager information	 */	RelationInitLockInfo(relation);		/* see lmgr.c */	/*	 * initialize physical addressing information for the relation	 */	RelationInitPhysicalAddr(relation);	/*	 * initialize the rel-has-index flag, using hardwired knowledge	 */	if (IsBootstrapProcessingMode())	{		/* In bootstrap mode, we have no indexes */		relation->rd_rel->relhasindex = false;	}	else	{		/* Otherwise, all the rels formrdesc is used for have indexes */		relation->rd_rel->relhasindex = true;	}	/*	 * add new reldesc to relcache	 */	RelationCacheInsert(relation);	/* It's fully valid */	relation->rd_isvalid = true;}/* ---------------------------------------------------------------- *				 Relation Descriptor Lookup Interface * ---------------------------------------------------------------- *//* *		RelationIdGetRelation * *		Lookup a reldesc by OID; make one if not already in cache. * *		Returns NULL if no pg_class row could be found for the given relid *		(suggesting we are trying to access a just-deleted relation). *		Any other error is reported via elog. * *		NB: caller should already have at least AccessShareLock on the *		relation ID, else there are nasty race conditions. * *		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;	/*	 * first try to find reldesc in the cache	 */	RelationIdCacheLookup(relationId, rd);	if (RelationIsValid(rd))	{		RelationIncrementReferenceCount(rd);		/* revalidate nailed index if necessary */		if (!rd->rd_isvalid)			RelationReloadIndexInfo(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 &&		relation->rd_newRelfilenodeSubid == InvalidSubTransactionId)		RelationClearRelation(relation, false);#endif}/* * RelationReloadIndexInfo - reload minimal information for an open index * *	This function is used only for indexes.  A relcache inval on an index *	can mean that its pg_class or pg_index row changed.  There are only *	very limited changes that are allowed to an existing index's schema, *	so we can update the relcache entry without a complete rebuild; which *	is fortunate because we can't rebuild an index entry that is "nailed" *	and/or in active use.  We support full replacement of the pg_class row, *	as well as updates of a few simple fields of the pg_index row. * *	We can't necessarily reread the catalog rows 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. * *	We assume that at the time we are called, we have at least AccessShareLock *	on the target index.  (Note: in the calls from RelationClearRelation, *	this is legitimate because we know the rel has positive refcount.) */static voidRelationReloadIndexInfo(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);	/* Reload reloptions in case they changed */	if (relation->rd_options)		pfree(relation->rd_options);	RelationParseRelOptions(relation, pg_class_tuple);	/* done with pg_class tuple */	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;	/* Must free any AM cached data, too */	if (relation->rd_amcache)		pfree(relation->rd_amcache);	relation->rd_amcache = NULL;	/*	 * For a non-system index, there are fields of the pg_index row that are	 * allowed to change, so re-read that row and update the relcache entry.	 * Most of the info derived from pg_index (such as support function lookup	 * info) cannot change, and indeed the whole point of this routine is to	 * update the relcache entry without clobbering that data; so wholesale	 * replacement is not appropriate.	 */	if (!IsSystemRelation(relation))	{		HeapTuple	tuple;		Form_pg_index index;		tuple = SearchSysCache(INDEXRELID,							   ObjectIdGetDatum(RelationGetRelid(relation)),							   0, 0, 0);		if (!HeapTupleIsValid(tuple))			elog(ERROR, "cache lookup failed for index %u",				 RelationGetRelid(relation));		index = (Form_pg_index) GETSTRUCT(tuple);		relation->rd_index->indisvalid = index->indisvalid;		relation->rd_index->indcheckxmin = index->indcheckxmin;		relation->rd_index->indisready = index->indisready;		HeapTupleHeaderSetXmin(relation->rd_indextuple->t_data,							   HeapTupleHeaderGetXmin(tuple->t_data));		ReleaseSysCache(tuple);	}	/* 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

⌨️ 快捷键说明

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