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

📄 catcache.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 4 页
字号:
/*------------------------------------------------------------------------- * * catcache.c *	  System catalog cache for tuples matching a key. * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.140.2.1 2008/03/05 17:01:33 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/hash.h"#include "access/heapam.h"#include "access/valid.h"#include "catalog/pg_operator.h"#include "catalog/pg_type.h"#include "miscadmin.h"#ifdef CATCACHE_STATS#include "storage/ipc.h"		/* for on_proc_exit */#endif#include "utils/builtins.h"#include "utils/fmgroids.h"#include "utils/memutils.h"#include "utils/relcache.h"#include "utils/resowner.h"#include "utils/syscache.h" /* #define CACHEDEBUG */	/* turns DEBUG elogs on *//* * Given a hash value and the size of the hash table, find the bucket * in which the hash value belongs. Since the hash table must contain * a power-of-2 number of elements, this is a simple bitmask. */#define HASH_INDEX(h, sz) ((Index) ((h) & ((sz) - 1)))/* *		variables, macros and other stuff */#ifdef CACHEDEBUG#define CACHE1_elog(a,b)				elog(a,b)#define CACHE2_elog(a,b,c)				elog(a,b,c)#define CACHE3_elog(a,b,c,d)			elog(a,b,c,d)#define CACHE4_elog(a,b,c,d,e)			elog(a,b,c,d,e)#define CACHE5_elog(a,b,c,d,e,f)		elog(a,b,c,d,e,f)#define CACHE6_elog(a,b,c,d,e,f,g)		elog(a,b,c,d,e,f,g)#else#define CACHE1_elog(a,b)#define CACHE2_elog(a,b,c)#define CACHE3_elog(a,b,c,d)#define CACHE4_elog(a,b,c,d,e)#define CACHE5_elog(a,b,c,d,e,f)#define CACHE6_elog(a,b,c,d,e,f,g)#endif/* Cache management header --- pointer is NULL until created */static CatCacheHeader *CacheHdr = NULL;static uint32 CatalogCacheComputeHashValue(CatCache *cache, int nkeys,							 ScanKey cur_skey);static uint32 CatalogCacheComputeTupleHashValue(CatCache *cache,								  HeapTuple tuple);#ifdef CATCACHE_STATSstatic void CatCachePrintStats(int code, Datum arg);#endifstatic void CatCacheRemoveCTup(CatCache *cache, CatCTup *ct);static void CatCacheRemoveCList(CatCache *cache, CatCList *cl);static void CatalogCacheInitializeCache(CatCache *cache);static CatCTup *CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp,						uint32 hashValue, Index hashIndex,						bool negative);static HeapTuple build_dummy_tuple(CatCache *cache, int nkeys, ScanKey skeys);/* *					internal support functions *//* * Look up the hash and equality functions for system types that are used * as cache key fields. * * XXX this should be replaced by catalog lookups, * but that seems to pose considerable risk of circularity... */static voidGetCCHashEqFuncs(Oid keytype, PGFunction *hashfunc, RegProcedure *eqfunc){	switch (keytype)	{		case BOOLOID:			*hashfunc = hashchar;			*eqfunc = F_BOOLEQ;			break;		case CHAROID:			*hashfunc = hashchar;			*eqfunc = F_CHAREQ;			break;		case NAMEOID:			*hashfunc = hashname;			*eqfunc = F_NAMEEQ;			break;		case INT2OID:			*hashfunc = hashint2;			*eqfunc = F_INT2EQ;			break;		case INT2VECTOROID:			*hashfunc = hashint2vector;			*eqfunc = F_INT2VECTOREQ;			break;		case INT4OID:			*hashfunc = hashint4;			*eqfunc = F_INT4EQ;			break;		case TEXTOID:			*hashfunc = hashtext;			*eqfunc = F_TEXTEQ;			break;		case OIDOID:		case REGPROCOID:		case REGPROCEDUREOID:		case REGOPEROID:		case REGOPERATOROID:		case REGCLASSOID:		case REGTYPEOID:		case REGCONFIGOID:		case REGDICTIONARYOID:			*hashfunc = hashoid;			*eqfunc = F_OIDEQ;			break;		case OIDVECTOROID:			*hashfunc = hashoidvector;			*eqfunc = F_OIDVECTOREQ;			break;		default:			elog(FATAL, "type %u not supported as catcache key", keytype);			*hashfunc = NULL;	/* keep compiler quiet */			*eqfunc = InvalidOid;			break;	}}/* *		CatalogCacheComputeHashValue * * Compute the hash value associated with a given set of lookup keys */static uint32CatalogCacheComputeHashValue(CatCache *cache, int nkeys, ScanKey cur_skey){	uint32		hashValue = 0;	uint32		oneHash;	CACHE4_elog(DEBUG2, "CatalogCacheComputeHashValue %s %d %p",				cache->cc_relname,				nkeys,				cache);	switch (nkeys)	{		case 4:			oneHash =				DatumGetUInt32(DirectFunctionCall1(cache->cc_hashfunc[3],												   cur_skey[3].sk_argument));			hashValue ^= oneHash << 24;			hashValue ^= oneHash >> 8;			/* FALLTHROUGH */		case 3:			oneHash =				DatumGetUInt32(DirectFunctionCall1(cache->cc_hashfunc[2],												   cur_skey[2].sk_argument));			hashValue ^= oneHash << 16;			hashValue ^= oneHash >> 16;			/* FALLTHROUGH */		case 2:			oneHash =				DatumGetUInt32(DirectFunctionCall1(cache->cc_hashfunc[1],												   cur_skey[1].sk_argument));			hashValue ^= oneHash << 8;			hashValue ^= oneHash >> 24;			/* FALLTHROUGH */		case 1:			oneHash =				DatumGetUInt32(DirectFunctionCall1(cache->cc_hashfunc[0],												   cur_skey[0].sk_argument));			hashValue ^= oneHash;			break;		default:			elog(FATAL, "wrong number of hash keys: %d", nkeys);			break;	}	return hashValue;}/* *		CatalogCacheComputeTupleHashValue * * Compute the hash value associated with a given tuple to be cached */static uint32CatalogCacheComputeTupleHashValue(CatCache *cache, HeapTuple tuple){	ScanKeyData cur_skey[4];	bool		isNull = false;	/* Copy pre-initialized overhead data for scankey */	memcpy(cur_skey, cache->cc_skey, sizeof(cur_skey));	/* Now extract key fields from tuple, insert into scankey */	switch (cache->cc_nkeys)	{		case 4:			cur_skey[3].sk_argument =				(cache->cc_key[3] == ObjectIdAttributeNumber)				? ObjectIdGetDatum(HeapTupleGetOid(tuple))				: fastgetattr(tuple,							  cache->cc_key[3],							  cache->cc_tupdesc,							  &isNull);			Assert(!isNull);			/* FALLTHROUGH */		case 3:			cur_skey[2].sk_argument =				(cache->cc_key[2] == ObjectIdAttributeNumber)				? ObjectIdGetDatum(HeapTupleGetOid(tuple))				: fastgetattr(tuple,							  cache->cc_key[2],							  cache->cc_tupdesc,							  &isNull);			Assert(!isNull);			/* FALLTHROUGH */		case 2:			cur_skey[1].sk_argument =				(cache->cc_key[1] == ObjectIdAttributeNumber)				? ObjectIdGetDatum(HeapTupleGetOid(tuple))				: fastgetattr(tuple,							  cache->cc_key[1],							  cache->cc_tupdesc,							  &isNull);			Assert(!isNull);			/* FALLTHROUGH */		case 1:			cur_skey[0].sk_argument =				(cache->cc_key[0] == ObjectIdAttributeNumber)				? ObjectIdGetDatum(HeapTupleGetOid(tuple))				: fastgetattr(tuple,							  cache->cc_key[0],							  cache->cc_tupdesc,							  &isNull);			Assert(!isNull);			break;		default:			elog(FATAL, "wrong number of hash keys: %d", cache->cc_nkeys);			break;	}	return CatalogCacheComputeHashValue(cache, cache->cc_nkeys, cur_skey);}#ifdef CATCACHE_STATSstatic voidCatCachePrintStats(int code, Datum arg){	CatCache   *cache;	long		cc_searches = 0;	long		cc_hits = 0;	long		cc_neg_hits = 0;	long		cc_newloads = 0;	long		cc_invals = 0;	long		cc_lsearches = 0;	long		cc_lhits = 0;	for (cache = CacheHdr->ch_caches; cache; cache = cache->cc_next)	{		if (cache->cc_ntup == 0 && cache->cc_searches == 0)			continue;			/* don't print unused caches */		elog(DEBUG2, "catcache %s/%u: %d tup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals, %ld lsrch, %ld lhits",			 cache->cc_relname,			 cache->cc_indexoid,			 cache->cc_ntup,			 cache->cc_searches,			 cache->cc_hits,			 cache->cc_neg_hits,			 cache->cc_hits + cache->cc_neg_hits,			 cache->cc_newloads,			 cache->cc_searches - cache->cc_hits - cache->cc_neg_hits - cache->cc_newloads,			 cache->cc_searches - cache->cc_hits - cache->cc_neg_hits,			 cache->cc_invals,			 cache->cc_lsearches,			 cache->cc_lhits);		cc_searches += cache->cc_searches;		cc_hits += cache->cc_hits;		cc_neg_hits += cache->cc_neg_hits;		cc_newloads += cache->cc_newloads;		cc_invals += cache->cc_invals;		cc_lsearches += cache->cc_lsearches;		cc_lhits += cache->cc_lhits;	}	elog(DEBUG2, "catcache totals: %d tup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals, %ld lsrch, %ld lhits",		 CacheHdr->ch_ntup,		 cc_searches,		 cc_hits,		 cc_neg_hits,		 cc_hits + cc_neg_hits,		 cc_newloads,		 cc_searches - cc_hits - cc_neg_hits - cc_newloads,		 cc_searches - cc_hits - cc_neg_hits,		 cc_invals,		 cc_lsearches,		 cc_lhits);}#endif   /* CATCACHE_STATS *//* *		CatCacheRemoveCTup * * Unlink and delete the given cache entry * * NB: if it is a member of a CatCList, the CatCList is deleted too. * Both the cache entry and the list had better have zero refcount. */static voidCatCacheRemoveCTup(CatCache *cache, CatCTup *ct){	Assert(ct->refcount == 0);	Assert(ct->my_cache == cache);	if (ct->c_list)	{		/*		 * The cleanest way to handle this is to call CatCacheRemoveCList,		 * which will recurse back to me, and the recursive call will do the		 * work.  Set the "dead" flag to make sure it does recurse.		 */		ct->dead = true;		CatCacheRemoveCList(cache, ct->c_list);		return;					/* nothing left to do */	}	/* delink from linked list */	DLRemove(&ct->cache_elem);	/* free associated tuple data */	if (ct->tuple.t_data != NULL)		pfree(ct->tuple.t_data);	pfree(ct);	--cache->cc_ntup;	--CacheHdr->ch_ntup;}/* *		CatCacheRemoveCList * * Unlink and delete the given cache list entry * * NB: any dead member entries that become unreferenced are deleted too. */static voidCatCacheRemoveCList(CatCache *cache, CatCList *cl){	int			i;	Assert(cl->refcount == 0);	Assert(cl->my_cache == cache);	/* delink from member tuples */	for (i = cl->n_members; --i >= 0;)	{		CatCTup    *ct = cl->members[i];		Assert(ct->c_list == cl);		ct->c_list = NULL;		/* if the member is dead and now has no references, remove it */		if (#ifndef CATCACHE_FORCE_RELEASE			ct->dead &&#endif			ct->refcount == 0)			CatCacheRemoveCTup(cache, ct);	}	/* delink from linked list */	DLRemove(&cl->cache_elem);	/* free associated tuple data */	if (cl->tuple.t_data != NULL)		pfree(cl->tuple.t_data);	pfree(cl);}/* *	CatalogCacheIdInvalidate * *	Invalidate entries in the specified cache, given a hash value and *	item pointer.  Positive entries are deleted if they match the item *	pointer.  Negative entries must be deleted if they match the hash *	value (since we do not have the exact key of the tuple that's being *	inserted).	But this should only rarely result in loss of a cache *	entry that could have been kept. * *	Note that it's not very relevant whether the tuple identified by *	the item pointer is being inserted or deleted.	We don't expect to *	find matching positive entries in the one case, and we don't expect *	to find matching negative entries in the other; but we will do the *	right things in any case. * *	This routine is only quasi-public: it should only be used by inval.c. */voidCatalogCacheIdInvalidate(int cacheId,						 uint32 hashValue,						 ItemPointer pointer){	CatCache   *ccp;	/*	 * sanity checks	 */	Assert(ItemPointerIsValid(pointer));	CACHE1_elog(DEBUG2, "CatalogCacheIdInvalidate: called");	/*	 * inspect caches to find the proper cache	 */	for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next)	{		Index		hashIndex;		Dlelem	   *elt,				   *nextelt;		if (cacheId != ccp->id)			continue;		/*		 * We don't bother to check whether the cache has finished		 * initialization yet; if not, there will be no entries in it so no		 * problem.		 */		/*

⌨️ 快捷键说明

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