summaryrefslogtreecommitdiff
path: root/src/backend/utils/hash/dynahash.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/hash/dynahash.c')
-rw-r--r--src/backend/utils/hash/dynahash.c1382
1 files changed, 725 insertions, 657 deletions
diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c
index db209e1c338..736ca39d09f 100644
--- a/src/backend/utils/hash/dynahash.c
+++ b/src/backend/utils/hash/dynahash.c
@@ -1,18 +1,18 @@
/*-------------------------------------------------------------------------
*
* dynahash.c--
- * dynamic hashing
+ * dynamic hashing
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.7 1997/08/12 22:54:50 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.8 1997/09/07 04:53:33 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
- *
+ *
* Dynamic hashing, after CACM April 1988 pp 446-457, by Per-Ake Larson.
* Coded into C, with minor code improvements, and with hsearch(3) interface,
* by [email protected], Jul 26, 1988: 13:16;
@@ -35,27 +35,27 @@
* concatenation property, in probably unnecessary code 'optimisation'.
*
* Modified [email protected] February 1990
- * added multiple table interface
+ * added multiple table interface
* Modified by [email protected] April 1990
- * changed ctl structure for shared memory
+ * changed ctl structure for shared memory
*/
-# include <stdio.h>
-# include <sys/types.h>
-# include <string.h>
-# include "postgres.h"
-# include "utils/dynahash.h"
-# include "utils/hsearch.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include "postgres.h"
+#include "utils/dynahash.h"
+#include "utils/hsearch.h"
#ifndef FRONTEND
-# include "utils/mcxt.h"
-#endif /* !FRONTEND */
-# include "utils/palloc.h"
+#include "utils/mcxt.h"
+#endif /* !FRONTEND */
+#include "utils/palloc.h"
/*
* Fast arithmetic, relying on powers of 2,
* and on pre-processor concatenation property
*/
-# define MOD(x,y) ((x) & ((y)-1))
+#define MOD(x,y) ((x) & ((y)-1))
/*
* external routines
@@ -64,14 +64,14 @@
/*
* Private function prototypes
*/
-static long *DynaHashAlloc(unsigned int size);
-static void DynaHashFree(Pointer ptr);
-static uint32 call_hash(HTAB *hashp, char *k, int len);
-static SEG_OFFSET seg_alloc(HTAB *hashp);
-static int bucket_alloc(HTAB *hashp);
-static int dir_realloc(HTAB *hashp);
+static long *DynaHashAlloc(unsigned int size);
+static void DynaHashFree(Pointer ptr);
+static uint32 call_hash(HTAB * hashp, char *k, int len);
+static SEG_OFFSET seg_alloc(HTAB * hashp);
+static int bucket_alloc(HTAB * hashp);
+static int dir_realloc(HTAB * hashp);
-typedef long * ((*dhalloc_ptr)());
+typedef long *((*dhalloc_ptr) ());
#ifndef FRONTEND
/* ----------------
@@ -82,54 +82,54 @@ typedef long * ((*dhalloc_ptr)());
* garbage collector is going to corrupt them. -wei
*
* ??? the "cache" memory context is intended to store only
- * system cache information. The user of the hashing
- * routines should specify which context to use or we
- * should create a separate memory context for these
- * hash routines. For now I have modified this code to
- * do the latter -cim 1/19/91
+ * system cache information. The user of the hashing
+ * routines should specify which context to use or we
+ * should create a separate memory context for these
+ * hash routines. For now I have modified this code to
+ * do the latter -cim 1/19/91
* ----------------
*/
-GlobalMemory DynaHashCxt = (GlobalMemory) NULL;
+GlobalMemory DynaHashCxt = (GlobalMemory) NULL;
-static long *
+static long *
DynaHashAlloc(unsigned int size)
{
- if (! DynaHashCxt)
- DynaHashCxt = CreateGlobalMemory("DynaHash");
+ if (!DynaHashCxt)
+ DynaHashCxt = CreateGlobalMemory("DynaHash");
- return (long *)
- MemoryContextAlloc((MemoryContext)DynaHashCxt, size);
+ return (long *)
+ MemoryContextAlloc((MemoryContext) DynaHashCxt, size);
}
static void
DynaHashFree(Pointer ptr)
{
- MemoryContextFree((MemoryContext)DynaHashCxt, ptr);
+ MemoryContextFree((MemoryContext) DynaHashCxt, ptr);
}
-#define MEM_ALLOC DynaHashAlloc
-#define MEM_FREE DynaHashFree
+#define MEM_ALLOC DynaHashAlloc
+#define MEM_FREE DynaHashFree
-#else /* FRONTEND */
+#else /* FRONTEND */
-#define MEM_ALLOC palloc
-#define MEM_FREE pfree
+#define MEM_ALLOC palloc
+#define MEM_FREE pfree
-#endif /* FRONTEND */
+#endif /* FRONTEND */
/* ----------------
* Internal routines
* ----------------
*/
-static int expand_table(HTAB *hashp);
-static int hdefault(HTAB *hashp);
-static int init_htab(HTAB *hashp, int nelem);
+static int expand_table(HTAB * hashp);
+static int hdefault(HTAB * hashp);
+static int init_htab(HTAB * hashp, int nelem);
/*
* pointer access macros. Shared memory implementation cannot
- * store pointers in the hash table data structures because
+ * store pointers in the hash table data structures because
* pointer values will be different in different address spaces.
* these macros convert offsets to pointers and pointers to offsets.
* Shared memory need not be contiguous, but all addresses must be
@@ -145,282 +145,318 @@ static int init_htab(HTAB *hashp, int nelem);
#define MAKE_HASHOFFSET(hp,ptr)\
( ((unsigned long) ptr) - ((unsigned long) (hp)->segbase) )
-# if HASH_STATISTICS
-static long hash_accesses, hash_collisions, hash_expansions;
-# endif
+#if HASH_STATISTICS
+static long hash_accesses,
+ hash_collisions,
+ hash_expansions;
+
+#endif
/************************** CREATE ROUTINES **********************/
-HTAB *
-hash_create(int nelem, HASHCTL *info, int flags)
+HTAB *
+hash_create(int nelem, HASHCTL * info, int flags)
{
- register HHDR * hctl;
- HTAB * hashp;
-
-
- hashp = (HTAB *) MEM_ALLOC((unsigned long) sizeof(HTAB));
- memset(hashp, 0, sizeof(HTAB));
-
- if ( flags & HASH_FUNCTION ) {
- hashp->hash = info->hash;
- } else {
- /* default */
- hashp->hash = string_hash;
- }
-
- if ( flags & HASH_SHARED_MEM ) {
- /* ctl structure is preallocated for shared memory tables */
-
- hashp->hctl = (HHDR *) info->hctl;
- hashp->segbase = (char *) info->segbase;
- hashp->alloc = info->alloc;
- hashp->dir = (SEG_OFFSET *)info->dir;
-
- /* hash table already exists, we're just attaching to it */
- if (flags & HASH_ATTACH) {
- return(hashp);
+ register HHDR *hctl;
+ HTAB *hashp;
+
+
+ hashp = (HTAB *) MEM_ALLOC((unsigned long) sizeof(HTAB));
+ memset(hashp, 0, sizeof(HTAB));
+
+ if (flags & HASH_FUNCTION)
+ {
+ hashp->hash = info->hash;
+ }
+ else
+ {
+ /* default */
+ hashp->hash = string_hash;
+ }
+
+ if (flags & HASH_SHARED_MEM)
+ {
+ /* ctl structure is preallocated for shared memory tables */
+
+ hashp->hctl = (HHDR *) info->hctl;
+ hashp->segbase = (char *) info->segbase;
+ hashp->alloc = info->alloc;
+ hashp->dir = (SEG_OFFSET *) info->dir;
+
+ /* hash table already exists, we're just attaching to it */
+ if (flags & HASH_ATTACH)
+ {
+ return (hashp);
+ }
+
+ }
+ else
+ {
+ /* setup hash table defaults */
+
+ hashp->alloc = (dhalloc_ptr) MEM_ALLOC;
+ hashp->dir = NULL;
+ hashp->segbase = NULL;
+
}
-
- } else {
- /* setup hash table defaults */
-
- hashp->alloc = (dhalloc_ptr) MEM_ALLOC;
- hashp->dir = NULL;
- hashp->segbase = NULL;
-
- }
-
- if (! hashp->hctl) {
- hashp->hctl = (HHDR *) hashp->alloc((unsigned long)sizeof(HHDR));
- if (! hashp->hctl) {
- return(0);
+
+ if (!hashp->hctl)
+ {
+ hashp->hctl = (HHDR *) hashp->alloc((unsigned long) sizeof(HHDR));
+ if (!hashp->hctl)
+ {
+ return (0);
+ }
}
- }
-
- if ( !hdefault(hashp) ) return(0);
- hctl = hashp->hctl;
+
+ if (!hdefault(hashp))
+ return (0);
+ hctl = hashp->hctl;
#ifdef HASH_STATISTICS
- hctl->accesses = hctl->collisions = 0;
+ 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;
- hctl->sshift = my_log2(info->ssize);
- }
- if ( flags & HASH_FFACTOR ) {
- hctl->ffactor = info->ffactor;
- }
-
- /*
- * SHM hash tables have fixed maximum size (allocate
- * a maximal sized directory).
- */
- if ( flags & HASH_DIRSIZE ) {
- hctl->max_dsize = my_log2(info->max_size);
- hctl->dsize = my_log2(info->dsize);
- }
- /* hash table now allocates space for key and data
- * but you have to say how much space to allocate
- */
- if ( flags & HASH_ELEM ) {
- hctl->keysize = info->keysize;
- hctl->datasize = info->datasize;
- }
- if ( flags & HASH_ALLOC ) {
- hashp->alloc = info->alloc;
- }
-
- if ( init_htab (hashp, nelem ) ) {
- hash_destroy(hashp);
- return(0);
- }
- return(hashp);
+
+ if (flags & HASH_BUCKET)
+ {
+ hctl->bsize = info->bsize;
+ hctl->bshift = my_log2(info->bsize);
+ }
+ if (flags & HASH_SEGMENT)
+ {
+ hctl->ssize = info->ssize;
+ hctl->sshift = my_log2(info->ssize);
+ }
+ if (flags & HASH_FFACTOR)
+ {
+ hctl->ffactor = info->ffactor;
+ }
+
+ /*
+ * SHM hash tables have fixed maximum size (allocate a maximal sized
+ * directory).
+ */
+ if (flags & HASH_DIRSIZE)
+ {
+ hctl->max_dsize = my_log2(info->max_size);
+ hctl->dsize = my_log2(info->dsize);
+ }
+
+ /*
+ * hash table now allocates space for key and data but you have to say
+ * how much space to allocate
+ */
+ if (flags & HASH_ELEM)
+ {
+ hctl->keysize = info->keysize;
+ hctl->datasize = info->datasize;
+ }
+ if (flags & HASH_ALLOC)
+ {
+ hashp->alloc = info->alloc;
+ }
+
+ if (init_htab(hashp, nelem))
+ {
+ hash_destroy(hashp);
+ return (0);
+ }
+ return (hashp);
}
/*
- Allocate and initialize an HTAB structure
+ Allocate and initialize an HTAB structure
*/
static int
-hdefault(HTAB *hashp)
+hdefault(HTAB * hashp)
{
- HHDR *hctl;
-
- 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;
- hctl->ffactor = DEF_FFACTOR;
- hctl->nkeys = 0;
- hctl->nsegs = 0;
-
- /* I added these MS. */
-
- /* default memory allocation for hash buckets */
- hctl->keysize = sizeof(char *);
- hctl->datasize = sizeof(char *);
-
- /* table has no fixed maximum size */
- hctl->max_dsize = NO_MAX_DSIZE;
-
- /* garbage collection for HASH_REMOVE */
- hctl->freeBucketIndex = INVALID_INDEX;
-
- return(1);
+ HHDR *hctl;
+
+ 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;
+ hctl->ffactor = DEF_FFACTOR;
+ hctl->nkeys = 0;
+ hctl->nsegs = 0;
+
+ /* I added these MS. */
+
+ /* default memory allocation for hash buckets */
+ hctl->keysize = sizeof(char *);
+ hctl->datasize = sizeof(char *);
+
+ /* table has no fixed maximum size */
+ hctl->max_dsize = NO_MAX_DSIZE;
+
+ /* garbage collection for HASH_REMOVE */
+ hctl->freeBucketIndex = INVALID_INDEX;
+
+ return (1);
}
static int
-init_htab (HTAB *hashp, int nelem)
+init_htab(HTAB * hashp, int nelem)
{
- register SEG_OFFSET *segp;
- register int nbuckets;
- register int nsegs;
- int l2;
- HHDR *hctl;
-
- hctl = hashp->hctl;
- /*
- * Divide number of elements by the fill factor and 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;
-
- hctl->max_bucket = hctl->low_mask = nbuckets - 1;
- hctl->high_mask = (nbuckets << 1) - 1;
-
- 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);
- */
-
- /* allocate a directory */
- if (!(hashp->dir)) {
- hashp->dir =
- (SEG_OFFSET *)hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
- if (! hashp->dir)
- return(-1);
- }
-
- /* Allocate initial segments */
- for (segp = hashp->dir; hctl->nsegs < nsegs; hctl->nsegs++, segp++ ) {
- *segp = seg_alloc(hashp);
- if ( *segp == (SEG_OFFSET)0 ) {
- hash_destroy(hashp);
- return (0);
+ register SEG_OFFSET *segp;
+ register int nbuckets;
+ register int nsegs;
+ int l2;
+ HHDR *hctl;
+
+ hctl = hashp->hctl;
+
+ /*
+ * Divide number of elements by the fill factor and 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;
+
+ hctl->max_bucket = hctl->low_mask = nbuckets - 1;
+ hctl->high_mask = (nbuckets << 1) - 1;
+
+ 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);
+ */
+
+ /* allocate a directory */
+ if (!(hashp->dir))
+ {
+ hashp->dir =
+ (SEG_OFFSET *) hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
+ if (!hashp->dir)
+ return (-1);
+ }
+
+ /* Allocate initial segments */
+ for (segp = hashp->dir; hctl->nsegs < nsegs; hctl->nsegs++, segp++)
+ {
+ *segp = seg_alloc(hashp);
+ if (*segp == (SEG_OFFSET) 0)
+ {
+ hash_destroy(hashp);
+ return (0);
+ }
}
- }
-
-# 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",
- "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,
- "FILL FACTOR ", hctl->ffactor,
- "MAX BUCKET ", hctl->max_bucket,
- "HIGH MASK ", hctl->high_mask,
- "LOW MASK ", hctl->low_mask,
- "NSEGS ", hctl->nsegs,
- "NKEYS ", hctl->nkeys );
-# endif
- return (0);
+
+#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",
+ "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,
+ "FILL FACTOR ", hctl->ffactor,
+ "MAX BUCKET ", hctl->max_bucket,
+ "HIGH MASK ", hctl->high_mask,
+ "LOW MASK ", hctl->low_mask,
+ "NSEGS ", hctl->nsegs,
+ "NKEYS ", hctl->nkeys);
+#endif
+ return (0);
}
/********************** DESTROY ROUTINES ************************/
void
-hash_destroy (HTAB *hashp)
+hash_destroy(HTAB * hashp)
{
- /* cannot destroy a shared memory hash table */
- Assert(! hashp->segbase);
-
- if (hashp != NULL) {
- register SEG_OFFSET segNum;
- SEGMENT segp;
- int nsegs = hashp->hctl->nsegs;
- int j;
- BUCKET_INDEX *elp,p,q;
- ELEMENT *curr;
-
- for (segNum = 0; nsegs > 0; nsegs--, segNum++) {
-
- segp = GET_SEG(hashp,segNum);
- for (j = 0, elp = segp; j < hashp->hctl->ssize; j++, elp++) {
- for ( p = *elp; p != INVALID_INDEX; p = q ){
- curr = GET_BUCKET(hashp,p);
- q = curr->next;
- MEM_FREE((char *) curr);
+ /* cannot destroy a shared memory hash table */
+ Assert(!hashp->segbase);
+
+ if (hashp != NULL)
+ {
+ register SEG_OFFSET segNum;
+ SEGMENT segp;
+ int nsegs = hashp->hctl->nsegs;
+ int j;
+ BUCKET_INDEX *elp,
+ p,
+ q;
+ ELEMENT *curr;
+
+ for (segNum = 0; nsegs > 0; nsegs--, segNum++)
+ {
+
+ segp = GET_SEG(hashp, segNum);
+ for (j = 0, elp = segp; j < hashp->hctl->ssize; j++, elp++)
+ {
+ for (p = *elp; p != INVALID_INDEX; p = q)
+ {
+ curr = GET_BUCKET(hashp, p);
+ q = curr->next;
+ MEM_FREE((char *) curr);
+ }
+ }
+ free((char *) segp);
}
- }
- free((char *)segp);
+ MEM_FREE((char *) hashp->dir);
+ MEM_FREE((char *) hashp->hctl);
+ hash_stats("destroy", hashp);
+ MEM_FREE((char *) hashp);
}
- MEM_FREE( (char *) hashp->dir);
- MEM_FREE( (char *) hashp->hctl);
- hash_stats("destroy",hashp);
- MEM_FREE( (char *) hashp);
- }
}
void
-hash_stats(char *where, HTAB *hashp)
+hash_stats(char *where, HTAB * hashp)
{
-# if HASH_STATISTICS
-
- fprintf(stderr,"%s: this HTAB -- accesses %ld collisions %ld\n",
- where,hashp->hctl->accesses,hashp->hctl->collisions);
-
- fprintf(stderr,"hash_stats: keys %ld keysize %ld maxp %d segmentcount %d\n",
- hashp->hctl->nkeys, hashp->hctl->keysize,
- hashp->hctl->max_bucket, hashp->hctl->nsegs);
- fprintf(stderr,"%s: total accesses %ld total collisions %ld\n",
- where, hash_accesses, hash_collisions);
- fprintf(stderr,"hash_stats: total expansions %ld\n",
- hash_expansions);
-
-# endif
-
+#if HASH_STATISTICS
+
+ fprintf(stderr, "%s: this HTAB -- accesses %ld collisions %ld\n",
+ where, hashp->hctl->accesses, hashp->hctl->collisions);
+
+ fprintf(stderr, "hash_stats: keys %ld keysize %ld maxp %d segmentcount %d\n",
+ hashp->hctl->nkeys, hashp->hctl->keysize,
+ hashp->hctl->max_bucket, hashp->hctl->nsegs);
+ fprintf(stderr, "%s: total accesses %ld total collisions %ld\n",
+ where, hash_accesses, hash_collisions);
+ fprintf(stderr, "hash_stats: total expansions %ld\n",
+ hash_expansions);
+
+#endif
+
}
/*******************************SEARCH ROUTINES *****************************/
-static uint32
-call_hash(HTAB *hashp, char *k, int len)
+static uint32
+call_hash(HTAB * hashp, char *k, int len)
{
- long hash_val, bucket;
- HHDR *hctl;
-
- hctl = hashp->hctl;
- hash_val = hashp->hash(k, len);
-
- bucket = hash_val & hctl->high_mask;
- if ( bucket > hctl->max_bucket ) {
- bucket = bucket & hctl->low_mask;
- }
-
- return(bucket);
+ long hash_val,
+ bucket;
+ HHDR *hctl;
+
+ hctl = hashp->hctl;
+ hash_val = hashp->hash(k, len);
+
+ bucket = hash_val & hctl->high_mask;
+ if (bucket > hctl->max_bucket)
+ {
+ bucket = bucket & hctl->low_mask;
+ }
+
+ return (bucket);
}
/*
@@ -429,430 +465,462 @@ call_hash(HTAB *hashp, char *k, int len)
* action is one of HASH_FIND/HASH_ENTER/HASH_REMOVE
*
* RETURNS: NULL if table is corrupted, a pointer to the element
- * found/removed/entered if applicable, TRUE otherwise.
- * foundPtr is TRUE if we found an element in the table
- * (FALSE if we entered one).
+ * found/removed/entered if applicable, TRUE otherwise.
+ * foundPtr is TRUE if we found an element in the table
+ * (FALSE if we entered one).
*/
-long *
-hash_search(HTAB *hashp,
- char *keyPtr,
- HASHACTION action, /*
- * HASH_FIND / HASH_ENTER / HASH_REMOVE
- * HASH_FIND_SAVE / HASH_REMOVE_SAVED
- */
- bool *foundPtr)
+long *
+hash_search(HTAB * hashp,
+ char *keyPtr,
+ HASHACTION action, /* HASH_FIND / HASH_ENTER / HASH_REMOVE
+ * HASH_FIND_SAVE / HASH_REMOVE_SAVED */
+ bool * foundPtr)
{
- uint32 bucket;
- long segment_num;
- long segment_ndx;
- SEGMENT segp;
- register ELEMENT *curr;
- HHDR *hctl;
- BUCKET_INDEX currIndex;
- BUCKET_INDEX *prevIndexPtr;
- char * destAddr;
- static struct State {
- ELEMENT *currElem;
- BUCKET_INDEX currIndex;
- BUCKET_INDEX *prevIndex;
- } saveState;
-
- Assert((hashp && keyPtr));
- Assert((action == HASH_FIND) || (action == HASH_REMOVE) || (action == HASH_ENTER) || (action == HASH_FIND_SAVE) || (action == HASH_REMOVE_SAVED));
-
- hctl = hashp->hctl;
-
-# if HASH_STATISTICS
- hash_accesses++;
- hashp->hctl->accesses++;
-# endif
- if (action == HASH_REMOVE_SAVED)
- {
- curr = saveState.currElem;
- currIndex = saveState.currIndex;
- prevIndexPtr = saveState.prevIndex;
- /*
- * Try to catch subsequent errors
- */
- Assert(saveState.currElem && !(saveState.currElem = 0));
+ uint32 bucket;
+ long segment_num;
+ long segment_ndx;
+ SEGMENT segp;
+ register ELEMENT *curr;
+ HHDR *hctl;
+ BUCKET_INDEX currIndex;
+ BUCKET_INDEX *prevIndexPtr;
+ char *destAddr;
+ static struct State
+ {
+ ELEMENT *currElem;
+ BUCKET_INDEX currIndex;
+ BUCKET_INDEX *prevIndex;
+ } saveState;
+
+ Assert((hashp && keyPtr));
+ Assert((action == HASH_FIND) || (action == HASH_REMOVE) || (action == HASH_ENTER) || (action == HASH_FIND_SAVE) || (action == HASH_REMOVE_SAVED));
+
+ hctl = hashp->hctl;
+
+#if HASH_STATISTICS
+ hash_accesses++;
+ hashp->hctl->accesses++;
+#endif
+ if (action == HASH_REMOVE_SAVED)
+ {
+ curr = saveState.currElem;
+ currIndex = saveState.currIndex;
+ prevIndexPtr = saveState.prevIndex;
+
+ /*
+ * Try to catch subsequent errors
+ */
+ Assert(saveState.currElem && !(saveState.currElem = 0));
}
- else
- {
- bucket = call_hash(hashp, keyPtr, hctl->keysize);
- segment_num = bucket >> hctl->sshift;
- segment_ndx = bucket & ( hctl->ssize - 1 );
-
- segp = GET_SEG(hashp,segment_num);
-
- Assert(segp);
-
- prevIndexPtr = &segp[segment_ndx];
- currIndex = *prevIndexPtr;
- /*
- * Follow collision chain
- */
- for (curr = NULL;currIndex != INVALID_INDEX;) {
- /* coerce bucket index into a pointer */
- curr = GET_BUCKET(hashp,currIndex);
-
- if (! memcmp((char *)&(curr->key), keyPtr, hctl->keysize)) {
- break;
- }
- prevIndexPtr = &(curr->next);
+ else
+ {
+ bucket = call_hash(hashp, keyPtr, hctl->keysize);
+ segment_num = bucket >> hctl->sshift;
+ segment_ndx = bucket & (hctl->ssize - 1);
+
+ segp = GET_SEG(hashp, segment_num);
+
+ Assert(segp);
+
+ prevIndexPtr = &segp[segment_ndx];
currIndex = *prevIndexPtr;
-# if HASH_STATISTICS
- hash_collisions++;
- hashp->hctl->collisions++;
-# endif
- }
- }
-
- /*
- * if we found an entry or if we weren't trying
- * to insert, we're done now.
- */
- *foundPtr = (bool) (currIndex != INVALID_INDEX);
- switch (action) {
- case HASH_ENTER:
- if (currIndex != INVALID_INDEX)
- return(&(curr->key));
- break;
- case HASH_REMOVE:
- case HASH_REMOVE_SAVED:
- if (currIndex != INVALID_INDEX) {
- Assert(hctl->nkeys > 0);
- hctl->nkeys--;
-
- /* add the bucket to the freelist for this table. */
- *prevIndexPtr = curr->next;
- curr->next = hctl->freeBucketIndex;
- hctl->freeBucketIndex = currIndex;
-
- /* better hope the caller is synchronizing access to
- * this element, because someone else is going to reuse
- * it the next time something is added to the table
- */
- return (&(curr->key));
+
+ /*
+ * Follow collision chain
+ */
+ for (curr = NULL; currIndex != INVALID_INDEX;)
+ {
+ /* coerce bucket index into a pointer */
+ curr = GET_BUCKET(hashp, currIndex);
+
+ if (!memcmp((char *) &(curr->key), keyPtr, hctl->keysize))
+ {
+ break;
+ }
+ prevIndexPtr = &(curr->next);
+ currIndex = *prevIndexPtr;
+#if HASH_STATISTICS
+ hash_collisions++;
+ hashp->hctl->collisions++;
+#endif
+ }
}
- return((long *) TRUE);
- case HASH_FIND:
- if (currIndex != INVALID_INDEX)
- return(&(curr->key));
- return((long *)TRUE);
- case HASH_FIND_SAVE:
- if (currIndex != INVALID_INDEX)
- {
- saveState.currElem = curr;
- saveState.prevIndex = prevIndexPtr;
- saveState.currIndex = currIndex;
- return(&(curr->key));
- }
- return((long *)TRUE);
- default:
- /* can't get here */
- return (NULL);
- }
-
- /*
- If we got here, then we didn't find the element and
- we have to insert it into the hash table
- */
- Assert(currIndex == INVALID_INDEX);
-
- /* get the next free bucket */
- currIndex = hctl->freeBucketIndex;
- if (currIndex == INVALID_INDEX) {
-
- /* no free elements. allocate another chunk of buckets */
- if (! bucket_alloc(hashp)) {
- return(NULL);
+
+ /*
+ * if we found an entry or if we weren't trying to insert, we're done
+ * now.
+ */
+ *foundPtr = (bool) (currIndex != INVALID_INDEX);
+ switch (action)
+ {
+ case HASH_ENTER:
+ if (currIndex != INVALID_INDEX)
+ return (&(curr->key));
+ break;
+ case HASH_REMOVE:
+ case HASH_REMOVE_SAVED:
+ if (currIndex != INVALID_INDEX)
+ {
+ Assert(hctl->nkeys > 0);
+ hctl->nkeys--;
+
+ /* add the bucket to the freelist for this table. */
+ *prevIndexPtr = curr->next;
+ curr->next = hctl->freeBucketIndex;
+ hctl->freeBucketIndex = currIndex;
+
+ /*
+ * better hope the caller is synchronizing access to this
+ * element, because someone else is going to reuse it the next
+ * time something is added to the table
+ */
+ return (&(curr->key));
+ }
+ return ((long *) TRUE);
+ case HASH_FIND:
+ if (currIndex != INVALID_INDEX)
+ return (&(curr->key));
+ return ((long *) TRUE);
+ case HASH_FIND_SAVE:
+ if (currIndex != INVALID_INDEX)
+ {
+ saveState.currElem = curr;
+ saveState.prevIndex = prevIndexPtr;
+ saveState.currIndex = currIndex;
+ return (&(curr->key));
+ }
+ return ((long *) TRUE);
+ default:
+ /* can't get here */
+ return (NULL);
}
+
+ /*
+ * If we got here, then we didn't find the element and we have to
+ * insert it into the hash table
+ */
+ Assert(currIndex == INVALID_INDEX);
+
+ /* get the next free bucket */
currIndex = hctl->freeBucketIndex;
- }
- Assert(currIndex != INVALID_INDEX);
-
- curr = GET_BUCKET(hashp,currIndex);
- hctl->freeBucketIndex = curr->next;
-
- /* link into chain */
- *prevIndexPtr = currIndex;
-
- /* copy key and data */
- destAddr = (char *) &(curr->key);
- memmove(destAddr,keyPtr,hctl->keysize);
- curr->next = INVALID_INDEX;
-
- /* let the caller initialize the data field after
- * hash_search returns.
- */
- /* memmove(destAddr,keyPtr,hctl->keysize+hctl->datasize);*/
-
- /*
- * Check if it is time to split the segment
- */
- if (++hctl->nkeys / (hctl->max_bucket+1) > hctl->ffactor) {
+ if (currIndex == INVALID_INDEX)
+ {
+
+ /* no free elements. allocate another chunk of buckets */
+ if (!bucket_alloc(hashp))
+ {
+ return (NULL);
+ }
+ currIndex = hctl->freeBucketIndex;
+ }
+ Assert(currIndex != INVALID_INDEX);
+
+ curr = GET_BUCKET(hashp, currIndex);
+ hctl->freeBucketIndex = curr->next;
+
+ /* link into chain */
+ *prevIndexPtr = currIndex;
+
+ /* copy key and data */
+ destAddr = (char *) &(curr->key);
+ memmove(destAddr, keyPtr, hctl->keysize);
+ curr->next = INVALID_INDEX;
+
/*
- fprintf(stderr,"expanding on '%s'\n",keyPtr);
- hash_stats("expanded table",hashp);
- */
- if (! expand_table(hashp))
- return(NULL);
- }
- return (&(curr->key));
+ * let the caller initialize the data field after hash_search returns.
+ */
+ /* memmove(destAddr,keyPtr,hctl->keysize+hctl->datasize); */
+
+ /*
+ * Check if it is time to split the segment
+ */
+ if (++hctl->nkeys / (hctl->max_bucket + 1) > hctl->ffactor)
+ {
+
+ /*
+ * fprintf(stderr,"expanding on '%s'\n",keyPtr);
+ * hash_stats("expanded table",hashp);
+ */
+ if (!expand_table(hashp))
+ return (NULL);
+ }
+ return (&(curr->key));
}
/*
* hash_seq -- sequentially search through hash table and return
- * all the elements one by one, return NULL on error and
- * return TRUE in the end.
+ * all the elements one by one, return NULL on error and
+ * return TRUE in the end.
*
*/
-long *
-hash_seq(HTAB *hashp)
+long *
+hash_seq(HTAB * hashp)
{
- static uint32 curBucket = 0;
- static BUCKET_INDEX curIndex;
- ELEMENT *curElem;
- long segment_num;
- long segment_ndx;
- SEGMENT segp;
- HHDR *hctl;
-
- if (hashp == NULL)
- {
- /*
- * reset static state
- */
- curBucket = 0;
- curIndex = INVALID_INDEX;
- return((long *) NULL);
+ static uint32 curBucket = 0;
+ static BUCKET_INDEX curIndex;
+ ELEMENT *curElem;
+ long segment_num;
+ long segment_ndx;
+ SEGMENT segp;
+ HHDR *hctl;
+
+ if (hashp == NULL)
+ {
+
+ /*
+ * reset static state
+ */
+ curBucket = 0;
+ curIndex = INVALID_INDEX;
+ return ((long *) NULL);
}
-
- hctl = hashp->hctl;
- while (curBucket <= hctl->max_bucket) {
- if (curIndex != INVALID_INDEX) {
- curElem = GET_BUCKET(hashp, curIndex);
- curIndex = curElem->next;
- if (curIndex == INVALID_INDEX) /* end of this bucket */
- ++curBucket;
- return(&(curElem->key));
+
+ hctl = hashp->hctl;
+ while (curBucket <= hctl->max_bucket)
+ {
+ if (curIndex != INVALID_INDEX)
+ {
+ curElem = GET_BUCKET(hashp, curIndex);
+ curIndex = curElem->next;
+ if (curIndex == INVALID_INDEX) /* end of this bucket */
+ ++curBucket;
+ return (&(curElem->key));
+ }
+
+ /*
+ * initialize the search within this bucket.
+ */
+ segment_num = curBucket >> hctl->sshift;
+ segment_ndx = curBucket & (hctl->ssize - 1);
+
+ /*
+ * first find the right segment in the table directory.
+ */
+ segp = GET_SEG(hashp, segment_num);
+ if (segp == NULL)
+ /* this is probably an error */
+ return ((long *) NULL);
+
+ /*
+ * now find the right index into the segment for the first item in
+ * this bucket's chain. if the bucket is not empty (its entry in
+ * the dir is valid), we know this must correspond to a valid
+ * element and not a freed element because it came out of the
+ * directory of valid stuff. if there are elements in the bucket
+ * chains that point to the freelist we're in big trouble.
+ */
+ curIndex = segp[segment_ndx];
+
+ if (curIndex == INVALID_INDEX) /* empty bucket */
+ ++curBucket;
}
-
- /*
- * initialize the search within this bucket.
- */
- segment_num = curBucket >> hctl->sshift;
- segment_ndx = curBucket & ( hctl->ssize - 1 );
-
- /*
- * first find the right segment in the table directory.
- */
- segp = GET_SEG(hashp, segment_num);
- if (segp == NULL)
- /* this is probably an error */
- return((long *) NULL);
-
- /*
- * now find the right index into the segment for the first
- * item in this bucket's chain. if the bucket is not empty
- * (its entry in the dir is valid), we know this must
- * correspond to a valid element and not a freed element
- * because it came out of the directory of valid stuff. if
- * there are elements in the bucket chains that point to the
- * freelist we're in big trouble.
- */
- curIndex = segp[segment_ndx];
-
- if (curIndex == INVALID_INDEX) /* empty bucket */
- ++curBucket;
- }
-
- return((long *) TRUE); /* out of buckets */
+
+ return ((long *) TRUE); /* out of buckets */
}
/********************************* UTILITIES ************************/
static int
-expand_table(HTAB *hashp)
+expand_table(HTAB * hashp)
{
- HHDR *hctl;
- SEGMENT old_seg,new_seg;
- long old_bucket, new_bucket;
- long new_segnum, new_segndx;
- long old_segnum, old_segndx;
- ELEMENT *chain;
- BUCKET_INDEX *old,*newbi;
- register BUCKET_INDEX chainIndex,nextIndex;
-
+ HHDR *hctl;
+ SEGMENT old_seg,
+ new_seg;
+ long old_bucket,
+ new_bucket;
+ long new_segnum,
+ new_segndx;
+ long old_segnum,
+ old_segndx;
+ ELEMENT *chain;
+ BUCKET_INDEX *old,
+ *newbi;
+ register BUCKET_INDEX chainIndex,
+ nextIndex;
+
#ifdef HASH_STATISTICS
- hash_expansions++;
+ hash_expansions++;
#endif
-
- hctl = hashp->hctl;
- new_bucket = ++hctl->max_bucket;
- old_bucket = (hctl->max_bucket & hctl->low_mask);
-
- new_segnum = new_bucket >> hctl->sshift;
- new_segndx = MOD ( new_bucket, hctl->ssize );
-
- if ( new_segnum >= hctl->nsegs ) {
-
- /* Allocate new segment if necessary */
- if (new_segnum >= hctl->dsize) {
- dir_realloc(hashp);
+
+ hctl = hashp->hctl;
+ new_bucket = ++hctl->max_bucket;
+ old_bucket = (hctl->max_bucket & hctl->low_mask);
+
+ new_segnum = new_bucket >> hctl->sshift;
+ new_segndx = MOD(new_bucket, hctl->ssize);
+
+ if (new_segnum >= hctl->nsegs)
+ {
+
+ /* Allocate new segment if necessary */
+ if (new_segnum >= hctl->dsize)
+ {
+ dir_realloc(hashp);
+ }
+ if (!(hashp->dir[new_segnum] = seg_alloc(hashp)))
+ {
+ return (0);
+ }
+ hctl->nsegs++;
}
- if (! (hashp->dir[new_segnum] = seg_alloc(hashp))) {
- return (0);
+
+
+ if (new_bucket > hctl->high_mask)
+ {
+ /* Starting a new doubling */
+ hctl->low_mask = hctl->high_mask;
+ hctl->high_mask = new_bucket | hctl->low_mask;
}
- hctl->nsegs++;
- }
-
-
- if ( new_bucket > hctl->high_mask ) {
- /* Starting a new doubling */
- hctl->low_mask = hctl->high_mask;
- hctl->high_mask = new_bucket | hctl->low_mask;
- }
-
- /*
- * Relocate records to the new bucket
- */
- old_segnum = old_bucket >> hctl->sshift;
- old_segndx = MOD(old_bucket, hctl->ssize);
-
- old_seg = GET_SEG(hashp,old_segnum);
- new_seg = GET_SEG(hashp,new_segnum);
-
- old = &old_seg[old_segndx];
- newbi = &new_seg[new_segndx];
- for (chainIndex = *old;
- chainIndex != INVALID_INDEX;
- chainIndex = nextIndex){
-
- chain = GET_BUCKET(hashp,chainIndex);
- nextIndex = chain->next;
- if ( call_hash(hashp,
- (char *)&(chain->key),
- hctl->keysize) == old_bucket ) {
- *old = chainIndex;
- old = &chain->next;
- } else {
- *newbi = chainIndex;
- newbi = &chain->next;
+
+ /*
+ * Relocate records to the new bucket
+ */
+ old_segnum = old_bucket >> hctl->sshift;
+ old_segndx = MOD(old_bucket, hctl->ssize);
+
+ old_seg = GET_SEG(hashp, old_segnum);
+ new_seg = GET_SEG(hashp, new_segnum);
+
+ old = &old_seg[old_segndx];
+ newbi = &new_seg[new_segndx];
+ for (chainIndex = *old;
+ chainIndex != INVALID_INDEX;
+ chainIndex = nextIndex)
+ {
+
+ chain = GET_BUCKET(hashp, chainIndex);
+ nextIndex = chain->next;
+ if (call_hash(hashp,
+ (char *) &(chain->key),
+ hctl->keysize) == old_bucket)
+ {
+ *old = chainIndex;
+ old = &chain->next;
+ }
+ else
+ {
+ *newbi = chainIndex;
+ newbi = &chain->next;
+ }
+ chain->next = INVALID_INDEX;
}
- chain->next = INVALID_INDEX;
- }
- return (1);
+ return (1);
}
static int
-dir_realloc(HTAB *hashp)
+dir_realloc(HTAB * hashp)
{
- register char *p;
- char **p_ptr;
- long old_dirsize;
- long new_dirsize;
-
-
- if (hashp->hctl->max_dsize != NO_MAX_DSIZE)
+ register char *p;
+ char **p_ptr;
+ 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;
+
+ p_ptr = (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;
+ return (1);
+ }
return (0);
-
- /* Reallocate directory */
- old_dirsize = hashp->hctl->dsize * sizeof ( SEGMENT * );
- new_dirsize = old_dirsize << 1;
-
- p_ptr = (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;
- return(1);
- }
- return (0);
-
+
}
-static SEG_OFFSET
+static SEG_OFFSET
seg_alloc(HTAB * hashp)
{
- SEGMENT segp;
- SEG_OFFSET segOffset;
-
-
- segp = (SEGMENT) hashp->alloc((unsigned long)
- sizeof(SEGMENT)*hashp->hctl->ssize);
-
- if (! segp) {
- return(0);
- }
-
- memset((char *)segp, 0,
- (long) sizeof(SEGMENT)*hashp->hctl->ssize);
-
- segOffset = MAKE_HASHOFFSET(hashp,segp);
- return(segOffset);
+ SEGMENT segp;
+ SEG_OFFSET segOffset;
+
+
+ segp = (SEGMENT) hashp->alloc((unsigned long)
+ sizeof(SEGMENT) * hashp->hctl->ssize);
+
+ if (!segp)
+ {
+ return (0);
+ }
+
+ memset((char *) segp, 0,
+ (long) sizeof(SEGMENT) * hashp->hctl->ssize);
+
+ segOffset = MAKE_HASHOFFSET(hashp, segp);
+ return (segOffset);
}
/*
* allocate some new buckets and link them into the free list
*/
static int
-bucket_alloc(HTAB *hashp)
+bucket_alloc(HTAB * hashp)
{
- int i;
- ELEMENT *tmpBucket;
- long bucketSize;
- BUCKET_INDEX tmpIndex,lastIndex;
-
- bucketSize =
- sizeof(BUCKET_INDEX) + hashp->hctl->keysize + hashp->hctl->datasize;
-
- /* make sure its aligned correctly */
- bucketSize += sizeof(long *) - (bucketSize % sizeof(long *));
-
- /* tmpIndex is the shmem offset into the first bucket of
- * the array.
- */
- tmpBucket = (ELEMENT *)
- hashp->alloc((unsigned long) BUCKET_ALLOC_INCR*bucketSize);
-
- if (! tmpBucket) {
- return(0);
- }
-
- tmpIndex = MAKE_HASHOFFSET(hashp,tmpBucket);
-
- /* set the freebucket list to point to the first bucket */
- 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++) {
- tmpBucket = GET_BUCKET(hashp,tmpIndex);
- tmpIndex += bucketSize;
- tmpBucket->next = tmpIndex;
- }
-
- /* the last bucket points to the old freelist head (which is
- * probably invalid or we wouldnt be here)
- */
- tmpBucket->next = lastIndex;
-
- return(1);
+ int i;
+ ELEMENT *tmpBucket;
+ long bucketSize;
+ BUCKET_INDEX tmpIndex,
+ lastIndex;
+
+ bucketSize =
+ sizeof(BUCKET_INDEX) + hashp->hctl->keysize + hashp->hctl->datasize;
+
+ /* make sure its aligned correctly */
+ bucketSize += sizeof(long *) - (bucketSize % sizeof(long *));
+
+ /*
+ * tmpIndex is the shmem offset into the first bucket of the array.
+ */
+ tmpBucket = (ELEMENT *)
+ hashp->alloc((unsigned long) BUCKET_ALLOC_INCR * bucketSize);
+
+ if (!tmpBucket)
+ {
+ return (0);
+ }
+
+ tmpIndex = MAKE_HASHOFFSET(hashp, tmpBucket);
+
+ /* set the freebucket list to point to the first bucket */
+ 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++)
+ {
+ tmpBucket = GET_BUCKET(hashp, tmpIndex);
+ tmpIndex += bucketSize;
+ tmpBucket->next = tmpIndex;
+ }
+
+ /*
+ * the last bucket points to the old freelist head (which is probably
+ * invalid or we wouldnt be here)
+ */
+ tmpBucket->next = lastIndex;
+
+ return (1);
}
/* calculate the log base 2 of num */
int
my_log2(long num)
{
- int i = 1;
- int limit;
-
- for ( i = 0, limit = 1; limit < num; limit = 2 * limit, i++ );
- return (i);
+ int i = 1;
+ int limit;
+
+ for (i = 0, limit = 1; limit < num; limit = 2 * limit, i++);
+ return (i);
}