示例#1
0
/******************************************************************************
       Name : HashInsert()
Description : Function to insert new record into the hash table.
 Parameters : htable  - address (void *) of hashtable header
            : record  - address (void *) of record to insert
            : recsize - size of record (bytes)
    Returns : 
   Comments : This routine takes a copy of the user record.
            : New record placed in front of any existing equal hash record.
 ******************************************************************************/
void
HashInsert(HASHTABLE htable, void *record, int recsize)
{
    HTAB *h = (HTAB *) htable;
    int  hash = h->hash(record) % h->numentries;
    BHDR *newbhdr = malloc(sizeof(BHDR));
    void *newrec = malloc(recsize);

    if (newbhdr == NULL || newrec == NULL)
        error("Out of memory");

    memcpy(newrec, record, recsize);

    newbhdr->data = newrec;
    newbhdr->next = h->table[hash];
    h->table[hash] = newbhdr;
}
示例#2
0
/******************************************************************************
       Name : HashLookup()
Description : Look for a record in a hashtable.
 Parameters : htable - hashtable to look in
            : record - the record to look for
    Returns : Returns found data or NULL if not found.
   Comments : 
 ******************************************************************************/
void *
HashLookup(HASHTABLE htable, void *record)
{
    void *result = NULL;
    HTAB *h = (HTAB *) htable;
    int  hash = h->hash(record) % h->numentries;
    BHDR *bptr;

    bptr = h->table[hash];

    while (bptr != NULL)
    {
        if (h->compare(record, bptr->data) == 0)
        {
            result = bptr->data;
            break;
        }

        bptr = bptr->next;
    }

    return result;
}
示例#3
0
/* ARGSUSED */
DB *
__hash_open(const char *file, int flags, int mode,
    const HASHINFO *info,	/* Special directives for create */
    int dflags)
{
	HTAB *hashp;
	struct stat statbuf;
	DB *dbp;
	int bpages, hdrsize, new_table, nsegs, save_errno;

	if ((flags & O_ACCMODE) == O_WRONLY) {
		errno = EINVAL;
		return (NULL);
	}

	if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB))))
		return (NULL);
	hashp->fp = -1;

	/*
	 * Even if user wants write only, we need to be able to read
	 * the actual file, so we need to open it read/write. But, the
	 * field in the hashp structure needs to be accurate so that
	 * we can check accesses.
	 */
	hashp->flags = flags;

	if (file) {
		if ((hashp->fp = _open(file, flags | O_CLOEXEC, mode)) == -1)
			RETURN_ERROR(errno, error0);
		new_table = _fstat(hashp->fp, &statbuf) == 0 &&
		    statbuf.st_size == 0 && (flags & O_ACCMODE) != O_RDONLY;
	} else
		new_table = 1;

	if (new_table) {
		if (!(hashp = init_hash(hashp, file, info)))
			RETURN_ERROR(errno, error1);
	} else {
		/* Table already exists */
		if (info && info->hash)
			hashp->hash = info->hash;
		else
			hashp->hash = __default_hash;

		hdrsize = _read(hashp->fp, &hashp->hdr, sizeof(HASHHDR));
#if BYTE_ORDER == LITTLE_ENDIAN
		swap_header(hashp);
#endif
		if (hdrsize == -1)
			RETURN_ERROR(errno, error1);
		if (hdrsize != sizeof(HASHHDR))
			RETURN_ERROR(EFTYPE, error1);
		/* Verify file type, versions and hash function */
		if (hashp->MAGIC != HASHMAGIC)
			RETURN_ERROR(EFTYPE, error1);
#define	OLDHASHVERSION	1
		if (hashp->VERSION != HASHVERSION &&
		    hashp->VERSION != OLDHASHVERSION)
			RETURN_ERROR(EFTYPE, error1);
		if ((int32_t)hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY)
			RETURN_ERROR(EFTYPE, error1);
		/*
		 * Figure out how many segments we need.  Max_Bucket is the
		 * maximum bucket number, so the number of buckets is
		 * max_bucket + 1.
		 */
		nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) /
			 hashp->SGSIZE;
		if (alloc_segs(hashp, nsegs))
			/*
			 * If alloc_segs fails, table will have been destroyed
			 * and errno will have been set.
			 */
			return (NULL);
		/* Read in bitmaps */
		bpages = (hashp->SPARES[hashp->OVFL_POINT] +
		    (hashp->BSIZE << BYTE_SHIFT) - 1) >>
		    (hashp->BSHIFT + BYTE_SHIFT);

		hashp->nmaps = bpages;
		(void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_int32_t *));
	}

	/* Initialize Buffer Manager */
	if (info && info->cachesize)
		__buf_init(hashp, info->cachesize);
	else
		__buf_init(hashp, DEF_BUFSIZE);

	hashp->new_file = new_table;
	hashp->save_file = file && (hashp->flags & O_RDWR);
	hashp->cbucket = -1;
	if (!(dbp = (DB *)malloc(sizeof(DB)))) {
		save_errno = errno;
		hdestroy(hashp);
		errno = save_errno;
		return (NULL);
	}
	dbp->internal = hashp;
	dbp->close = hash_close;
	dbp->del = hash_delete;
	dbp->fd = hash_fd;
	dbp->get = hash_get;
	dbp->put = hash_put;
	dbp->seq = hash_seq;
	dbp->sync = hash_sync;
	dbp->type = DB_HASH;

#ifdef DEBUG
	(void)fprintf(stderr,
"%s\n%s%p\n%s%d\n%s%d\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     ", hashp->BSIZE,
	    "BUCKET SHIFT    ", hashp->BSHIFT,
	    "DIRECTORY SIZE  ", hashp->DSIZE,
	    "SEGMENT SIZE    ", hashp->SGSIZE,
	    "SEGMENT SHIFT   ", hashp->SSHIFT,
	    "FILL FACTOR     ", hashp->FFACTOR,
	    "MAX BUCKET      ", hashp->MAX_BUCKET,
	    "OVFL POINT	     ", hashp->OVFL_POINT,
	    "LAST FREED      ", hashp->LAST_FREED,
	    "HIGH MASK       ", hashp->HIGH_MASK,
	    "LOW  MASK       ", hashp->LOW_MASK,
	    "NSEGS           ", hashp->nsegs,
	    "NKEYS           ", hashp->NKEYS);
#endif
#ifdef HASH_STATISTICS
	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
#endif
	return (dbp);

error1:
	if (hashp != NULL)
		(void)_close(hashp->fp);

error0:
	free(hashp);
	errno = save_errno;
	return (NULL);
}
示例#4
0
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);
	}
	
    } 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 ( !hdefault(hashp) ) return(0);
    hctl = hashp->hctl;
#ifdef HASH_STATISTICS
    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);
}
示例#5
0
/*
 * hash_create -- create a new dynamic hash table
 *
 *	tabname: a name for the table (for debugging purposes)
 *	nelem: maximum number of elements expected
 *	*info: additional table parameters, as indicated by flags
 *	flags: bitmask indicating which parameters to take from *info
 *
 * Note: for a shared-memory hashtable, nelem needs to be a pretty good
 * estimate, since we can't expand the table on the fly.  But an unshared
 * hashtable can be expanded on-the-fly, so it's better for nelem to be
 * on the small side and let the table grow if it's exceeded.  An overly
 * large nelem will penalize hash_seq_search speed without buying much.
 */
HTAB *
hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
{
	HTAB	   *hashp;
	HASHHDR    *hctl;

	/*
	 * For shared hash tables, we have a local hash header (HTAB struct) that
	 * we allocate in TopMemoryContext; all else is in shared memory.
	 *
	 * For non-shared hash tables, everything including the hash header is in
	 * a memory context created specially for the hash table --- this makes
	 * hash_destroy very simple.  The memory context is made a child of either
	 * a context specified by the caller, or TopMemoryContext if nothing is
	 * specified.
	 */
	if (flags & HASH_SHARED_MEM)
	{
		/* Set up to allocate the hash header */
		CurrentDynaHashCxt = TopMemoryContext;
	}
	else
	{
		/* Create the hash table's private memory context */
		if (flags & HASH_CONTEXT)
			CurrentDynaHashCxt = info->hcxt;
		else
			CurrentDynaHashCxt = TopMemoryContext;
		CurrentDynaHashCxt = AllocSetContextCreate(CurrentDynaHashCxt,
												   tabname,
												   ALLOCSET_DEFAULT_MINSIZE,
												   ALLOCSET_DEFAULT_INITSIZE,
												   ALLOCSET_DEFAULT_MAXSIZE);
	}

	/* Initialize the hash header, plus a copy of the table name */
	hashp = (HTAB *) DynaHashAlloc(sizeof(HTAB) + strlen(tabname) +1);
	MemSet(hashp, 0, sizeof(HTAB));

	hashp->tabname = (char *) (hashp + 1);
	strcpy(hashp->tabname, tabname);

	if (flags & HASH_FUNCTION)
		hashp->hash = info->hash;
	else
		hashp->hash = string_hash;		/* default hash function */

	/*
	 * If you don't specify a match function, it defaults to string_compare if
	 * you used string_hash (either explicitly or by default) and to memcmp
	 * otherwise.  (Prior to PostgreSQL 7.4, memcmp was always used.)
	 */
	if (flags & HASH_COMPARE)
		hashp->match = info->match;
	else if (hashp->hash == string_hash)
		hashp->match = (HashCompareFunc) string_compare;
	else
		hashp->match = memcmp;

	/*
	 * Similarly, the key-copying function defaults to strlcpy or memcpy.
	 */
	if (flags & HASH_KEYCOPY)
		hashp->keycopy = info->keycopy;
	else if (hashp->hash == string_hash)
		hashp->keycopy = (HashCopyFunc) strlcpy;
	else
		hashp->keycopy = memcpy;

	if (flags & HASH_ALLOC)
		hashp->alloc = info->alloc;
	else
		hashp->alloc = DynaHashAlloc;

	if (flags & HASH_SHARED_MEM)
	{
		/*
		 * ctl structure and directory are preallocated for shared memory
		 * tables.	Note that HASH_DIRSIZE and HASH_ALLOC had better be set as
		 * well.
		 */
		hashp->hctl = info->hctl;
		hashp->dir = (HASHSEGMENT *) (((char *) info->hctl) + sizeof(HASHHDR));
		hashp->hcxt = NULL;
		hashp->isshared = true;

		/* hash table already exists, we're just attaching to it */
		if (flags & HASH_ATTACH)
		{
			/* make local copies of some heavily-used values */
			hctl = hashp->hctl;
			hashp->keysize = hctl->keysize;
			hashp->ssize = hctl->ssize;
			hashp->sshift = hctl->sshift;

			return hashp;
		}
	}
	else
	{
		/* setup hash table defaults */
		hashp->hctl = NULL;
		hashp->dir = NULL;
		hashp->hcxt = CurrentDynaHashCxt;
		hashp->isshared = false;
	}

	if (!hashp->hctl)
	{
		hashp->hctl = (HASHHDR *) hashp->alloc(sizeof(HASHHDR));
		if (!hashp->hctl)
			ereport(ERROR,
					(errcode(ERRCODE_OUT_OF_MEMORY),
					 errmsg("out of memory")));
	}

	hashp->frozen = false;

	hdefault(hashp);

	hctl = hashp->hctl;

	if (flags & HASH_PARTITION)
	{
		/* Doesn't make sense to partition a local hash table */
		Assert(flags & HASH_SHARED_MEM);

		/*
		 * The number of partitions had better be a power of 2. Also, it must
		 * be less than INT_MAX (see init_htab()), so call the int version of
		 * next_pow2.
		 */
		Assert(info->num_partitions == next_pow2_int(info->num_partitions));

		hctl->num_partitions = info->num_partitions;
	}

	if (flags & HASH_SEGMENT)
	{
		hctl->ssize = info->ssize;
		hctl->sshift = my_log2(info->ssize);
		/* ssize had better be a power of 2 */
		Assert(hctl->ssize == (1L << hctl->sshift));
	}
	if (flags & HASH_FFACTOR)
		hctl->ffactor = info->ffactor;

	/*
	 * SHM hash tables have fixed directory size passed by the caller.
	 */
	if (flags & HASH_DIRSIZE)
	{
		hctl->max_dsize = info->max_dsize;
		hctl->dsize = 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)
	{
		Assert(info->entrysize >= info->keysize);
		hctl->keysize = info->keysize;
		hctl->entrysize = info->entrysize;
	}

	/* make local copies of heavily-used constant fields */
	hashp->keysize = hctl->keysize;
	hashp->ssize = hctl->ssize;
	hashp->sshift = hctl->sshift;

	/* Build the hash directory structure */
	if (!init_htab(hashp, nelem))
		elog(ERROR, "failed to initialize hash table \"%s\"", hashp->tabname);

	/*
	 * For a shared hash table, preallocate the requested number of elements.
	 * This reduces problems with run-time out-of-shared-memory conditions.
	 *
	 * For a non-shared hash table, preallocate the requested number of
	 * elements if it's less than our chosen nelem_alloc.  This avoids wasting
	 * space if the caller correctly estimates a small table size.
	 */
	if ((flags & HASH_SHARED_MEM) ||
		nelem < hctl->nelem_alloc)
	{
		if (!element_alloc(hashp, (int) nelem))
			ereport(ERROR,
					(errcode(ERRCODE_OUT_OF_MEMORY),
					 errmsg("out of memory")));
	}

	if (flags & HASH_FIXED_SIZE)
		hashp->isfixed = true;
	return hashp;
}
示例#6
0
HTAB *
hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
{
	HTAB	   *hashp;
	HASHHDR    *hctl;

	/* First time through, create a memory context for hash tables */
	if (!DynaHashCxt)
		DynaHashCxt = AllocSetContextCreate(TopMemoryContext,
											"DynaHash",
											ALLOCSET_DEFAULT_MINSIZE,
											ALLOCSET_DEFAULT_INITSIZE,
											ALLOCSET_DEFAULT_MAXSIZE);

	/* Select allocation context for this hash table */
	if (flags & HASH_CONTEXT)
		CurrentDynaHashCxt = info->hcxt;
	else
		CurrentDynaHashCxt = DynaHashCxt;

	/* Initialize the hash header */
	hashp = (HTAB *) MEM_ALLOC(sizeof(HTAB));
	if (!hashp)
		return NULL;
	MemSet(hashp, 0, sizeof(HTAB));

	hashp->tabname = (char *) MEM_ALLOC(strlen(tabname) + 1);
	strcpy(hashp->tabname, tabname);

	if (flags & HASH_FUNCTION)
		hashp->hash = info->hash;
	else
		hashp->hash = string_hash;		/* default hash function */

	/*
	 * If you don't specify a match function, it defaults to strncmp() if
	 * you used string_hash (either explicitly or by default) and to
	 * memcmp() otherwise.  (Prior to PostgreSQL 7.4, memcmp() was always
	 * used.)
	 */
	if (flags & HASH_COMPARE)
		hashp->match = info->match;
	else if (hashp->hash == string_hash)
		hashp->match = (HashCompareFunc) strncmp;
	else
		hashp->match = memcmp;

	/*
	 * Similarly, the key-copying function defaults to strncpy() or memcpy().
	 */
	if (hashp->hash == string_hash)
		hashp->keycopy = (HashCopyFunc) strncpy;
	else
		hashp->keycopy = memcpy;

	if (flags & HASH_SHARED_MEM)
	{
		/*
		 * ctl structure is preallocated for shared memory tables. Note
		 * that HASH_DIRSIZE had better be set as well.
		 */
		hashp->hctl = info->hctl;
		hashp->dir = info->dir;
		hashp->alloc = info->alloc;
		hashp->hcxt = NULL;
		hashp->isshared = true;

		/* hash table already exists, we're just attaching to it */
		if (flags & HASH_ATTACH)
			return hashp;
	}
	else
	{
		/* setup hash table defaults */
		hashp->hctl = NULL;
		hashp->dir = NULL;
		hashp->alloc = MEM_ALLOC;
		hashp->hcxt = CurrentDynaHashCxt;
		hashp->isshared = false;
	}

	if (!hashp->hctl)
	{
		hashp->hctl = (HASHHDR *) hashp->alloc(sizeof(HASHHDR));
		if (!hashp->hctl)
			return NULL;
	}

	if (!hdefault(hashp))
		return NULL;

	hctl = hashp->hctl;
#ifdef HASH_STATISTICS
	hctl->accesses = hctl->collisions = 0;
#endif

	if (flags & HASH_SEGMENT)
	{
		hctl->ssize = info->ssize;
		hctl->sshift = my_log2(info->ssize);
		/* ssize had better be a power of 2 */
		Assert(hctl->ssize == (1L << hctl->sshift));
	}
	if (flags & HASH_FFACTOR)
		hctl->ffactor = info->ffactor;

	/*
	 * SHM hash tables have fixed directory size passed by the caller.
	 */
	if (flags & HASH_DIRSIZE)
	{
		hctl->max_dsize = info->max_dsize;
		hctl->dsize = 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->entrysize = info->entrysize;
	}

	if (flags & HASH_ALLOC)
		hashp->alloc = info->alloc;
	else
	{
		/* remaining hash table structures live in child of given context */
		hashp->hcxt = AllocSetContextCreate(CurrentDynaHashCxt,
											"DynaHashTable",
											ALLOCSET_DEFAULT_MINSIZE,
											ALLOCSET_DEFAULT_INITSIZE,
											ALLOCSET_DEFAULT_MAXSIZE);
		CurrentDynaHashCxt = hashp->hcxt;
	}

	if (!init_htab(hashp, nelem))
	{
		hash_destroy(hashp);
		return NULL;
	}
	return hashp;
}