X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Futils%2Fcache%2Fcatcache.c;h=da89c8a7e4c2018eadeb2b2e6f7447e28826d8af;hb=239d769e7e05e0a5ef3bd6828e93e22ef3962780;hp=a52882592c81fd67b663ed0dc0d027ad25ac1a2f;hpb=73b0300b2a9c170f67f5202f5003be10b529e0f5;p=postgresql diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index a52882592c..da89c8a7e4 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -3,12 +3,12 @@ * catcache.c * System catalog cache for tuples matching a key. * - * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.142 2008/03/26 21:10:39 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.153 2010/07/06 19:18:58 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,8 @@ #include "access/genam.h" #include "access/hash.h" #include "access/heapam.h" +#include "access/relscan.h" +#include "access/sysattr.h" #include "access/valid.h" #include "catalog/pg_operator.h" #include "catalog/pg_type.h" @@ -26,8 +28,9 @@ #endif #include "utils/builtins.h" #include "utils/fmgroids.h" +#include "utils/inval.h" #include "utils/memutils.h" -#include "utils/relcache.h" +#include "utils/rel.h" #include "utils/resowner.h" #include "utils/syscache.h" #include "utils/tqual.h" @@ -102,30 +105,37 @@ GetCCHashEqFuncs(Oid keytype, PGFunction *hashfunc, RegProcedure *eqfunc) { case BOOLOID: *hashfunc = hashchar; + *eqfunc = F_BOOLEQ; break; case CHAROID: *hashfunc = hashchar; + *eqfunc = F_CHAREQ; break; case NAMEOID: *hashfunc = hashname; + *eqfunc = F_NAMEEQ; break; case INT2OID: *hashfunc = hashint2; + *eqfunc = F_INT2EQ; break; case INT2VECTOROID: *hashfunc = hashint2vector; + *eqfunc = F_INT2VECTOREQ; break; case INT4OID: *hashfunc = hashint4; + *eqfunc = F_INT4EQ; break; case TEXTOID: *hashfunc = hashtext; + *eqfunc = F_TEXTEQ; break; case OIDOID: @@ -138,15 +148,18 @@ GetCCHashEqFuncs(Oid keytype, PGFunction *hashfunc, RegProcedure *eqfunc) case REGCONFIGOID: case REGDICTIONARYOID: *hashfunc = hashoid; + *eqfunc = F_OIDEQ; break; case OIDVECTOROID: *hashfunc = hashoidvector; + *eqfunc = F_OIDVECTOREQ; break; default: elog(FATAL, "type %u not supported as catcache key", keytype); *hashfunc = NULL; /* keep compiler quiet */ + *eqfunc = InvalidOid; break; } @@ -213,7 +226,7 @@ CatalogCacheComputeHashValue(CatCache *cache, int nkeys, ScanKey cur_skey) static uint32 CatalogCacheComputeTupleHashValue(CatCache *cache, HeapTuple tuple) { - ScanKeyData cur_skey[4]; + ScanKeyData cur_skey[CATCACHE_MAXKEYS]; bool isNull = false; /* Copy pre-initialized overhead data for scankey */ @@ -660,107 +673,43 @@ ResetCatalogCaches(void) } /* - * CatalogCacheFlushRelation + * CatalogCacheFlushCatalog * - * This is called by RelationFlushRelation() to clear out cached information - * about a relation being dropped. (This could be a DROP TABLE command, - * or a temp table being dropped at end of transaction, or a table created - * during the current transaction that is being dropped because of abort.) - * Remove all cache entries relevant to the specified relation OID. - * - * 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 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 + * Flush all catcache entries that came from the specified system catalog. + * This is needed after VACUUM FULL/CLUSTER on the catalog, since the + * tuples very likely now have different TIDs than before. (At one point + * we also tried to force re-execution of CatalogCacheInitializeCache for + * the cache(s) on that catalog. 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 -CatalogCacheFlushRelation(Oid relId) +CatalogCacheFlushCatalog(Oid catId) { CatCache *cache; - CACHE2_elog(DEBUG2, "CatalogCacheFlushRelation called for %u", relId); + CACHE2_elog(DEBUG2, "CatalogCacheFlushCatalog called for %u", catId); 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) + /* Does this cache store tuples of the target catalog? */ + if (cache->cc_tupdesc->attrs[0]->attrelid == catId) { /* 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_nbuckets; 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); - - /* - * Negative entries are never considered related to a rel, - * even if the rel is part of their lookup key. - */ - if (ct->negative) - continue; - - if (cache->cc_reloidattr == ObjectIdAttributeNumber) - tupRelid = HeapTupleGetOid(&ct->tuple); - 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->c_list && ct->c_list->refcount > 0)) - { - ct->dead = true; - /* parent list must be considered dead too */ - if (ct->c_list) - ct->c_list->dead = true; - } - else - CatCacheRemoveCTup(cache, ct); -#ifdef CATCACHE_STATS - cache->cc_invals++; -#endif - } - } + /* Tell inval.c to call syscache callbacks for this cache */ + CallSyscacheCallbacks(cache->id, NULL); } } - CACHE1_elog(DEBUG2, "end of CatalogCacheFlushRelation call"); + CACHE1_elog(DEBUG2, "end of CatalogCacheFlushCatalog call"); } /* @@ -786,7 +735,6 @@ CatCache * InitCatCache(int id, Oid reloid, Oid indexoid, - int reloidattr, int nkeys, const int *key, int nbuckets) @@ -850,7 +798,6 @@ InitCatCache(int id, cp->cc_indexoid = indexoid; cp->cc_relisshared = false; /* temporary */ cp->cc_tupdesc = (TupleDesc) NULL; - cp->cc_reloidattr = reloidattr; cp->cc_ntup = 0; cp->cc_nbuckets = nbuckets; cp->cc_nkeys = nkeys; @@ -1034,34 +981,55 @@ InitCatCachePhase2(CatCache *cache, bool touch_index) * certain system indexes that support critical syscaches. * We can't use an indexscan to fetch these, else we'll get into * infinite recursion. A plain heap scan will work, however. - * * Once we have completed relcache initialization (signaled by * criticalRelcachesBuilt), we don't have to worry anymore. + * + * Similarly, during backend startup we have to be able to use the + * pg_authid and pg_auth_members syscaches for authentication even if + * we don't yet have relcache entries for those catalogs' indexes. */ static bool IndexScanOK(CatCache *cache, ScanKey cur_skey) { - if (cache->id == INDEXRELID) + switch (cache->id) { - /* - * Rather than tracking exactly which indexes have to be loaded before - * we can use indexscans (which changes from time to time), just force - * all pg_index searches to be heap scans until we've built the - * critical relcaches. - */ - if (!criticalRelcachesBuilt) + case INDEXRELID: + + /* + * Rather than tracking exactly which indexes have to be loaded + * before we can use indexscans (which changes from time to time), + * just force all pg_index searches to be heap scans until we've + * built the critical relcaches. + */ + if (!criticalRelcachesBuilt) + return false; + break; + + case AMOID: + case AMNAME: + + /* + * Always do heap scans in pg_am, because it's so small there's + * not much point in an indexscan anyway. We *must* do this when + * initially building critical relcache entries, but we might as + * well just always do it. + */ return false; - } - else if (cache->id == AMOID || - cache->id == AMNAME) - { - /* - * Always do heap scans in pg_am, because it's so small there's not - * much point in an indexscan anyway. We *must* do this when - * initially building critical relcache entries, but we might as well - * just always do it. - */ - return false; + + case AUTHNAME: + case AUTHOID: + case AUTHMEMMEMROLE: + + /* + * Protect authentication lookups occurring before relcache has + * collected entries for shared indexes. + */ + if (!criticalSharedRelcachesBuilt) + return false; + break; + + default: + break; } /* Normal case, allow index scan */ @@ -1091,7 +1059,7 @@ SearchCatCache(CatCache *cache, Datum v3, Datum v4) { - ScanKeyData cur_skey[4]; + ScanKeyData cur_skey[CATCACHE_MAXKEYS]; uint32 hashValue; Index hashIndex; Dlelem *elt; @@ -1332,7 +1300,7 @@ SearchCatCacheList(CatCache *cache, Datum v3, Datum v4) { - ScanKeyData cur_skey[4]; + ScanKeyData cur_skey[CATCACHE_MAXKEYS]; uint32 lHashValue; Dlelem *elt; CatCList *cl; @@ -1450,7 +1418,7 @@ SearchCatCacheList(CatCache *cache, scandesc = systable_beginscan(relation, cache->cc_indexoid, - true, + IndexScanOK(cache, cur_skey), SnapshotNow, nkeys, cur_skey); @@ -1671,16 +1639,16 @@ build_dummy_tuple(CatCache *cache, int nkeys, ScanKey skeys) HeapTuple ntp; TupleDesc tupDesc = cache->cc_tupdesc; Datum *values; - char *nulls; + bool *nulls; Oid tupOid = InvalidOid; NameData tempNames[4]; int i; values = (Datum *) palloc(tupDesc->natts * sizeof(Datum)); - nulls = (char *) palloc(tupDesc->natts * sizeof(char)); + nulls = (bool *) palloc(tupDesc->natts * sizeof(bool)); memset(values, 0, tupDesc->natts * sizeof(Datum)); - memset(nulls, 'n', tupDesc->natts * sizeof(char)); + memset(nulls, true, tupDesc->natts * sizeof(bool)); for (i = 0; i < nkeys; i++) { @@ -1693,7 +1661,7 @@ build_dummy_tuple(CatCache *cache, int nkeys, ScanKey skeys) * Here we must be careful in case the caller passed a C string * where a NAME is wanted: convert the given argument to a * correctly padded NAME. Otherwise the memcpy() done in - * heap_formtuple could fall off the end of memory. + * heap_form_tuple could fall off the end of memory. */ if (cache->cc_isname[i]) { @@ -1703,7 +1671,7 @@ build_dummy_tuple(CatCache *cache, int nkeys, ScanKey skeys) keyval = NameGetDatum(newval); } values[attindex - 1] = keyval; - nulls[attindex - 1] = ' '; + nulls[attindex - 1] = false; } else { @@ -1712,7 +1680,7 @@ build_dummy_tuple(CatCache *cache, int nkeys, ScanKey skeys) } } - ntp = heap_formtuple(tupDesc, values, nulls); + ntp = heap_form_tuple(tupDesc, values, nulls); if (tupOid != InvalidOid) HeapTupleSetOid(ntp, tupOid);