*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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
#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
*
* 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,
#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
{
switch (keytype)
{
- case BOOLOID:
- case CHAROID:
+ case BOOLOID:
+ case CHAROID:
return hashchar;
case NAMEOID:
return cc_hashname;
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
void
CreateCacheMemoryContext(void)
{
-
/*
* Purely for paranoia, check that context doesn't exist; caller
* probably did so already.
* 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 \
Relation relation;
MemoryContext oldcxt;
TupleDesc tupdesc;
- short i;
+ int i;
CatalogCacheInitializeCache_DEBUG1;
* 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);
/*
* CatalogCacheComputeHashIndex
- *
*/
static Index
CatalogCacheComputeHashIndex(CatCache *cache, ScanKey cur_skey)
/*
* CatalogCacheComputeTupleHashIndex
- *
*/
static Index
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);
pfree(ct);
--cache->cc_ntup;
+ --CacheHdr->ch_ntup;
}
/*
* 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,
/*
* 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;
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);
* public functions
*
* AtEOXact_CatCache
- * ResetSystemCache
+ * ResetCatalogCaches
* InitCatCache
* SearchCatCache
* ReleaseCatCache
* 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;
+ Dlelem *elt,
+ *nextelt;
- for (cache = Caches; cache; cache = cache->cc_next)
+ for (elt = DLGetHead(&CacheHdr->ch_lrulist); elt; elt = nextelt)
{
- Dlelem *elt,
- *nextelt;
+ CatCTup *ct = (CatCTup *) DLE_VAL(elt);
- for (elt = DLGetHead(&cache->cc_lrulist); elt; elt = nextelt)
- {
- CatCTup *ct = (CatCTup *) DLE_VAL(elt);
+ nextelt = DLGetSucc(elt);
- nextelt = DLGetSucc(elt);
-
- if (ct->refcount != 0)
- {
- if (isCommit)
- elog(NOTICE, "Cache reference leak: cache %s (%d), tuple %u has count %d",
- cache->cc_relname, cache->id,
- ct->tuple.t_data->t_oid,
- ct->refcount);
- ct->refcount = 0;
- }
-
- /* Clean up any now-deletable dead entries */
- if (ct->dead)
- CatCacheRemoveCTup(cache, ct);
+ if (ct->refcount != 0)
+ {
+ if (isCommit)
+ elog(NOTICE, "Cache reference leak: cache %s (%d), tuple %u has count %d",
+ ct->my_cache->cc_relname, ct->my_cache->id,
+ ct->tuple.t_data->t_oid,
+ ct->refcount);
+ ct->refcount = 0;
}
+
+ /* Clean up any now-deletable dead entries */
+ if (ct->dead)
+ 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;
-
- CACHE1_elog(DEBUG, "ResetSystemCache called");
+ int i;
- /* ----------------
- * 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);
CatCacheRemoveCTup(cache, ct);
}
}
+}
- CACHE1_elog(DEBUG, "end of ResetSystemCache call");
+/*
+ * 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");
}
/*
- * SystemCacheRelationFlushed
+ * CatalogCacheFlushRelation
*
* This is called by RelationFlushRelation() to clear out cached information
* about a relation being dropped. (This could be a DROP TABLE command,
* 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");
}
/*
* 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 \
#define InitCatCache_DEBUG1
#endif
-CatCache *
+CatCache *
InitCatCache(int id,
char *relname,
char *indname,
+ int reloidattr,
int nkeys,
int *key)
{
/*
* first switch to the cache context so our allocations do not vanish
* at the end of a transaction
- *
*/
if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/*
- * allocate a new cache structure
- *
+ * if first time through, initialize the cache group header,
+ * including global LRU list header
*/
- cp = (CatCache *) palloc(sizeof(CatCache));
- MemSet((char *) cp, 0, sizeof(CatCache));
+ if (CacheHdr == NULL)
+ {
+ CacheHdr = (CatCacheHeader *) palloc(sizeof(CatCacheHeader));
+ CacheHdr->ch_caches = NULL;
+ CacheHdr->ch_ntup = 0;
+ CacheHdr->ch_maxtup = MAXCCTUPLES;
+ DLInitList(&CacheHdr->ch_lrulist);
+ }
/*
- * initialize the cache buckets (each bucket is a list header) and the
- * LRU tuple list
- *
+ * allocate a new cache structure
*/
- DLInitList(&cp->cc_lrulist);
- for (i = 0; i < NCCBUCK; ++i)
- DLInitList(&cp->cc_cache[i]);
+ cp = (CatCache *) palloc(sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist));
+ MemSet((char *) cp, 0, sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist));
/*
- * 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.
- *
+ * initialize the cache buckets (each bucket is a list header)
*/
- 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);
*
* 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,
/*
* 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;
/*
* 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))
{
/*
* 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,
* subsequent searches. (The most frequently accessed elements in
* any hashbucket will tend to be near the front of the
* hashbucket's list.)
- *
*/
ct->refcount++;
* 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;
/*
* 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;
/*
* 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))
{
{
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);
* 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)
#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);
}
}
* 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.
*
* 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,
{
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
* ----------------
*/
- 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;
*
*
* 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
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
/*
* 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 */
};
static struct cachedesc cacheinfo[] = {
{AggregateRelationName, /* AGGNAME */
AggregateNameTypeIndex,
+ 0,
2,
{
Anum_pg_aggregate_aggname,
}},
{AccessMethodRelationName, /* AMNAME */
AmNameIndex,
+ 0,
1,
{
Anum_pg_am_amname,
}},
{AccessMethodOperatorRelationName, /* AMOPOPID */
AccessMethodOpidIndex,
+ 0,
3,
{
Anum_pg_amop_amopclaid,
}},
{AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
AccessMethodStrategyIndex,
+ 0,
3,
{
Anum_pg_amop_amopid,
}},
{AttributeRelationName, /* ATTNAME */
AttributeRelidNameIndex,
+ Anum_pg_attribute_attrelid,
2,
{
Anum_pg_attribute_attrelid,
}},
{AttributeRelationName, /* ATTNUM */
AttributeRelidNumIndex,
+ Anum_pg_attribute_attrelid,
2,
{
Anum_pg_attribute_attrelid,
}},
{OperatorClassRelationName, /* CLADEFTYPE */
OpclassDeftypeIndex,
+ 0,
1,
{
Anum_pg_opclass_opcdeftype,
}},
{OperatorClassRelationName, /* CLANAME */
OpclassNameIndex,
+ 0,
1,
{
Anum_pg_opclass_opcname,
}},
{GroupRelationName, /* GRONAME */
GroupNameIndex,
+ 0,
1,
{
Anum_pg_group_groname,
}},
{GroupRelationName, /* GROSYSID */
GroupSysidIndex,
+ 0,
1,
{
Anum_pg_group_grosysid,
}},
{IndexRelationName, /* INDEXRELID */
IndexRelidIndex,
+ Anum_pg_index_indrelid,
1,
{
Anum_pg_index_indexrelid,
}},
{InheritsRelationName, /* INHRELID */
InheritsRelidSeqnoIndex,
+ Anum_pg_inherits_inhrelid,
2,
{
Anum_pg_inherits_inhrelid,
}},
{LanguageRelationName, /* LANGNAME */
LanguageNameIndex,
+ 0,
1,
{
Anum_pg_language_lanname,
}},
{LanguageRelationName, /* LANGOID */
LanguageOidIndex,
+ 0,
1,
{
ObjectIdAttributeNumber,
}},
{OperatorRelationName, /* OPERNAME */
OperatorNameIndex,
+ 0,
4,
{
Anum_pg_operator_oprname,
}},
{OperatorRelationName, /* OPEROID */
OperatorOidIndex,
+ 0,
1,
{
ObjectIdAttributeNumber,
}},
{ProcedureRelationName, /* PROCNAME */
ProcedureNameIndex,
+ 0,
3,
{
Anum_pg_proc_proname,
}},
{ProcedureRelationName, /* PROCOID */
ProcedureOidIndex,
+ 0,
1,
{
ObjectIdAttributeNumber,
}},
{RelationRelationName, /* RELNAME */
ClassNameIndex,
+ ObjectIdAttributeNumber,
1,
{
Anum_pg_class_relname,
}},
{RelationRelationName, /* RELOID */
ClassOidIndex,
+ ObjectIdAttributeNumber,
1,
{
ObjectIdAttributeNumber,
}},
{RewriteRelationName, /* RULENAME */
RewriteRulenameIndex,
+ Anum_pg_rewrite_ev_class,
1,
{
Anum_pg_rewrite_rulename,
}},
{ShadowRelationName, /* SHADOWNAME */
ShadowNameIndex,
+ 0,
1,
{
Anum_pg_shadow_usename,
}},
{ShadowRelationName, /* SHADOWSYSID */
ShadowSysidIndex,
+ 0,
1,
{
Anum_pg_shadow_usesysid,
}},
{StatisticRelationName, /* STATRELATT */
StatisticRelidAttnumIndex,
+ Anum_pg_statistic_starelid,
2,
{
Anum_pg_statistic_starelid,
}},
{TypeRelationName, /* TYPENAME */
TypeNameIndex,
+ Anum_pg_type_typrelid,
1,
{
Anum_pg_type_typname,
}},
{TypeRelationName, /* TYPEOID */
TypeOidIndex,
+ Anum_pg_type_typrelid,
1,
{
ObjectIdAttributeNumber,
}}
};
-static CatCache *SysCache[
- lengthof(cacheinfo)];
+static CatCache *SysCache[lengthof(cacheinfo)];
static int SysCacheSize = lengthof(cacheinfo);
static bool CacheInitialized = false;
SysCache[cacheId] = InitCatCache(cacheId,
cacheinfo[cacheId].name,
cacheinfo[cacheId].indname,
+ cacheinfo[cacheId].reloidattr,
cacheinfo[cacheId].nkeys,
cacheinfo[cacheId].key);
if (!PointerIsValid(SysCache[cacheId]))
* 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
} 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;
extern void AtEOXact_CatCache(bool isCommit);
extern CatCache *InitCatCache(int id, char *relname, char *indname,
- int nkeys, int *key);
+ int reloidattr,
+ int nkeys, int *key);
extern HeapTuple SearchCatCache(CatCache *cache,
Datum v1, Datum v2,
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,