Retrofit hashtable and shared-mem-size-estimation bug fixes REL6_4 github/REL6_4
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 7 Mar 1999 02:01:09 +0000 (02:01 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 7 Mar 1999 02:01:09 +0000 (02:01 +0000)
into REL6_4.

src/backend/storage/buffer/buf_init.c
src/backend/storage/ipc/ipci.c
src/backend/storage/ipc/shmem.c
src/backend/storage/lmgr/lock.c
src/backend/storage/smgr/mm.c
src/backend/utils/hash/dynahash.c
src/include/storage/lock.h
src/include/utils/hsearch.h

index 975e999ec2b26e1871b0f4aaebcd4f71339af78a..ff836506b8029176b9bb8fa6c2db4cf23b8a4435 100644 (file)
@@ -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;
 }
index f6ce9eda241a6cbbc57a2e80de0e663db88741cb..38a964b15e67d099b84563c16fb5d5207d8a30a7 100644 (file)
@@ -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);
 
        /* ----------------
index 18b8d718d67fb9a77790f53264def058465c321f..67bac2f239dfd3a8b7904f1620bad62337af2293 100644 (file)
@@ -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);
 }
 
 /*
index adc4d1a42eaae7497c3716722a293268c30a382b..ccae5df3b731822683145a0f616caa77ec60f52a 100644 (file)
@@ -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);
+       size += MAXALIGN(sizeof(PROC_HDR)); /* ProcGlobal */
+       size += MAXALIGN(MaxBackendId * sizeof(PROC)); /* each MyProc */
+       size += MAXALIGN(MaxBackendId * sizeof(LOCKMETHODCTL));         /* each
+                                                                                                                                * lockMethodTable->ctl */
 
-       nXidBuckets = 1 << (int) my_log2((NLOCKS_PER_XACT - 1) / DEF_FFACTOR + 1);
-       nXidSegs = 1 << (int) my_log2((nLockBuckets - 1) / DEF_SEGSIZE + 1);
+       /* lockHash table */
+       size += hash_estimate_size(NLOCKENTS,
+                                                          SHMEM_LOCKTAB_KEYSIZE,
+                                                          SHMEM_LOCKTAB_DATASIZE);
 
-       size += MAXALIGN(NBACKENDS * sizeof(PROC)); /* each MyProc */
-       size += MAXALIGN(NBACKENDS * sizeof(LOCKMETHODCTL));            /* each
-                                                                                                                                * lockMethodTable->ctl */
-       size += MAXALIGN(sizeof(PROC_HDR)); /* ProcGlobal */
+       /* xidHash table */
+       size += hash_estimate_size(MaxBackendId,
+                                                          SHMEM_XIDTAB_KEYSIZE,
+                                                          SHMEM_XIDTAB_DATASIZE);
 
-       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 */
-
-       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 */
+       /* Since the lockHash entry count above is only an estimate,
+        * add 10% safety margin.
+        */
+       size += size / 10;
 
        return size;
 }
index b3e72e37d687754aeafaab2296f36bb434d4552b..cbd39301d52b9a0bc9b90b7f474ecbd7ef068d28 100644 (file)
@@ -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
index ecf87b08f5e8c3adbe2a6970d81c0b50649ec318..bae8965f2c4a707ad9ae1f5856ed264778b7af75 100644 (file)
@@ -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;
 }
index 329aa758a7fd560c41f5f8b466f23454a1195423..07cf6a903d32b8dd3f67d4f17aad0ed7c74da812 100644 (file)
@@ -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
index f0a800977658110925c9d10d3fca1ebea3ebc4f6..96efd8874823bd223a29f53d87b6f128072a630d 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 
 /*
  * 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