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

📄 catcache.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * catcache.c *	  System catalog cache for tuples matching a key. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.43.2.1 1999/08/02 05:24:59 scrappy Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/heapam.h"#include "access/valid.h"#include "catalog/pg_type.h"#include "miscadmin.h"#include "utils/builtins.h"#include "utils/catcache.h"static void CatCacheRemoveCTup(CatCache *cache, Dlelem *e);static Index CatalogCacheComputeHashIndex(struct catcache * cacheInP);static Index CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP,								  Relation relation, HeapTuple tuple);static void CatalogCacheInitializeCache(struct catcache * cache,							Relation relation);static long comphash(long l, char *v);/* ---------------- *		variables, macros and other stuff * *	note CCSIZE allocates 51 buckets .. one was already allocated in *	the catcache structure. * ---------------- */#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)#endifstatic CatCache   *Caches = NULL; /* head of list of caches */GlobalMemory CacheCxt;			/* context in which caches are allocated *//* CacheCxt is global because relcache uses it too. *//* ---------------- *		EQPROC is used in CatalogCacheInitializeCache *		XXX this should be replaced by catalog lookups soon * ---------------- */static long eqproc[] = {	F_BOOLEQ, 0l, F_CHAREQ, F_NAMEEQ, 0l,	F_INT2EQ, F_KEYFIRSTEQ, F_INT4EQ, 0l, F_TEXTEQ,	F_OIDEQ, 0l, 0l, 0l, F_OID8EQ};#define EQPROC(SYSTEMTYPEOID)	eqproc[(SYSTEMTYPEOID)-16]/* ---------------------------------------------------------------- *					internal support functions * ---------------------------------------------------------------- *//* -------------------------------- *		CatalogCacheInitializeCache * -------------------------------- */#ifdef CACHEDEBUG#define CatalogCacheInitializeCache_DEBUG1 \do { \	elog(DEBUG, "CatalogCacheInitializeCache: cache @%08lx", cache); \	if (relation) \		elog(DEBUG, "CatalogCacheInitializeCache: called w/relation(inval)"); \	else \		elog(DEBUG, "CatalogCacheInitializeCache: called w/relname %s", \			cache->cc_relname) \} while(0)#define CatalogCacheInitializeCache_DEBUG2 \do { \		if (cache->cc_key[i] > 0) { \			elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d, %d", \				i+1, cache->cc_nkeys, cache->cc_key[i], \				relation->rd_att->attrs[cache->cc_key[i] - 1]->attlen); \		} else { \			elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d", \				i+1, cache->cc_nkeys, cache->cc_key[i]); \		} \} while(0)#else#define CatalogCacheInitializeCache_DEBUG1#define CatalogCacheInitializeCache_DEBUG2#endifstatic voidCatalogCacheInitializeCache(struct catcache * cache,							Relation relation){	MemoryContext oldcxt;	short		didopen = 0;	short		i;	TupleDesc	tupdesc;	CatalogCacheInitializeCache_DEBUG1;	/* ----------------	 *	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);	/* ----------------	 *	If no relation was passed we must open it to get access to	 *	its fields.  If one of the other caches has already opened	 *	it we use heap_open() instead of heap_openr()	 * ----------------	 */	if (!RelationIsValid(relation))	{		struct catcache *cp;		/* ----------------		 *	scan the caches to see if any other cache has opened the relation		 * ----------------		 */		for (cp = Caches; cp; cp = cp->cc_next)		{			if (strncmp(cp->cc_relname, cache->cc_relname, NAMEDATALEN) == 0)			{				if (cp->relationId != InvalidOid)					break;			}		}		/* ----------------		 *	open the relation by name or by id		 * ----------------		 */		if (cp)			relation = heap_open(cp->relationId);		else			relation = heap_openr(cache->cc_relname);		didopen = 1;	}	/* ----------------	 *	initialize the cache's relation id	 * ----------------	 */	Assert(RelationIsValid(relation));	cache->relationId = RelationGetRelid(relation);	tupdesc = cache->cc_tupdesc = RelationGetDescr(relation);	CACHE3_elog(DEBUG, "CatalogCacheInitializeCache: relid %u, %d keys",				cache->relationId, cache->cc_nkeys);	/* ----------------	 *	initialize cache's key information	 * ----------------	 */	for (i = 0; i < cache->cc_nkeys; ++i)	{		CatalogCacheInitializeCache_DEBUG2;		if (cache->cc_key[i] > 0)		{			/*			 * Yoiks.  The implementation of the hashing code and the			 * implementation of int28's are at loggerheads.  The right			 * thing to do is to throw out the implementation of int28's			 * altogether; until that happens, we do the right thing here			 * to guarantee that the hash key generator doesn't try to			 * dereference an int2 by mistake.			 */			if (tupdesc->attrs[cache->cc_key[i] - 1]->atttypid == INT28OID)				cache->cc_klen[i] = sizeof(short);			else				cache->cc_klen[i] = tupdesc->attrs[cache->cc_key[i] - 1]->attlen;			cache->cc_skey[i].sk_procedure = EQPROC(tupdesc->attrs[cache->cc_key[i] - 1]->atttypid);			fmgr_info(cache->cc_skey[i].sk_procedure,					  &cache->cc_skey[i].sk_func);			cache->cc_skey[i].sk_nargs = cache->cc_skey[i].sk_func.fn_nargs;			CACHE5_elog(DEBUG, "CatalogCacheInit %s %d %d %x",						&relation->rd_rel->relname,						i,						tupdesc->attrs[cache->cc_key[i] - 1]->attlen,						cache);		}	}	/* ----------------	 *	close the relation if we opened it	 * ----------------	 */	if (didopen)		heap_close(relation);	/* ----------------	 *	initialize index information for the cache.  this	 *	should only be done once per cache.	 * ----------------	 */	if (cache->cc_indname != NULL && cache->indexId == InvalidOid)	{		if (RelationGetForm(relation)->relhasindex)		{			/*			 * If the index doesn't exist we are in trouble.			 */			relation = index_openr(cache->cc_indname);			Assert(relation);			cache->indexId = RelationGetRelid(relation);			index_close(relation);		}		else			cache->cc_indname = NULL;	}	/* ----------------	 *	return to the proper memory context	 * ----------------	 */	MemoryContextSwitchTo(oldcxt);}/* -------------------------------- *		CatalogCacheSetId * *		XXX temporary function * -------------------------------- */#ifdef NOT_USEDvoidCatalogCacheSetId(CatCache *cacheInOutP, int id){	Assert(id == InvalidCatalogCacheId || id >= 0);	cacheInOutP->id = id;}#endif/* ---------------- * comphash *		Compute a hash value, somehow. * * XXX explain algorithm here. * * l is length of the attribute value, v * v is the attribute value ("Datum") * ---------------- */static longcomphash(long l, char *v){	long		i;	NameData	n;	CACHE3_elog(DEBUG, "comphash (%d,%x)", l, v);	switch (l)	{		case 1:		case 2:		case 4:			return (long) v;	}	if (l == NAMEDATALEN)	{		/*		 * if it's a name, make sure that the values are null-padded.		 *		 * Note that this other fixed-length types can also have the same		 * typelen so this may break them	  - XXX		 */		namestrcpy(&n, v);		v = n.data;	}	else if (l < 0)		l = VARSIZE(v);	i = 0;	while (l--)		i += *v++;	return i;}/* -------------------------------- *		CatalogCacheComputeHashIndex * -------------------------------- */static IndexCatalogCacheComputeHashIndex(struct catcache * cacheInP){	Index		hashIndex;	hashIndex = 0x0;	CACHE6_elog(DEBUG, "CatalogCacheComputeHashIndex %s %d %d %d %x",				cacheInP->cc_relname,				cacheInP->cc_nkeys,				cacheInP->cc_klen[0],				cacheInP->cc_klen[1],				cacheInP);	switch (cacheInP->cc_nkeys)	{		case 4:			hashIndex ^= comphash(cacheInP->cc_klen[3],						 (char *) cacheInP->cc_skey[3].sk_argument) << 9;			/* FALLTHROUGH */		case 3:			hashIndex ^= comphash(cacheInP->cc_klen[2],						 (char *) cacheInP->cc_skey[2].sk_argument) << 6;			/* FALLTHROUGH */		case 2:			hashIndex ^= comphash(cacheInP->cc_klen[1],						 (char *) cacheInP->cc_skey[1].sk_argument) << 3;			/* FALLTHROUGH */		case 1:			hashIndex ^= comphash(cacheInP->cc_klen[0],							  (char *) cacheInP->cc_skey[0].sk_argument);			break;		default:			elog(FATAL, "CCComputeHashIndex: %d cc_nkeys", cacheInP->cc_nkeys);			break;	}	hashIndex %= cacheInP->cc_size;	return hashIndex;}/* -------------------------------- *		CatalogCacheComputeTupleHashIndex * -------------------------------- */static IndexCatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP,								  Relation relation,								  HeapTuple tuple){	bool		isNull = '\0';	if (cacheInOutP->relationId == InvalidOid)		CatalogCacheInitializeCache(cacheInOutP, relation);	switch (cacheInOutP->cc_nkeys)	{		case 4:			cacheInOutP->cc_skey[3].sk_argument =				(cacheInOutP->cc_key[3] == ObjectIdAttributeNumber)				? (Datum) tuple->t_data->t_oid				: fastgetattr(tuple,							  cacheInOutP->cc_key[3],							  RelationGetDescr(relation),							  &isNull);			Assert(!isNull);			/* FALLTHROUGH */		case 3:			cacheInOutP->cc_skey[2].sk_argument =				(cacheInOutP->cc_key[2] == ObjectIdAttributeNumber)				? (Datum) tuple->t_data->t_oid				: fastgetattr(tuple,							  cacheInOutP->cc_key[2],							  RelationGetDescr(relation),							  &isNull);			Assert(!isNull);			/* FALLTHROUGH */		case 2:			cacheInOutP->cc_skey[1].sk_argument =				(cacheInOutP->cc_key[1] == ObjectIdAttributeNumber)				? (Datum) tuple->t_data->t_oid				: fastgetattr(tuple,							  cacheInOutP->cc_key[1],							  RelationGetDescr(relation),							  &isNull);			Assert(!isNull);			/* FALLTHROUGH */		case 1:			cacheInOutP->cc_skey[0].sk_argument =				(cacheInOutP->cc_key[0] == ObjectIdAttributeNumber)				? (Datum) tuple->t_data->t_oid				: fastgetattr(tuple,							  cacheInOutP->cc_key[0],							  RelationGetDescr(relation),							  &isNull);			Assert(!isNull);			break;		default:			elog(FATAL, "CCComputeTupleHashIndex: %d cc_nkeys",				 cacheInOutP->cc_nkeys				);			break;	}	return CatalogCacheComputeHashIndex(cacheInOutP);}/* -------------------------------- *		CatCacheRemoveCTup * -------------------------------- */static voidCatCacheRemoveCTup(CatCache *cache, Dlelem *elt){	CatCTup    *ct;	CatCTup    *other_ct;	Dlelem	   *other_elt;	if (elt)		ct = (CatCTup *) DLE_VAL(elt);	else		return;	other_elt = ct->ct_node;	other_ct = (CatCTup *) DLE_VAL(other_elt);	DLRemove(other_elt);	DLFreeElem(other_elt);	free(other_ct);	DLRemove(elt);	DLFreeElem(elt);	free(ct);	--cache->cc_ntup;}/* -------------------------------- *	CatalogCacheIdInvalidate() * *	Invalidate a tuple given a cache id.  In this case the id should always *	be found (whether the cache has opened its relation or not).  Of course, *	if the cache has yet to open its relation, there will be no tuples so *	no problem. * -------------------------------- */voidCatalogCacheIdInvalidate(int cacheId,	/* XXX */						 Index hashIndex,						 ItemPointer pointer){	CatCache   *ccp;	CatCTup    *ct;	Dlelem	   *elt;	MemoryContext oldcxt;	/* ----------------	 *	sanity checks	 * ----------------	 */	Assert(hashIndex < NCCBUCK);	Assert(ItemPointerIsValid(pointer));	CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: called");	/* ----------------	 *	switch to the cache context for our memory allocations	 * ----------------	 */	if (!CacheCxt)		CacheCxt = CreateGlobalMemory("Cache");	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);	/* ----------------	 *	inspect every cache that could contain the tuple	 * ----------------	 */	for (ccp = Caches; ccp; ccp = ccp->cc_next)	{		if (cacheId != ccp->id)			continue;		/* ----------------		 *	inspect the hash bucket until we find a match or exhaust		 * ----------------		 */		for (elt = DLGetHead(ccp->cc_cache[hashIndex]);			 elt;			 elt = DLGetSucc(elt))		{			ct = (CatCTup *) DLE_VAL(elt);			if (ItemPointerEquals(pointer, &ct->ct_tup->t_self))				break;		}		/* ----------------		 *	if we found a matching tuple, invalidate it.		 * ----------------		 */		if (elt)		{			CatCacheRemoveCTup(ccp, elt);			CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: invalidated");		}		if (cacheId != InvalidCatalogCacheId)			break;	}	/* ----------------	 *	return to the proper memory context	 * ----------------	 */	MemoryContextSwitchTo(oldcxt);	/* sendpm('I', "Invalidated tuple"); */}/* ---------------------------------------------------------------- *					   public functions * *		ResetSystemCache *		InitIndexedSysCache *		InitSysCache *		SearchSysCache *		RelationInvalidateCatalogCacheTuple * ---------------------------------------------------------------- *//* -------------------------------- *		ResetSystemCache * -------------------------------- */voidResetSystemCache(){	MemoryContext oldcxt;	struct catcache *cache;	CACHE1_elog(DEBUG, "ResetSystemCache called");	/* ----------------	 *	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);	/* ----------------	 *	here we purge the contents of all the caches	 *	 *	for each system cache	 *	   for each hash bucket	 *		   for each tuple in hash bucket	 *			   remove the tuple	 * ----------------	 */	for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next)	{		int			hash;		for (hash = 0; hash < NCCBUCK; hash += 1)		{			Dlelem	   *elt,					   *nextelt;			for (elt = DLGetHead(cache->cc_cache[hash]); elt; elt = nextelt)			{				nextelt = DLGetSucc(elt);

⌨️ 快捷键说明

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