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

📄 catcache.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 2 页
字号:
				CatCacheRemoveCTup(cache, elt);				if (cache->cc_ntup < 0)					elog(NOTICE,						 "ResetSystemCache: cc_ntup<0 (software error)");			}		}		cache->cc_ntup = 0;		/* in case of WARN error above */		cache->busy = false;	/* to recover from recursive-use error */	}	CACHE1_elog(DEBUG, "end of ResetSystemCache call");	/* ----------------	 *	back to the old context before we return...	 * ----------------	 */	MemoryContextSwitchTo(oldcxt);}/* -------------------------------- *		SystemCacheRelationFlushed * *	This is called by RelationFlushRelation() to clear out cached information *	about a relation being dropped.  (This could be a DROP TABLE command, *	or a temp table being dropped at end of transaction, or a table created *	during the current transaction that is being dropped because of abort.) *	Remove all cache entries relevant to the specified relation OID. * *	A special case occurs when relId is itself one of the cacheable system *	tables --- although those'll never be dropped, they can get flushed from *	the relcache (VACUUM causes this, for example).  In that case we need to *	force the next SearchSysCache() call to reinitialize the cache itself, *	because we have info (such as cc_tupdesc) that is pointing at the about- *	to-be-deleted relcache entry. * -------------------------------- */voidSystemCacheRelationFlushed(Oid relId){	struct catcache *cache;	/*	 * XXX Ideally we'd search the caches and just zap entries that actually	 * refer to the indicated relation.  For now, we take the brute-force	 * approach: just flush the caches entirely.	 */	ResetSystemCache();	/*	 * If relcache is dropping a system relation's cache entry, mark the	 * associated cache structures invalid, so we can rebuild them from	 * scratch (not just repopulate them) next time they are used.	 */	for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next)	{		if (cache->relationId == relId)			cache->relationId = InvalidOid;	}}/* -------------------------------- *		InitIndexedSysCache * *	This allocates and initializes a cache for a system catalog relation. *	Actually, the cache is only partially initialized to avoid opening the *	relation.  The relation will be opened and the rest of the cache *	structure initialized on the first access. * -------------------------------- */#ifdef CACHEDEBUG#define InitSysCache_DEBUG1 \do { \	elog(DEBUG, "InitSysCache: rid=%u id=%d nkeys=%d size=%d\n", \		cp->relationId, cp->id, cp->cc_nkeys, cp->cc_size); \	for (i = 0; i < nkeys; i += 1) \	{ \		elog(DEBUG, "InitSysCache: key=%d len=%d skey=[%d %d %d %d]\n", \			 cp->cc_key[i], cp->cc_klen[i], \			 cp->cc_skey[i].sk_flags, \			 cp->cc_skey[i].sk_attno, \			 cp->cc_skey[i].sk_procedure, \			 cp->cc_skey[i].sk_argument); \	} \} while(0)#else#define InitSysCache_DEBUG1#endifCatCache   *InitSysCache(char *relname,			 char *iname,			 int id,			 int nkeys,			 int *key,			 HeapTuple (*iScanfuncP) ()){	CatCache   *cp;	int			i;	MemoryContext oldcxt;	char	   *indname;	indname = (iname) ? iname : NULL;	/* ----------------	 *	first switch to the cache context so our allocations	 *	do not vanish at the end of a transaction	 * ----------------	 */	if (!CacheCxt)		CacheCxt = CreateGlobalMemory("Cache");	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);	/* ----------------	 *	allocate a new cache structure	 * ----------------	 */	cp = (CatCache *) palloc(sizeof(CatCache));	MemSet((char *) cp, 0, sizeof(CatCache));	/* ----------------	 *	initialize the cache buckets (each bucket is a list header)	 *	and the LRU tuple list	 * ----------------	 */	{		/*		 * We can only do this optimization because the number of hash		 * buckets never changes.  Without it, we call malloc() too much.		 * We could move this to dllist.c, but the way we do this is not		 * dynamic/portabl, so why allow other routines to use it.		 */		Dllist	   *cache_begin = malloc((NCCBUCK + 1) * sizeof(Dllist));		for (i = 0; i <= NCCBUCK; ++i)		{			cp->cc_cache[i] = &cache_begin[i];			cp->cc_cache[i]->dll_head = 0;			cp->cc_cache[i]->dll_tail = 0;		}	}	cp->cc_lrulist = DLNewList();	/* ----------------	 *	Caches is the pointer to the head of the list of all the	 *	system caches.	here we add the new cache to the top of the list.	 * ----------------	 */	cp->cc_next = Caches;		/* list of caches (single link) */	Caches = cp;	/* ----------------	 *	initialize the cache's relation information for the relation	 *	corresponding to this cache and initialize some of the the new	 *	cache's other internal fields.	 * ----------------	 */	cp->relationId = InvalidOid;	cp->indexId = InvalidOid;	cp->cc_relname = relname;	cp->cc_indname = indname;	cp->cc_tupdesc = (TupleDesc) NULL;	cp->id = id;	cp->busy = false;	cp->cc_maxtup = MAXTUP;	cp->cc_size = NCCBUCK;	cp->cc_nkeys = nkeys;	cp->cc_iscanfunc = iScanfuncP;	/* ----------------	 *	initialize the cache's key information	 * ----------------	 */	for (i = 0; i < nkeys; ++i)	{		cp->cc_key[i] = key[i];		if (!key[i])			elog(FATAL, "InitSysCache: called with 0 key[%d]", i);		if (key[i] < 0)		{			if (key[i] != ObjectIdAttributeNumber)				elog(FATAL, "InitSysCache: called with %d key[%d]", key[i], i);			else			{				cp->cc_klen[i] = sizeof(Oid);				/*				 * ScanKeyEntryData and struct skey are equivalent. It				 * looks like a move was made to obsolete struct skey, but				 * it didn't reach this file.  Someday we should clean up				 * this code and consolidate to ScanKeyEntry - mer 10 Nov				 * 1991				 */				ScanKeyEntryInitialize(&cp->cc_skey[i],									   (bits16) 0,									   (AttrNumber) key[i],									   (RegProcedure) F_OIDEQ,									   (Datum) 0);				continue;			}		}		cp->cc_skey[i].sk_attno = key[i];	}	/* ----------------	 *	all done.  new cache is initialized.  print some debugging	 *	information, if appropriate.	 * ----------------	 */	InitSysCache_DEBUG1;	/* ----------------	 *	back to the old context before we return...	 * ----------------	 */	MemoryContextSwitchTo(oldcxt);	return cp;}/* -------------------------------- *		SearchSysCache * *		This call searches a system cache for a tuple, opening the relation *		if necessary (the first access to a particular cache). * -------------------------------- */HeapTupleSearchSysCache(struct catcache * cache,			   Datum v1,			   Datum v2,			   Datum v3,			   Datum v4){	unsigned	hash;	CatCTup    *ct = NULL;	CatCTup    *nct;	CatCTup    *nct2;	Dlelem	   *elt;	HeapTuple	ntp = 0;	Relation	relation;	MemoryContext oldcxt;	/* ----------------	 *	sanity checks	 * ----------------	 */	if (cache->relationId == InvalidOid)		CatalogCacheInitializeCache(cache, NULL);	/* ----------------	 *	initialize the search key information	 * ----------------	 */	cache->cc_skey[0].sk_argument = v1;	cache->cc_skey[1].sk_argument = v2;	cache->cc_skey[2].sk_argument = v3;	cache->cc_skey[3].sk_argument = v4;	/* ----------------	 *	find the hash bucket in which to look for the tuple	 * ----------------	 */	hash = CatalogCacheComputeHashIndex(cache);	/* ----------------	 *	scan the hash bucket until we find a match or exhaust our tuples	 * ----------------	 */	for (elt = DLGetHead(cache->cc_cache[hash]);		 elt;		 elt = DLGetSucc(elt))	{		bool		res;		ct = (CatCTup *) DLE_VAL(elt);		/* ----------------		 *	see if the cached tuple matches our key.		 *	(should we be worried about time ranges? -cim 10/2/90)		 * ----------------		 */		HeapKeyTest(ct->ct_tup,					cache->cc_tupdesc,					cache->cc_nkeys,					cache->cc_skey,					res);		if (res)			break;	}	/* ----------------	 *	if we found a tuple in the cache, move it to the top of the	 *	lru list, and return it.  We also move it to the front of the	 *	list for its hashbucket, in order to speed subsequent searches.	 *	(The most frequently accessed elements in any hashbucket will	 *	tend to be near the front of the hashbucket's list.)	 * ----------------	 */	if (elt)	{		Dlelem	   *old_lru_elt = ((CatCTup *) DLE_VAL(elt))->ct_node;		DLMoveToFront(old_lru_elt);		DLMoveToFront(elt);#ifdef CACHEDEBUG		relation = heap_open(cache->relationId);		CACHE3_elog(DEBUG, "SearchSysCache(%s): found in bucket %d",					RelationGetRelationName(relation), hash);		heap_close(relation);#endif	 /* CACHEDEBUG */		return ct->ct_tup;	}	/* ----------------	 *	Tuple was not found in cache, so we have to try and	 *	retrieve it directly from the relation.  If it's found,	 *	we add it to the cache.	 *	 *	To guard against possible infinite recursion, we mark this cache	 *	"busy" while trying to load a new entry for it.  It is OK to	 *	recursively invoke SearchSysCache for a different cache, but	 *	a recursive call for the same cache will error out.  (We could	 *	store the specific key(s) being looked for, and consider only	 *	a recursive request for the same key to be an error, but this	 *	simple scheme is sufficient for now.)	 * ----------------	 */	if (cache->busy)	{		elog(ERROR, "SearchSysCache: recursive use of cache %d", cache->id);	}	cache->busy = true;	/* ----------------	 *	open the relation associated with the cache	 * ----------------	 */	relation = heap_open(cache->relationId);	CACHE2_elog(DEBUG, "SearchSysCache(%s)",				RelationGetRelationName(relation));	/* ----------------	 *	Switch to the cache memory context.	 * ----------------	 */	if (!CacheCxt)		CacheCxt = CreateGlobalMemory("Cache");	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);	/* ----------------	 *	Scan the relation to find the tuple.  If there's an index, and	 *	if this isn't bootstrap (initdb) time, use the index.	 * ----------------	 */	CACHE2_elog(DEBUG, "SearchSysCache: performing scan (override==%d)",				heapisoverride());	if ((RelationGetForm(relation))->relhasindex		&& !IsBootstrapProcessingMode())	{		/* ----------		 *	Switch back to old memory context so memory not freed		 *	in the scan function will go away at transaction end.		 *	wieck - 10/18/1996		 * ----------		 */		MemoryContextSwitchTo(oldcxt);		Assert(cache->cc_iscanfunc);		switch (cache->cc_nkeys)		{			case 4:				ntp = cache->cc_iscanfunc(relation, v1, v2, v3, v4);				break;			case 3:				ntp = cache->cc_iscanfunc(relation, v1, v2, v3);				break;			case 2:				ntp = cache->cc_iscanfunc(relation, v1, v2);				break;			case 1:				ntp = cache->cc_iscanfunc(relation, v1);				break;		}		/* ----------		 *	Back to Cache context. If we got a tuple copy it		 *	into our context.		 *	wieck - 10/18/1996		 * ----------		 */		MemoryContextSwitchTo((MemoryContext) CacheCxt);		if (HeapTupleIsValid(ntp))			ntp = heap_copytuple(ntp);	}	else	{		HeapScanDesc sd;		/* ----------		 *	As above do the lookup in the callers memory		 *	context.		 *	wieck - 10/18/1996		 * ----------		 */		MemoryContextSwitchTo(oldcxt);		sd = heap_beginscan(relation, 0, SnapshotNow,							cache->cc_nkeys, cache->cc_skey);		ntp = heap_getnext(sd, 0);		MemoryContextSwitchTo((MemoryContext) CacheCxt);		if (HeapTupleIsValid(ntp))		{			CACHE1_elog(DEBUG, "SearchSysCache: found tuple");			ntp = heap_copytuple(ntp);		}		MemoryContextSwitchTo(oldcxt);		heap_endscan(sd);		MemoryContextSwitchTo((MemoryContext) CacheCxt);	}	cache->busy = false;	/* ----------------	 *	scan is complete.  if tup is valid, we copy it and add the copy to	 *	the cache.	 * ----------------	 */	if (HeapTupleIsValid(ntp))	{		/* ----------------		 *	allocate a new cache tuple holder, store the pointer		 *	to the heap tuple there and initialize the list pointers.		 * ----------------		 */		Dlelem	   *lru_elt;		/*		 * this is a little cumbersome here because we want the Dlelem's		 * in both doubly linked lists to point to one another. That makes		 * it easier to remove something from both the cache bucket and		 * the lru list at the same time		 */		nct = (CatCTup *) malloc(sizeof(CatCTup));		nct->ct_tup = ntp;		elt = DLNewElem(nct);		nct2 = (CatCTup *) malloc(sizeof(CatCTup));		nct2->ct_tup = ntp;		lru_elt = DLNewElem(nct2);		nct2->ct_node = elt;		nct->ct_node = lru_elt;		DLAddHead(cache->cc_lrulist, lru_elt);		DLAddHead(cache->cc_cache[hash], elt);		/* ----------------		 *	If we've exceeded the desired size of this cache,		 *	throw away the least recently used entry.		 * ----------------		 */		if (++cache->cc_ntup > cache->cc_maxtup)		{			CatCTup    *ct;			elt = DLGetTail(cache->cc_lrulist);			ct = (CatCTup *) DLE_VAL(elt);			if (ct != nct)		/* shouldn't be possible, but be safe... */			{				CACHE2_elog(DEBUG, "SearchSysCache(%s): Overflow, LRU removal",							RelationGetRelationName(relation));				CatCacheRemoveCTup(cache, elt);			}		}		CACHE4_elog(DEBUG, "SearchSysCache(%s): Contains %d/%d tuples",					RelationGetRelationName(relation),					cache->cc_ntup, cache->cc_maxtup);		CACHE3_elog(DEBUG, "SearchSysCache(%s): put in bucket %d",					RelationGetRelationName(relation), hash);	}	/* ----------------	 *	close the relation, switch back to the original memory context	 *	and return the tuple we found (or NULL)	 * ----------------	 */	heap_close(relation);	MemoryContextSwitchTo(oldcxt);	return ntp;}/* -------------------------------- *	RelationInvalidateCatalogCacheTuple() * *	Invalidate a tuple from a specific relation.  This call determines the *	cache in question and calls CatalogCacheIdInvalidate().  It is -ok- *	if the relation cannot be found, it simply means this backend has yet *	to open it. * -------------------------------- */voidRelationInvalidateCatalogCacheTuple(Relation relation,									HeapTuple tuple,							  void (*function) (int, Index, ItemPointer)){	struct catcache *ccp;	MemoryContext oldcxt;	Oid			relationId;	/* ----------------	 *	sanity checks	 * ----------------	 */	Assert(RelationIsValid(relation));	Assert(HeapTupleIsValid(tuple));	Assert(PointerIsValid(function));	CACHE1_elog(DEBUG, "RelationInvalidateCatalogCacheTuple: called");	/* ----------------	 *	switch to the cache memory context	 * ----------------	 */	if (!CacheCxt)		CacheCxt = CreateGlobalMemory("Cache");	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);	/* ----------------	 *	for each cache	 *	   if the cache contains tuples from the specified relation	 *		   call the invalidation function on the tuples	 *		   in the proper hash bucket	 * ----------------	 */	relationId = RelationGetRelid(relation);	for (ccp = Caches; ccp; ccp = ccp->cc_next)	{		if (relationId != ccp->relationId)			continue;#ifdef NOT_USED		/* OPT inline simplification of CatalogCacheIdInvalidate */		if (!PointerIsValid(function))			function = CatalogCacheIdInvalidate;#endif		(*function) (ccp->id,				 CatalogCacheComputeTupleHashIndex(ccp, relation, tuple),					 &tuple->t_self);		heap_close(relation);	}	/* ----------------	 *	return to the proper memory context	 * ----------------	 */	MemoryContextSwitchTo(oldcxt);	/* sendpm('I', "Invalidated tuple"); */}

⌨️ 快捷键说明

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