diff options
Diffstat (limited to 'src/backend/utils/cache')
-rw-r--r-- | src/backend/utils/cache/catcache.c | 391 | ||||
-rw-r--r-- | src/backend/utils/cache/lsyscache.c | 349 | ||||
-rw-r--r-- | src/backend/utils/cache/syscache.c | 187 | ||||
-rw-r--r-- | src/backend/utils/cache/temprel.c | 3 |
4 files changed, 527 insertions, 403 deletions
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index 39e05d0fb09..3d8e7d80ba8 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.71 2000/11/10 00:33:10 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.72 2000/11/16 22:30:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -28,7 +28,8 @@ #include "utils/catcache.h" #include "utils/syscache.h" -static void CatCacheRemoveCTup(CatCache *cache, Dlelem *e); + +static void CatCacheRemoveCTup(CatCache *cache, CatCTup *ct); static Index CatalogCacheComputeHashIndex(CatCache *cache, ScanKey cur_skey); static Index CatalogCacheComputeTupleHashIndex(CatCache *cache, @@ -388,28 +389,17 @@ CatalogCacheComputeTupleHashIndex(CatCache *cache, * -------------------------------- */ static void -CatCacheRemoveCTup(CatCache *cache, Dlelem *elt) +CatCacheRemoveCTup(CatCache *cache, CatCTup *ct) { - CatCTup *ct; - CatCTup *other_ct; - Dlelem *other_elt; - - if (!elt) /* probably-useless safety check */ - return; - - /* We need to zap both linked-list elements as well as the tuple */ + Assert(ct->refcount == 0); - ct = (CatCTup *) DLE_VAL(elt); - other_elt = ct->ct_node; - other_ct = (CatCTup *) DLE_VAL(other_elt); + /* delink from linked lists */ + DLRemove(&ct->lrulist_elem); + DLRemove(&ct->cache_elem); - heap_freetuple(ct->ct_tup); - - DLRemove(other_elt); - DLFreeElem(other_elt); - pfree(other_ct); - DLRemove(elt); - DLFreeElem(elt); + /* free associated tuple data */ + if (ct->tuple.t_data != NULL) + pfree(ct->tuple.t_data); pfree(ct); --cache->cc_ntup; @@ -425,13 +415,11 @@ CatCacheRemoveCTup(CatCache *cache, Dlelem *elt) * -------------------------------- */ void -CatalogCacheIdInvalidate(int cacheId, /* XXX */ +CatalogCacheIdInvalidate(int cacheId, Index hashIndex, ItemPointer pointer) { CatCache *ccp; - CatCTup *ct; - Dlelem *elt; /* ---------------- * sanity checks @@ -442,54 +430,101 @@ CatalogCacheIdInvalidate(int cacheId, /* XXX */ CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: called"); /* ---------------- - * inspect every cache that could contain the tuple + * inspect caches to find the proper cache * ---------------- */ for (ccp = Caches; ccp; ccp = ccp->cc_next) { + Dlelem *elt, + *nextelt; + 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)) + for (elt = DLGetHead(&ccp->cc_cache[hashIndex]); elt; elt = nextelt) { - ct = (CatCTup *) DLE_VAL(elt); - if (ItemPointerEquals(pointer, &ct->ct_tup->t_self)) - break; - } - - /* ---------------- - * if we found a matching tuple, invalidate it. - * ---------------- - */ + CatCTup *ct = (CatCTup *) DLE_VAL(elt); - if (elt) - { - CatCacheRemoveCTup(ccp, elt); + nextelt = DLGetSucc(elt); - CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: invalidated"); + if (ItemPointerEquals(pointer, &ct->tuple.t_self)) + { + if (ct->refcount > 0) + ct->dead = true; + else + CatCacheRemoveCTup(ccp, ct); + CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: invalidated"); + /* could be multiple matches, so keep looking! */ + } } - - if (cacheId != InvalidCatalogCacheId) - break; + break; /* need only search this one cache */ } } /* ---------------------------------------------------------------- * public functions * + * AtEOXact_CatCache * ResetSystemCache - * InitSysCache - * SearchSysCache + * InitCatCache + * SearchCatCache + * ReleaseCatCache * RelationInvalidateCatalogCacheTuple * ---------------------------------------------------------------- */ + + +/* -------------------------------- + * AtEOXact_CatCache + * + * Clean up catcaches at end of transaction (either commit or abort) + * + * We scan the caches to reset refcounts to zero. This is of course + * 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) + { + CatCTup *ct = (CatCTup *) DLE_VAL(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); + } + } +} + /* -------------------------------- * ResetSystemCache + * + * Reset caches when a shared cache inval event forces it * -------------------------------- */ void @@ -503,34 +538,25 @@ ResetSystemCache(void) * 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 each tuple + * remove the tuple, or at least mark it dead * ---------------- */ - for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next) + for (cache = Caches; cache; cache = cache->cc_next) { - int hash; + Dlelem *elt, + *nextelt; - for (hash = 0; hash < NCCBUCK; hash += 1) + for (elt = DLGetHead(&cache->cc_lrulist); elt; elt = nextelt) { - Dlelem *elt, - *nextelt; + CatCTup *ct = (CatCTup *) DLE_VAL(elt); - for (elt = DLGetHead(cache->cc_cache[hash]); elt; elt = nextelt) - { - nextelt = DLGetSucc(elt); - CatCacheRemoveCTup(cache, elt); - } - } + nextelt = DLGetSucc(elt); - /* double-check that ntup is now zero */ - if (cache->cc_ntup != 0) - { - elog(NOTICE, - "ResetSystemCache: cache %d has cc_ntup = %d, should be 0", - cache->id, cache->cc_ntup); - cache->cc_ntup = 0; + if (ct->refcount > 0) + ct->dead = true; + else + CatCacheRemoveCTup(cache, ct); } } @@ -572,7 +598,7 @@ SystemCacheRelationFlushed(Oid relId) } /* -------------------------------- - * InitSysCache + * InitCatCache * * This allocates and initializes a cache for a system catalog relation. * Actually, the cache is only partially initialized to avoid opening the @@ -581,18 +607,18 @@ SystemCacheRelationFlushed(Oid relId) * -------------------------------- */ #ifdef CACHEDEBUG -#define InitSysCache_DEBUG1 \ +#define InitCatCache_DEBUG1 \ do { \ - elog(DEBUG, "InitSysCache: rel=%s id=%d nkeys=%d size=%d\n", \ + elog(DEBUG, "InitCatCache: rel=%s id=%d nkeys=%d size=%d\n", \ cp->cc_relname, cp->id, cp->cc_nkeys, cp->cc_size); \ } while(0) #else -#define InitSysCache_DEBUG1 +#define InitCatCache_DEBUG1 #endif CatCache * -InitSysCache(int id, +InitCatCache(int id, char *relname, char *indname, int nkeys, @@ -624,25 +650,9 @@ InitSysCache(int id, * and the LRU tuple list * ---------------- */ - { - - /* - * We can only do this optimization because the number of hash - * buckets never changes. Without it, we call palloc() too much. - * We could move this to dllist.c, but the way we do this is not - * dynamic/portable, so why allow other routines to use it. - */ - Dllist *cache_begin = palloc((NCCBUCK + 1) * sizeof(Dllist)); - - for (i = 0; i <= NCCBUCK; ++i) - { - cp->cc_cache[i] = &cache_begin[i]; - cp->cc_cache[i]->dll_head = 0; - cp->cc_cache[i]->dll_tail = 0; - } - } - - cp->cc_lrulist = DLNewList(); + 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 @@ -673,7 +683,7 @@ InitSysCache(int id, * information, if appropriate. * ---------------- */ - InitSysCache_DEBUG1; + InitCatCache_DEBUG1; /* ---------------- * back to the old context before we return... @@ -742,14 +752,14 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey) } /* -------------------------------- - * SearchSysCache + * SearchCatCache * * This call searches a system cache for a tuple, opening the relation * if necessary (the first access to a particular cache). * -------------------------------- */ HeapTuple -SearchSysCache(CatCache *cache, +SearchCatCache(CatCache *cache, Datum v1, Datum v2, Datum v3, @@ -757,10 +767,8 @@ SearchSysCache(CatCache *cache, { ScanKeyData cur_skey[4]; Index hash; - CatCTup *ct = NULL; - CatCTup *nct; - CatCTup *nct2; Dlelem *elt; + CatCTup *ct; HeapTuple ntp; Relation relation; MemoryContext oldcxt; @@ -792,48 +800,50 @@ SearchSysCache(CatCache *cache, * 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_cache[hash]); elt; elt = DLGetSucc(elt)) { bool res; ct = (CatCTup *) DLE_VAL(elt); + + if (ct->dead) + continue; /* ignore dead entries */ + /* ---------------- * see if the cached tuple matches our key. * (should we be worried about time ranges? -cim 10/2/90) * ---------------- */ - HeapKeyTest(ct->ct_tup, + HeapKeyTest(&ct->tuple, cache->cc_tupdesc, cache->cc_nkeys, cur_skey, res); - if (res) - break; - } + if (! res) + continue; - /* ---------------- - * if we found a tuple in the cache, move it to the top of the - * lru list, and return it. We also move it to the front of the - * list for its hashbucket, in order to speed subsequent searches. - * (The most frequently accessed elements in any hashbucket will - * tend to be near the front of the hashbucket's list.) - * ---------------- - */ - if (elt) - { - Dlelem *old_lru_elt = ((CatCTup *) DLE_VAL(elt))->ct_node; + /* ---------------- + * we found a tuple in the cache: bump its refcount, move it to + * the front of the LRU list, and return it. We also move it + * to the front of the list for its hashbucket, in order to speed + * subsequent searches. (The most frequently accessed elements + * in any hashbucket will tend to be near the front of the + * hashbucket's list.) + * ---------------- + */ + ct->refcount++; - DLMoveToFront(old_lru_elt); - DLMoveToFront(elt); + DLMoveToFront(&ct->lrulist_elem); + DLMoveToFront(&ct->cache_elem); #ifdef CACHEDEBUG - CACHE3_elog(DEBUG, "SearchSysCache(%s): found in bucket %d", + CACHE3_elog(DEBUG, "SearchCatCache(%s): found in bucket %d", cache->cc_relname, hash); #endif /* CACHEDEBUG */ - return ct->ct_tup; + return &ct->tuple; } /* ---------------- @@ -864,7 +874,7 @@ SearchSysCache(CatCache *cache, * if it's safe to do so, use the index. Else do a heap scan. * ---------------- */ - ntp = NULL; + ct = NULL; if ((RelationGetForm(relation))->relhasindex && !IsIgnoringSystemIndexes() && @@ -876,7 +886,7 @@ SearchSysCache(CatCache *cache, HeapTupleData tuple; Buffer buffer; - CACHE2_elog(DEBUG, "SearchSysCache(%s): performing index scan", + CACHE2_elog(DEBUG, "SearchCatCache(%s): performing index scan", cache->cc_relname); idesc = index_openr(cache->cc_indname); @@ -892,7 +902,8 @@ SearchSysCache(CatCache *cache, { /* Copy tuple into our context */ oldcxt = MemoryContextSwitchTo(CacheMemoryContext); - ntp = heap_copytuple(&tuple); + ct = (CatCTup *) palloc(sizeof(CatCTup)); + heap_copytuple_with_tuple(&tuple, &ct->tuple); MemoryContextSwitchTo(oldcxt); ReleaseBuffer(buffer); break; @@ -906,7 +917,7 @@ SearchSysCache(CatCache *cache, HeapScanDesc sd; int i; - CACHE2_elog(DEBUG, "SearchSysCache(%s): performing heap scan", + CACHE2_elog(DEBUG, "SearchCatCache(%s): performing heap scan", cache->cc_relname); /* @@ -925,7 +936,8 @@ SearchSysCache(CatCache *cache, { /* Copy tuple into our context */ oldcxt = MemoryContextSwitchTo(CacheMemoryContext); - ntp = heap_copytuple(ntp); + ct = (CatCTup *) palloc(sizeof(CatCTup)); + heap_copytuple_with_tuple(ntp, &ct->tuple); MemoryContextSwitchTo(oldcxt); /* We should not free the result of heap_getnext... */ } @@ -934,77 +946,102 @@ SearchSysCache(CatCache *cache, } /* ---------------- - * scan is complete. if tup is valid, we can add it to the cache. - * note we have already copied it into the cache memory context. + * close the relation * ---------------- */ - if (HeapTupleIsValid(ntp)) - { - /* ---------------- - * allocate a new cache tuple holder, store the pointer - * to the heap tuple there and initialize the list pointers. - * ---------------- - */ - Dlelem *lru_elt; - - CACHE1_elog(DEBUG, "SearchSysCache: found tuple"); + heap_close(relation, AccessShareLock); - oldcxt = MemoryContextSwitchTo(CacheMemoryContext); + /* ---------------- + * scan is complete. if tup was found, we can add it to the cache. + * ---------------- + */ + if (ct == NULL) + return NULL; - /* - * this is a little cumbersome here because we want the Dlelem's - * in both doubly linked lists to point to one another. That makes - * it easier to remove something from both the cache bucket and - * the lru list at the same time - */ - nct = (CatCTup *) palloc(sizeof(CatCTup)); - nct->ct_tup = ntp; - elt = DLNewElem(nct); - nct2 = (CatCTup *) palloc(sizeof(CatCTup)); - nct2->ct_tup = ntp; - lru_elt = DLNewElem(nct2); - nct2->ct_node = elt; - nct->ct_node = lru_elt; + /* ---------------- + * Finish initializing the CatCTup header, and add it to the + * linked lists. + * ---------------- + */ + CACHE1_elog(DEBUG, "SearchCatCache: found tuple"); - DLAddHead(cache->cc_lrulist, lru_elt); - DLAddHead(cache->cc_cache[hash], elt); + ct->ct_magic = CT_MAGIC; + DLInitElem(&ct->lrulist_elem, (void *) ct); + DLInitElem(&ct->cache_elem, (void *) ct); + ct->refcount = 1; /* count this first reference */ + ct->dead = false; - MemoryContextSwitchTo(oldcxt); + DLAddHead(&cache->cc_lrulist, &ct->lrulist_elem); + DLAddHead(&cache->cc_cache[hash], &ct->cache_elem); - /* ---------------- - * If we've exceeded the desired size of this cache, - * throw away the least recently used entry. - * ---------------- - */ - if (++cache->cc_ntup > cache->cc_maxtup) + /* ---------------- + * If we've exceeded the desired size of this cache, + * try to throw away the least recently used entry. + * ---------------- + */ + if (++cache->cc_ntup > cache->cc_maxtup) + { + for (elt = DLGetTail(&cache->cc_lrulist); + elt; + elt = DLGetPred(elt)) { - CatCTup *ct; + CatCTup *oldct = (CatCTup *) DLE_VAL(elt); - elt = DLGetTail(cache->cc_lrulist); - ct = (CatCTup *) DLE_VAL(elt); - - if (ct != nct) /* shouldn't be possible, but be safe... */ + if (oldct->refcount == 0) { - CACHE2_elog(DEBUG, "SearchSysCache(%s): Overflow, LRU removal", + CACHE2_elog(DEBUG, "SearchCatCache(%s): Overflow, LRU removal", cache->cc_relname); - - CatCacheRemoveCTup(cache, elt); + CatCacheRemoveCTup(cache, oldct); + break; } } - - CACHE4_elog(DEBUG, "SearchSysCache(%s): Contains %d/%d tuples", - cache->cc_relname, cache->cc_ntup, cache->cc_maxtup); - CACHE3_elog(DEBUG, "SearchSysCache(%s): put in bucket %d", - cache->cc_relname, hash); } - /* ---------------- - * close the relation and return the tuple we found (or NULL) - * ---------------- - */ - heap_close(relation, AccessShareLock); + CACHE4_elog(DEBUG, "SearchCatCache(%s): Contains %d/%d tuples", + cache->cc_relname, cache->cc_ntup, cache->cc_maxtup); + CACHE3_elog(DEBUG, "SearchCatCache(%s): put in bucket %d", + cache->cc_relname, hash); + + return &ct->tuple; +} - return ntp; +/* -------------------------------- + * ReleaseCatCache() + * + * Decrement the reference count of a catcache entry (releasing the + * hold grabbed by a successful SearchCatCache). + * + * NOTE: if compiled with -DCATCACHE_FORCE_RELEASE then catcache entries + * 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) +{ + CatCTup *ct = (CatCTup *) (((char *) tuple) - + offsetof(CatCTup, tuple)); + + /* Safety checks to ensure we were handed a cache entry */ + Assert(ct->ct_magic == CT_MAGIC); + Assert(ct->refcount > 0); + + ct->refcount--; + + if (ct->refcount == 0 +#ifndef CATCACHE_FORCE_RELEASE + && ct->dead +#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); + } } /* -------------------------------- diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index b9bd9f8b9e9..e07445837a5 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.46 2000/10/05 19:48:29 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.47 2000/11/16 22:30:33 tgl Exp $ * * NOTES * Eventually, the index information should go through here, too. @@ -32,14 +32,11 @@ bool op_class(Oid opno, Oid opclass, Oid amopid) { - if (HeapTupleIsValid(SearchSysCacheTuple(AMOPOPID, - ObjectIdGetDatum(opclass), - ObjectIdGetDatum(opno), - ObjectIdGetDatum(amopid), - 0))) - return true; - else - return false; + return SearchSysCacheExists(AMOPOPID, + ObjectIdGetDatum(opclass), + ObjectIdGetDatum(opno), + ObjectIdGetDatum(amopid), + 0); } /* ---------- ATTRIBUTE CACHES ---------- */ @@ -49,21 +46,26 @@ op_class(Oid opno, Oid opclass, Oid amopid) * * Given the relation id and the attribute number, * return the "attname" field from the attribute relation. + * + * Note: returns a palloc'd copy of the string, or NULL if no such operator. */ char * get_attname(Oid relid, AttrNumber attnum) { HeapTuple tp; - tp = SearchSysCacheTuple(ATTNUM, - ObjectIdGetDatum(relid), - Int16GetDatum(attnum), - 0, 0); + tp = SearchSysCache(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum), + 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp); + char *result; - return pstrdup(NameStr(att_tup->attname)); + result = pstrdup(NameStr(att_tup->attname)); + ReleaseSysCache(tp); + return result; } else return NULL; @@ -80,15 +82,18 @@ get_attnum(Oid relid, char *attname) { HeapTuple tp; - tp = SearchSysCacheTuple(ATTNAME, - ObjectIdGetDatum(relid), - PointerGetDatum(attname), - 0, 0); + tp = SearchSysCache(ATTNAME, + ObjectIdGetDatum(relid), + PointerGetDatum(attname), + 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp); + AttrNumber result; - return att_tup->attnum; + result = att_tup->attnum; + ReleaseSysCache(tp); + return result; } else return InvalidAttrNumber; @@ -105,15 +110,18 @@ get_atttype(Oid relid, AttrNumber attnum) { HeapTuple tp; - tp = SearchSysCacheTuple(ATTNUM, - ObjectIdGetDatum(relid), - Int16GetDatum(attnum), - 0, 0); + tp = SearchSysCache(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum), + 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp); + Oid result; - return att_tup->atttypid; + result = att_tup->atttypid; + ReleaseSysCache(tp); + return result; } else return InvalidOid; @@ -128,15 +136,18 @@ get_attisset(Oid relid, char *attname) { HeapTuple tp; - tp = SearchSysCacheTuple(ATTNAME, - ObjectIdGetDatum(relid), - PointerGetDatum(attname), - 0, 0); + tp = SearchSysCache(ATTNAME, + ObjectIdGetDatum(relid), + PointerGetDatum(attname), + 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp); + bool result; - return att_tup->attisset; + result = att_tup->attisset; + ReleaseSysCache(tp); + return result; } else return false; @@ -153,15 +164,18 @@ get_atttypmod(Oid relid, AttrNumber attnum) { HeapTuple tp; - tp = SearchSysCacheTuple(ATTNUM, - ObjectIdGetDatum(relid), - Int16GetDatum(attnum), - 0, 0); + tp = SearchSysCache(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum), + 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp); + int32 result; - return att_tup->atttypmod; + result = att_tup->atttypmod; + ReleaseSysCache(tp); + return result; } else return -1; @@ -185,12 +199,13 @@ get_attdispersion(Oid relid, AttrNumber attnum, double min_estimate) HeapTuple atp; Form_pg_attribute att_tup; double dispersion; + Oid atttypid; int32 ntuples; - atp = SearchSysCacheTuple(ATTNUM, - ObjectIdGetDatum(relid), - Int16GetDatum(attnum), - 0, 0); + atp = SearchSysCache(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum), + 0, 0); if (!HeapTupleIsValid(atp)) { /* this should not happen */ @@ -198,9 +213,14 @@ get_attdispersion(Oid relid, AttrNumber attnum, double min_estimate) relid, attnum); return min_estimate; } + att_tup = (Form_pg_attribute) GETSTRUCT(atp); dispersion = att_tup->attdispersion; + atttypid = att_tup->atttypid; + + ReleaseSysCache(atp); + if (dispersion > 0.0) return dispersion; /* we have a specific estimate from VACUUM */ @@ -211,7 +231,7 @@ get_attdispersion(Oid relid, AttrNumber attnum, double min_estimate) * * Are there any other cases we should wire in special estimates for? */ - if (att_tup->atttypid == BOOLOID) + if (atttypid == BOOLOID) return 0.5; /* @@ -219,9 +239,9 @@ get_attdispersion(Oid relid, AttrNumber attnum, double min_estimate) * 1/numtuples). Either way, we need the relation size. */ - atp = SearchSysCacheTuple(RELOID, - ObjectIdGetDatum(relid), - 0, 0, 0); + atp = SearchSysCache(RELOID, + ObjectIdGetDatum(relid), + 0, 0, 0); if (!HeapTupleIsValid(atp)) { /* this should not happen */ @@ -231,6 +251,8 @@ get_attdispersion(Oid relid, AttrNumber attnum, double min_estimate) ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples; + ReleaseSysCache(atp); + if (ntuples == 0) return min_estimate; /* no data available */ @@ -277,14 +299,17 @@ get_opcode(Oid opno) { HeapTuple tp; - tp = SearchSysCacheTuple(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache(OPEROID, + ObjectIdGetDatum(opno), + 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); + RegProcedure result; - return optup->oprcode; + result = optup->oprcode; + ReleaseSysCache(tp); + return result; } else return (RegProcedure) InvalidOid; @@ -301,14 +326,17 @@ get_opname(Oid opno) { HeapTuple tp; - tp = SearchSysCacheTuple(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache(OPEROID, + ObjectIdGetDatum(opno), + 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); + char *result; - return pstrdup(NameStr(optup->oprname)); + result = pstrdup(NameStr(optup->oprname)); + ReleaseSysCache(tp); + return result; } else return NULL; @@ -324,10 +352,11 @@ bool op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp) { HeapTuple tp; + bool result = false; - tp = SearchSysCacheTuple(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache(OPEROID, + ObjectIdGetDatum(opno), + 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); @@ -339,10 +368,11 @@ op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp) { *leftOp = optup->oprlsortop; *rightOp = optup->oprrsortop; - return true; + result = true; } + ReleaseSysCache(tp); } - return false; + return result; } /* @@ -355,10 +385,11 @@ Oid op_hashjoinable(Oid opno, Oid ltype, Oid rtype) { HeapTuple tp; + Oid result = InvalidOid; - tp = SearchSysCacheTuple(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache(OPEROID, + ObjectIdGetDatum(opno), + 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); @@ -366,9 +397,10 @@ op_hashjoinable(Oid opno, Oid ltype, Oid rtype) if (optup->oprcanhash && optup->oprleft == ltype && optup->oprright == rtype) - return opno; + result = opno; + ReleaseSysCache(tp); } - return InvalidOid; + return result; } /* @@ -387,14 +419,6 @@ op_iscachable(Oid opno) return func_iscachable((Oid) funcid); } -HeapTuple -get_operator_tuple(Oid opno) -{ - return SearchSysCacheTuple(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); -} - /* * get_commutator * @@ -405,14 +429,17 @@ get_commutator(Oid opno) { HeapTuple tp; - tp = SearchSysCacheTuple(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache(OPEROID, + ObjectIdGetDatum(opno), + 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); + Oid result; - return optup->oprcom; + result = optup->oprcom; + ReleaseSysCache(tp); + return result; } else return InvalidOid; @@ -428,14 +455,17 @@ get_negator(Oid opno) { HeapTuple tp; - tp = SearchSysCacheTuple(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache(OPEROID, + ObjectIdGetDatum(opno), + 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); + Oid result; - return optup->oprnegate; + result = optup->oprnegate; + ReleaseSysCache(tp); + return result; } else return InvalidOid; @@ -451,14 +481,17 @@ get_oprrest(Oid opno) { HeapTuple tp; - tp = SearchSysCacheTuple(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache(OPEROID, + ObjectIdGetDatum(opno), + 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); + RegProcedure result; - return optup->oprrest; + result = optup->oprrest; + ReleaseSysCache(tp); + return result; } else return (RegProcedure) InvalidOid; @@ -474,14 +507,17 @@ get_oprjoin(Oid opno) { HeapTuple tp; - tp = SearchSysCacheTuple(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache(OPEROID, + ObjectIdGetDatum(opno), + 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); + RegProcedure result; - return optup->oprjoin; + result = optup->oprjoin; + ReleaseSysCache(tp); + return result; } else return (RegProcedure) InvalidOid; @@ -496,15 +532,18 @@ get_oprjoin(Oid opno) Oid get_func_rettype(Oid funcid) { - HeapTuple func_tuple; + HeapTuple tp; + Oid result; - func_tuple = SearchSysCacheTuple(PROCOID, - ObjectIdGetDatum(funcid), - 0, 0, 0); - if (!HeapTupleIsValid(func_tuple)) + tp = SearchSysCache(PROCOID, + ObjectIdGetDatum(funcid), + 0, 0, 0); + if (!HeapTupleIsValid(tp)) elog(ERROR, "Function OID %u does not exist", funcid); - return ((Form_pg_proc) GETSTRUCT(func_tuple))->prorettype; + result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype; + ReleaseSysCache(tp); + return result; } /* @@ -514,15 +553,18 @@ get_func_rettype(Oid funcid) bool func_iscachable(Oid funcid) { - HeapTuple func_tuple; + HeapTuple tp; + bool result; - func_tuple = SearchSysCacheTuple(PROCOID, - ObjectIdGetDatum(funcid), - 0, 0, 0); - if (!HeapTupleIsValid(func_tuple)) + tp = SearchSysCache(PROCOID, + ObjectIdGetDatum(funcid), + 0, 0, 0); + if (!HeapTupleIsValid(tp)) elog(ERROR, "Function OID %u does not exist", funcid); - return ((Form_pg_proc) GETSTRUCT(func_tuple))->proiscachable; + result = ((Form_pg_proc) GETSTRUCT(tp))->proiscachable; + ReleaseSysCache(tp); + return result; } /* ---------- RELATION CACHE ---------- */ @@ -538,14 +580,17 @@ get_relnatts(Oid relid) { HeapTuple tp; - tp = SearchSysCacheTuple(RELOID, - ObjectIdGetDatum(relid), - 0, 0, 0); + tp = SearchSysCache(RELOID, + ObjectIdGetDatum(relid), + 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp); + int result; - return reltup->relnatts; + result = reltup->relnatts; + ReleaseSysCache(tp); + return result; } else return InvalidAttrNumber; @@ -556,20 +601,25 @@ get_relnatts(Oid relid) * get_rel_name * * Returns the name of a given relation. + * + * Note: returns a palloc'd copy of the string, or NULL if no such operator. */ char * get_rel_name(Oid relid) { HeapTuple tp; - tp = SearchSysCacheTuple(RELOID, - ObjectIdGetDatum(relid), - 0, 0, 0); + tp = SearchSysCache(RELOID, + ObjectIdGetDatum(relid), + 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp); + char *result; - return pstrdup(NameStr(reltup->relname)); + result = pstrdup(NameStr(reltup->relname)); + ReleaseSysCache(tp); + return result; } else return NULL; @@ -587,14 +637,17 @@ get_typlen(Oid typid) { HeapTuple tp; - tp = SearchSysCacheTuple(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache(TYPEOID, + ObjectIdGetDatum(typid), + 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); + int16 result; - return typtup->typlen; + result = typtup->typlen; + ReleaseSysCache(tp); + return result; } else return 0; @@ -611,33 +664,66 @@ get_typbyval(Oid typid) { HeapTuple tp; - tp = SearchSysCacheTuple(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache(TYPEOID, + ObjectIdGetDatum(typid), + 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); + bool result; - return typtup->typbyval; + result = typtup->typbyval; + ReleaseSysCache(tp); + return result; } else return false; } +/* + * get_typlenbyval + * + * A two-fer: given the type OID, return both typlen and typbyval. + * + * Since both pieces of info are needed to know how to copy a Datum, + * many places need both. Might as well get them with one cache lookup + * instead of two. Also, this routine raises an error instead of + * returning a bogus value when given a bad type OID. + */ +void +get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval) +{ + HeapTuple tp; + Form_pg_type typtup; + + tp = SearchSysCache(TYPEOID, + ObjectIdGetDatum(typid), + 0, 0, 0); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for type %u", typid); + typtup = (Form_pg_type) GETSTRUCT(tp); + *typlen = typtup->typlen; + *typbyval = typtup->typbyval; + ReleaseSysCache(tp); +} + #ifdef NOT_USED char get_typalign(Oid typid) { HeapTuple tp; - tp = SearchSysCacheTuple(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache(TYPEOID, + ObjectIdGetDatum(typid), + 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); + char result; - return typtup->typalign; + result = typtup->typalign; + ReleaseSysCache(tp); + return result; } else return 'i'; @@ -666,9 +752,9 @@ get_typdefault(Oid typid) bool typByVal; Datum returnValue; - typeTuple = SearchSysCacheTuple(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + typeTuple = SearchSysCache(TYPEOID, + ObjectIdGetDatum(typid), + 0, 0, 0); if (!HeapTupleIsValid(typeTuple)) elog(ERROR, "get_typdefault: failed to lookup type %u", typid); @@ -679,13 +765,17 @@ get_typdefault(Oid typid) * First, see if there is a non-null typdefault field (usually there * isn't) */ - typDefault = (struct varlena *) SysCacheGetAttr(TYPEOID, - typeTuple, - Anum_pg_type_typdefault, - &isNull); + typDefault = (struct varlena *) + DatumGetPointer(SysCacheGetAttr(TYPEOID, + typeTuple, + Anum_pg_type_typdefault, + &isNull)); if (isNull) + { + ReleaseSysCache(typeTuple); return PointerGetDatum(NULL); + } /* * Otherwise, extract/copy the value. @@ -748,6 +838,8 @@ get_typdefault(Oid typid) } } + ReleaseSysCache(typeTuple); + return returnValue; } @@ -764,14 +856,17 @@ get_typtype(Oid typid) { HeapTuple tp; - tp = SearchSysCacheTuple(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache(TYPEOID, + ObjectIdGetDatum(typid), + 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); + char result; - return typtup->typtype; + result = typtup->typtype; + ReleaseSysCache(tp); + return result; } else return '\0'; diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 7f35f192089..bb9a55b869a 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.56 2000/11/10 00:33:10 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.57 2000/11/16 22:30:33 tgl Exp $ * * NOTES * These routines allow the parser/planner/executor to perform @@ -343,7 +343,7 @@ static struct cachedesc cacheinfo[] = { }; static CatCache *SysCache[lengthof(cacheinfo)]; -static int32 SysCacheSize = lengthof(cacheinfo); +static int SysCacheSize = lengthof(cacheinfo); static bool CacheInitialized = false; @@ -355,98 +355,67 @@ IsCacheInitialized(void) /* - * zerocaches + * InitCatalogCache - initialize the caches * - * Make sure the SysCache structure is zero'd. + * Note that no database access is done here; we only allocate memory + * and initialize the cache structure. Interrogation of the database + * to complete initialization of a cache happens only upon first use + * of that cache. */ void -zerocaches() +InitCatalogCache(void) { - MemSet((char *) SysCache, 0, SysCacheSize * sizeof(CatCache *)); -} + int cacheId; + Assert(!CacheInitialized); -/* - * InitCatalogCache - initialize the caches - */ -void -InitCatalogCache() -{ - int cacheId; /* XXX type */ + MemSet((char *) SysCache, 0, sizeof(SysCache)); - if (!AMI_OVERRIDE) + for (cacheId = 0; cacheId < SysCacheSize; cacheId++) { - for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1) - { - Assert(!PointerIsValid(SysCache[cacheId])); - - SysCache[cacheId] = InitSysCache(cacheId, - cacheinfo[cacheId].name, - cacheinfo[cacheId].indname, - cacheinfo[cacheId].nkeys, - cacheinfo[cacheId].key); - if (!PointerIsValid(SysCache[cacheId])) - { - elog(ERROR, - "InitCatalogCache: Can't init cache %s (%d)", - cacheinfo[cacheId].name, - cacheId); - } - - } + SysCache[cacheId] = InitCatCache(cacheId, + cacheinfo[cacheId].name, + cacheinfo[cacheId].indname, + cacheinfo[cacheId].nkeys, + cacheinfo[cacheId].key); + if (!PointerIsValid(SysCache[cacheId])) + elog(ERROR, "InitCatalogCache: Can't init cache %s (%d)", + cacheinfo[cacheId].name, cacheId); } CacheInitialized = true; } /* - * SearchSysCacheTuple + * SearchSysCache * - * A layer on top of SearchSysCache that does the initialization and + * A layer on top of SearchCatCache that does the initialization and * key-setting for you. * * Returns the cache copy of the tuple if one is found, NULL if not. - * The tuple is the 'cache' copy. - * - * CAUTION: The tuple that is returned must NOT be freed by the caller! + * The tuple is the 'cache' copy and must NOT be modified! * - * CAUTION: The returned tuple may be flushed from the cache during - * subsequent cache lookup operations, or by shared cache invalidation. - * Callers should not expect the pointer to remain valid for long. + * When the caller is done using the tuple, call ReleaseSysCache() + * to release the reference count grabbed by SearchSysCache(). If this + * is not done, the tuple will remain locked in cache until end of + * transaction, which is tolerable but not desirable. * - * XXX we ought to have some kind of referencecount mechanism for - * cache entries, to ensure entries aren't deleted while in use. + * CAUTION: The tuple that is returned must NOT be freed by the caller! */ HeapTuple -SearchSysCacheTuple(int cacheId,/* cache selection code */ - Datum key1, - Datum key2, - Datum key3, - Datum key4) +SearchSysCache(int cacheId, + Datum key1, + Datum key2, + Datum key3, + Datum key4) { - HeapTuple tp; - if (cacheId < 0 || cacheId >= SysCacheSize) { - elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId); + elog(ERROR, "SearchSysCache: Bad cache id %d", cacheId); return (HeapTuple) NULL; } - Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId])); - - if (!PointerIsValid(SysCache[cacheId])) - { - SysCache[cacheId] = InitSysCache(cacheId, - cacheinfo[cacheId].name, - cacheinfo[cacheId].indname, - cacheinfo[cacheId].nkeys, - cacheinfo[cacheId].key); - if (!PointerIsValid(SysCache[cacheId])) - elog(ERROR, - "InitCatalogCache: Can't init cache %s(%d)", - cacheinfo[cacheId].name, - cacheId); - } + Assert(PointerIsValid(SysCache[cacheId])); /* * If someone tries to look up a relname, translate temp relation @@ -464,51 +433,75 @@ SearchSysCacheTuple(int cacheId,/* cache selection code */ key1 = CStringGetDatum(nontemp_relname); } - tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4); - if (!HeapTupleIsValid(tp)) - { -#ifdef CACHEDEBUG - elog(DEBUG, - "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed", - cacheinfo[cacheId].name, - cacheId, key1, key2, key3, key4); -#endif - return (HeapTuple) NULL; - } - return tp; + return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4); } +/* + * ReleaseSysCache + * Release previously grabbed reference count on a tuple + */ +void +ReleaseSysCache(HeapTuple tuple) +{ + ReleaseCatCache(tuple); +} /* - * SearchSysCacheTupleCopy + * SearchSysCacheCopy * - * This is like SearchSysCacheTuple, except it returns a palloc'd copy of - * the tuple. The caller should heap_freetuple() the returned copy when - * done with it. This routine should be used when the caller intends to - * continue to access the tuple for more than a very short period of time. + * A convenience routine that does SearchSysCache and (if successful) + * returns a modifiable copy of the syscache entry. The original + * syscache entry is released before returning. The caller should + * heap_freetuple() the result when done with it. */ HeapTuple -SearchSysCacheTupleCopy(int cacheId, /* cache selection code */ - Datum key1, - Datum key2, - Datum key3, - Datum key4) +SearchSysCacheCopy(int cacheId, + Datum key1, + Datum key2, + Datum key3, + Datum key4) { - HeapTuple cachetup; - - cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4); - if (PointerIsValid(cachetup)) - return heap_copytuple(cachetup); - else - return cachetup; /* NULL */ + HeapTuple tuple, + newtuple; + + tuple = SearchSysCache(cacheId, key1, key2, key3, key4); + if (!HeapTupleIsValid(tuple)) + return tuple; + newtuple = heap_copytuple(tuple); + ReleaseSysCache(tuple); + return newtuple; } +/* + * GetSysCacheOid + * + * A convenience routine that does SearchSysCache and returns the OID + * of the found tuple, or InvalidOid if no tuple could be found. + * No lock is retained on the syscache entry. + */ +Oid +GetSysCacheOid(int cacheId, + Datum key1, + Datum key2, + Datum key3, + Datum key4) +{ + HeapTuple tuple; + Oid result; + + tuple = SearchSysCache(cacheId, key1, key2, key3, key4); + if (!HeapTupleIsValid(tuple)) + return InvalidOid; + result = tuple->t_data->t_oid; + ReleaseSysCache(tuple); + return result; +} /* * SysCacheGetAttr * - * Given a tuple previously fetched by SearchSysCacheTuple() or - * SearchSysCacheTupleCopy(), extract a specific attribute. + * Given a tuple previously fetched by SearchSysCache(), + * extract a specific attribute. * * This is equivalent to using heap_getattr() on a tuple fetched * from a non-cached relation. Usually, this is only used for attributes diff --git a/src/backend/utils/cache/temprel.c b/src/backend/utils/cache/temprel.c index 31591663cee..0134b47a0f9 100644 --- a/src/backend/utils/cache/temprel.c +++ b/src/backend/utils/cache/temprel.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.30 2000/11/08 22:10:01 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.31 2000/11/16 22:30:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -34,7 +34,6 @@ #include "catalog/heap.h" #include "catalog/index.h" #include "miscadmin.h" -#include "utils/catcache.h" #include "utils/temprel.h" |