From 2ecbf94430265822e08758df375ffea9d041a86a Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 7 Mar 1999 02:01:09 +0000 Subject: [PATCH] Retrofit hashtable and shared-mem-size-estimation bug fixes into REL6_4. --- src/backend/storage/buffer/buf_init.c | 33 ++--- src/backend/storage/ipc/ipci.c | 15 +- src/backend/storage/ipc/shmem.c | 32 ++--- src/backend/storage/lmgr/lock.c | 52 +++---- src/backend/storage/smgr/mm.c | 35 ++--- src/backend/utils/hash/dynahash.c | 196 ++++++++++++++++---------- src/include/storage/lock.h | 8 +- src/include/utils/hsearch.h | 33 +++-- 8 files changed, 211 insertions(+), 193 deletions(-) diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 975e999ec2..ff836506b8 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -7,7 +7,7 @@ * * * 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 "miscadmin.h" #include "utils/builtins.h" -#include "utils/dynahash.h" #include "utils/hsearch.h" #include "utils/memutils.h" #include "executor/execdebug.h" /* for NDirectFileRead */ @@ -270,21 +269,11 @@ int BufferShmemSize() { int size = 0; - int nbuckets; - int nsegs; - int tmp; - nbuckets = 1 << (int) my_log2((NBuffers - 1) / DEF_FFACTOR + 1); - nsegs = 1 << (int) my_log2((nbuckets - 1) / DEF_SEGSIZE + 1); - - /* size of shmem index table */ - 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 shmem index hash table */ + size += hash_estimate_size(SHMEM_INDEX_SIZE, + SHMEM_INDEX_KEYSIZE, + SHMEM_INDEX_DATASIZE); /* size of buffer descriptors */ size += MAXALIGN((NBuffers + 1) * sizeof(BufferDesc)); @@ -293,17 +282,13 @@ BufferShmemSize() size += NBuffers * MAXALIGN(BLCKSZ); /* size of buffer hash table */ - size += MAXALIGN(my_log2(NBuffers) * sizeof(void *)); /* HTAB->dir */ - size += MAXALIGN(sizeof(HHDR)); /* HTAB->hctl */ - size += nsegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT)); - tmp = (int) ceil((double) NBuffers / BUCKET_ALLOC_INCR); - size += tmp * BUCKET_ALLOC_INCR * - (MAXALIGN(sizeof(BUCKET_INDEX)) + - MAXALIGN(sizeof(BufferTag)) + - MAXALIGN(sizeof(Buffer))); + size += hash_estimate_size(NBuffers, + sizeof(BufferTag), + sizeof(Buffer)); #ifdef BMTRACE size += (BMT_LIMIT * sizeof(bmtrace)) + sizeof(long); #endif + return size; } diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index f6ce9eda24..38a964b15e 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -7,7 +7,7 @@ * * * 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)); - 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 size += MMShmemSize(); #endif + size += 100000; if (DebugLvl > 1) { @@ -113,8 +119,6 @@ CreateSharedMemoryAndSemaphores(IPCKey key) void AttachSharedMemoryAndSemaphores(IPCKey key) { - int size; - /* ---------------- * create rather than attach if using private key * ---------------- @@ -136,8 +140,7 @@ AttachSharedMemoryAndSemaphores(IPCKey key) * attach the buffer manager buffer pool (and semaphore) * ---------------- */ - size = BufferShmemSize() + LockShmemSize(); - InitShmem(key, size); + InitShmem(key, 0); InitBufferPool(key); /* ---------------- diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c index 18b8d718d6..67bac2f239 100644 --- a/src/backend/storage/ipc/shmem.c +++ b/src/backend/storage/ipc/shmem.c @@ -7,7 +7,7 @@ * * * 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 */ info.keysize = SHMEM_INDEX_KEYSIZE; info.datasize = SHMEM_INDEX_DATASIZE; - hash_flags = (HASH_ELEM); + hash_flags = HASH_ELEM; /* This will acquire the shmem index lock, but not release it. */ ShmemIndex = ShmemInitHash("ShmemIndex", @@ -340,8 +340,8 @@ ShmemIsValid(unsigned long addr) */ HTAB * ShmemInitHash(char *name, /* table string name for shmem index */ - long init_size, /* initial size */ - long max_size, /* max size of the table */ + long init_size, /* initial table size */ + long max_size, /* max size of the table (NOT USED) */ HASHCTL *infoP, /* info about key and bucket size */ int hash_flags) /* info about infoP */ { @@ -349,18 +349,20 @@ ShmemInitHash(char *name, /* table string name for shmem index */ long *location; /* - * shared memory hash tables have a fixed max size so that the control - * structures don't try to grow. The segbase is for calculating - * pointer values. The shared memory allocator must be specified. + * Hash tables allocated in shared memory have a fixed directory; + * it can't grow or other backends wouldn't be able to find it. + * 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->alloc = ShmemAlloc; - infoP->max_size = max_size; - hash_flags |= HASH_SHARED_MEM; + hash_flags |= HASH_SHARED_MEM | HASH_DIRSIZE; /* look it up in the shmem index */ - location = - ShmemInitStruct(name, my_log2(max_size) + sizeof(HHDR), &found); + location = ShmemInitStruct(name, + sizeof(HHDR) + DEF_DIRSIZE * sizeof(SEG_OFFSET), + &found); /* * 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) hash_flags |= HASH_ATTACH; - /* these structures were allocated or bound in ShmemInitStruct */ - /* control information and parameters */ + /* Now provide the header and directory pointers */ infoP->hctl = (long *) location; - /* directory for hash lookup */ - infoP->dir = (long *) (location + sizeof(HHDR)); + infoP->dir = (long *) (((char*) location) + sizeof(HHDR)); - return hash_create(init_size, infoP, hash_flags);; + return hash_create(init_size, infoP, hash_flags); } /* diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index adc4d1a42e..ccae5df3b7 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -7,7 +7,7 @@ * * * 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 * Outside modules can create a lock table and acquire/release @@ -42,7 +42,6 @@ #include "storage/spin.h" #include "storage/proc.h" #include "storage/lock.h" -#include "utils/dynahash.h" #include "utils/hsearch.h" #include "utils/memutils.h" #include "utils/palloc.h" @@ -340,8 +339,8 @@ LockMethodTableInit(char *tabName, * to find the different locks. * ---------------------- */ - info.keysize = sizeof(LOCKTAG); - info.datasize = sizeof(LOCK); + info.keysize = SHMEM_LOCKTAB_KEYSIZE; + info.datasize = SHMEM_LOCKTAB_DATASIZE; info.hash = tag_hash; hash_flags = (HASH_ELEM | HASH_FUNCTION); @@ -362,8 +361,8 @@ LockMethodTableInit(char *tabName, * the same lock, additional information must be saved (locks per tx). * ------------------------- */ - info.keysize = XID_TAGSIZE; - info.datasize = sizeof(XIDLookupEnt); + info.keysize = SHMEM_XIDTAB_KEYSIZE; + info.datasize = SHMEM_XIDTAB_DATASIZE; info.hash = tag_hash; hash_flags = (HASH_ELEM | HASH_FUNCTION); @@ -1491,35 +1490,26 @@ int LockShmemSize() { 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(MaxBackendId * sizeof(PROC)); /* each MyProc */ + size += MAXALIGN(MaxBackendId * sizeof(LOCKMETHODCTL)); /* each + * lockMethodTable->ctl */ - size += MAXALIGN(my_log2(NLOCKENTS) * sizeof(void *)); - size += MAXALIGN(sizeof(HHDR)); - size += nLockSegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT)); - size += NLOCKENTS * /* XXX not multiple of BUCKET_ALLOC_INCR? */ - (MAXALIGN(sizeof(BUCKET_INDEX)) + - MAXALIGN(sizeof(LOCK))); /* contains hash key */ + /* lockHash table */ + size += hash_estimate_size(NLOCKENTS, + SHMEM_LOCKTAB_KEYSIZE, + SHMEM_LOCKTAB_DATASIZE); - size += MAXALIGN(my_log2(NBACKENDS) * sizeof(void *)); - size += MAXALIGN(sizeof(HHDR)); - size += nXidSegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT)); - size += NBACKENDS * /* XXX not multiple of BUCKET_ALLOC_INCR? */ - (MAXALIGN(sizeof(BUCKET_INDEX)) + - MAXALIGN(sizeof(XIDLookupEnt))); /* contains hash key */ + /* xidHash table */ + size += hash_estimate_size(MaxBackendId, + SHMEM_XIDTAB_KEYSIZE, + SHMEM_XIDTAB_DATASIZE); + + /* Since the lockHash entry count above is only an estimate, + * add 10% safety margin. + */ + size += size / 10; return size; } diff --git a/src/backend/storage/smgr/mm.c b/src/backend/storage/smgr/mm.c index b3e72e37d6..cbd39301d5 100644 --- a/src/backend/storage/smgr/mm.c +++ b/src/backend/storage/smgr/mm.c @@ -10,7 +10,7 @@ * * * 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/spin.h" -#include "utils/dynahash.h" #include "utils/hsearch.h" #include "utils/rel.h" #include "utils/memutils.h" @@ -111,7 +110,7 @@ mminit() } info.keysize = sizeof(MMCacheTag); - info.datasize = sizeof(int); + info.datasize = sizeof(MMHashEntry) - sizeof(MMCacheTag); info.hash = tag_hash; MMCacheHT = (HTAB *) ShmemInitHash("Main memory store HT", @@ -125,7 +124,7 @@ mminit() } info.keysize = sizeof(MMRelTag); - info.datasize = sizeof(int); + info.datasize = sizeof(MMRelHashEntry) - sizeof(MMRelTag); info.hash = tag_hash; MMRelCacheHT = (HTAB *) ShmemInitHash("Main memory rel HT", @@ -565,36 +564,20 @@ int MMShmemSize() { int size = 0; - int nbuckets; - int nsegs; - int tmp; /* * first compute space occupied by the (dbid,relid,blkno) hash table */ - - nbuckets = 1 << (int) my_log2((MMNBUFFERS - 1) / DEF_FFACTOR + 1); - nsegs = 1 << (int) my_log2((nbuckets - 1) / DEF_SEGSIZE + 1); - - 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 */ + size += hash_estimate_size(MMNBUFFERS, + 0, /* MMHashEntry includes key */ + sizeof(MMHashEntry)); /* * now do the same for the rel hash table */ - - size += MAXALIGN(my_log2(MMNRELATIONS) * sizeof(void *)); - size += MAXALIGN(sizeof(HHDR)); - 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 */ + size += hash_estimate_size(MMNRELATIONS, + 0, /* MMRelHashEntry includes key */ + sizeof(MMRelHashEntry)); /* * finally, add in the memory block we use directly diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c index ecf87b08f5..bae8965f2c 100644 --- a/src/backend/utils/hash/dynahash.c +++ b/src/backend/utils/hash/dynahash.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * - * dynahash.c-- + * dynahash.c * dynamic hashing * * Copyright (c) 1994, Regents of the University of California * * * 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) { - /* 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->segbase = (char *) info->segbase; @@ -190,6 +192,7 @@ hash_create(int nelem, HASHCTL *info, int flags) { /* setup hash table defaults */ + hashp->hctl = NULL; hashp->alloc = (dhalloc_ptr) MEM_ALLOC; hashp->dir = NULL; hashp->segbase = NULL; @@ -210,11 +213,6 @@ hash_create(int nelem, HASHCTL *info, int flags) hctl->accesses = hctl->collisions = 0; #endif - if (flags & HASH_BUCKET) - { - hctl->bsize = info->bsize; - hctl->bshift = my_log2(info->bsize); - } if (flags & HASH_SEGMENT) { hctl->ssize = info->ssize; @@ -224,13 +222,12 @@ hash_create(int nelem, HASHCTL *info, int flags) hctl->ffactor = info->ffactor; /* - * SHM hash tables have fixed maximum size (allocate a maximal sized - * directory). + * SHM hash tables have fixed directory size passed by the caller. */ if (flags & HASH_DIRSIZE) { - hctl->max_dsize = my_log2(info->max_size); - hctl->dsize = my_log2(info->dsize); + hctl->max_dsize = info->max_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 hdefault(HTAB *hashp) { @@ -264,8 +261,6 @@ hdefault(HTAB *hashp) MemSet(hashp->hctl, 0, sizeof(HHDR)); hctl = hashp->hctl; - hctl->bsize = DEF_BUCKET_SIZE; - hctl->bshift = DEF_BUCKET_SHIFT; hctl->ssize = DEF_SEGSIZE; hctl->sshift = DEF_SEGSIZE_SHIFT; hctl->dsize = DEF_DIRSIZE; @@ -295,42 +290,44 @@ init_htab(HTAB *hashp, int nelem) SEG_OFFSET *segp; int nbuckets; int nsegs; - int l2; HHDR *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 * power of two number of buckets */ nelem = (nelem - 1) / hctl->ffactor + 1; - l2 = my_log2(nelem); - nbuckets = 1 << l2; + nbuckets = 1 << my_log2(nelem); hctl->max_bucket = hctl->low_mask = nbuckets - 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 = 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 ( - * !(hctl->mod = bit_alloc ( nbuckets )) ) return(-1); + * Make sure directory is big enough. + * 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)) { - hashp->dir = - (SEG_OFFSET *) hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET)); + hashp->dir = (SEG_OFFSET *) hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET)); if (!hashp->dir) return -1; } @@ -347,11 +344,9 @@ init_htab(HTAB *hashp, int nelem) } #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:", "TABLE POINTER ", hashp, - "BUCKET SIZE ", hctl->bsize, - "BUCKET SHIFT ", hctl->bshift, "DIRECTORY SIZE ", hctl->dsize, "SEGMENT SIZE ", hctl->ssize, "SEGMENT SHIFT ", hctl->sshift, @@ -365,14 +360,59 @@ init_htab(HTAB *hashp, int nelem) 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 ************************/ +/* + * 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 hash_destroy(HTAB *hashp) { - /* cannot destroy a shared memory hash table */ - Assert(!hashp->segbase); - if (hashp != NULL) { SEG_OFFSET segNum; @@ -384,6 +424,13 @@ hash_destroy(HTAB *hashp) q; 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++) { @@ -397,11 +444,10 @@ hash_destroy(HTAB *hashp) MEM_FREE((char *) curr); } } - free((char *) segp); + MEM_FREE((char *) segp); } MEM_FREE((char *) hashp->dir); MEM_FREE((char *) hashp->hctl); - hash_stats("destroy", hashp); MEM_FREE((char *) hashp); } } @@ -603,7 +649,7 @@ hash_search(HTAB *hashp, /* link into chain */ *prevIndexPtr = currIndex; - /* copy key and data */ + /* copy key into record */ destAddr = (char *) &(curr->key); memmove(destAddr, keyPtr, hctl->keysize); curr->next = INVALID_INDEX; @@ -618,13 +664,10 @@ hash_search(HTAB *hashp, */ if (++hctl->nkeys / (hctl->max_bucket + 1) > hctl->ffactor) { - - /* - * fprintf(stderr,"expanding on '%s'\n",keyPtr); - * hash_stats("expanded table",hashp); + /* NOTE: failure to expand table is not a fatal error, + * it just means we have to run at higher fill factor than we wanted. */ - if (!expand_table(hashp)) - return NULL; + expand_table(hashp); } return &(curr->key); } @@ -725,23 +768,25 @@ expand_table(HTAB *hashp) #endif 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_segndx = MOD(new_bucket, hctl->ssize); if (new_segnum >= hctl->nsegs) { - - /* Allocate new segment if necessary */ + /* Allocate new segment if necessary -- could fail if dir full */ if (new_segnum >= hctl->dsize) - dir_realloc(hashp); + if (! dir_realloc(hashp)) + return 0; if (!(hashp->dir[new_segnum] = seg_alloc(hashp))) return 0; 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) { @@ -790,31 +835,32 @@ static int dir_realloc(HTAB *hashp) { char *p; - char **p_ptr; + char *old_p; + long new_dsize; long old_dirsize; long new_dirsize; - if (hashp->hctl->max_dsize != NO_MAX_DSIZE) return 0; /* Reallocate directory */ - old_dirsize = hashp->hctl->dsize * sizeof(SEGMENT *); - new_dirsize = old_dirsize << 1; + new_dsize = hashp->hctl->dsize << 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); + if (p != NULL) { - memmove(p, *p_ptr, old_dirsize); - MemSet(*p_ptr + old_dirsize, 0, new_dirsize - old_dirsize); - free((char *) *p_ptr); - *p_ptr = p; - hashp->hctl->dsize = new_dirsize; + memmove(p, old_p, old_dirsize); + MemSet(p + old_dirsize, 0, new_dirsize - old_dirsize); + MEM_FREE((char *) old_p); + hashp->dir = (SEG_OFFSET *) p; + hashp->hctl->dsize = new_dsize; return 1; } return 0; - } @@ -824,15 +870,14 @@ seg_alloc(HTAB *hashp) SEGMENT segp; SEG_OFFSET segOffset; - segp = (SEGMENT) hashp->alloc((unsigned long) - sizeof(SEGMENT) * hashp->hctl->ssize); + sizeof(BUCKET_INDEX) * hashp->hctl->ssize); if (!segp) return 0; MemSet((char *) segp, 0, - (long) sizeof(SEGMENT) * hashp->hctl->ssize); + (long) sizeof(BUCKET_INDEX) * hashp->hctl->ssize); segOffset = MAKE_HASHOFFSET(hashp, segp); return segOffset; @@ -850,11 +895,11 @@ bucket_alloc(HTAB *hashp) BUCKET_INDEX tmpIndex, lastIndex; - bucketSize = - sizeof(BUCKET_INDEX) + hashp->hctl->keysize + hashp->hctl->datasize; + /* Each bucket has a BUCKET_INDEX header plus user data. */ + bucketSize = sizeof(BUCKET_INDEX) + hashp->hctl->keysize + hashp->hctl->datasize; /* 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. @@ -871,8 +916,10 @@ bucket_alloc(HTAB *hashp) lastIndex = hashp->hctl->freeBucketIndex; hashp->hctl->freeBucketIndex = tmpIndex; - /* initialize each bucket to point to the one behind it */ - for (i = 0; i < (BUCKET_ALLOC_INCR - 1); i++) + /* initialize each bucket to point to the one behind it. + * NOTE: loop sets last bucket incorrectly; we fix below. + */ + for (i = 0; i < BUCKET_ALLOC_INCR; i++) { tmpBucket = GET_BUCKET(hashp, tmpIndex); tmpIndex += bucketSize; @@ -881,20 +928,21 @@ bucket_alloc(HTAB *hashp) /* * 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; return 1; } -/* calculate the log base 2 of num */ +/* calculate ceil(log base 2) of num */ int my_log2(long num) { - int i = 1; - int limit; + int i; + 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; } diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index 329aa758a7..07cf6a903d 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -6,7 +6,7 @@ * * 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; } XIDLookupEnt; +#define SHMEM_XIDTAB_KEYSIZE sizeof(XIDTAG) +#define SHMEM_XIDTAB_DATASIZE (sizeof(XIDLookupEnt) - SHMEM_XIDTAB_KEYSIZE) + #define XID_TAGSIZE (sizeof(XIDTAG)) #define XIDENT_LOCKMETHOD(xident) (XIDTAG_LOCKMETHOD((xident).tag)) @@ -211,6 +214,9 @@ typedef struct LOCK int nActive; } 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 LockGetLock_nHolders(l) l->nHolders diff --git a/src/include/utils/hsearch.h b/src/include/utils/hsearch.h index f0a8009776..96efd88748 100644 --- a/src/include/utils/hsearch.h +++ b/src/include/utils/hsearch.h @@ -6,7 +6,7 @@ * * 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 + * + * 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_SHIFT 8 /* log2(SEGSIZE) */ +#define DEF_SEGSIZE_SHIFT 8 /* log2(SEGSIZE) */ #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 DEF_FFACTOR 1 -#define SPLTMAX 8 /* @@ -46,10 +53,8 @@ typedef unsigned long SEG_OFFSET; typedef struct hashhdr { - long bsize; /* Bucket/Page Size */ - long bshift; /* Bucket shift */ long dsize; /* Directory Size */ - long ssize; /* Segment Size */ + long ssize; /* Segment Size --- must be power of 2 */ long sshift; /* Segment shift */ long max_bucket; /* ID of Maximum bucket in use */ long high_mask; /* Mask to modulo into entire table */ @@ -59,8 +64,7 @@ typedef struct hashhdr long nsegs; /* Number of allocated segments */ long keysize; /* hash key length in bytes */ long datasize; /* elem data length in bytes */ - long max_dsize; /* 'dsize' limit if directory is fixed - * size */ + long max_dsize; /* 'dsize' limit if directory is fixed size */ BUCKET_INDEX freeBucketIndex; /* index of first free bucket */ #ifdef HASH_STATISTICS @@ -83,14 +87,13 @@ typedef struct htab typedef struct hashctl { - long bsize; /* Bucket Size */ long ssize; /* Segment Size */ long dsize; /* Dirsize Size */ long ffactor; /* Fill factor */ long (*hash) (); /* Hash Function */ long keysize; /* hash key 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 */ long *segbase; /* base for calculating bucket + seg ptrs */ long *(*alloc) (); /* memory allocation function */ @@ -100,7 +103,6 @@ typedef struct hashctl } HASHCTL; /* Flags to indicate action for hctl */ -#define HASH_BUCKET 0x001 /* Setting bucket size */ #define HASH_SEGMENT 0x002 /* Setting segment size */ #define HASH_DIRSIZE 0x004 /* Setting directory size */ #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, bool *foundPtr); extern long *hash_seq(HTAB *hashp); +extern long hash_estimate_size(long num_entries, long keysize, long datasize); /* * prototypes from functions in hashfn.c