relcache.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,282 行 · 第 1/5 页

C
2,282
字号
	else		relation->rd_node.tblNode = MyDatabaseId;	relation->rd_node.relNode = relation->rd_rel->relfilenode;	/* make sure relation is marked as having no open file yet */	relation->rd_fd = -1;	/*	 * Insert newly created relation into relcache hash tables.	 */	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);	RelationCacheInsert(relation);	MemoryContextSwitchTo(oldcxt);	/*	 * If it's a temp rel, RelationGetNumberOfBlocks will assume that	 * rd_nblocks is correct.  Must forcibly update the block count when	 * creating the relcache entry.  But if we are doing a rebuild, don't	 * do this yet; leave it to RelationClearRelation to do at the end.	 * (Otherwise, an elog in RelationUpdateNumberOfBlocks would leave us	 * with inconsistent relcache state.)	 */	if (relation->rd_istemp && oldrelation == NULL)		RelationUpdateNumberOfBlocks(relation);	return relation;}/* * Initialize index-access-method support data for an index relation */voidRelationInitIndexAccessInfo(Relation relation){	HeapTuple	tuple;	Form_pg_am	aform;	MemoryContext indexcxt;	MemoryContext oldcontext;	IndexStrategy strategy;	Oid		   *operator;	RegProcedure *support;	FmgrInfo   *supportinfo;	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	 */	if (amstrategies > 0)	{		int			noperators = natts * amstrategies;		Size		stratSize;		stratSize = AttributeNumberGetIndexStrategySize(natts, amstrategies);		strategy = (IndexStrategy) MemoryContextAlloc(indexcxt, stratSize);		MemSet(strategy, 0, stratSize);		operator = (Oid *)			MemoryContextAlloc(indexcxt, noperators * sizeof(Oid));		MemSet(operator, 0, noperators * sizeof(Oid));	}	else	{		strategy = NULL;		operator = NULL;	}	if (amsupport > 0)	{		int			nsupport = natts * amsupport;		support = (RegProcedure *)			MemoryContextAlloc(indexcxt, nsupport * sizeof(RegProcedure));		MemSet(support, 0, nsupport * sizeof(RegProcedure));		supportinfo = (FmgrInfo *)			MemoryContextAlloc(indexcxt, nsupport * sizeof(FmgrInfo));		MemSet(supportinfo, 0, nsupport * sizeof(FmgrInfo));	}	else	{		support = NULL;		supportinfo = NULL;	}	relation->rd_istrat = strategy;	relation->rd_operator = operator;	relation->rd_support = support;	relation->rd_supportinfo = supportinfo;	/*	 * Fill the strategy map and the support RegProcedure arrays.	 * (supportinfo is left as zeroes, and is filled on-the-fly when used)	 */	IndexSupportInitialize(relation->rd_index,						   strategy, operator, support,						   amstrategies, amsupport, natts);	/*	 * expressions and predicate cache will be filled later	 */	relation->rd_indexprs = NIL;	relation->rd_indpred = NIL;}/* * IndexSupportInitialize *		Initializes an index strategy and associated support procedures, *		given the index's pg_index tuple. * * Data is returned into *indexStrategy, *indexOperator, and *indexSupport, * all of which are objects 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(Form_pg_index iform,					   IndexStrategy indexStrategy,					   Oid *indexOperator,					   RegProcedure *indexSupport,					   StrategyNumber maxStrategyNumber,					   StrategyNumber maxSupportNumber,					   AttrNumber maxAttributeNumber){	int			attIndex;	maxStrategyNumber = AMStrategies(maxStrategyNumber);	/*	 * XXX note that the following assumes the INDEX tuple is well formed	 * and that the *key and *class are 0 terminated.	 */	for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)	{		OpClassCacheEnt *opcentry;		if (!OidIsValid(iform->indclass[attIndex]))			elog(ERROR, "bogus pg_index tuple");		/* look up the info for this opclass, using a cache */		opcentry = LookupOpclassInfo(iform->indclass[attIndex],									 maxStrategyNumber,									 maxSupportNumber);		/* load the strategy information for the index operators */		if (maxStrategyNumber > 0)		{			StrategyMap map;			Oid		   *opers;			StrategyNumber strategy;			map = IndexStrategyGetStrategyMap(indexStrategy,											  maxStrategyNumber,											  attIndex + 1);			opers = &indexOperator[attIndex * maxStrategyNumber];			for (strategy = 0; strategy < maxStrategyNumber; strategy++)			{				ScanKey		mapentry;				mapentry = StrategyMapGetScanKeyEntry(map, strategy + 1);				if (RegProcedureIsValid(opcentry->operatorProcs[strategy]))				{					MemSet(mapentry, 0, sizeof(*mapentry));					mapentry->sk_flags = 0;					mapentry->sk_procedure = opcentry->operatorProcs[strategy];					/*					 * Mark mapentry->sk_func invalid, until and unless					 * someone sets it up.					 */					mapentry->sk_func.fn_oid = InvalidOid;				}				else					ScanKeyEntrySetIllegal(mapentry);				opers[strategy] = opcentry->operatorOids[strategy];			}		}		/* if support routines exist for this access method, load them */		if (maxSupportNumber > 0)		{			RegProcedure *procs;			StrategyNumber support;			procs = &indexSupport[attIndex * maxSupportNumber];			for (support = 0; support < maxSupportNumber; ++support)				procs[support] = opcentry->supportProcs[support];		}	}}/* * 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. * * XXX There isn't any provision for flushing the cache.  However, there * isn't any provision for flushing relcache entries when opclass info * changes, either :-( */static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,				  StrategyNumber numStrats,				  StrategyNumber numSupport){	OpClassCacheEnt *opcentry;	bool		found;	Relation	pg_amop_desc;	Relation	pg_amproc_desc;	SysScanDesc pg_amop_scan;	SysScanDesc pg_amproc_scan;	ScanKeyData key;	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 = tag_hash;		OpClassCache = hash_create("Operator class cache", 64,								   &ctl, HASH_ELEM | HASH_FUNCTION);	}	opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,											   (void *) &operatorClassOid,											   HASH_ENTER, &found);	if (opcentry == NULL)		ereport(ERROR,				(errcode(ERRCODE_OUT_OF_MEMORY),				 errmsg("out of memory")));	if (found && opcentry->valid)	{		/* Already made an entry for it */		Assert(numStrats == opcentry->numStrats);		Assert(numSupport == opcentry->numSupport);		return opcentry;	}	/* Need to fill in new entry */	opcentry->valid = false;	/* until known OK */	opcentry->numStrats = numStrats;	opcentry->numSupport = numSupport;	if (numStrats > 0)	{		opcentry->operatorOids = (Oid *)			MemoryContextAlloc(CacheMemoryContext,							   numStrats * sizeof(Oid));		MemSet(opcentry->operatorOids, 0, numStrats * sizeof(Oid));		opcentry->operatorProcs = (RegProcedure *)			MemoryContextAlloc(CacheMemoryContext,							   numStrats * sizeof(RegProcedure));		MemSet(opcentry->operatorProcs, 0, numStrats * sizeof(RegProcedure));	}	else	{		opcentry->operatorOids = NULL;		opcentry->operatorProcs = NULL;	}	if (numSupport > 0)	{		opcentry->supportProcs = (RegProcedure *)			MemoryContextAlloc(CacheMemoryContext,							   numSupport * sizeof(RegProcedure));		MemSet(opcentry->supportProcs, 0, numSupport * sizeof(RegProcedure));	}	else		opcentry->supportProcs = NULL;	/*	 * To avoid infinite recursion during startup, force a heap scan 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);	/*	 * Scan pg_amop to obtain operators for the opclass	 */	if (numStrats > 0)	{		ScanKeyEntryInitialize(&key, 0,							   Anum_pg_amop_amopclaid,							   F_OIDEQ,							   ObjectIdGetDatum(operatorClassOid));		pg_amop_desc = heap_openr(AccessMethodOperatorRelationName,								  AccessShareLock);		pg_amop_scan = systable_beginscan(pg_amop_desc,										  AccessMethodStrategyIndex,										  indexOK,										  SnapshotNow,										  1, &key);		while (HeapTupleIsValid(htup = systable_getnext(pg_amop_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;			opcentry->operatorProcs[amopform->amopstrategy - 1] =				get_opcode(amopform->amopopr);		}		systable_endscan(pg_amop_scan);		heap_close(pg_amop_desc, AccessShareLock);	}	/*	 * Scan pg_amproc to obtain support procs for the opclass	 */	if (numSupport > 0)	{		ScanKeyEntryInitialize(&key, 0,							   Anum_pg_amproc_amopclaid,							   F_OIDEQ,							   ObjectIdGetDatum(operatorClassOid));		pg_amproc_desc = heap_openr(AccessMethodProcedureRelationName,									AccessShareLock);		pg_amproc_scan = systable_beginscan(pg_amproc_desc,											AccessMethodProcedureIndex,											indexOK,											SnapshotNow,											1, &key);		while (HeapTupleIsValid(htup = systable_getnext(pg_amproc_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(pg_amproc_scan);		heap_close(pg_amproc_desc, AccessShareLock);	}	opcentry->valid = true;	return opcentry;}/* *		formrdesc * *		This is a special cut-down version of RelationBuildDesc() *		used by RelationCacheInitialize() 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 RelationCacheInitialize). * * 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,		  int natts,		  FormData_pg_attribute *att){	Relation	relation;	int			i;	bool		has_not_null;	/*	 * allocate new relation desc clear all fields of reldesc

⌨️ 快捷键说明

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