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

📄 catcache.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 4 页
字号:
	 */	lHashValue = CatalogCacheComputeHashValue(cache, nkeys, cur_skey);	/*	 * scan the items until we find a match or exhaust our list	 */	for (elt = DLGetHead(&cache->cc_lists);		 elt;		 elt = DLGetSucc(elt))	{		bool		res;		cl = (CatCList *) DLE_VAL(elt);		if (cl->dead)			continue;			/* ignore dead entries */		if (cl->hash_value != lHashValue)			continue;			/* quickly skip entry if wrong hash val */		/*		 * see if the cached list matches our key.		 */		if (cl->nkeys != nkeys)			continue;		HeapKeyTest(&cl->tuple,					cache->cc_tupdesc,					nkeys,					cur_skey,					res);		if (!res)			continue;		/*		 * We found a matching list.  Move the list to the front of the		 * cache's list-of-lists, to speed subsequent searches.  (We do not		 * move the members to the fronts of their hashbucket lists, however,		 * since there's no point in that unless they are searched for		 * individually.)		 */		DLMoveToFront(&cl->cache_elem);		/* Bump the list's refcount and return it */		ResourceOwnerEnlargeCatCacheListRefs(CurrentResourceOwner);		cl->refcount++;		ResourceOwnerRememberCatCacheListRef(CurrentResourceOwner, cl);		CACHE2_elog(DEBUG2, "SearchCatCacheList(%s): found list",					cache->cc_relname);#ifdef CATCACHE_STATS		cache->cc_lhits++;#endif		return cl;	}	/*	 * List was not found in cache, so we have to build it by reading the	 * relation.  For each matching tuple found in the relation, use an	 * existing cache entry if possible, else build a new one.	 *	 * We have to bump the member refcounts temporarily to ensure they won't	 * get dropped from the cache while loading other members. We use a PG_TRY	 * block to ensure we can undo those refcounts if we get an error before	 * we finish constructing the CatCList.	 */	ResourceOwnerEnlargeCatCacheListRefs(CurrentResourceOwner);	ctlist = NIL;	PG_TRY();	{		Relation	relation;		SysScanDesc scandesc;		relation = heap_open(cache->cc_reloid, AccessShareLock);		scandesc = systable_beginscan(relation,									  cache->cc_indexoid,									  true,									  SnapshotNow,									  nkeys,									  cur_skey);		/* The list will be ordered iff we are doing an index scan */		ordered = (scandesc->irel != NULL);		while (HeapTupleIsValid(ntp = systable_getnext(scandesc)))		{			uint32		hashValue;			Index		hashIndex;			/*			 * See if there's an entry for this tuple already.			 */			ct = NULL;			hashValue = CatalogCacheComputeTupleHashValue(cache, ntp);			hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);			for (elt = DLGetHead(&cache->cc_bucket[hashIndex]);				 elt;				 elt = DLGetSucc(elt))			{				ct = (CatCTup *) DLE_VAL(elt);				if (ct->dead || ct->negative)					continue;	/* ignore dead and negative entries */				if (ct->hash_value != hashValue)					continue;	/* quickly skip entry if wrong hash val */				if (!ItemPointerEquals(&(ct->tuple.t_self), &(ntp->t_self)))					continue;	/* not same tuple */				/*				 * Found a match, but can't use it if it belongs to another				 * list already				 */				if (ct->c_list)					continue;				break;			/* A-OK */			}			if (elt == NULL)			{				/* We didn't find a usable entry, so make a new one */				ct = CatalogCacheCreateEntry(cache, ntp,											 hashValue, hashIndex,											 false);			}			/* Careful here: add entry to ctlist, then bump its refcount */			/* This way leaves state correct if lappend runs out of memory */			ctlist = lappend(ctlist, ct);			ct->refcount++;		}		systable_endscan(scandesc);		heap_close(relation, AccessShareLock);		/*		 * Now we can build the CatCList entry.  First we need a dummy tuple		 * containing the key values...		 */		ntp = build_dummy_tuple(cache, nkeys, cur_skey);		oldcxt = MemoryContextSwitchTo(CacheMemoryContext);		nmembers = list_length(ctlist);		cl = (CatCList *)			palloc(sizeof(CatCList) + nmembers * sizeof(CatCTup *));		heap_copytuple_with_tuple(ntp, &cl->tuple);		MemoryContextSwitchTo(oldcxt);		heap_freetuple(ntp);		/*		 * We are now past the last thing that could trigger an elog before we		 * have finished building the CatCList and remembering it in the		 * resource owner.	So it's OK to fall out of the PG_TRY, and indeed		 * we'd better do so before we start marking the members as belonging		 * to the list.		 */	}	PG_CATCH();	{		foreach(ctlist_item, ctlist)		{			ct = (CatCTup *) lfirst(ctlist_item);			Assert(ct->c_list == NULL);			Assert(ct->refcount > 0);			ct->refcount--;			if (#ifndef CATCACHE_FORCE_RELEASE				ct->dead &&#endif				ct->refcount == 0 &&				(ct->c_list == NULL || ct->c_list->refcount == 0))				CatCacheRemoveCTup(cache, ct);		}		PG_RE_THROW();	}	PG_END_TRY();	cl->cl_magic = CL_MAGIC;	cl->my_cache = cache;	DLInitElem(&cl->cache_elem, cl);	cl->refcount = 0;			/* for the moment */	cl->dead = false;	cl->ordered = ordered;	cl->nkeys = nkeys;	cl->hash_value = lHashValue;	cl->n_members = nmembers;	i = 0;	foreach(ctlist_item, ctlist)	{		cl->members[i++] = ct = (CatCTup *) lfirst(ctlist_item);		Assert(ct->c_list == NULL);		ct->c_list = cl;		/* release the temporary refcount on the member */		Assert(ct->refcount > 0);		ct->refcount--;		/* mark list dead if any members already dead */		if (ct->dead)			cl->dead = true;	}	Assert(i == nmembers);	DLAddHead(&cache->cc_lists, &cl->cache_elem);	/* Finally, bump the list's refcount and return it */	cl->refcount++;	ResourceOwnerRememberCatCacheListRef(CurrentResourceOwner, cl);	CACHE3_elog(DEBUG2, "SearchCatCacheList(%s): made list of %d members",				cache->cc_relname, nmembers);	return cl;}/* *	ReleaseCatCacheList * *	Decrement the reference count of a catcache list. */voidReleaseCatCacheList(CatCList *list){	/* Safety checks to ensure we were handed a cache entry */	Assert(list->cl_magic == CL_MAGIC);	Assert(list->refcount > 0);	list->refcount--;	ResourceOwnerForgetCatCacheListRef(CurrentResourceOwner, list);	if (#ifndef CATCACHE_FORCE_RELEASE		list->dead &&#endif		list->refcount == 0)		CatCacheRemoveCList(list->my_cache, list);}/* * CatalogCacheCreateEntry *		Create a new CatCTup entry, copying the given HeapTuple and other *		supplied data into it.	The new entry initially has refcount 0. */static CatCTup *CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp,						uint32 hashValue, Index hashIndex, bool negative){	CatCTup    *ct;	MemoryContext oldcxt;	/*	 * Allocate CatCTup header in cache memory, and copy the tuple there too.	 */	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);	ct = (CatCTup *) palloc(sizeof(CatCTup));	heap_copytuple_with_tuple(ntp, &ct->tuple);	MemoryContextSwitchTo(oldcxt);	/*	 * Finish initializing the CatCTup header, and add it to the cache's	 * linked list and counts.	 */	ct->ct_magic = CT_MAGIC;	ct->my_cache = cache;	DLInitElem(&ct->cache_elem, (void *) ct);	ct->c_list = NULL;	ct->refcount = 0;			/* for the moment */	ct->dead = false;	ct->negative = negative;	ct->hash_value = hashValue;	DLAddHead(&cache->cc_bucket[hashIndex], &ct->cache_elem);	cache->cc_ntup++;	CacheHdr->ch_ntup++;	return ct;}/* * build_dummy_tuple *		Generate a palloc'd HeapTuple that contains the specified key *		columns, and NULLs for other columns. * * This is used to store the keys for negative cache entries and CatCList * entries, which don't have real tuples associated with them. */static HeapTuplebuild_dummy_tuple(CatCache *cache, int nkeys, ScanKey skeys){	HeapTuple	ntp;	TupleDesc	tupDesc = cache->cc_tupdesc;	Datum	   *values;	char	   *nulls;	Oid			tupOid = InvalidOid;	NameData	tempNames[4];	int			i;	values = (Datum *) palloc(tupDesc->natts * sizeof(Datum));	nulls = (char *) palloc(tupDesc->natts * sizeof(char));	memset(values, 0, tupDesc->natts * sizeof(Datum));	memset(nulls, 'n', tupDesc->natts * sizeof(char));	for (i = 0; i < nkeys; i++)	{		int			attindex = cache->cc_key[i];		Datum		keyval = skeys[i].sk_argument;		if (attindex > 0)		{			/*			 * Here we must be careful in case the caller passed a C string			 * where a NAME is wanted: convert the given argument to a			 * correctly padded NAME.  Otherwise the memcpy() done in			 * heap_formtuple could fall off the end of memory.			 */			if (cache->cc_isname[i])			{				Name		newval = &tempNames[i];				namestrcpy(newval, DatumGetCString(keyval));				keyval = NameGetDatum(newval);			}			values[attindex - 1] = keyval;			nulls[attindex - 1] = ' ';		}		else		{			Assert(attindex == ObjectIdAttributeNumber);			tupOid = DatumGetObjectId(keyval);		}	}	ntp = heap_formtuple(tupDesc, values, nulls);	if (tupOid != InvalidOid)		HeapTupleSetOid(ntp, tupOid);	pfree(values);	pfree(nulls);	return ntp;}/* *	PrepareToInvalidateCacheTuple() * *	This is part of a rather subtle chain of events, so pay attention: * *	When a tuple is inserted or deleted, it cannot be flushed from the *	catcaches immediately, for reasons explained at the top of cache/inval.c. *	Instead we have to add entry(s) for the tuple to a list of pending tuple *	invalidations that will be done at the end of the command or transaction. * *	The lists of tuples that need to be flushed are kept by inval.c.  This *	routine is a helper routine for inval.c.  Given a tuple belonging to *	the specified relation, find all catcaches it could be in, compute the *	correct hash value for each such catcache, and call the specified function *	to record the cache id, hash value, and tuple ItemPointer in inval.c's *	lists.	CatalogCacheIdInvalidate will be called later, if appropriate, *	using the recorded information. * *	Note that it is irrelevant whether the given tuple is actually loaded *	into the catcache at the moment.  Even if it's not there now, it might *	be by the end of the command, or there might be a matching negative entry *	to flush --- or other backends' caches might have such entries --- so *	we have to make list entries to flush it later. * *	Also note that it's not an error if there are no catcaches for the *	specified relation.  inval.c doesn't know exactly which rels have *	catcaches --- it will call this routine for any tuple that's in a *	system relation. */voidPrepareToInvalidateCacheTuple(Relation relation,							  HeapTuple tuple,							void (*function) (int, uint32, ItemPointer, Oid)){	CatCache   *ccp;	Oid			reloid;	CACHE1_elog(DEBUG2, "PrepareToInvalidateCacheTuple: called");	/*	 * sanity checks	 */	Assert(RelationIsValid(relation));	Assert(HeapTupleIsValid(tuple));	Assert(PointerIsValid(function));	Assert(CacheHdr != NULL);	reloid = RelationGetRelid(relation);	/* ----------------	 *	for each cache	 *	   if the cache contains tuples from the specified relation	 *		   compute the tuple's hash value in this cache,	 *		   and call the passed function to register the information.	 * ----------------	 */	for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next)	{		if (ccp->cc_reloid != reloid)			continue;		/* Just in case cache hasn't finished initialization yet... */		if (ccp->cc_tupdesc == NULL)			CatalogCacheInitializeCache(ccp);		(*function) (ccp->id,					 CatalogCacheComputeTupleHashValue(ccp, tuple),					 &tuple->t_self,					 ccp->cc_relisshared ? (Oid) 0 : MyDatabaseId);	}}/* * Subroutines for warning about reference leaks.  These are exported so * that resowner.c can call them. */voidPrintCatCacheLeakWarning(HeapTuple tuple){	CatCTup    *ct = (CatCTup *) (((char *) tuple) -								  offsetof(CatCTup, tuple));	/* Safety check to ensure we were handed a cache entry */	Assert(ct->ct_magic == CT_MAGIC);	elog(WARNING, "cache reference leak: cache %s (%d), tuple %u/%u has count %d",		 ct->my_cache->cc_relname, ct->my_cache->id,		 ItemPointerGetBlockNumber(&(tuple->t_self)),		 ItemPointerGetOffsetNumber(&(tuple->t_self)),		 ct->refcount);}voidPrintCatCacheListLeakWarning(CatCList *list){	elog(WARNING, "cache reference leak: cache %s (%d), list %p has count %d",		 list->my_cache->cc_relname, list->my_cache->id,		 list, list->refcount);}

⌨️ 快捷键说明

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