relcache.c

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

C
2,134
字号
	 */	if (relation->rd_rel->relhasrules)		RelationBuildRuleLock(relation);	else	{		relation->rd_rules = NULL;		relation->rd_rulescxt = NULL;	}	if (relation->rd_rel->reltriggers > 0)		RelationBuildTriggers(relation);	else		relation->trigdesc = NULL;	/*	 * if it's an index, initialize index-related information	 */	if (OidIsValid(relation->rd_rel->relam))		RelationInitIndexAccessInfo(relation);	/* extract reloptions if any */	RelationParseRelOptions(relation, pg_class_tuple);	/*	 * initialize the relation lock manager information	 */	RelationInitLockInfo(relation);		/* see lmgr.c */	/*	 * initialize physical addressing information for the relation	 */	RelationInitPhysicalAddr(relation);	/* make sure relation is marked as having no open file yet */	relation->rd_smgr = NULL;	/*	 * now we can free the memory allocated for pg_class_tuple	 */	heap_freetuple(pg_class_tuple);	/*	 * Insert newly created relation into relcache hash tables.	 */	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);	RelationCacheInsert(relation);	MemoryContextSwitchTo(oldcxt);	/* It's fully valid */	relation->rd_isvalid = true;	return relation;}/* * Initialize the physical addressing info (RelFileNode) for a relcache entry */static voidRelationInitPhysicalAddr(Relation relation){	if (relation->rd_rel->reltablespace)		relation->rd_node.spcNode = relation->rd_rel->reltablespace;	else		relation->rd_node.spcNode = MyDatabaseTableSpace;	if (relation->rd_rel->relisshared)		relation->rd_node.dbNode = InvalidOid;	else		relation->rd_node.dbNode = MyDatabaseId;	relation->rd_node.relNode = relation->rd_rel->relfilenode;}/* * Initialize index-access-method support data for an index relation */voidRelationInitIndexAccessInfo(Relation relation){	HeapTuple	tuple;	Form_pg_am	aform;	Datum		indclassDatum;	Datum		indoptionDatum;	bool		isnull;	oidvector  *indclass;	int2vector *indoption;	MemoryContext indexcxt;	MemoryContext oldcontext;	int			natts;	uint16		amstrategies;	uint16		amsupport;	/*	 * Make a copy of the pg_index entry for the index.  Since pg_index	 * contains variable-length and possibly-null fields, we have to do this	 * honestly rather than just treating it as a Form_pg_index struct.	 */	tuple = SearchSysCache(INDEXRELID,						   ObjectIdGetDatum(RelationGetRelid(relation)),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "cache lookup failed for index %u",			 RelationGetRelid(relation));	oldcontext = MemoryContextSwitchTo(CacheMemoryContext);	relation->rd_indextuple = heap_copytuple(tuple);	relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple);	MemoryContextSwitchTo(oldcontext);	ReleaseSysCache(tuple);	/*	 * Make a copy of the pg_am entry for the index's access method	 */	tuple = SearchSysCache(AMOID,						   ObjectIdGetDatum(relation->rd_rel->relam),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "cache lookup failed for access method %u",			 relation->rd_rel->relam);	aform = (Form_pg_am) MemoryContextAlloc(CacheMemoryContext, sizeof *aform);	memcpy(aform, GETSTRUCT(tuple), sizeof *aform);	ReleaseSysCache(tuple);	relation->rd_am = aform;	natts = relation->rd_rel->relnatts;	if (natts != relation->rd_index->indnatts)		elog(ERROR, "relnatts disagrees with indnatts for index %u",			 RelationGetRelid(relation));	amstrategies = aform->amstrategies;	amsupport = aform->amsupport;	/*	 * Make the private context to hold index access info.	The reason we need	 * a context, and not just a couple of pallocs, is so that we won't leak	 * any subsidiary info attached to fmgr lookup records.	 *	 * Context parameters are set on the assumption that it'll probably not	 * contain much data.	 */	indexcxt = AllocSetContextCreate(CacheMemoryContext,									 RelationGetRelationName(relation),									 ALLOCSET_SMALL_MINSIZE,									 ALLOCSET_SMALL_INITSIZE,									 ALLOCSET_SMALL_MAXSIZE);	relation->rd_indexcxt = indexcxt;	/*	 * Allocate arrays to hold data	 */	relation->rd_aminfo = (RelationAmInfo *)		MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));	relation->rd_opfamily = (Oid *)		MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));	relation->rd_opcintype = (Oid *)		MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));	if (amstrategies > 0)		relation->rd_operator = (Oid *)			MemoryContextAllocZero(indexcxt,								   natts * amstrategies * sizeof(Oid));	else		relation->rd_operator = NULL;	if (amsupport > 0)	{		int			nsupport = natts * amsupport;		relation->rd_support = (RegProcedure *)			MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));		relation->rd_supportinfo = (FmgrInfo *)			MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));	}	else	{		relation->rd_support = NULL;		relation->rd_supportinfo = NULL;	}	relation->rd_indoption = (int16 *)		MemoryContextAllocZero(indexcxt, natts * sizeof(int16));	/*	 * indclass cannot be referenced directly through the C struct, because it	 * comes after the variable-width indkey field.  Must extract the datum	 * the hard way...	 */	indclassDatum = fastgetattr(relation->rd_indextuple,								Anum_pg_index_indclass,								GetPgIndexDescriptor(),								&isnull);	Assert(!isnull);	indclass = (oidvector *) DatumGetPointer(indclassDatum);	/*	 * Fill the operator and support procedure OID arrays, as well as the info	 * about opfamilies and opclass input types.  (aminfo and supportinfo are	 * left as zeroes, and are filled on-the-fly when used)	 */	IndexSupportInitialize(indclass,						   relation->rd_operator, relation->rd_support,						   relation->rd_opfamily, relation->rd_opcintype,						   amstrategies, amsupport, natts);	/*	 * Similarly extract indoption and copy it to the cache entry	 */	indoptionDatum = fastgetattr(relation->rd_indextuple,								 Anum_pg_index_indoption,								 GetPgIndexDescriptor(),								 &isnull);	Assert(!isnull);	indoption = (int2vector *) DatumGetPointer(indoptionDatum);	memcpy(relation->rd_indoption, indoption->values, natts * sizeof(int16));	/*	 * expressions and predicate cache will be filled later	 */	relation->rd_indexprs = NIL;	relation->rd_indpred = NIL;	relation->rd_amcache = NULL;}/* * IndexSupportInitialize *		Initializes an index's cached opclass information, *		given the index's pg_index.indclass entry. * * Data is returned into *indexOperator, *indexSupport, *opFamily, and * *opcInType, which are arrays allocated by the caller. * * The caller also passes maxStrategyNumber, maxSupportNumber, and * maxAttributeNumber, since these indicate the size of the arrays * it has allocated --- but in practice these numbers must always match * those obtainable from the system catalog entries for the index and * access method. */static voidIndexSupportInitialize(oidvector *indclass,					   Oid *indexOperator,					   RegProcedure *indexSupport,					   Oid *opFamily,					   Oid *opcInType,					   StrategyNumber maxStrategyNumber,					   StrategyNumber maxSupportNumber,					   AttrNumber maxAttributeNumber){	int			attIndex;	for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)	{		OpClassCacheEnt *opcentry;		if (!OidIsValid(indclass->values[attIndex]))			elog(ERROR, "bogus pg_index tuple");		/* look up the info for this opclass, using a cache */		opcentry = LookupOpclassInfo(indclass->values[attIndex],									 maxStrategyNumber,									 maxSupportNumber);		/* copy cached data into relcache entry */		opFamily[attIndex] = opcentry->opcfamily;		opcInType[attIndex] = opcentry->opcintype;		if (maxStrategyNumber > 0)			memcpy(&indexOperator[attIndex * maxStrategyNumber],				   opcentry->operatorOids,				   maxStrategyNumber * sizeof(Oid));		if (maxSupportNumber > 0)			memcpy(&indexSupport[attIndex * maxSupportNumber],				   opcentry->supportProcs,				   maxSupportNumber * sizeof(RegProcedure));	}}/* * LookupOpclassInfo * * This routine maintains a per-opclass cache of the information needed * by IndexSupportInitialize().  This is more efficient than relying on * the catalog cache, because we can load all the info about a particular * opclass in a single indexscan of pg_amproc or pg_amop. * * The information from pg_am about expected range of strategy and support * numbers is passed in, rather than being looked up, mainly because the * caller will have it already. * * Note there is no provision for flushing the cache.  This is OK at the * moment because there is no way to ALTER any interesting properties of an * existing opclass --- all you can do is drop it, which will result in * a useless but harmless dead entry in the cache.  To support altering * opclass membership (not the same as opfamily membership!), we'd need to * be able to flush this cache as well as the contents of relcache entries * for indexes. */static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,				  StrategyNumber numStrats,				  StrategyNumber numSupport){	OpClassCacheEnt *opcentry;	bool		found;	Relation	rel;	SysScanDesc scan;	ScanKeyData skey[3];	HeapTuple	htup;	bool		indexOK;	if (OpClassCache == NULL)	{		/* First time through: initialize the opclass cache */		HASHCTL		ctl;		if (!CacheMemoryContext)			CreateCacheMemoryContext();		MemSet(&ctl, 0, sizeof(ctl));		ctl.keysize = sizeof(Oid);		ctl.entrysize = sizeof(OpClassCacheEnt);		ctl.hash = oid_hash;		OpClassCache = hash_create("Operator class cache", 64,								   &ctl, HASH_ELEM | HASH_FUNCTION);	}	opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,											   (void *) &operatorClassOid,											   HASH_ENTER, &found);	if (!found)	{		/* Need to allocate memory for new entry */		opcentry->valid = false;	/* until known OK */		opcentry->numStrats = numStrats;		opcentry->numSupport = numSupport;		if (numStrats > 0)			opcentry->operatorOids = (Oid *)				MemoryContextAllocZero(CacheMemoryContext,									   numStrats * sizeof(Oid));		else			opcentry->operatorOids = NULL;		if (numSupport > 0)			opcentry->supportProcs = (RegProcedure *)				MemoryContextAllocZero(CacheMemoryContext,									   numSupport * sizeof(RegProcedure));		else			opcentry->supportProcs = NULL;	}	else	{		Assert(numStrats == opcentry->numStrats);		Assert(numSupport == opcentry->numSupport);	}	/*	 * When testing for cache-flush hazards, we intentionally disable the	 * operator class cache and force reloading of the info on each call.	 * This is helpful because we want to test the case where a cache flush	 * occurs while we are loading the info, and it's very hard to provoke	 * that if this happens only once per opclass per backend.	 */#if defined(CLOBBER_CACHE_ALWAYS)	opcentry->valid = false;#endif	if (opcentry->valid)		return opcentry;	/*	 * Need to fill in new entry.	 *	 * To avoid infinite recursion during startup, force heap scans if we're	 * looking up info for the opclasses used by the indexes we would like to	 * reference here.	 */	indexOK = criticalRelcachesBuilt ||		(operatorClassOid != OID_BTREE_OPS_OID &&		 operatorClassOid != INT2_BTREE_OPS_OID);	/*	 * We have to fetch the pg_opclass row to determine its opfamily and	 * opcintype, which are needed to look up the operators and functions.	 * It'd be convenient to use the syscache here, but that probably doesn't	 * work while bootstrapping.	 */	ScanKeyInit(&skey[0],				ObjectIdAttributeNumber,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(operatorClassOid));	rel = heap_open(OperatorClassRelationId, AccessShareLock);	scan = systable_beginscan(rel, OpclassOidIndexId, indexOK,							  SnapshotNow, 1, skey);	if (HeapTupleIsValid(htup = systable_getnext(scan)))	{		Form_pg_opclass opclassform = (Form_pg_opclass) GETSTRUCT(htup);		opcentry->opcfamily = opclassform->opcfamily;		opcentry->opcintype = opclassform->opcintype;	}	else		elog(ERROR, "could not find tuple for opclass %u", operatorClassOid);	systable_endscan(scan);	heap_close(rel, AccessShareLock);	/*	 * Scan pg_amop to obtain operators for the opclass.  We only fetch the	 * default ones (those with lefttype = righttype = opcintype).	 */	if (numStrats > 0)	{		ScanKeyInit(&skey[0],					Anum_pg_amop_amopfamily,					BTEqualStrategyNumber, F_OIDEQ,					ObjectIdGetDatum(opcentry->opcfamily));		ScanKeyInit(&skey[1],					Anum_pg_amop_amoplefttype,					BTEqualStrategyNumber, F_OIDEQ,					ObjectIdGetDatum(opcentry->opcintype));		ScanKeyInit(&skey[2],					Anum_pg_amop_amoprighttype,					BTEqualStrategyNumber, F_OIDEQ,					ObjectIdGetDatum(opcentry->opcintype));		rel = heap_open(AccessMethodOperatorRelationId, AccessShareLock);		scan = systable_beginscan(rel, AccessMethodStrategyIndexId, indexOK,								  SnapshotNow, 3, skey);

⌨️ 快捷键说明

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