mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
Clean up some really grotty coding in catcache.c, improve hashing
performance in catcache lookups.
This commit is contained in:
174
src/backend/utils/cache/catcache.c
vendored
174
src/backend/utils/cache/catcache.c
vendored
@ -8,12 +8,14 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.61 2000/02/18 09:28:53 inoue Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.62 2000/02/21 03:36:49 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "access/hash.h"
|
||||
#include "access/heapam.h"
|
||||
#include "access/valid.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
@ -28,10 +30,11 @@
|
||||
static void CatCacheRemoveCTup(CatCache *cache, Dlelem *e);
|
||||
static Index CatalogCacheComputeHashIndex(struct catcache * cacheInP);
|
||||
static Index CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP,
|
||||
Relation relation, HeapTuple tuple);
|
||||
Relation relation,
|
||||
HeapTuple tuple);
|
||||
static void CatalogCacheInitializeCache(struct catcache * cache,
|
||||
Relation relation);
|
||||
static long comphash(long l, char *v);
|
||||
Relation relation);
|
||||
static uint32 cc_hashname(NameData *n);
|
||||
|
||||
/* ----------------
|
||||
* variables, macros and other stuff
|
||||
@ -63,6 +66,7 @@ GlobalMemory CacheCxt; /* context in which caches are allocated */
|
||||
/* ----------------
|
||||
* EQPROC is used in CatalogCacheInitializeCache to find the equality
|
||||
* functions for system types that are used as cache key fields.
|
||||
* See also GetCCHashFunc, which should support the same set of types.
|
||||
*
|
||||
* XXX this should be replaced by catalog lookups,
|
||||
* but that seems to pose considerable risk of circularity...
|
||||
@ -70,7 +74,7 @@ GlobalMemory CacheCxt; /* context in which caches are allocated */
|
||||
*/
|
||||
static const Oid eqproc[] = {
|
||||
F_BOOLEQ, InvalidOid, F_CHAREQ, F_NAMEEQ, InvalidOid,
|
||||
F_INT2EQ, F_KEYFIRSTEQ, F_INT4EQ, F_OIDEQ, F_TEXTEQ,
|
||||
F_INT2EQ, F_INT2VECTOREQ, F_INT4EQ, F_OIDEQ, F_TEXTEQ,
|
||||
F_OIDEQ, InvalidOid, InvalidOid, InvalidOid, F_OIDVECTOREQ
|
||||
};
|
||||
|
||||
@ -80,6 +84,54 @@ static const Oid eqproc[] = {
|
||||
* internal support functions
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static CCHashFunc
|
||||
GetCCHashFunc(Oid keytype)
|
||||
{
|
||||
switch (keytype)
|
||||
{
|
||||
case BOOLOID:
|
||||
case CHAROID:
|
||||
return (CCHashFunc) hashchar;
|
||||
case NAMEOID:
|
||||
return (CCHashFunc) cc_hashname;
|
||||
case INT2OID:
|
||||
return (CCHashFunc) hashint2;
|
||||
case INT2VECTOROID:
|
||||
return (CCHashFunc) hashint2vector;
|
||||
case INT4OID:
|
||||
return (CCHashFunc) hashint4;
|
||||
case TEXTOID:
|
||||
return (CCHashFunc) hashtext;
|
||||
case REGPROCOID:
|
||||
case OIDOID:
|
||||
return (CCHashFunc) hashoid;
|
||||
case OIDVECTOROID:
|
||||
return (CCHashFunc) hashoidvector;
|
||||
default:
|
||||
elog(FATAL, "GetCCHashFunc: type %u unsupported as catcache key",
|
||||
keytype);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32
|
||||
cc_hashname(NameData *n)
|
||||
{
|
||||
/*
|
||||
* We need our own variant of hashname because we want to accept
|
||||
* null-terminated C strings as search values for name fields.
|
||||
* So, we have to make sure the data is correctly padded before
|
||||
* we compute the hash value.
|
||||
*/
|
||||
NameData my_n;
|
||||
|
||||
namestrcpy(&my_n, NameStr(*n));
|
||||
|
||||
return hashname(&my_n);
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* CatalogCacheInitializeCache
|
||||
* --------------------------------
|
||||
@ -190,31 +242,20 @@ CatalogCacheInitializeCache(struct catcache * cache,
|
||||
|
||||
if (cache->cc_key[i] > 0)
|
||||
{
|
||||
Oid keytype = tupdesc->attrs[cache->cc_key[i] - 1]->atttypid;
|
||||
|
||||
/*
|
||||
* Yoiks. The implementation of the hashing code and the
|
||||
* implementation of int2vector's are at loggerheads. The right
|
||||
* thing to do is to throw out the implementation of int2vector'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.
|
||||
*/
|
||||
cache->cc_hashfunc[i] = GetCCHashFunc(keytype);
|
||||
|
||||
if (tupdesc->attrs[cache->cc_key[i] - 1]->atttypid == INT2VECTOROID)
|
||||
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);
|
||||
/* If GetCCHashFunc liked the type, safe to index into eqproc[] */
|
||||
cache->cc_skey[i].sk_procedure = EQPROC(keytype);
|
||||
|
||||
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",
|
||||
CACHE4_elog(DEBUG, "CatalogCacheInit %s %d %x",
|
||||
RelationGetRelationName(relation),
|
||||
i,
|
||||
tupdesc->attrs[cache->cc_key[i] - 1]->attlen,
|
||||
cache);
|
||||
}
|
||||
}
|
||||
@ -255,53 +296,6 @@ CatalogCacheInitializeCache(struct catcache * cache,
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* 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 long
|
||||
comphash(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 = NameStr(n);
|
||||
}
|
||||
else if (l < 0)
|
||||
l = VARSIZE(v);
|
||||
|
||||
i = 0;
|
||||
while (l--)
|
||||
i += *v++;
|
||||
return i;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* CatalogCacheComputeHashIndex
|
||||
* --------------------------------
|
||||
@ -309,40 +303,37 @@ comphash(long l, char *v)
|
||||
static Index
|
||||
CatalogCacheComputeHashIndex(struct catcache * cacheInP)
|
||||
{
|
||||
Index hashIndex;
|
||||
uint32 hashIndex = 0;
|
||||
|
||||
hashIndex = 0x0;
|
||||
CACHE6_elog(DEBUG, "CatalogCacheComputeHashIndex %s %d %d %d %x",
|
||||
CACHE4_elog(DEBUG, "CatalogCacheComputeHashIndex %s %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;
|
||||
hashIndex ^=
|
||||
(*cacheInP->cc_hashfunc[3])(cacheInP->cc_skey[3].sk_argument) << 9;
|
||||
/* FALLTHROUGH */
|
||||
case 3:
|
||||
hashIndex ^= comphash(cacheInP->cc_klen[2],
|
||||
(char *) cacheInP->cc_skey[2].sk_argument) << 6;
|
||||
hashIndex ^=
|
||||
(*cacheInP->cc_hashfunc[2])(cacheInP->cc_skey[2].sk_argument) << 6;
|
||||
/* FALLTHROUGH */
|
||||
case 2:
|
||||
hashIndex ^= comphash(cacheInP->cc_klen[1],
|
||||
(char *) cacheInP->cc_skey[1].sk_argument) << 3;
|
||||
hashIndex ^=
|
||||
(*cacheInP->cc_hashfunc[1])(cacheInP->cc_skey[1].sk_argument) << 3;
|
||||
/* FALLTHROUGH */
|
||||
case 1:
|
||||
hashIndex ^= comphash(cacheInP->cc_klen[0],
|
||||
(char *) cacheInP->cc_skey[0].sk_argument);
|
||||
hashIndex ^=
|
||||
(*cacheInP->cc_hashfunc[0])(cacheInP->cc_skey[0].sk_argument);
|
||||
break;
|
||||
default:
|
||||
elog(FATAL, "CCComputeHashIndex: %d cc_nkeys", cacheInP->cc_nkeys);
|
||||
break;
|
||||
}
|
||||
hashIndex %= cacheInP->cc_size;
|
||||
return hashIndex;
|
||||
hashIndex %= (uint32) cacheInP->cc_size;
|
||||
return (Index) hashIndex;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
@ -645,8 +636,8 @@ do { \
|
||||
cp->relationId, cp->id, cp->cc_nkeys, cp->cc_size); \
|
||||
for (i = 0; i < nkeys; i += 1) \
|
||||
{ \
|
||||
elog(DEBUG, "InitSysCache: key=%d len=%d skey=[%d %d %d %d]\n", \
|
||||
cp->cc_key[i], cp->cc_klen[i], \
|
||||
elog(DEBUG, "InitSysCache: key=%d skey=[%d %d %d %d]\n", \
|
||||
cp->cc_key[i], \
|
||||
cp->cc_skey[i].sk_flags, \
|
||||
cp->cc_skey[i].sk_attno, \
|
||||
cp->cc_skey[i].sk_procedure, \
|
||||
@ -742,7 +733,8 @@ InitSysCache(char *relname,
|
||||
cp->cc_iscanfunc = iScanfuncP;
|
||||
|
||||
/* ----------------
|
||||
* initialize the cache's key information
|
||||
* partially initialize the cache's key information
|
||||
* CatalogCacheInitializeCache() will do the rest
|
||||
* ----------------
|
||||
*/
|
||||
for (i = 0; i < nkeys; ++i)
|
||||
@ -756,15 +748,7 @@ InitSysCache(char *relname,
|
||||
elog(FATAL, "InitSysCache: called with %d key[%d]", key[i], i);
|
||||
else
|
||||
{
|
||||
cp->cc_klen[i] = sizeof(Oid);
|
||||
|
||||
/*
|
||||
* ScanKeyEntryData and struct skey are equivalent. It
|
||||
* looks like a move was made to obsolete struct skey, but
|
||||
* it didn't reach this file. Someday we should clean up
|
||||
* this code and consolidate to ScanKeyEntry - mer 10 Nov
|
||||
* 1991
|
||||
*/
|
||||
cp->cc_hashfunc[i] = GetCCHashFunc(OIDOID);
|
||||
ScanKeyEntryInitialize(&cp->cc_skey[i],
|
||||
(bits16) 0,
|
||||
(AttrNumber) key[i],
|
||||
|
Reference in New Issue
Block a user