* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
#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"
{
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:
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;
}
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 */
}
/*
- * 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");
}
/*
InitCatCache(int id,
Oid reloid,
Oid indexoid,
- int reloidattr,
int nkeys,
const int *key,
int nbuckets)
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;
* 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 */
Datum v3,
Datum v4)
{
- ScanKeyData cur_skey[4];
+ ScanKeyData cur_skey[CATCACHE_MAXKEYS];
uint32 hashValue;
Index hashIndex;
Dlelem *elt;
Datum v3,
Datum v4)
{
- ScanKeyData cur_skey[4];
+ ScanKeyData cur_skey[CATCACHE_MAXKEYS];
uint32 lHashValue;
Dlelem *elt;
CatCList *cl;
scandesc = systable_beginscan(relation,
cache->cc_indexoid,
- true,
+ IndexScanOK(cache, cur_skey),
SnapshotNow,
nkeys,
cur_skey);
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++)
{
* 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])
{
keyval = NameGetDatum(newval);
}
values[attindex - 1] = keyval;
- nulls[attindex - 1] = ' ';
+ nulls[attindex - 1] = false;
}
else
{
}
}
- ntp = heap_formtuple(tupDesc, values, nulls);
+ ntp = heap_form_tuple(tupDesc, values, nulls);
if (tupOid != InvalidOid)
HeapTupleSetOid(ntp, tupOid);