📄 catcache.c
字号:
/*------------------------------------------------------------------------- * * 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 + -