mirror of https://github.com/postgres/postgres
Do some restructuring to improve performance of the catcaches. Teach
CatalogCacheFlushRelation (formerly called SystemCacheRelationFlushed) how to distinguish tuples it should flush from those it needn't; this means a relcache flush event now only removes the catcache entries it ought to, rather than zapping the caches completely as it used to. Testing with the regression tests indicates that this considerably improves the lifespan of catcache entries. Also, rearrange catcache data structures so that the limit on number of cached tuples applies globally across all the catcaches, rather than being per-catcache. It was a little silly to have the same size limit on both, say, pg_attribute caches and pg_am caches (there being only four possible rows in the latter...). Doing LRU removal across all the caches instead of locally in each one should reduce cache reload traffic in the more heavily used caches and improve the efficiency of cache memory use.
This commit is contained in:
parent
41c377f5c6
commit
2c5aa2acb4
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.78 2001/06/01 02:41:36 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.79 2001/06/18 03:35:07 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -29,17 +29,15 @@
|
|||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
static void CatCacheRemoveCTup(CatCache *cache, CatCTup *ct);
|
||||
static Index CatalogCacheComputeHashIndex(CatCache *cache,
|
||||
ScanKey cur_skey);
|
||||
static Index CatalogCacheComputeTupleHashIndex(CatCache *cache,
|
||||
HeapTuple tuple);
|
||||
static void CatalogCacheInitializeCache(CatCache *cache);
|
||||
static Datum cc_hashname(PG_FUNCTION_ARGS);
|
||||
/* #define CACHEDEBUG */ /* turns DEBUG elogs on */
|
||||
|
||||
/* voodoo constants */
|
||||
#define NCCBUCKETS 257 /* Hash buckets per CatCache (prime!) */
|
||||
#define MAXCCTUPLES 5000 /* Maximum # of tuples in all caches */
|
||||
|
||||
|
||||
/*
|
||||
* variables, macros and other stuff
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef CACHEDEBUG
|
||||
|
@ -58,8 +56,8 @@ static Datum cc_hashname(PG_FUNCTION_ARGS);
|
|||
#define CACHE6_elog(a,b,c,d,e,f,g)
|
||||
#endif
|
||||
|
||||
static CatCache *Caches = NULL; /* head of list of caches */
|
||||
|
||||
/* Cache management header --- pointer is NULL until created */
|
||||
static CatCacheHeader *CacheHdr = NULL;
|
||||
|
||||
/*
|
||||
* EQPROC is used in CatalogCacheInitializeCache to find the equality
|
||||
|
@ -68,7 +66,6 @@ static CatCache *Caches = NULL; /* head of list of caches */
|
|||
*
|
||||
* XXX this should be replaced by catalog lookups,
|
||||
* but that seems to pose considerable risk of circularity...
|
||||
*
|
||||
*/
|
||||
static const Oid eqproc[] = {
|
||||
F_BOOLEQ, InvalidOid, F_CHAREQ, F_NAMEEQ, InvalidOid,
|
||||
|
@ -78,9 +75,18 @@ static const Oid eqproc[] = {
|
|||
|
||||
#define EQPROC(SYSTEMTYPEOID) eqproc[(SYSTEMTYPEOID)-BOOLOID]
|
||||
|
||||
|
||||
static void CatCacheRemoveCTup(CatCache *cache, CatCTup *ct);
|
||||
static Index CatalogCacheComputeHashIndex(CatCache *cache,
|
||||
ScanKey cur_skey);
|
||||
static Index CatalogCacheComputeTupleHashIndex(CatCache *cache,
|
||||
HeapTuple tuple);
|
||||
static void CatalogCacheInitializeCache(CatCache *cache);
|
||||
static Datum cc_hashname(PG_FUNCTION_ARGS);
|
||||
|
||||
|
||||
/*
|
||||
* internal support functions
|
||||
*
|
||||
*/
|
||||
|
||||
static PGFunction
|
||||
|
@ -116,7 +122,6 @@ GetCCHashFunc(Oid keytype)
|
|||
static Datum
|
||||
cc_hashname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
|
||||
/*
|
||||
* We need our own variant of hashname because we want to accept
|
||||
* null-terminated C strings as search values for name fields. So, we
|
||||
|
@ -141,7 +146,6 @@ cc_hashname(PG_FUNCTION_ARGS)
|
|||
void
|
||||
CreateCacheMemoryContext(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* Purely for paranoia, check that context doesn't exist; caller
|
||||
* probably did so already.
|
||||
|
@ -161,7 +165,6 @@ CreateCacheMemoryContext(void)
|
|||
* This function does final initialization of a catcache: obtain the tuple
|
||||
* descriptor and set up the hash and equality function links. We assume
|
||||
* that the relcache entry can be opened at this point!
|
||||
*
|
||||
*/
|
||||
#ifdef CACHEDEBUG
|
||||
#define CatalogCacheInitializeCache_DEBUG1 \
|
||||
|
@ -191,7 +194,7 @@ CatalogCacheInitializeCache(CatCache *cache)
|
|||
Relation relation;
|
||||
MemoryContext oldcxt;
|
||||
TupleDesc tupdesc;
|
||||
short i;
|
||||
int i;
|
||||
|
||||
CatalogCacheInitializeCache_DEBUG1;
|
||||
|
||||
|
@ -206,8 +209,7 @@ CatalogCacheInitializeCache(CatCache *cache)
|
|||
* switch to the cache context so our allocations do not vanish at the
|
||||
* end of a transaction
|
||||
*/
|
||||
if (!CacheMemoryContext)
|
||||
CreateCacheMemoryContext();
|
||||
Assert(CacheMemoryContext != NULL);
|
||||
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
|
@ -286,7 +288,6 @@ CatalogCacheInitializeCache(CatCache *cache)
|
|||
|
||||
/*
|
||||
* CatalogCacheComputeHashIndex
|
||||
*
|
||||
*/
|
||||
static Index
|
||||
CatalogCacheComputeHashIndex(CatCache *cache, ScanKey cur_skey)
|
||||
|
@ -330,7 +331,6 @@ CatalogCacheComputeHashIndex(CatCache *cache, ScanKey cur_skey)
|
|||
|
||||
/*
|
||||
* CatalogCacheComputeTupleHashIndex
|
||||
*
|
||||
*/
|
||||
static Index
|
||||
CatalogCacheComputeTupleHashIndex(CatCache *cache,
|
||||
|
@ -396,12 +396,12 @@ CatalogCacheComputeTupleHashIndex(CatCache *cache,
|
|||
|
||||
/*
|
||||
* CatCacheRemoveCTup
|
||||
*
|
||||
*/
|
||||
static void
|
||||
CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)
|
||||
{
|
||||
Assert(ct->refcount == 0);
|
||||
Assert(ct->my_cache == cache);
|
||||
|
||||
/* delink from linked lists */
|
||||
DLRemove(&ct->lrulist_elem);
|
||||
|
@ -413,6 +413,7 @@ CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)
|
|||
pfree(ct);
|
||||
|
||||
--cache->cc_ntup;
|
||||
--CacheHdr->ch_ntup;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -422,7 +423,6 @@ CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)
|
|||
* 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.
|
||||
*
|
||||
*/
|
||||
void
|
||||
CatalogCacheIdInvalidate(int cacheId,
|
||||
|
@ -433,17 +433,14 @@ CatalogCacheIdInvalidate(int cacheId,
|
|||
|
||||
/*
|
||||
* sanity checks
|
||||
*
|
||||
*/
|
||||
Assert(hashIndex < NCCBUCK);
|
||||
Assert(ItemPointerIsValid(pointer));
|
||||
CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: called");
|
||||
|
||||
/*
|
||||
* inspect caches to find the proper cache
|
||||
*
|
||||
*/
|
||||
for (ccp = Caches; ccp; ccp = ccp->cc_next)
|
||||
for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next)
|
||||
{
|
||||
Dlelem *elt,
|
||||
*nextelt;
|
||||
|
@ -451,11 +448,12 @@ CatalogCacheIdInvalidate(int cacheId,
|
|||
if (cacheId != ccp->id)
|
||||
continue;
|
||||
|
||||
Assert(hashIndex < ccp->cc_size);
|
||||
|
||||
/*
|
||||
* inspect the hash bucket until we find a match or exhaust
|
||||
*
|
||||
*/
|
||||
for (elt = DLGetHead(&ccp->cc_cache[hashIndex]); elt; elt = nextelt)
|
||||
for (elt = DLGetHead(&ccp->cc_bucket[hashIndex]); elt; elt = nextelt)
|
||||
{
|
||||
CatCTup *ct = (CatCTup *) DLE_VAL(elt);
|
||||
|
||||
|
@ -479,7 +477,7 @@ CatalogCacheIdInvalidate(int cacheId,
|
|||
* public functions
|
||||
*
|
||||
* AtEOXact_CatCache
|
||||
* ResetSystemCache
|
||||
* ResetCatalogCaches
|
||||
* InitCatCache
|
||||
* SearchCatCache
|
||||
* ReleaseCatCache
|
||||
|
@ -497,19 +495,14 @@ CatalogCacheIdInvalidate(int cacheId,
|
|||
* necessary in the abort case, since elog() may have interrupted routines.
|
||||
* In the commit case, any nonzero counts indicate failure to call
|
||||
* ReleaseSysCache, so we put out a notice for debugging purposes.
|
||||
*
|
||||
*/
|
||||
void
|
||||
AtEOXact_CatCache(bool isCommit)
|
||||
{
|
||||
CatCache *cache;
|
||||
|
||||
for (cache = Caches; cache; cache = cache->cc_next)
|
||||
{
|
||||
Dlelem *elt,
|
||||
*nextelt;
|
||||
|
||||
for (elt = DLGetHead(&cache->cc_lrulist); elt; elt = nextelt)
|
||||
for (elt = DLGetHead(&CacheHdr->ch_lrulist); elt; elt = nextelt)
|
||||
{
|
||||
CatCTup *ct = (CatCTup *) DLE_VAL(elt);
|
||||
|
||||
|
@ -519,7 +512,7 @@ AtEOXact_CatCache(bool isCommit)
|
|||
{
|
||||
if (isCommit)
|
||||
elog(NOTICE, "Cache reference leak: cache %s (%d), tuple %u has count %d",
|
||||
cache->cc_relname, cache->id,
|
||||
ct->my_cache->cc_relname, ct->my_cache->id,
|
||||
ct->tuple.t_data->t_oid,
|
||||
ct->refcount);
|
||||
ct->refcount = 0;
|
||||
|
@ -527,38 +520,30 @@ AtEOXact_CatCache(bool isCommit)
|
|||
|
||||
/* Clean up any now-deletable dead entries */
|
||||
if (ct->dead)
|
||||
CatCacheRemoveCTup(cache, ct);
|
||||
}
|
||||
CatCacheRemoveCTup(ct->my_cache, ct);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ResetSystemCache
|
||||
* ResetCatalogCache
|
||||
*
|
||||
* Reset caches when a shared cache inval event forces it
|
||||
* Reset one catalog cache to empty.
|
||||
*
|
||||
* This is not very efficient if the target cache is nearly empty.
|
||||
* However, it shouldn't need to be efficient; we don't invoke it often.
|
||||
*/
|
||||
void
|
||||
ResetSystemCache(void)
|
||||
static void
|
||||
ResetCatalogCache(CatCache *cache)
|
||||
{
|
||||
CatCache *cache;
|
||||
int i;
|
||||
|
||||
CACHE1_elog(DEBUG, "ResetSystemCache called");
|
||||
|
||||
/* ----------------
|
||||
* here we purge the contents of all the caches
|
||||
*
|
||||
* for each system cache
|
||||
* for each tuple
|
||||
* remove the tuple, or at least mark it dead
|
||||
* ----------------
|
||||
*/
|
||||
for (cache = Caches; cache; cache = cache->cc_next)
|
||||
/* Remove each tuple in this cache, or at least mark it dead */
|
||||
for (i = 0; i < cache->cc_size; i++)
|
||||
{
|
||||
Dlelem *elt,
|
||||
*nextelt;
|
||||
|
||||
for (elt = DLGetHead(&cache->cc_lrulist); elt; elt = nextelt)
|
||||
for (elt = DLGetHead(&cache->cc_bucket[i]); elt; elt = nextelt)
|
||||
{
|
||||
CatCTup *ct = (CatCTup *) DLE_VAL(elt);
|
||||
|
||||
|
@ -570,12 +555,28 @@ ResetSystemCache(void)
|
|||
CatCacheRemoveCTup(cache, ct);
|
||||
}
|
||||
}
|
||||
|
||||
CACHE1_elog(DEBUG, "end of ResetSystemCache call");
|
||||
}
|
||||
|
||||
/*
|
||||
* SystemCacheRelationFlushed
|
||||
* ResetCatalogCaches
|
||||
*
|
||||
* Reset all caches when a shared cache inval event forces it
|
||||
*/
|
||||
void
|
||||
ResetCatalogCaches(void)
|
||||
{
|
||||
CatCache *cache;
|
||||
|
||||
CACHE1_elog(DEBUG, "ResetCatalogCaches called");
|
||||
|
||||
for (cache = CacheHdr->ch_caches; cache; cache = cache->cc_next)
|
||||
ResetCatalogCache(cache);
|
||||
|
||||
CACHE1_elog(DEBUG, "end of ResetCatalogCaches call");
|
||||
}
|
||||
|
||||
/*
|
||||
* CatalogCacheFlushRelation
|
||||
*
|
||||
* This is called by RelationFlushRelation() to clear out cached information
|
||||
* about a relation being dropped. (This could be a DROP TABLE command,
|
||||
|
@ -586,26 +587,80 @@ ResetSystemCache(void)
|
|||
* 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 flush all cache entries from that table. The brute-force method
|
||||
* currently used takes care of that quite handily. (At one point we
|
||||
* to flush all cache entries that came from that table. (At one point we
|
||||
* also tried to force re-execution of CatalogCacheInitializeCache for
|
||||
* the cache(s) on that table. This is a bad idea since it leads to all
|
||||
* kinds of trouble if a cache flush occurs while loading cache entries.
|
||||
* We now avoid the need to do it by copying cc_tupdesc out of the relcache,
|
||||
* rather than relying on the relcache to keep a tupdesc for us. Of course
|
||||
* this assumes the tupdesc of a cachable system table will not change...)
|
||||
*
|
||||
*/
|
||||
void
|
||||
SystemCacheRelationFlushed(Oid relId)
|
||||
CatalogCacheFlushRelation(Oid relId)
|
||||
{
|
||||
CatCache *cache;
|
||||
|
||||
/*
|
||||
* XXX Ideally we'd search the caches and just zap entries that
|
||||
* actually refer to or come from the indicated relation. For now, we
|
||||
* take the brute-force approach: just flush the caches entirely.
|
||||
*/
|
||||
ResetSystemCache();
|
||||
CACHE2_elog(DEBUG, "CatalogCacheFlushRelation called for %u", relId);
|
||||
|
||||
for (cache = CacheHdr->ch_caches; cache; cache = cache->cc_next)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* We can ignore uninitialized caches, since they must be empty */
|
||||
if (cache->cc_tupdesc == NULL)
|
||||
continue;
|
||||
|
||||
/* Does this cache store tuples of the target relation itself? */
|
||||
if (cache->cc_tupdesc->attrs[0]->attrelid == relId)
|
||||
{
|
||||
/* Yes, so flush all its contents */
|
||||
ResetCatalogCache(cache);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Does this cache store tuples associated with relations at all? */
|
||||
if (cache->cc_reloidattr == 0)
|
||||
continue; /* nope, leave it alone */
|
||||
|
||||
/* Yes, scan the tuples and remove those related to relId */
|
||||
for (i = 0; i < cache->cc_size; i++)
|
||||
{
|
||||
Dlelem *elt,
|
||||
*nextelt;
|
||||
|
||||
for (elt = DLGetHead(&cache->cc_bucket[i]); elt; elt = nextelt)
|
||||
{
|
||||
CatCTup *ct = (CatCTup *) DLE_VAL(elt);
|
||||
Oid tupRelid;
|
||||
|
||||
nextelt = DLGetSucc(elt);
|
||||
|
||||
if (cache->cc_reloidattr == ObjectIdAttributeNumber)
|
||||
tupRelid = ct->tuple.t_data->t_oid;
|
||||
else
|
||||
{
|
||||
bool isNull;
|
||||
|
||||
tupRelid = DatumGetObjectId(
|
||||
fastgetattr(&ct->tuple,
|
||||
cache->cc_reloidattr,
|
||||
cache->cc_tupdesc,
|
||||
&isNull));
|
||||
Assert(!isNull);
|
||||
}
|
||||
|
||||
if (tupRelid == relId)
|
||||
{
|
||||
if (ct->refcount > 0)
|
||||
ct->dead = true;
|
||||
else
|
||||
CatCacheRemoveCTup(cache, ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CACHE1_elog(DEBUG, "end of CatalogCacheFlushRelation call");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -615,7 +670,6 @@ SystemCacheRelationFlushed(Oid relId)
|
|||
* 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 InitCatCache_DEBUG1 \
|
||||
|
@ -632,6 +686,7 @@ CatCache *
|
|||
InitCatCache(int id,
|
||||
char *relname,
|
||||
char *indname,
|
||||
int reloidattr,
|
||||
int nkeys,
|
||||
int *key)
|
||||
{
|
||||
|
@ -642,63 +697,67 @@ InitCatCache(int id,
|
|||
/*
|
||||
* first switch to the cache context so our allocations do not vanish
|
||||
* at the end of a transaction
|
||||
*
|
||||
*/
|
||||
if (!CacheMemoryContext)
|
||||
CreateCacheMemoryContext();
|
||||
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
/*
|
||||
* if first time through, initialize the cache group header,
|
||||
* including global LRU list header
|
||||
*/
|
||||
if (CacheHdr == NULL)
|
||||
{
|
||||
CacheHdr = (CatCacheHeader *) palloc(sizeof(CatCacheHeader));
|
||||
CacheHdr->ch_caches = NULL;
|
||||
CacheHdr->ch_ntup = 0;
|
||||
CacheHdr->ch_maxtup = MAXCCTUPLES;
|
||||
DLInitList(&CacheHdr->ch_lrulist);
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate a new cache structure
|
||||
*
|
||||
*/
|
||||
cp = (CatCache *) palloc(sizeof(CatCache));
|
||||
MemSet((char *) cp, 0, sizeof(CatCache));
|
||||
cp = (CatCache *) palloc(sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist));
|
||||
MemSet((char *) cp, 0, sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist));
|
||||
|
||||
/*
|
||||
* initialize the cache buckets (each bucket is a list header) and the
|
||||
* LRU tuple list
|
||||
*
|
||||
* initialize the cache buckets (each bucket is a list header)
|
||||
*/
|
||||
DLInitList(&cp->cc_lrulist);
|
||||
for (i = 0; i < NCCBUCK; ++i)
|
||||
DLInitList(&cp->cc_cache[i]);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
for (i = 0; i < NCCBUCKETS; ++i)
|
||||
DLInitList(&cp->cc_bucket[i]);
|
||||
|
||||
/*
|
||||
* initialize the cache's relation information for the relation
|
||||
* corresponding to this cache, and initialize some of the new cache's
|
||||
* other internal fields. But don't open the relation yet.
|
||||
*
|
||||
*/
|
||||
cp->id = id;
|
||||
cp->cc_relname = relname;
|
||||
cp->cc_indname = indname;
|
||||
cp->cc_reloidattr = reloidattr;
|
||||
cp->cc_tupdesc = (TupleDesc) NULL;
|
||||
cp->id = id;
|
||||
cp->cc_maxtup = MAXTUP;
|
||||
cp->cc_size = NCCBUCK;
|
||||
cp->cc_ntup = 0;
|
||||
cp->cc_size = NCCBUCKETS;
|
||||
cp->cc_nkeys = nkeys;
|
||||
for (i = 0; i < nkeys; ++i)
|
||||
cp->cc_key[i] = key[i];
|
||||
|
||||
/*
|
||||
* all done. new cache is initialized. print some debugging
|
||||
* information, if appropriate.
|
||||
*
|
||||
* new cache is initialized as far as we can go for now.
|
||||
* print some debugging information, if appropriate.
|
||||
*/
|
||||
InitCatCache_DEBUG1;
|
||||
|
||||
/*
|
||||
* add completed cache to top of group header's list
|
||||
*/
|
||||
cp->cc_next = CacheHdr->ch_caches;
|
||||
CacheHdr->ch_caches = cp;
|
||||
|
||||
/*
|
||||
* back to the old context before we return...
|
||||
*
|
||||
*/
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
|
@ -766,7 +825,6 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey)
|
|||
*
|
||||
* This call searches a system cache for a tuple, opening the relation
|
||||
* if necessary (the first access to a particular cache).
|
||||
*
|
||||
*/
|
||||
HeapTuple
|
||||
SearchCatCache(CatCache *cache,
|
||||
|
@ -785,14 +843,12 @@ SearchCatCache(CatCache *cache,
|
|||
|
||||
/*
|
||||
* one-time startup overhead
|
||||
*
|
||||
*/
|
||||
if (cache->cc_tupdesc == NULL)
|
||||
CatalogCacheInitializeCache(cache);
|
||||
|
||||
/*
|
||||
* initialize the search key information
|
||||
*
|
||||
*/
|
||||
memcpy(cur_skey, cache->cc_skey, sizeof(cur_skey));
|
||||
cur_skey[0].sk_argument = v1;
|
||||
|
@ -802,15 +858,13 @@ SearchCatCache(CatCache *cache,
|
|||
|
||||
/*
|
||||
* find the hash bucket in which to look for the tuple
|
||||
*
|
||||
*/
|
||||
hash = CatalogCacheComputeHashIndex(cache, cur_skey);
|
||||
|
||||
/*
|
||||
* scan the hash bucket until we find a match or exhaust our tuples
|
||||
*
|
||||
*/
|
||||
for (elt = DLGetHead(&cache->cc_cache[hash]);
|
||||
for (elt = DLGetHead(&cache->cc_bucket[hash]);
|
||||
elt;
|
||||
elt = DLGetSucc(elt))
|
||||
{
|
||||
|
@ -824,7 +878,6 @@ SearchCatCache(CatCache *cache,
|
|||
/*
|
||||
* see if the cached tuple matches our key. (should we be worried
|
||||
* about time ranges? -cim 10/2/90)
|
||||
*
|
||||
*/
|
||||
HeapKeyTest(&ct->tuple,
|
||||
cache->cc_tupdesc,
|
||||
|
@ -841,7 +894,6 @@ SearchCatCache(CatCache *cache,
|
|||
* subsequent searches. (The most frequently accessed elements in
|
||||
* any hashbucket will tend to be near the front of the
|
||||
* hashbucket's list.)
|
||||
*
|
||||
*/
|
||||
ct->refcount++;
|
||||
|
||||
|
@ -869,19 +921,16 @@ SearchCatCache(CatCache *cache,
|
|||
* will never be referenced again, and will eventually age out of the
|
||||
* cache, so there's no functional problem. This case is rare enough
|
||||
* that it's not worth expending extra cycles to detect.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* open the relation associated with the cache
|
||||
*
|
||||
*/
|
||||
relation = heap_openr(cache->cc_relname, AccessShareLock);
|
||||
|
||||
/*
|
||||
* Scan the relation to find the tuple. If there's an index, and if
|
||||
* it's safe to do so, use the index. Else do a heap scan.
|
||||
*
|
||||
*/
|
||||
ct = NULL;
|
||||
|
||||
|
@ -958,13 +1007,11 @@ SearchCatCache(CatCache *cache,
|
|||
|
||||
/*
|
||||
* close the relation
|
||||
*
|
||||
*/
|
||||
heap_close(relation, AccessShareLock);
|
||||
|
||||
/*
|
||||
* scan is complete. if tup was found, we can add it to the cache.
|
||||
*
|
||||
*/
|
||||
if (ct == NULL)
|
||||
return NULL;
|
||||
|
@ -972,27 +1019,27 @@ SearchCatCache(CatCache *cache,
|
|||
/*
|
||||
* Finish initializing the CatCTup header, and add it to the linked
|
||||
* lists.
|
||||
*
|
||||
*/
|
||||
CACHE1_elog(DEBUG, "SearchCatCache: found tuple");
|
||||
|
||||
ct->ct_magic = CT_MAGIC;
|
||||
ct->my_cache = cache;
|
||||
DLInitElem(&ct->lrulist_elem, (void *) ct);
|
||||
DLInitElem(&ct->cache_elem, (void *) ct);
|
||||
ct->refcount = 1; /* count this first reference */
|
||||
ct->dead = false;
|
||||
|
||||
DLAddHead(&cache->cc_lrulist, &ct->lrulist_elem);
|
||||
DLAddHead(&cache->cc_cache[hash], &ct->cache_elem);
|
||||
DLAddHead(&CacheHdr->ch_lrulist, &ct->lrulist_elem);
|
||||
DLAddHead(&cache->cc_bucket[hash], &ct->cache_elem);
|
||||
|
||||
/*
|
||||
* If we've exceeded the desired size of this cache, try to throw away
|
||||
* If we've exceeded the desired size of the caches, try to throw away
|
||||
* the least recently used entry.
|
||||
*
|
||||
*/
|
||||
if (++cache->cc_ntup > cache->cc_maxtup)
|
||||
++cache->cc_ntup;
|
||||
if (++CacheHdr->ch_ntup > CacheHdr->ch_maxtup)
|
||||
{
|
||||
for (elt = DLGetTail(&cache->cc_lrulist);
|
||||
for (elt = DLGetTail(&CacheHdr->ch_lrulist);
|
||||
elt;
|
||||
elt = DLGetPred(elt))
|
||||
{
|
||||
|
@ -1002,14 +1049,14 @@ SearchCatCache(CatCache *cache,
|
|||
{
|
||||
CACHE2_elog(DEBUG, "SearchCatCache(%s): Overflow, LRU removal",
|
||||
cache->cc_relname);
|
||||
CatCacheRemoveCTup(cache, oldct);
|
||||
CatCacheRemoveCTup(oldct->my_cache, oldct);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CACHE4_elog(DEBUG, "SearchCatCache(%s): Contains %d/%d tuples",
|
||||
cache->cc_relname, cache->cc_ntup, cache->cc_maxtup);
|
||||
cache->cc_relname, cache->cc_ntup, CacheHdr->ch_ntup);
|
||||
CACHE3_elog(DEBUG, "SearchCatCache(%s): put in bucket %d",
|
||||
cache->cc_relname, hash);
|
||||
|
||||
|
@ -1026,7 +1073,6 @@ SearchCatCache(CatCache *cache,
|
|||
* will be freed as soon as their refcount goes to zero. In combination
|
||||
* with aset.c's CLOBBER_FREED_MEMORY option, this provides a good test
|
||||
* to catch references to already-released catcache entries.
|
||||
*
|
||||
*/
|
||||
void
|
||||
ReleaseCatCache(HeapTuple tuple)
|
||||
|
@ -1046,12 +1092,7 @@ ReleaseCatCache(HeapTuple tuple)
|
|||
#endif
|
||||
)
|
||||
{
|
||||
/* We can find the associated cache using the dllist pointers */
|
||||
Dllist *lru = DLGetListHdr(&ct->lrulist_elem);
|
||||
CatCache *cache = (CatCache *) (((char *) lru) -
|
||||
offsetof(CatCache, cc_lrulist));
|
||||
|
||||
CatCacheRemoveCTup(cache, ct);
|
||||
CatCacheRemoveCTup(ct->my_cache, ct);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1061,7 +1102,7 @@ ReleaseCatCache(HeapTuple tuple)
|
|||
* This is part of a rather subtle chain of events, so pay attention:
|
||||
*
|
||||
* When a tuple is updated or deleted, it cannot be flushed from the
|
||||
* catcaches immediately, for reasons explained at the top of inval.c.
|
||||
* 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.
|
||||
*
|
||||
|
@ -1081,7 +1122,6 @@ ReleaseCatCache(HeapTuple tuple)
|
|||
* 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.
|
||||
*
|
||||
*/
|
||||
void
|
||||
PrepareToInvalidateCacheTuple(Relation relation,
|
||||
|
@ -1090,14 +1130,15 @@ PrepareToInvalidateCacheTuple(Relation relation,
|
|||
{
|
||||
CatCache *ccp;
|
||||
|
||||
CACHE1_elog(DEBUG, "PrepareToInvalidateCacheTuple: called");
|
||||
|
||||
/*
|
||||
* sanity checks
|
||||
*
|
||||
*/
|
||||
Assert(RelationIsValid(relation));
|
||||
Assert(HeapTupleIsValid(tuple));
|
||||
Assert(PointerIsValid(function));
|
||||
CACHE1_elog(DEBUG, "PrepareToInvalidateCacheTuple: called");
|
||||
Assert(CacheHdr != NULL);
|
||||
|
||||
/* ----------------
|
||||
* for each cache
|
||||
|
@ -1107,7 +1148,7 @@ PrepareToInvalidateCacheTuple(Relation relation,
|
|||
* ----------------
|
||||
*/
|
||||
|
||||
for (ccp = Caches; ccp; ccp = ccp->cc_next)
|
||||
for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next)
|
||||
{
|
||||
if (strcmp(ccp->cc_relname, RelationGetRelationName(relation)) != 0)
|
||||
continue;
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.43 2001/06/01 20:23:06 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.44 2001/06/18 03:35:07 tgl Exp $
|
||||
*
|
||||
* Note - this code is real crufty... badly needs a rewrite to improve
|
||||
* readability and portability. (Shouldn't assume Oid == Index, for example)
|
||||
|
@ -478,16 +478,20 @@ CacheIdInvalidate(Index cacheId,
|
|||
}
|
||||
|
||||
/*
|
||||
* ResetSystemCaches
|
||||
* InvalidateSystemCaches
|
||||
*
|
||||
* This blows away all tuples in the system catalog caches and
|
||||
* all the cached relation descriptors (and closes their files too).
|
||||
* Relation descriptors that have positive refcounts are then rebuilt.
|
||||
*
|
||||
* We call this when we see a shared-inval-queue overflow signal,
|
||||
* since that tells us we've lost some shared-inval messages and hence
|
||||
* don't know what needs to be invalidated.
|
||||
*/
|
||||
static void
|
||||
ResetSystemCaches(void)
|
||||
InvalidateSystemCaches(void)
|
||||
{
|
||||
ResetSystemCache();
|
||||
ResetCatalogCaches();
|
||||
RelationCacheInvalidate();
|
||||
}
|
||||
|
||||
|
@ -643,7 +647,7 @@ DiscardInvalid(void)
|
|||
elog(DEBUG, "DiscardInvalid called");
|
||||
#endif /* defined(INVALIDDEBUG) */
|
||||
|
||||
InvalidateSharedInvalid(CacheIdInvalidate, ResetSystemCaches);
|
||||
InvalidateSharedInvalid(CacheIdInvalidate, InvalidateSystemCaches);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.137 2001/06/12 05:55:49 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.138 2001/06/18 03:35:07 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -1657,7 +1657,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
|
|||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
/* Clear out catcache's entries for this relation */
|
||||
SystemCacheRelationFlushed(RelationGetRelid(relation));
|
||||
CatalogCacheFlushRelation(RelationGetRelid(relation));
|
||||
|
||||
/*
|
||||
* Free all the subsidiary data structures of the relcache entry. We
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.62 2001/06/12 05:55:49 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.63 2001/06/18 03:35:07 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* These routines allow the parser/planner/executor to perform
|
||||
|
@ -54,7 +54,12 @@
|
|||
|
||||
Add your entry to the cacheinfo[] array below. All cache lists are
|
||||
alphabetical, so add it in the proper place. Specify the relation
|
||||
name, index name, number of keys, and key attribute numbers.
|
||||
name, index name, number of keys, and key attribute numbers. If the
|
||||
relation contains tuples that are associated with a particular relation
|
||||
(for example, its attributes, rules, triggers, etc) then specify the
|
||||
attribute number that contains the OID of the associated relation.
|
||||
This is used by CatalogCacheFlushRelation() to remove the correct
|
||||
tuples during a table drop or relcache invalidation event.
|
||||
|
||||
In include/catalog/indexing.h, add a define for the number of indexes
|
||||
on the relation, add define(s) for the index name(s), add an extern
|
||||
|
@ -76,12 +81,12 @@
|
|||
|
||||
/*
|
||||
* struct cachedesc: information defining a single syscache
|
||||
*
|
||||
*/
|
||||
struct cachedesc
|
||||
{
|
||||
char *name; /* name of the relation being cached */
|
||||
char *indname; /* name of index relation for this cache */
|
||||
int reloidattr; /* attr number of rel OID reference, or 0 */
|
||||
int nkeys; /* # of keys needed for cache lookup */
|
||||
int key[4]; /* attribute numbers of key attrs */
|
||||
};
|
||||
|
@ -89,6 +94,7 @@ struct cachedesc
|
|||
static struct cachedesc cacheinfo[] = {
|
||||
{AggregateRelationName, /* AGGNAME */
|
||||
AggregateNameTypeIndex,
|
||||
0,
|
||||
2,
|
||||
{
|
||||
Anum_pg_aggregate_aggname,
|
||||
|
@ -98,6 +104,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{AccessMethodRelationName, /* AMNAME */
|
||||
AmNameIndex,
|
||||
0,
|
||||
1,
|
||||
{
|
||||
Anum_pg_am_amname,
|
||||
|
@ -107,6 +114,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{AccessMethodOperatorRelationName, /* AMOPOPID */
|
||||
AccessMethodOpidIndex,
|
||||
0,
|
||||
3,
|
||||
{
|
||||
Anum_pg_amop_amopclaid,
|
||||
|
@ -116,6 +124,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
|
||||
AccessMethodStrategyIndex,
|
||||
0,
|
||||
3,
|
||||
{
|
||||
Anum_pg_amop_amopid,
|
||||
|
@ -125,6 +134,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{AttributeRelationName, /* ATTNAME */
|
||||
AttributeRelidNameIndex,
|
||||
Anum_pg_attribute_attrelid,
|
||||
2,
|
||||
{
|
||||
Anum_pg_attribute_attrelid,
|
||||
|
@ -134,6 +144,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{AttributeRelationName, /* ATTNUM */
|
||||
AttributeRelidNumIndex,
|
||||
Anum_pg_attribute_attrelid,
|
||||
2,
|
||||
{
|
||||
Anum_pg_attribute_attrelid,
|
||||
|
@ -143,6 +154,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{OperatorClassRelationName, /* CLADEFTYPE */
|
||||
OpclassDeftypeIndex,
|
||||
0,
|
||||
1,
|
||||
{
|
||||
Anum_pg_opclass_opcdeftype,
|
||||
|
@ -152,6 +164,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{OperatorClassRelationName, /* CLANAME */
|
||||
OpclassNameIndex,
|
||||
0,
|
||||
1,
|
||||
{
|
||||
Anum_pg_opclass_opcname,
|
||||
|
@ -161,6 +174,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{GroupRelationName, /* GRONAME */
|
||||
GroupNameIndex,
|
||||
0,
|
||||
1,
|
||||
{
|
||||
Anum_pg_group_groname,
|
||||
|
@ -170,6 +184,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{GroupRelationName, /* GROSYSID */
|
||||
GroupSysidIndex,
|
||||
0,
|
||||
1,
|
||||
{
|
||||
Anum_pg_group_grosysid,
|
||||
|
@ -179,6 +194,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{IndexRelationName, /* INDEXRELID */
|
||||
IndexRelidIndex,
|
||||
Anum_pg_index_indrelid,
|
||||
1,
|
||||
{
|
||||
Anum_pg_index_indexrelid,
|
||||
|
@ -188,6 +204,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{InheritsRelationName, /* INHRELID */
|
||||
InheritsRelidSeqnoIndex,
|
||||
Anum_pg_inherits_inhrelid,
|
||||
2,
|
||||
{
|
||||
Anum_pg_inherits_inhrelid,
|
||||
|
@ -197,6 +214,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{LanguageRelationName, /* LANGNAME */
|
||||
LanguageNameIndex,
|
||||
0,
|
||||
1,
|
||||
{
|
||||
Anum_pg_language_lanname,
|
||||
|
@ -206,6 +224,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{LanguageRelationName, /* LANGOID */
|
||||
LanguageOidIndex,
|
||||
0,
|
||||
1,
|
||||
{
|
||||
ObjectIdAttributeNumber,
|
||||
|
@ -215,6 +234,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{OperatorRelationName, /* OPERNAME */
|
||||
OperatorNameIndex,
|
||||
0,
|
||||
4,
|
||||
{
|
||||
Anum_pg_operator_oprname,
|
||||
|
@ -224,6 +244,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{OperatorRelationName, /* OPEROID */
|
||||
OperatorOidIndex,
|
||||
0,
|
||||
1,
|
||||
{
|
||||
ObjectIdAttributeNumber,
|
||||
|
@ -233,6 +254,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{ProcedureRelationName, /* PROCNAME */
|
||||
ProcedureNameIndex,
|
||||
0,
|
||||
3,
|
||||
{
|
||||
Anum_pg_proc_proname,
|
||||
|
@ -242,6 +264,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{ProcedureRelationName, /* PROCOID */
|
||||
ProcedureOidIndex,
|
||||
0,
|
||||
1,
|
||||
{
|
||||
ObjectIdAttributeNumber,
|
||||
|
@ -251,6 +274,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{RelationRelationName, /* RELNAME */
|
||||
ClassNameIndex,
|
||||
ObjectIdAttributeNumber,
|
||||
1,
|
||||
{
|
||||
Anum_pg_class_relname,
|
||||
|
@ -260,6 +284,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{RelationRelationName, /* RELOID */
|
||||
ClassOidIndex,
|
||||
ObjectIdAttributeNumber,
|
||||
1,
|
||||
{
|
||||
ObjectIdAttributeNumber,
|
||||
|
@ -269,6 +294,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{RewriteRelationName, /* RULENAME */
|
||||
RewriteRulenameIndex,
|
||||
Anum_pg_rewrite_ev_class,
|
||||
1,
|
||||
{
|
||||
Anum_pg_rewrite_rulename,
|
||||
|
@ -278,6 +304,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{ShadowRelationName, /* SHADOWNAME */
|
||||
ShadowNameIndex,
|
||||
0,
|
||||
1,
|
||||
{
|
||||
Anum_pg_shadow_usename,
|
||||
|
@ -287,6 +314,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{ShadowRelationName, /* SHADOWSYSID */
|
||||
ShadowSysidIndex,
|
||||
0,
|
||||
1,
|
||||
{
|
||||
Anum_pg_shadow_usesysid,
|
||||
|
@ -296,6 +324,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{StatisticRelationName, /* STATRELATT */
|
||||
StatisticRelidAttnumIndex,
|
||||
Anum_pg_statistic_starelid,
|
||||
2,
|
||||
{
|
||||
Anum_pg_statistic_starelid,
|
||||
|
@ -305,6 +334,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{TypeRelationName, /* TYPENAME */
|
||||
TypeNameIndex,
|
||||
Anum_pg_type_typrelid,
|
||||
1,
|
||||
{
|
||||
Anum_pg_type_typname,
|
||||
|
@ -314,6 +344,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}},
|
||||
{TypeRelationName, /* TYPEOID */
|
||||
TypeOidIndex,
|
||||
Anum_pg_type_typrelid,
|
||||
1,
|
||||
{
|
||||
ObjectIdAttributeNumber,
|
||||
|
@ -323,8 +354,7 @@ static struct cachedesc cacheinfo[] = {
|
|||
}}
|
||||
};
|
||||
|
||||
static CatCache *SysCache[
|
||||
lengthof(cacheinfo)];
|
||||
static CatCache *SysCache[lengthof(cacheinfo)];
|
||||
static int SysCacheSize = lengthof(cacheinfo);
|
||||
static bool CacheInitialized = false;
|
||||
|
||||
|
@ -358,6 +388,7 @@ InitCatalogCache(void)
|
|||
SysCache[cacheId] = InitCatCache(cacheId,
|
||||
cacheinfo[cacheId].name,
|
||||
cacheinfo[cacheId].indname,
|
||||
cacheinfo[cacheId].reloidattr,
|
||||
cacheinfo[cacheId].nkeys,
|
||||
cacheinfo[cacheId].key);
|
||||
if (!PointerIsValid(SysCache[cacheId]))
|
||||
|
|
|
@ -13,32 +13,49 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: catcache.h,v 1.32 2001/03/22 04:01:11 momjian Exp $
|
||||
* $Id: catcache.h,v 1.33 2001/06/18 03:35:07 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef CATCACHE_H
|
||||
#define CATCACHE_H
|
||||
|
||||
/* #define CACHEDEBUG *//* turns DEBUG elogs on */
|
||||
|
||||
#include "access/htup.h"
|
||||
#include "lib/dllist.h"
|
||||
|
||||
/*
|
||||
* struct catctup: individual tuple in the cache.
|
||||
* struct catcache: information for managing a cache.
|
||||
* struct catcacheheader: information for managing all the caches.
|
||||
*/
|
||||
|
||||
typedef struct catcache
|
||||
{
|
||||
int id; /* cache identifier --- see syscache.h */
|
||||
struct catcache *cc_next; /* link to next catcache */
|
||||
char *cc_relname; /* name of relation the tuples come from */
|
||||
char *cc_indname; /* name of index matching cache keys */
|
||||
int cc_reloidattr; /* AttrNumber of relation OID, or 0 */
|
||||
TupleDesc cc_tupdesc; /* tuple descriptor (copied from reldesc) */
|
||||
int cc_ntup; /* # of tuples currently in this cache */
|
||||
int cc_size; /* # of hash buckets in this cache */
|
||||
int cc_nkeys; /* number of keys (1..4) */
|
||||
int cc_key[4]; /* AttrNumber of each key */
|
||||
PGFunction cc_hashfunc[4]; /* hash function to use for each key */
|
||||
ScanKeyData cc_skey[4]; /* precomputed key info for heap scans */
|
||||
Dllist cc_bucket[1]; /* hash buckets --- VARIABLE LENGTH ARRAY */
|
||||
} CatCache; /* VARIABLE LENGTH STRUCT */
|
||||
|
||||
|
||||
typedef struct catctup
|
||||
{
|
||||
int ct_magic; /* for Assert checks */
|
||||
#define CT_MAGIC 0x57261502
|
||||
|
||||
CatCache *my_cache; /* link to owning catcache */
|
||||
/*
|
||||
* Each tuple in a cache is a member of two lists: one lists all the
|
||||
* elements in that cache in LRU order, and the other lists just the
|
||||
* elements in one hashbucket, also in LRU order.
|
||||
* elements in all the caches in LRU order, and the other lists just
|
||||
* the elements in one hashbucket of one cache, also in LRU order.
|
||||
*
|
||||
* A tuple marked "dead" must not be returned by subsequent searches.
|
||||
* However, it won't be physically deleted from the cache until its
|
||||
|
@ -52,30 +69,14 @@ typedef struct catctup
|
|||
} CatCTup;
|
||||
|
||||
|
||||
/* voodoo constants */
|
||||
#define NCCBUCK 500 /* CatCache buckets */
|
||||
#define MAXTUP 500 /* Maximum # of tuples stored per cache */
|
||||
|
||||
|
||||
typedef struct catcache
|
||||
typedef struct catcacheheader
|
||||
{
|
||||
int id; /* cache identifier --- see syscache.h */
|
||||
struct catcache *cc_next; /* link to next catcache */
|
||||
char *cc_relname; /* name of relation the tuples come from */
|
||||
char *cc_indname; /* name of index matching cache keys */
|
||||
TupleDesc cc_tupdesc; /* tuple descriptor (copied from reldesc) */
|
||||
short cc_ntup; /* # of tuples in this cache */
|
||||
short cc_maxtup; /* max # of tuples allowed (LRU) */
|
||||
short cc_size; /* # of hash buckets in this cache */
|
||||
short cc_nkeys; /* number of keys (1..4) */
|
||||
short cc_key[4]; /* AttrNumber of each key */
|
||||
PGFunction cc_hashfunc[4]; /* hash function to use for each key */
|
||||
ScanKeyData cc_skey[4]; /* precomputed key info for heap scans */
|
||||
Dllist cc_lrulist; /* overall LRU list, most recent first */
|
||||
Dllist cc_cache[NCCBUCK]; /* hash buckets */
|
||||
} CatCache;
|
||||
CatCache *ch_caches; /* head of list of CatCache structs */
|
||||
int ch_ntup; /* # of tuples in all caches */
|
||||
int ch_maxtup; /* max # of tuples allowed (LRU) */
|
||||
Dllist ch_lrulist; /* overall LRU list, most recent first */
|
||||
} CatCacheHeader;
|
||||
|
||||
#define InvalidCatalogCacheId (-1)
|
||||
|
||||
/* this extern duplicates utils/memutils.h... */
|
||||
extern MemoryContext CacheMemoryContext;
|
||||
|
@ -84,6 +85,7 @@ extern void CreateCacheMemoryContext(void);
|
|||
extern void AtEOXact_CatCache(bool isCommit);
|
||||
|
||||
extern CatCache *InitCatCache(int id, char *relname, char *indname,
|
||||
int reloidattr,
|
||||
int nkeys, int *key);
|
||||
|
||||
extern HeapTuple SearchCatCache(CatCache *cache,
|
||||
|
@ -91,8 +93,8 @@ extern HeapTuple SearchCatCache(CatCache *cache,
|
|||
Datum v3, Datum v4);
|
||||
extern void ReleaseCatCache(HeapTuple tuple);
|
||||
|
||||
extern void ResetSystemCache(void);
|
||||
extern void SystemCacheRelationFlushed(Oid relId);
|
||||
extern void ResetCatalogCaches(void);
|
||||
extern void CatalogCacheFlushRelation(Oid relId);
|
||||
extern void CatalogCacheIdInvalidate(int cacheId, Index hashIndex,
|
||||
ItemPointer pointer);
|
||||
extern void PrepareToInvalidateCacheTuple(Relation relation,
|
||||
|
|
Loading…
Reference in New Issue