示例#1
0
/********************************* UTILITIES ************************/
static int
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;
    
#ifdef HASH_STATISTICS
    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);
	}
	if (! (hashp->dir[new_segnum] = seg_alloc(hashp))) {
	    return (0);
	}
	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;
	}
	chain->next = INVALID_INDEX;
    }
    return (1);
}
示例#2
0
/*
 * Expand the table by adding one more hash bucket.
 */
static bool
expand_table(HTAB *hashp)
{
	HASHHDR    *hctl = hashp->hctl;
	HASHSEGMENT old_seg,
				new_seg;
	long		old_bucket,
				new_bucket;
	long		new_segnum,
				new_segndx;
	long		old_segnum,
				old_segndx;
	HASHBUCKET *oldlink,
			   *newlink;
	HASHBUCKET	currElement,
				nextElement;

	Assert(!IS_PARTITIONED(hctl));

#ifdef HASH_STATISTICS
	hash_expansions++;
#endif

	new_bucket = hctl->max_bucket + 1;
	new_segnum = new_bucket >> hashp->sshift;
	new_segndx = MOD(new_bucket, hashp->ssize);

	if (new_segnum >= hctl->nsegs)
	{
		/* Allocate new segment if necessary -- could fail if dir full */
		if (new_segnum >= hctl->dsize)
			if (!dir_realloc(hashp))
				return false;
		if (!(hashp->dir[new_segnum] = seg_alloc(hashp)))
			return false;
		hctl->nsegs++;
	}

	/* OK, we created a new bucket */
	hctl->max_bucket++;

	/*
	 * *Before* changing masks, find old bucket corresponding to same hash
	 * values; values in that bucket may need to be relocated to new bucket.
	 * Note that new_bucket is certainly larger than low_mask at this point,
	 * so we can skip the first step of the regular hash mask calc.
	 */
	old_bucket = (new_bucket & hctl->low_mask);

	/*
	 * If we crossed a power of 2, readjust masks.
	 */
	if ((uint32) new_bucket > hctl->high_mask)
	{
		hctl->low_mask = hctl->high_mask;
		hctl->high_mask = (uint32) new_bucket | hctl->low_mask;
	}

	/*
	 * Relocate records to the new bucket.	NOTE: because of the way the hash
	 * masking is done in calc_bucket, only one old bucket can need to be
	 * split at this point.  With a different way of reducing the hash value,
	 * that might not be true!
	 */
	old_segnum = old_bucket >> hashp->sshift;
	old_segndx = MOD(old_bucket, hashp->ssize);

	old_seg = hashp->dir[old_segnum];
	new_seg = hashp->dir[new_segnum];

	oldlink = &old_seg[old_segndx];
	newlink = &new_seg[new_segndx];

	for (currElement = *oldlink;
		 currElement != NULL;
		 currElement = nextElement)
	{
		nextElement = currElement->link;
		if ((long) calc_bucket(hctl, currElement->hashvalue) == old_bucket)
		{
			*oldlink = currElement;
			oldlink = &currElement->link;
		}
		else
		{
			*newlink = currElement;
			newlink = &currElement->link;
		}
	}
	/* don't forget to terminate the rebuilt hash chains... */
	*oldlink = NULL;
	*newlink = NULL;

	return true;
}