Retrofit hashtable and shared-mem-size-estimation bug fixes

into REL6_4.
This commit is contained in:
Tom Lane 1999-03-07 02:01:09 +00:00
parent 0fda84bfcd
commit 2ecbf94430
8 changed files with 211 additions and 193 deletions

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.19 1998/09/01 04:31:39 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.19.2.1 1999/03/07 02:01:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -33,7 +33,6 @@
#include "storage/lmgr.h" #include "storage/lmgr.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/dynahash.h"
#include "utils/hsearch.h" #include "utils/hsearch.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#include "executor/execdebug.h" /* for NDirectFileRead */ #include "executor/execdebug.h" /* for NDirectFileRead */
@ -270,21 +269,11 @@ int
BufferShmemSize() BufferShmemSize()
{ {
int size = 0; int size = 0;
int nbuckets;
int nsegs;
int tmp;
nbuckets = 1 << (int) my_log2((NBuffers - 1) / DEF_FFACTOR + 1); /* size of shmem index hash table */
nsegs = 1 << (int) my_log2((nbuckets - 1) / DEF_SEGSIZE + 1); size += hash_estimate_size(SHMEM_INDEX_SIZE,
SHMEM_INDEX_KEYSIZE,
/* size of shmem index table */ SHMEM_INDEX_DATASIZE);
size += MAXALIGN(my_log2(SHMEM_INDEX_SIZE) * sizeof(void *)); /* HTAB->dir */
size += MAXALIGN(sizeof(HHDR)); /* HTAB->hctl */
size += MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
size += BUCKET_ALLOC_INCR *
(MAXALIGN(sizeof(BUCKET_INDEX)) +
MAXALIGN(SHMEM_INDEX_KEYSIZE) +
MAXALIGN(SHMEM_INDEX_DATASIZE));
/* size of buffer descriptors */ /* size of buffer descriptors */
size += MAXALIGN((NBuffers + 1) * sizeof(BufferDesc)); size += MAXALIGN((NBuffers + 1) * sizeof(BufferDesc));
@ -293,17 +282,13 @@ BufferShmemSize()
size += NBuffers * MAXALIGN(BLCKSZ); size += NBuffers * MAXALIGN(BLCKSZ);
/* size of buffer hash table */ /* size of buffer hash table */
size += MAXALIGN(my_log2(NBuffers) * sizeof(void *)); /* HTAB->dir */ size += hash_estimate_size(NBuffers,
size += MAXALIGN(sizeof(HHDR)); /* HTAB->hctl */ sizeof(BufferTag),
size += nsegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT)); sizeof(Buffer));
tmp = (int) ceil((double) NBuffers / BUCKET_ALLOC_INCR);
size += tmp * BUCKET_ALLOC_INCR *
(MAXALIGN(sizeof(BUCKET_INDEX)) +
MAXALIGN(sizeof(BufferTag)) +
MAXALIGN(sizeof(Buffer)));
#ifdef BMTRACE #ifdef BMTRACE
size += (BMT_LIMIT * sizeof(bmtrace)) + sizeof(long); size += (BMT_LIMIT * sizeof(bmtrace)) + sizeof(long);
#endif #endif
return size; return size;
} }

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.16 1998/09/01 03:25:10 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.16.2.1 1999/03/07 02:00:46 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -71,11 +71,17 @@ CreateSharedMemoryAndSemaphores(IPCKey key)
* ---------------- * ----------------
*/ */
CreateSpinlocks(IPCKeyGetSpinLockSemaphoreKey(key)); CreateSpinlocks(IPCKeyGetSpinLockSemaphoreKey(key));
size = BufferShmemSize() + LockShmemSize();
/*
* Size of the primary shared-memory block is estimated via
* moderately-accurate estimates for the big hogs, plus 100K for
* the stuff that's too small to bother with estimating.
*/
size = BufferShmemSize() + LockShmemSize();
#ifdef STABLE_MEMORY_STORAGE #ifdef STABLE_MEMORY_STORAGE
size += MMShmemSize(); size += MMShmemSize();
#endif #endif
size += 100000;
if (DebugLvl > 1) if (DebugLvl > 1)
{ {
@ -113,8 +119,6 @@ CreateSharedMemoryAndSemaphores(IPCKey key)
void void
AttachSharedMemoryAndSemaphores(IPCKey key) AttachSharedMemoryAndSemaphores(IPCKey key)
{ {
int size;
/* ---------------- /* ----------------
* create rather than attach if using private key * create rather than attach if using private key
* ---------------- * ----------------
@ -136,8 +140,7 @@ AttachSharedMemoryAndSemaphores(IPCKey key)
* attach the buffer manager buffer pool (and semaphore) * attach the buffer manager buffer pool (and semaphore)
* ---------------- * ----------------
*/ */
size = BufferShmemSize() + LockShmemSize(); InitShmem(key, 0);
InitShmem(key, size);
InitBufferPool(key); InitBufferPool(key);
/* ---------------- /* ----------------

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.31 1998/09/01 04:31:49 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.31.2.1 1999/03/07 02:00:46 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -215,7 +215,7 @@ InitShmem(unsigned int key, unsigned int size)
/* create OR attach to the shared memory shmem index */ /* create OR attach to the shared memory shmem index */
info.keysize = SHMEM_INDEX_KEYSIZE; info.keysize = SHMEM_INDEX_KEYSIZE;
info.datasize = SHMEM_INDEX_DATASIZE; info.datasize = SHMEM_INDEX_DATASIZE;
hash_flags = (HASH_ELEM); hash_flags = HASH_ELEM;
/* This will acquire the shmem index lock, but not release it. */ /* This will acquire the shmem index lock, but not release it. */
ShmemIndex = ShmemInitHash("ShmemIndex", ShmemIndex = ShmemInitHash("ShmemIndex",
@ -340,8 +340,8 @@ ShmemIsValid(unsigned long addr)
*/ */
HTAB * HTAB *
ShmemInitHash(char *name, /* table string name for shmem index */ ShmemInitHash(char *name, /* table string name for shmem index */
long init_size, /* initial size */ long init_size, /* initial table size */
long max_size, /* max size of the table */ long max_size, /* max size of the table (NOT USED) */
HASHCTL *infoP, /* info about key and bucket size */ HASHCTL *infoP, /* info about key and bucket size */
int hash_flags) /* info about infoP */ int hash_flags) /* info about infoP */
{ {
@ -349,18 +349,20 @@ ShmemInitHash(char *name, /* table string name for shmem index */
long *location; long *location;
/* /*
* shared memory hash tables have a fixed max size so that the control * Hash tables allocated in shared memory have a fixed directory;
* structures don't try to grow. The segbase is for calculating * it can't grow or other backends wouldn't be able to find it.
* pointer values. The shared memory allocator must be specified. * The segbase is for calculating pointer values.
* The shared memory allocator must be specified too.
*/ */
infoP->dsize = infoP->max_dsize = DEF_DIRSIZE;
infoP->segbase = (long *) ShmemBase; infoP->segbase = (long *) ShmemBase;
infoP->alloc = ShmemAlloc; infoP->alloc = ShmemAlloc;
infoP->max_size = max_size; hash_flags |= HASH_SHARED_MEM | HASH_DIRSIZE;
hash_flags |= HASH_SHARED_MEM;
/* look it up in the shmem index */ /* look it up in the shmem index */
location = location = ShmemInitStruct(name,
ShmemInitStruct(name, my_log2(max_size) + sizeof(HHDR), &found); sizeof(HHDR) + DEF_DIRSIZE * sizeof(SEG_OFFSET),
&found);
/* /*
* shmem index is corrupted. Let someone else give the error * shmem index is corrupted. Let someone else give the error
@ -376,13 +378,11 @@ ShmemInitHash(char *name, /* table string name for shmem index */
if (found) if (found)
hash_flags |= HASH_ATTACH; hash_flags |= HASH_ATTACH;
/* these structures were allocated or bound in ShmemInitStruct */ /* Now provide the header and directory pointers */
/* control information and parameters */
infoP->hctl = (long *) location; infoP->hctl = (long *) location;
/* directory for hash lookup */ infoP->dir = (long *) (((char*) location) + sizeof(HHDR));
infoP->dir = (long *) (location + sizeof(HHDR));
return hash_create(init_size, infoP, hash_flags);; return hash_create(init_size, infoP, hash_flags);
} }
/* /*

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.38 1998/10/08 18:29:57 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.38.2.1 1999/03/07 02:00:49 tgl Exp $
* *
* NOTES * NOTES
* Outside modules can create a lock table and acquire/release * Outside modules can create a lock table and acquire/release
@ -42,7 +42,6 @@
#include "storage/spin.h" #include "storage/spin.h"
#include "storage/proc.h" #include "storage/proc.h"
#include "storage/lock.h" #include "storage/lock.h"
#include "utils/dynahash.h"
#include "utils/hsearch.h" #include "utils/hsearch.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#include "utils/palloc.h" #include "utils/palloc.h"
@ -340,8 +339,8 @@ LockMethodTableInit(char *tabName,
* to find the different locks. * to find the different locks.
* ---------------------- * ----------------------
*/ */
info.keysize = sizeof(LOCKTAG); info.keysize = SHMEM_LOCKTAB_KEYSIZE;
info.datasize = sizeof(LOCK); info.datasize = SHMEM_LOCKTAB_DATASIZE;
info.hash = tag_hash; info.hash = tag_hash;
hash_flags = (HASH_ELEM | HASH_FUNCTION); hash_flags = (HASH_ELEM | HASH_FUNCTION);
@ -362,8 +361,8 @@ LockMethodTableInit(char *tabName,
* the same lock, additional information must be saved (locks per tx). * the same lock, additional information must be saved (locks per tx).
* ------------------------- * -------------------------
*/ */
info.keysize = XID_TAGSIZE; info.keysize = SHMEM_XIDTAB_KEYSIZE;
info.datasize = sizeof(XIDLookupEnt); info.datasize = SHMEM_XIDTAB_DATASIZE;
info.hash = tag_hash; info.hash = tag_hash;
hash_flags = (HASH_ELEM | HASH_FUNCTION); hash_flags = (HASH_ELEM | HASH_FUNCTION);
@ -1491,35 +1490,26 @@ int
LockShmemSize() LockShmemSize()
{ {
int size = 0; int size = 0;
int nLockBuckets,
nLockSegs;
int nXidBuckets,
nXidSegs;
nLockBuckets = 1 << (int) my_log2((NLOCKENTS - 1) / DEF_FFACTOR + 1);
nLockSegs = 1 << (int) my_log2((nLockBuckets - 1) / DEF_SEGSIZE + 1);
nXidBuckets = 1 << (int) my_log2((NLOCKS_PER_XACT - 1) / DEF_FFACTOR + 1);
nXidSegs = 1 << (int) my_log2((nLockBuckets - 1) / DEF_SEGSIZE + 1);
size += MAXALIGN(NBACKENDS * sizeof(PROC)); /* each MyProc */
size += MAXALIGN(NBACKENDS * sizeof(LOCKMETHODCTL)); /* each
* lockMethodTable->ctl */
size += MAXALIGN(sizeof(PROC_HDR)); /* ProcGlobal */ size += MAXALIGN(sizeof(PROC_HDR)); /* ProcGlobal */
size += MAXALIGN(MaxBackendId * sizeof(PROC)); /* each MyProc */
size += MAXALIGN(MaxBackendId * sizeof(LOCKMETHODCTL)); /* each
* lockMethodTable->ctl */
size += MAXALIGN(my_log2(NLOCKENTS) * sizeof(void *)); /* lockHash table */
size += MAXALIGN(sizeof(HHDR)); size += hash_estimate_size(NLOCKENTS,
size += nLockSegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT)); SHMEM_LOCKTAB_KEYSIZE,
size += NLOCKENTS * /* XXX not multiple of BUCKET_ALLOC_INCR? */ SHMEM_LOCKTAB_DATASIZE);
(MAXALIGN(sizeof(BUCKET_INDEX)) +
MAXALIGN(sizeof(LOCK))); /* contains hash key */
size += MAXALIGN(my_log2(NBACKENDS) * sizeof(void *)); /* xidHash table */
size += MAXALIGN(sizeof(HHDR)); size += hash_estimate_size(MaxBackendId,
size += nXidSegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT)); SHMEM_XIDTAB_KEYSIZE,
size += NBACKENDS * /* XXX not multiple of BUCKET_ALLOC_INCR? */ SHMEM_XIDTAB_DATASIZE);
(MAXALIGN(sizeof(BUCKET_INDEX)) +
MAXALIGN(sizeof(XIDLookupEnt))); /* contains hash key */ /* Since the lockHash entry count above is only an estimate,
* add 10% safety margin.
*/
size += size / 10;
return size; return size;
} }

View File

@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/Attic/mm.c,v 1.12 1998/09/01 04:32:07 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/smgr/Attic/mm.c,v 1.12.2.1 1999/03/07 02:00:52 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -25,7 +25,6 @@
#include "storage/shmem.h" #include "storage/shmem.h"
#include "storage/spin.h" #include "storage/spin.h"
#include "utils/dynahash.h"
#include "utils/hsearch.h" #include "utils/hsearch.h"
#include "utils/rel.h" #include "utils/rel.h"
#include "utils/memutils.h" #include "utils/memutils.h"
@ -111,7 +110,7 @@ mminit()
} }
info.keysize = sizeof(MMCacheTag); info.keysize = sizeof(MMCacheTag);
info.datasize = sizeof(int); info.datasize = sizeof(MMHashEntry) - sizeof(MMCacheTag);
info.hash = tag_hash; info.hash = tag_hash;
MMCacheHT = (HTAB *) ShmemInitHash("Main memory store HT", MMCacheHT = (HTAB *) ShmemInitHash("Main memory store HT",
@ -125,7 +124,7 @@ mminit()
} }
info.keysize = sizeof(MMRelTag); info.keysize = sizeof(MMRelTag);
info.datasize = sizeof(int); info.datasize = sizeof(MMRelHashEntry) - sizeof(MMRelTag);
info.hash = tag_hash; info.hash = tag_hash;
MMRelCacheHT = (HTAB *) ShmemInitHash("Main memory rel HT", MMRelCacheHT = (HTAB *) ShmemInitHash("Main memory rel HT",
@ -565,36 +564,20 @@ int
MMShmemSize() MMShmemSize()
{ {
int size = 0; int size = 0;
int nbuckets;
int nsegs;
int tmp;
/* /*
* first compute space occupied by the (dbid,relid,blkno) hash table * first compute space occupied by the (dbid,relid,blkno) hash table
*/ */
size += hash_estimate_size(MMNBUFFERS,
nbuckets = 1 << (int) my_log2((MMNBUFFERS - 1) / DEF_FFACTOR + 1); 0, /* MMHashEntry includes key */
nsegs = 1 << (int) my_log2((nbuckets - 1) / DEF_SEGSIZE + 1); sizeof(MMHashEntry));
size += MAXALIGN(my_log2(MMNBUFFERS) * sizeof(void *));
size += MAXALIGN(sizeof(HHDR));
size += nsegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
tmp = (int) ceil((double) MMNBUFFERS / BUCKET_ALLOC_INCR);
size += tmp * BUCKET_ALLOC_INCR *
(MAXALIGN(sizeof(BUCKET_INDEX)) +
MAXALIGN(sizeof(MMHashEntry))); /* contains hash key */
/* /*
* now do the same for the rel hash table * now do the same for the rel hash table
*/ */
size += hash_estimate_size(MMNRELATIONS,
size += MAXALIGN(my_log2(MMNRELATIONS) * sizeof(void *)); 0, /* MMRelHashEntry includes key */
size += MAXALIGN(sizeof(HHDR)); sizeof(MMRelHashEntry));
size += nsegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
tmp = (int) ceil((double) MMNRELATIONS / BUCKET_ALLOC_INCR);
size += tmp * BUCKET_ALLOC_INCR *
(MAXALIGN(sizeof(BUCKET_INDEX)) +
MAXALIGN(sizeof(MMRelHashEntry))); /* contains hash key */
/* /*
* finally, add in the memory block we use directly * finally, add in the memory block we use directly

View File

@ -1,13 +1,13 @@
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* dynahash.c-- * dynahash.c
* dynamic hashing * dynamic hashing
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.16 1998/09/01 04:33:11 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.16.2.1 1999/03/07 02:01:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -174,7 +174,9 @@ hash_create(int nelem, HASHCTL *info, int flags)
if (flags & HASH_SHARED_MEM) if (flags & HASH_SHARED_MEM)
{ {
/* ctl structure is preallocated for shared memory tables */ /* ctl structure is preallocated for shared memory tables.
* Note that HASH_DIRSIZE had better be set as well.
*/
hashp->hctl = (HHDR *) info->hctl; hashp->hctl = (HHDR *) info->hctl;
hashp->segbase = (char *) info->segbase; hashp->segbase = (char *) info->segbase;
@ -190,6 +192,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
{ {
/* setup hash table defaults */ /* setup hash table defaults */
hashp->hctl = NULL;
hashp->alloc = (dhalloc_ptr) MEM_ALLOC; hashp->alloc = (dhalloc_ptr) MEM_ALLOC;
hashp->dir = NULL; hashp->dir = NULL;
hashp->segbase = NULL; hashp->segbase = NULL;
@ -210,11 +213,6 @@ hash_create(int nelem, HASHCTL *info, int flags)
hctl->accesses = hctl->collisions = 0; hctl->accesses = hctl->collisions = 0;
#endif #endif
if (flags & HASH_BUCKET)
{
hctl->bsize = info->bsize;
hctl->bshift = my_log2(info->bsize);
}
if (flags & HASH_SEGMENT) if (flags & HASH_SEGMENT)
{ {
hctl->ssize = info->ssize; hctl->ssize = info->ssize;
@ -224,13 +222,12 @@ hash_create(int nelem, HASHCTL *info, int flags)
hctl->ffactor = info->ffactor; hctl->ffactor = info->ffactor;
/* /*
* SHM hash tables have fixed maximum size (allocate a maximal sized * SHM hash tables have fixed directory size passed by the caller.
* directory).
*/ */
if (flags & HASH_DIRSIZE) if (flags & HASH_DIRSIZE)
{ {
hctl->max_dsize = my_log2(info->max_size); hctl->max_dsize = info->max_dsize;
hctl->dsize = my_log2(info->dsize); hctl->dsize = info->dsize;
} }
/* /*
@ -254,8 +251,8 @@ hash_create(int nelem, HASHCTL *info, int flags)
} }
/* /*
Allocate and initialize an HTAB structure * Set default HHDR parameters.
*/ */
static int static int
hdefault(HTAB *hashp) hdefault(HTAB *hashp)
{ {
@ -264,8 +261,6 @@ hdefault(HTAB *hashp)
MemSet(hashp->hctl, 0, sizeof(HHDR)); MemSet(hashp->hctl, 0, sizeof(HHDR));
hctl = hashp->hctl; hctl = hashp->hctl;
hctl->bsize = DEF_BUCKET_SIZE;
hctl->bshift = DEF_BUCKET_SHIFT;
hctl->ssize = DEF_SEGSIZE; hctl->ssize = DEF_SEGSIZE;
hctl->sshift = DEF_SEGSIZE_SHIFT; hctl->sshift = DEF_SEGSIZE_SHIFT;
hctl->dsize = DEF_DIRSIZE; hctl->dsize = DEF_DIRSIZE;
@ -295,42 +290,44 @@ init_htab(HTAB *hashp, int nelem)
SEG_OFFSET *segp; SEG_OFFSET *segp;
int nbuckets; int nbuckets;
int nsegs; int nsegs;
int l2;
HHDR *hctl; HHDR *hctl;
hctl = hashp->hctl; hctl = hashp->hctl;
/* /*
* Divide number of elements by the fill factor and determine a * Divide number of elements by the fill factor to determine a
* desired number of buckets. Allocate space for the next greater * desired number of buckets. Allocate space for the next greater
* power of two number of buckets * power of two number of buckets
*/ */
nelem = (nelem - 1) / hctl->ffactor + 1; nelem = (nelem - 1) / hctl->ffactor + 1;
l2 = my_log2(nelem); nbuckets = 1 << my_log2(nelem);
nbuckets = 1 << l2;
hctl->max_bucket = hctl->low_mask = nbuckets - 1; hctl->max_bucket = hctl->low_mask = nbuckets - 1;
hctl->high_mask = (nbuckets << 1) - 1; hctl->high_mask = (nbuckets << 1) - 1;
/*
* Figure number of directory segments needed, round up to a power of 2
*/
nsegs = (nbuckets - 1) / hctl->ssize + 1; nsegs = (nbuckets - 1) / hctl->ssize + 1;
nsegs = 1 << my_log2(nsegs); nsegs = 1 << my_log2(nsegs);
if (nsegs > hctl->dsize)
hctl->dsize = nsegs;
/* Use two low order bits of points ???? */
/* /*
* if ( !(hctl->mem = bit_alloc ( nbuckets )) ) return(-1); if ( * Make sure directory is big enough.
* !(hctl->mod = bit_alloc ( nbuckets )) ) return(-1); * If pre-allocated directory is too small, choke (caller screwed up).
*/ */
if (nsegs > hctl->dsize)
{
if (!(hashp->dir))
hctl->dsize = nsegs;
else
return -1;
}
/* allocate a directory */ /* Allocate a directory */
if (!(hashp->dir)) if (!(hashp->dir))
{ {
hashp->dir = hashp->dir = (SEG_OFFSET *) hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
(SEG_OFFSET *) hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
if (!hashp->dir) if (!hashp->dir)
return -1; return -1;
} }
@ -347,11 +344,9 @@ init_htab(HTAB *hashp, int nelem)
} }
#if HASH_DEBUG #if HASH_DEBUG
fprintf(stderr, "%s\n%s%x\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n", fprintf(stderr, "%s\n%s%x\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
"init_htab:", "init_htab:",
"TABLE POINTER ", hashp, "TABLE POINTER ", hashp,
"BUCKET SIZE ", hctl->bsize,
"BUCKET SHIFT ", hctl->bshift,
"DIRECTORY SIZE ", hctl->dsize, "DIRECTORY SIZE ", hctl->dsize,
"SEGMENT SIZE ", hctl->ssize, "SEGMENT SIZE ", hctl->ssize,
"SEGMENT SHIFT ", hctl->sshift, "SEGMENT SHIFT ", hctl->sshift,
@ -365,14 +360,59 @@ init_htab(HTAB *hashp, int nelem)
return 0; return 0;
} }
/*
* Estimate the space needed for a hashtable containing the given number
* of entries of given size.
* NOTE: this is used to estimate the footprint of hashtables in shared
* memory; therefore it does not count HTAB which is in local memory.
* NB: assumes that all hash structure parameters have default values!
*/
long
hash_estimate_size(long num_entries, long keysize, long datasize)
{
long size = 0;
long nBuckets,
nSegments,
nDirEntries,
nRecordAllocs,
recordSize;
/* estimate number of buckets wanted */
nBuckets = 1L << my_log2((num_entries - 1) / DEF_FFACTOR + 1);
/* # of segments needed for nBuckets */
nSegments = 1L << my_log2((nBuckets - 1) / DEF_SEGSIZE + 1);
/* directory entries */
nDirEntries = DEF_DIRSIZE;
while (nDirEntries < nSegments)
nDirEntries <<= 1; /* dir_alloc doubles dsize at each call */
/* fixed control info */
size += MAXALIGN(sizeof(HHDR)); /* but not HTAB, per above */
/* directory */
size += MAXALIGN(nDirEntries * sizeof(SEG_OFFSET));
/* segments */
size += nSegments * MAXALIGN(DEF_SEGSIZE * sizeof(BUCKET_INDEX));
/* records --- allocated in groups of BUCKET_ALLOC_INCR */
recordSize = sizeof(BUCKET_INDEX) + keysize + datasize;
recordSize = MAXALIGN(recordSize);
nRecordAllocs = (num_entries - 1) / BUCKET_ALLOC_INCR + 1;
size += nRecordAllocs * BUCKET_ALLOC_INCR * recordSize;
return size;
}
/********************** DESTROY ROUTINES ************************/ /********************** DESTROY ROUTINES ************************/
/*
* XXX this sure looks thoroughly broken to me --- tgl 2/99.
* It's freeing every entry individually --- but they weren't
* allocated individually, see bucket_alloc!! Why doesn't it crash?
*/
void void
hash_destroy(HTAB *hashp) hash_destroy(HTAB *hashp)
{ {
/* cannot destroy a shared memory hash table */
Assert(!hashp->segbase);
if (hashp != NULL) if (hashp != NULL)
{ {
SEG_OFFSET segNum; SEG_OFFSET segNum;
@ -384,6 +424,13 @@ hash_destroy(HTAB *hashp)
q; q;
ELEMENT *curr; ELEMENT *curr;
/* cannot destroy a shared memory hash table */
Assert(!hashp->segbase);
/* allocation method must be one we know how to free, too */
Assert(hashp->alloc == (dhalloc_ptr) MEM_ALLOC);
hash_stats("destroy", hashp);
for (segNum = 0; nsegs > 0; nsegs--, segNum++) for (segNum = 0; nsegs > 0; nsegs--, segNum++)
{ {
@ -397,11 +444,10 @@ hash_destroy(HTAB *hashp)
MEM_FREE((char *) curr); MEM_FREE((char *) curr);
} }
} }
free((char *) segp); MEM_FREE((char *) segp);
} }
MEM_FREE((char *) hashp->dir); MEM_FREE((char *) hashp->dir);
MEM_FREE((char *) hashp->hctl); MEM_FREE((char *) hashp->hctl);
hash_stats("destroy", hashp);
MEM_FREE((char *) hashp); MEM_FREE((char *) hashp);
} }
} }
@ -603,7 +649,7 @@ hash_search(HTAB *hashp,
/* link into chain */ /* link into chain */
*prevIndexPtr = currIndex; *prevIndexPtr = currIndex;
/* copy key and data */ /* copy key into record */
destAddr = (char *) &(curr->key); destAddr = (char *) &(curr->key);
memmove(destAddr, keyPtr, hctl->keysize); memmove(destAddr, keyPtr, hctl->keysize);
curr->next = INVALID_INDEX; curr->next = INVALID_INDEX;
@ -618,13 +664,10 @@ hash_search(HTAB *hashp,
*/ */
if (++hctl->nkeys / (hctl->max_bucket + 1) > hctl->ffactor) if (++hctl->nkeys / (hctl->max_bucket + 1) > hctl->ffactor)
{ {
/* NOTE: failure to expand table is not a fatal error,
/* * it just means we have to run at higher fill factor than we wanted.
* fprintf(stderr,"expanding on '%s'\n",keyPtr);
* hash_stats("expanded table",hashp);
*/ */
if (!expand_table(hashp)) expand_table(hashp);
return NULL;
} }
return &(curr->key); return &(curr->key);
} }
@ -725,23 +768,25 @@ expand_table(HTAB *hashp)
#endif #endif
hctl = hashp->hctl; hctl = hashp->hctl;
new_bucket = ++hctl->max_bucket;
old_bucket = (hctl->max_bucket & hctl->low_mask);
new_bucket = hctl->max_bucket + 1;
new_segnum = new_bucket >> hctl->sshift; new_segnum = new_bucket >> hctl->sshift;
new_segndx = MOD(new_bucket, hctl->ssize); new_segndx = MOD(new_bucket, hctl->ssize);
if (new_segnum >= hctl->nsegs) if (new_segnum >= hctl->nsegs)
{ {
/* Allocate new segment if necessary -- could fail if dir full */
/* Allocate new segment if necessary */
if (new_segnum >= hctl->dsize) if (new_segnum >= hctl->dsize)
dir_realloc(hashp); if (! dir_realloc(hashp))
return 0;
if (!(hashp->dir[new_segnum] = seg_alloc(hashp))) if (!(hashp->dir[new_segnum] = seg_alloc(hashp)))
return 0; return 0;
hctl->nsegs++; hctl->nsegs++;
} }
/* OK, we got a new bucket */
hctl->max_bucket++;
old_bucket = (hctl->max_bucket & hctl->low_mask);
if (new_bucket > hctl->high_mask) if (new_bucket > hctl->high_mask)
{ {
@ -790,31 +835,32 @@ static int
dir_realloc(HTAB *hashp) dir_realloc(HTAB *hashp)
{ {
char *p; char *p;
char **p_ptr; char *old_p;
long new_dsize;
long old_dirsize; long old_dirsize;
long new_dirsize; long new_dirsize;
if (hashp->hctl->max_dsize != NO_MAX_DSIZE) if (hashp->hctl->max_dsize != NO_MAX_DSIZE)
return 0; return 0;
/* Reallocate directory */ /* Reallocate directory */
old_dirsize = hashp->hctl->dsize * sizeof(SEGMENT *); new_dsize = hashp->hctl->dsize << 1;
new_dirsize = old_dirsize << 1; old_dirsize = hashp->hctl->dsize * sizeof(SEG_OFFSET);
new_dirsize = new_dsize * sizeof(SEG_OFFSET);
p_ptr = (char **) hashp->dir; old_p = (char *) hashp->dir;
p = (char *) hashp->alloc((unsigned long) new_dirsize); p = (char *) hashp->alloc((unsigned long) new_dirsize);
if (p != NULL) if (p != NULL)
{ {
memmove(p, *p_ptr, old_dirsize); memmove(p, old_p, old_dirsize);
MemSet(*p_ptr + old_dirsize, 0, new_dirsize - old_dirsize); MemSet(p + old_dirsize, 0, new_dirsize - old_dirsize);
free((char *) *p_ptr); MEM_FREE((char *) old_p);
*p_ptr = p; hashp->dir = (SEG_OFFSET *) p;
hashp->hctl->dsize = new_dirsize; hashp->hctl->dsize = new_dsize;
return 1; return 1;
} }
return 0; return 0;
} }
@ -824,15 +870,14 @@ seg_alloc(HTAB *hashp)
SEGMENT segp; SEGMENT segp;
SEG_OFFSET segOffset; SEG_OFFSET segOffset;
segp = (SEGMENT) hashp->alloc((unsigned long) segp = (SEGMENT) hashp->alloc((unsigned long)
sizeof(SEGMENT) * hashp->hctl->ssize); sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
if (!segp) if (!segp)
return 0; return 0;
MemSet((char *) segp, 0, MemSet((char *) segp, 0,
(long) sizeof(SEGMENT) * hashp->hctl->ssize); (long) sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
segOffset = MAKE_HASHOFFSET(hashp, segp); segOffset = MAKE_HASHOFFSET(hashp, segp);
return segOffset; return segOffset;
@ -850,11 +895,11 @@ bucket_alloc(HTAB *hashp)
BUCKET_INDEX tmpIndex, BUCKET_INDEX tmpIndex,
lastIndex; lastIndex;
bucketSize = /* Each bucket has a BUCKET_INDEX header plus user data. */
sizeof(BUCKET_INDEX) + hashp->hctl->keysize + hashp->hctl->datasize; bucketSize = sizeof(BUCKET_INDEX) + hashp->hctl->keysize + hashp->hctl->datasize;
/* make sure its aligned correctly */ /* make sure its aligned correctly */
bucketSize += sizeof(long *) - (bucketSize % sizeof(long *)); bucketSize = MAXALIGN(bucketSize);
/* /*
* tmpIndex is the shmem offset into the first bucket of the array. * tmpIndex is the shmem offset into the first bucket of the array.
@ -871,8 +916,10 @@ bucket_alloc(HTAB *hashp)
lastIndex = hashp->hctl->freeBucketIndex; lastIndex = hashp->hctl->freeBucketIndex;
hashp->hctl->freeBucketIndex = tmpIndex; hashp->hctl->freeBucketIndex = tmpIndex;
/* initialize each bucket to point to the one behind it */ /* initialize each bucket to point to the one behind it.
for (i = 0; i < (BUCKET_ALLOC_INCR - 1); i++) * NOTE: loop sets last bucket incorrectly; we fix below.
*/
for (i = 0; i < BUCKET_ALLOC_INCR; i++)
{ {
tmpBucket = GET_BUCKET(hashp, tmpIndex); tmpBucket = GET_BUCKET(hashp, tmpIndex);
tmpIndex += bucketSize; tmpIndex += bucketSize;
@ -881,20 +928,21 @@ bucket_alloc(HTAB *hashp)
/* /*
* the last bucket points to the old freelist head (which is probably * the last bucket points to the old freelist head (which is probably
* invalid or we wouldnt be here) * invalid or we wouldn't be here)
*/ */
tmpBucket->next = lastIndex; tmpBucket->next = lastIndex;
return 1; return 1;
} }
/* calculate the log base 2 of num */ /* calculate ceil(log base 2) of num */
int int
my_log2(long num) my_log2(long num)
{ {
int i = 1; int i;
int limit; long limit;
for (i = 0, limit = 1; limit < num; limit = 2 * limit, i++); for (i = 0, limit = 1; limit < num; i++, limit <<= 1)
;
return i; return i;
} }

View File

@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: lock.h,v 1.19 1998/10/08 18:30:45 momjian Exp $ * $Id: lock.h,v 1.19.2.1 1999/03/07 02:00:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -175,6 +175,9 @@ typedef struct XIDLookupEnt
SHM_QUEUE queue; SHM_QUEUE queue;
} XIDLookupEnt; } XIDLookupEnt;
#define SHMEM_XIDTAB_KEYSIZE sizeof(XIDTAG)
#define SHMEM_XIDTAB_DATASIZE (sizeof(XIDLookupEnt) - SHMEM_XIDTAB_KEYSIZE)
#define XID_TAGSIZE (sizeof(XIDTAG)) #define XID_TAGSIZE (sizeof(XIDTAG))
#define XIDENT_LOCKMETHOD(xident) (XIDTAG_LOCKMETHOD((xident).tag)) #define XIDENT_LOCKMETHOD(xident) (XIDTAG_LOCKMETHOD((xident).tag))
@ -211,6 +214,9 @@ typedef struct LOCK
int nActive; int nActive;
} LOCK; } LOCK;
#define SHMEM_LOCKTAB_KEYSIZE sizeof(LOCKTAG)
#define SHMEM_LOCKTAB_DATASIZE (sizeof(LOCK) - SHMEM_LOCKTAB_KEYSIZE)
#define LOCK_LOCKMETHOD(lock) (LOCKTAG_LOCKMETHOD((lock).tag)) #define LOCK_LOCKMETHOD(lock) (LOCKTAG_LOCKMETHOD((lock).tag))
#define LockGetLock_nHolders(l) l->nHolders #define LockGetLock_nHolders(l) l->nHolders

View File

@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: hsearch.h,v 1.9 1998/09/01 04:39:12 momjian Exp $ * $Id: hsearch.h,v 1.9.2.1 1999/03/07 02:01:09 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -16,16 +16,23 @@
/* /*
* Constants * Constants
*
* A hash table has a top-level "directory", each of whose entries points
* to a "segment" of ssize bucket headers. The maximum number of hash
* buckets is thus dsize * ssize (but dsize may be expansible). Of course,
* the number of records in the table can be larger, but we don't want a
* whole lot of records per bucket or performance goes down.
*
* In a hash table allocated in shared memory, the directory cannot be
* expanded because it must stay at a fixed address.
*/ */
#define DEF_BUCKET_SIZE 256
#define DEF_BUCKET_SHIFT 8/* log2(BUCKET) */
#define DEF_SEGSIZE 256 #define DEF_SEGSIZE 256
#define DEF_SEGSIZE_SHIFT 8 /* log2(SEGSIZE) */ #define DEF_SEGSIZE_SHIFT 8 /* log2(SEGSIZE) */
#define DEF_DIRSIZE 256 #define DEF_DIRSIZE 256
#define PRIME1 37 #define DEF_FFACTOR 1 /* default fill factor */
#define PRIME1 37 /* for the hash function */
#define PRIME2 1048583 #define PRIME2 1048583
#define DEF_FFACTOR 1
#define SPLTMAX 8
/* /*
@ -46,10 +53,8 @@ typedef unsigned long SEG_OFFSET;
typedef struct hashhdr typedef struct hashhdr
{ {
long bsize; /* Bucket/Page Size */
long bshift; /* Bucket shift */
long dsize; /* Directory Size */ long dsize; /* Directory Size */
long ssize; /* Segment Size */ long ssize; /* Segment Size --- must be power of 2 */
long sshift; /* Segment shift */ long sshift; /* Segment shift */
long max_bucket; /* ID of Maximum bucket in use */ long max_bucket; /* ID of Maximum bucket in use */
long high_mask; /* Mask to modulo into entire table */ long high_mask; /* Mask to modulo into entire table */
@ -59,8 +64,7 @@ typedef struct hashhdr
long nsegs; /* Number of allocated segments */ long nsegs; /* Number of allocated segments */
long keysize; /* hash key length in bytes */ long keysize; /* hash key length in bytes */
long datasize; /* elem data length in bytes */ long datasize; /* elem data length in bytes */
long max_dsize; /* 'dsize' limit if directory is fixed long max_dsize; /* 'dsize' limit if directory is fixed size */
* size */
BUCKET_INDEX freeBucketIndex; BUCKET_INDEX freeBucketIndex;
/* index of first free bucket */ /* index of first free bucket */
#ifdef HASH_STATISTICS #ifdef HASH_STATISTICS
@ -83,14 +87,13 @@ typedef struct htab
typedef struct hashctl typedef struct hashctl
{ {
long bsize; /* Bucket Size */
long ssize; /* Segment Size */ long ssize; /* Segment Size */
long dsize; /* Dirsize Size */ long dsize; /* Dirsize Size */
long ffactor; /* Fill factor */ long ffactor; /* Fill factor */
long (*hash) (); /* Hash Function */ long (*hash) (); /* Hash Function */
long keysize; /* hash key length in bytes */ long keysize; /* hash key length in bytes */
long datasize; /* elem data length in bytes */ long datasize; /* elem data length in bytes */
long max_size; /* limit to dsize if directory size is long max_dsize; /* limit to dsize if directory size is
* limited */ * limited */
long *segbase; /* base for calculating bucket + seg ptrs */ long *segbase; /* base for calculating bucket + seg ptrs */
long *(*alloc) (); /* memory allocation function */ long *(*alloc) (); /* memory allocation function */
@ -100,7 +103,6 @@ typedef struct hashctl
} HASHCTL; } HASHCTL;
/* Flags to indicate action for hctl */ /* Flags to indicate action for hctl */
#define HASH_BUCKET 0x001 /* Setting bucket size */
#define HASH_SEGMENT 0x002 /* Setting segment size */ #define HASH_SEGMENT 0x002 /* Setting segment size */
#define HASH_DIRSIZE 0x004 /* Setting directory size */ #define HASH_DIRSIZE 0x004 /* Setting directory size */
#define HASH_FFACTOR 0x008 /* Setting fill factor */ #define HASH_FFACTOR 0x008 /* Setting fill factor */
@ -136,6 +138,7 @@ extern void hash_stats(char *where, HTAB *hashp);
extern long *hash_search(HTAB *hashp, char *keyPtr, HASHACTION action, extern long *hash_search(HTAB *hashp, char *keyPtr, HASHACTION action,
bool *foundPtr); bool *foundPtr);
extern long *hash_seq(HTAB *hashp); extern long *hash_seq(HTAB *hashp);
extern long hash_estimate_size(long num_entries, long keysize, long datasize);
/* /*
* prototypes from functions in hashfn.c * prototypes from functions in hashfn.c