Example #1
0
/*
 * Add the given pair to the page
 *
 * Returns:
 *	0 ==> OK
 *	1 ==> failure
 */
extern int
__addel(HTAB *hashp, BUFHEAD *bufp, const DBT *key, const DBT *val)
{
	u_int16_t *bp, *sop;
	int do_expand;

	bp = (u_int16_t *)bufp->page;
	do_expand = 0;
	while (bp[0] && (bp[2] < REAL_KEY || bp[bp[0]] < REAL_KEY))
		/* Exception case */
		if (bp[2] == FULL_KEY_DATA && bp[0] == 2)
			/* This is the last page of a big key/data pair
			   and we need to add another page */
			break;
		else if (bp[2] < REAL_KEY && bp[bp[0]] != OVFLPAGE) {
			bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
			if (!bufp)
				return (-1);
			bp = (u_int16_t *)bufp->page;
		} else
			/* Try to squeeze key on this page */
			if (FREESPACE(bp) > PAIRSIZE(key, val)) {
				squeeze_key(bp, key, val);
				return (0);
			} else {
				bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
				if (!bufp)
					return (-1);
				bp = (u_int16_t *)bufp->page;
			}

	if (PAIRFITS(bp, key, val))
		putpair(bufp->page, key, val);
	else {
		do_expand = 1;
		bufp = __add_ovflpage(hashp, bufp);
		if (!bufp)
			return (-1);
		sop = (u_int16_t *)bufp->page;

		if (PAIRFITS(sop, key, val))
			putpair((char *)sop, key, val);
		else
			if (__big_insert(hashp, bufp, key, val))
				return (-1);
	}
	bufp->flags |= BUF_MOD;
	/*
	 * If the average number of keys per bucket exceeds the fill factor,
	 * expand the table.
	 */
	hashp->NKEYS++;
	if (do_expand ||
	    (hashp->NKEYS / (hashp->MAX_BUCKET + 1) > hashp->FFACTOR))
		return (__expand_table(hashp));
	return (0);
}
Example #2
0
/*
 * Called when we encounter an overflow or big key/data page during split
 * handling.  This is special cased since we have to begin checking whether
 * the key/data pairs fit on their respective pages and because we may need
 * overflow pages for both the old and new pages.
 *
 * The first page might be a page with regular key/data pairs in which case
 * we have a regular overflow condition and just need to go on to the next
 * page or it might be a big key/data pair in which case we need to fix the
 * big key/data pair.
 *
 * Returns:
 *	 0 ==> success
 *	-1 ==> failure
 */
static int
ugly_split(
	HTAB *hashp,
	uint32_t obucket,	/* Same as __split_page. */
	BUFHEAD *old_bufp,
	BUFHEAD *new_bufp,
	int copyto,	/* First byte on page which contains key/data values. */
	int moved	/* Number of pairs moved to new page. */
)
{
	BUFHEAD *bufp;	/* Buffer header for ino */
	uint16_t *ino;	/* Page keys come off of */
	uint16_t *np;	/* New page */
	uint16_t *op;	/* Page keys go on to if they aren't moving */
	size_t temp;

	BUFHEAD *last_bfp;	/* Last buf header OVFL needing to be freed */
	DBT key, val;
	SPLIT_RETURN ret;
	uint16_t n, off, ov_addr, scopyto;
	char *cino;		/* Character value of ino */

	bufp = old_bufp;
	ino = (uint16_t *)(void *)old_bufp->page;
	np = (uint16_t *)(void *)new_bufp->page;
	op = (uint16_t *)(void *)old_bufp->page;
	last_bfp = NULL;
	scopyto = (uint16_t)copyto;	/* ANSI */

	n = ino[0] - 1;
	while (n < ino[0]) {
		if (ino[2] < REAL_KEY && ino[2] != OVFLPAGE) {
			if (__big_split(hashp, old_bufp,
			    new_bufp, bufp, (int)bufp->addr, obucket, &ret))
				return (-1);
			old_bufp = ret.oldp;
			if (!old_bufp)
				return (-1);
			op = (uint16_t *)(void *)old_bufp->page;
			new_bufp = ret.newp;
			if (!new_bufp)
				return (-1);
			np = (uint16_t *)(void *)new_bufp->page;
			bufp = ret.nextp;
			if (!bufp)
				return (0);
			cino = (char *)bufp->page;
			ino = (uint16_t *)(void *)cino;
			last_bfp = ret.nextp;
		} else if (ino[n + 1] == OVFLPAGE) {
			ov_addr = ino[n];
			/*
			 * Fix up the old page -- the extra 2 are the fields
			 * which contained the overflow information.
			 */
			ino[0] -= (moved + 2);
			temp = sizeof(uint16_t) * (ino[0] + 3);
			_DIAGASSERT(scopyto >= temp);
			FREESPACE(ino) = (uint16_t)(scopyto - temp);
			OFFSET(ino) = scopyto;

			bufp = __get_buf(hashp, (uint32_t)ov_addr, bufp, 0);
			if (!bufp)
				return (-1);

			ino = (uint16_t *)(void *)bufp->page;
			n = 1;
			scopyto = hashp->BSIZE;
			moved = 0;

			if (last_bfp)
				__free_ovflpage(hashp, last_bfp);
			last_bfp = bufp;
		}
		/* Move regular sized pairs of there are any */
		off = hashp->BSIZE;
		for (n = 1; (n < ino[0]) && (ino[n + 1] >= REAL_KEY); n += 2) {
			cino = (char *)(void *)ino;
			key.data = (uint8_t *)cino + ino[n];
			key.size = off - ino[n];
			val.data = (uint8_t *)cino + ino[n + 1];
			val.size = ino[n] - ino[n + 1];
			off = ino[n + 1];

			if (__call_hash(hashp, key.data, (int)key.size) == obucket) {
				/* Keep on old page */
				if (PAIRFITS(op, (&key), (&val)))
					putpair((char *)(void *)op, &key, &val);
				else {
					old_bufp =
					    __add_ovflpage(hashp, old_bufp);
					if (!old_bufp)
						return (-1);
					op = (uint16_t *)(void *)old_bufp->page;
					putpair((char *)(void *)op, &key, &val);
				}
				old_bufp->flags |= BUF_MOD;
			} else {
				/* Move to new page */
				if (PAIRFITS(np, (&key), (&val)))
					putpair((char *)(void *)np, &key, &val);
				else {
					new_bufp =
					    __add_ovflpage(hashp, new_bufp);
					if (!new_bufp)
						return (-1);
					np = (uint16_t *)(void *)new_bufp->page;
					putpair((char *)(void *)np, &key, &val);
				}
				new_bufp->flags |= BUF_MOD;
			}
		}
	}
	if (last_bfp)
		__free_ovflpage(hashp, last_bfp);
	return (0);
}
Example #3
0
/*
 * Big_insert
 *
 * You need to do an insert and the key/data pair is too big
 *
 * Returns:
 * 0 ==> OK
 *-1 ==> ERROR
 */
int
__big_insert(HTAB *hashp, BUFHEAD *bufp, const DBT *key, const DBT *val)
{
	uint16_t *p, n;
	size_t key_size, val_size;
	uint16_t space, move_bytes, off;
	char *cp, *key_data, *val_data;
	size_t temp;

	cp = bufp->page;		/* Character pointer of p. */
	p = (uint16_t *)(void *)cp;

	key_data = (char *)key->data;
	_DBFIT(key->size, int);
	key_size = key->size;
	val_data = (char *)val->data;
	_DBFIT(val->size, int);
	val_size = val->size;

	/* First move the Key */
	
	temp = FREESPACE(p) - BIGOVERHEAD;
	_DBFIT(temp, uint16_t);
	space = (uint16_t)temp;
	while (key_size) {
		move_bytes = MIN(space, key_size);
		off = OFFSET(p) - move_bytes;
		memmove(cp + off, key_data, (size_t)move_bytes);
		key_size -= move_bytes;
		key_data += move_bytes;
		n = p[0];
		p[++n] = off;
		p[0] = ++n;
		temp = off - PAGE_META(n);
		_DBFIT(temp, uint16_t);
		FREESPACE(p) = (uint16_t)temp;
		OFFSET(p) = off;
		p[n] = PARTIAL_KEY;
		bufp = __add_ovflpage(hashp, bufp);
		if (!bufp)
			return (-1);
		n = p[0];
		if (!key_size) {
			space = FREESPACE(p);
			if (space) {
				move_bytes = MIN(space, val_size);
				/*
				 * If the data would fit exactly in the
				 * remaining space, we must overflow it to the
				 * next page; otherwise the invariant that the
				 * data must end on a page with FREESPACE
				 * non-zero would fail.
				 */
				if (space == val_size && val_size == val->size)
					goto toolarge;
				off = OFFSET(p) - move_bytes;
				memmove(cp + off, val_data, (size_t)move_bytes);
				val_data += move_bytes;
				val_size -= move_bytes;
				p[n] = off;
				p[n - 2] = FULL_KEY_DATA;
				FREESPACE(p) = FREESPACE(p) - move_bytes;
				OFFSET(p) = off;
			} else {
			toolarge:
				p[n - 2] = FULL_KEY;
			}
		}
		p = (uint16_t *)(void *)bufp->page;
		cp = bufp->page;
		bufp->flags |= BUF_MOD;
		temp = FREESPACE(p) - BIGOVERHEAD;
		_DBFIT(temp, uint16_t);
		space = (uint16_t)temp;
	}

	/* Now move the data */
	temp = FREESPACE(p) - BIGOVERHEAD;
	_DBFIT(temp, uint16_t);
	space = (uint16_t)temp;
	while (val_size) {
		move_bytes = MIN(space, val_size);
		/*
		 * Here's the hack to make sure that if the data ends on the
		 * same page as the key ends, FREESPACE is at least one.
		 */
		if (space == val_size && val_size == val->size)
			move_bytes--;
		off = OFFSET(p) - move_bytes;
		memmove(cp + off, val_data, (size_t)move_bytes);
		val_size -= move_bytes;
		val_data += move_bytes;
		n = p[0];
		p[++n] = off;
		p[0] = ++n;
		temp = off - PAGE_META(n);
		_DBFIT(temp, uint16_t);
		FREESPACE(p) = (uint16_t)temp;
		OFFSET(p) = off;
		if (val_size) {
			p[n] = FULL_KEY;
			bufp = __add_ovflpage(hashp, bufp);
			if (!bufp)
				return (-1);
			cp = bufp->page;
			p = (uint16_t *)(void *)cp;
		} else
			p[n] = FULL_KEY_DATA;
		bufp->flags |= BUF_MOD;
		temp = FREESPACE(p) - BIGOVERHEAD;
		_DBFIT(temp, uint16_t);
		space = (uint16_t)temp;
	}
	return (0);
}
Example #4
0
/*
 * Returns:
 *  0 => OK
 * -1 => error
 */
int
__big_split(
	HTAB *hashp,
	BUFHEAD *op,	/* Pointer to where to put keys that go in old bucket */
	BUFHEAD *np,	/* Pointer to new bucket page */
			/* Pointer to first page containing the big key/data */
	BUFHEAD *big_keyp,
	int addr,	/* Address of big_keyp */
	uint32_t   obucket,/* Old Bucket */
	SPLIT_RETURN *ret
)
{
	BUFHEAD *tmpp;
	uint16_t *tp;
	BUFHEAD *bp;
	DBT key, val;
	uint32_t change;
	uint16_t free_space, n, off;
	size_t temp;

	bp = big_keyp;

	/* Now figure out where the big key/data goes */
	if (__big_keydata(hashp, big_keyp, &key, &val, 0))
		return (-1);
	change = (__call_hash(hashp, key.data, (int)key.size) != obucket);

	if ((ret->next_addr = __find_last_page(hashp, &big_keyp)) != 0) {
		if (!(ret->nextp =
		    __get_buf(hashp, (uint32_t)ret->next_addr, big_keyp, 0)))
			return (-1);
	} else
		ret->nextp = NULL;

	/* Now make one of np/op point to the big key/data pair */
	_DIAGASSERT(np->ovfl == NULL);
	if (change)
		tmpp = np;
	else
		tmpp = op;

	tmpp->flags |= BUF_MOD;
#ifdef DEBUG1
	(void)fprintf(stderr,
	    "BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr,
	    (tmpp->ovfl ? tmpp->ovfl->addr : 0), (bp ? bp->addr : 0));
#endif
	tmpp->ovfl = bp;	/* one of op/np point to big_keyp */
	tp = (uint16_t *)(void *)tmpp->page;
	_DIAGASSERT(FREESPACE(tp) >= OVFLSIZE);
	n = tp[0];
	off = OFFSET(tp);
	free_space = FREESPACE(tp);
	tp[++n] = (uint16_t)addr;
	tp[++n] = OVFLPAGE;
	tp[0] = n;
	OFFSET(tp) = off;
	temp = free_space - OVFLSIZE;
	_DBFIT(temp, uint16_t);
	FREESPACE(tp) = (uint16_t)temp;

	/*
	 * Finally, set the new and old return values. BIG_KEYP contains a
	 * pointer to the last page of the big key_data pair. Make sure that
	 * big_keyp has no following page (2 elements) or create an empty
	 * following page.
	 */

	ret->newp = np;
	ret->oldp = op;

	tp = (uint16_t *)(void *)big_keyp->page;
	big_keyp->flags |= BUF_MOD;
	if (tp[0] > 2) {
		/*
		 * There may be either one or two offsets on this page.  If
		 * there is one, then the overflow page is linked on normally
		 * and tp[4] is OVFLPAGE.  If there are two, tp[4] contains
		 * the second offset and needs to get stuffed in after the
		 * next overflow page is added.
		 */
		n = tp[4];
		free_space = FREESPACE(tp);
		off = OFFSET(tp);
		tp[0] -= 2;
		temp = free_space + OVFLSIZE;
		_DBFIT(temp, uint16_t);
		FREESPACE(tp) = (uint16_t)temp;
		OFFSET(tp) = off;
		tmpp = __add_ovflpage(hashp, big_keyp);
		if (!tmpp)
			return (-1);
		tp[4] = n;
	} else
		tmpp = big_keyp;

	if (change)
		ret->newp = tmpp;
	else
		ret->oldp = tmpp;
	return (0);
}
Example #5
0
/*
 * Add the given pair to the page
 *
 * Returns:
 *  0 ==> OK
 *  1 ==> failure
 */
extern int
__addel(HTAB *hashp, BUFHEAD *bufp, const DBT *key, const DBT *val)
{
    register uint16 *bp, *sop;
    int do_expand;

    bp = (uint16 *)bufp->page;
    do_expand = 0;
    while (bp[0] && (bp[2] < REAL_KEY || bp[bp[0]] < REAL_KEY))
        /* Exception case */
        if (bp[2] == FULL_KEY_DATA && bp[0] == 2)
            /* This is the last page of a big key/data pair
               and we need to add another page */
            break;
        else if (bp[2] < REAL_KEY && bp[bp[0]] != OVFLPAGE) {
            bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
            if (!bufp) {
#ifdef DEBUG
                assert(0);
#endif
                return (-1);
            }
            bp = (uint16 *)bufp->page;
        } else
            /* Try to squeeze key on this page */
            if (FREESPACE(bp) > PAIRSIZE(key, val)) {
            {
                squeeze_key(bp, key, val);

                /* LJM: I added this because I think it was
                 * left out on accident.
                 * if this isn't incremented nkeys will not
                 * be the actual number of keys in the db.
                 */
                hashp->NKEYS++;
                return (0);
            }
        } else {
            bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
            if (!bufp) {
#ifdef DEBUG
                assert(0);
#endif
                return (-1);
            }
            bp = (uint16 *)bufp->page;
        }

    if (PAIRFITS(bp, key, val))
        putpair(bufp->page, key, (DBT *)val);
    else {
        do_expand = 1;
        bufp = __add_ovflpage(hashp, bufp);
        if (!bufp) {
#ifdef DEBUG
            assert(0);
#endif
            return (-1);
        }
        sop = (uint16 *)bufp->page;

        if (PAIRFITS(sop, key, val))
            putpair((char *)sop, key, (DBT *)val);
        else if (__big_insert(hashp, bufp, key, val)) {
#ifdef DEBUG
            assert(0);
#endif
            return (-1);
        }
    }
    bufp->flags |= BUF_MOD;
    /*
     * If the average number of keys per bucket exceeds the fill factor,
     * expand the table.
     */
    hashp->NKEYS++;
    if (do_expand ||
        (hashp->NKEYS / (hashp->MAX_BUCKET + 1) > hashp->FFACTOR))
        return (__expand_table(hashp));
    return (0);
}
Example #6
0
static int
ugly_split(HTAB *hashp, uint32 obucket, BUFHEAD *old_bufp,
           BUFHEAD *new_bufp, /* Same as __split_page. */ int copyto, int moved)
/* int copyto;   First byte on page which contains key/data values. */
/* int moved;    Number of pairs moved to new page. */
{
    register BUFHEAD *bufp; /* Buffer header for ino */
    register uint16 *ino;   /* Page keys come off of */
    register uint16 *np;    /* New page */
    register uint16 *op;    /* Page keys go on to if they aren't moving */
    uint32 loop_detection = 0;

    BUFHEAD *last_bfp; /* Last buf header OVFL needing to be freed */
    DBT key, val;
    SPLIT_RETURN ret;
    uint16 n, off, ov_addr, scopyto;
    char *cino; /* Character value of ino */
    int status;

    bufp = old_bufp;
    ino = (uint16 *)old_bufp->page;
    np = (uint16 *)new_bufp->page;
    op = (uint16 *)old_bufp->page;
    last_bfp = NULL;
    scopyto = (uint16)copyto; /* ANSI */

    n = ino[0] - 1;
    while (n < ino[0]) {

        /* this function goes nuts sometimes and never returns.
         * I havent found the problem yet but I need a solution
         * so if we loop too often we assume a database curruption error
         * :LJM
         */
        loop_detection++;

        if (loop_detection > MAX_UGLY_SPLIT_LOOPS)
            return DATABASE_CORRUPTED_ERROR;

        if (ino[2] < REAL_KEY && ino[2] != OVFLPAGE) {
            if ((status = __big_split(hashp, old_bufp,
                                      new_bufp, bufp, bufp->addr, obucket, &ret)))
                return (status);
            old_bufp = ret.oldp;
            if (!old_bufp)
                return (-1);
            op = (uint16 *)old_bufp->page;
            new_bufp = ret.newp;
            if (!new_bufp)
                return (-1);
            np = (uint16 *)new_bufp->page;
            bufp = ret.nextp;
            if (!bufp)
                return (0);
            cino = (char *)bufp->page;
            ino = (uint16 *)cino;
            last_bfp = ret.nextp;
        } else if (ino[n + 1] == OVFLPAGE) {
            ov_addr = ino[n];
            /*
             * Fix up the old page -- the extra 2 are the fields
             * which contained the overflow information.
             */
            ino[0] -= (moved + 2);
            FREESPACE(ino) =
                scopyto - sizeof(uint16) * (ino[0] + 3);
            OFFSET(ino) = scopyto;

            bufp = __get_buf(hashp, ov_addr, bufp, 0);
            if (!bufp)
                return (-1);

            ino = (uint16 *)bufp->page;
            n = 1;
            scopyto = hashp->BSIZE;
            moved = 0;

            if (last_bfp)
                __free_ovflpage(hashp, last_bfp);
            last_bfp = bufp;
        }
        /* Move regular sized pairs of there are any */
        off = hashp->BSIZE;
        for (n = 1; (n < ino[0]) && (ino[n + 1] >= REAL_KEY); n += 2) {
            cino = (char *)ino;
            key.data = (uint8 *)cino + ino[n];
            key.size = off - ino[n];
            val.data = (uint8 *)cino + ino[n + 1];
            val.size = ino[n] - ino[n + 1];
            off = ino[n + 1];

            if (__call_hash(hashp, (char *)key.data, key.size) == obucket) {
                /* Keep on old page */
                if (PAIRFITS(op, (&key), (&val)))
                    putpair((char *)op, &key, &val);
                else {
                    old_bufp =
                        __add_ovflpage(hashp, old_bufp);
                    if (!old_bufp)
                        return (-1);
                    op = (uint16 *)old_bufp->page;
                    putpair((char *)op, &key, &val);
                }
                old_bufp->flags |= BUF_MOD;
            } else {
                /* Move to new page */
                if (PAIRFITS(np, (&key), (&val)))
                    putpair((char *)np, &key, &val);
                else {
                    new_bufp =
                        __add_ovflpage(hashp, new_bufp);
                    if (!new_bufp)
                        return (-1);
                    np = (uint16 *)new_bufp->page;
                    putpair((char *)np, &key, &val);
                }
                new_bufp->flags |= BUF_MOD;
            }
        }
    }
    if (last_bfp)
        __free_ovflpage(hashp, last_bfp);
    return (0);
}
Example #7
0
/*
 * Big_insert
 *
 * You need to do an insert and the key/data pair is too big
 *
 * Returns:
 * 0 ==> OK
 *-1 ==> ERROR
 */
extern int
__big_insert(HTAB *hashp, BUFHEAD *bufp, const DBT *key, const DBT *val)
{
    register uint16 *p;
    uint key_size, n, val_size;
    uint16 space, move_bytes, off;
    char *cp, *key_data, *val_data;

    cp = bufp->page; /* Character pointer of p. */
    p = (uint16 *)cp;

    key_data = (char *)key->data;
    key_size = key->size;
    val_data = (char *)val->data;
    val_size = val->size;

    /* First move the Key */
    for (space = FREESPACE(p) - BIGOVERHEAD; key_size;
         space = FREESPACE(p) - BIGOVERHEAD) {
        move_bytes = PR_MIN(space, key_size);
        off = OFFSET(p) - move_bytes;
        memmove(cp + off, key_data, move_bytes);
        key_size -= move_bytes;
        key_data += move_bytes;
        n = p[0];
        p[++n] = off;
        p[0] = ++n;
        FREESPACE(p) = off - PAGE_META(n);
        OFFSET(p) = off;
        p[n] = PARTIAL_KEY;
        bufp = __add_ovflpage(hashp, bufp);
        if (!bufp)
            return (-1);
        n = p[0];
        if (!key_size) {
            if (FREESPACE(p)) {
                move_bytes = PR_MIN(FREESPACE(p), val_size);
                off = OFFSET(p) - move_bytes;
                p[n] = off;
                memmove(cp + off, val_data, move_bytes);
                val_data += move_bytes;
                val_size -= move_bytes;
                p[n - 2] = FULL_KEY_DATA;
                FREESPACE(p) = FREESPACE(p) - move_bytes;
                OFFSET(p) = off;
            }
            else
                p[n - 2] = FULL_KEY;
        }
        p = (uint16 *)bufp->page;
        cp = bufp->page;
        bufp->flags |= BUF_MOD;
    }

    /* Now move the data */
    for (space = FREESPACE(p) - BIGOVERHEAD; val_size;
         space = FREESPACE(p) - BIGOVERHEAD) {
        move_bytes = PR_MIN(space, val_size);
        /*
         * Here's the hack to make sure that if the data ends on the
         * same page as the key ends, FREESPACE is at least one.
         */
        if (space == val_size && val_size == val->size)
            move_bytes--;
        off = OFFSET(p) - move_bytes;
        memmove(cp + off, val_data, move_bytes);
        val_size -= move_bytes;
        val_data += move_bytes;
        n = p[0];
        p[++n] = off;
        p[0] = ++n;
        FREESPACE(p) = off - PAGE_META(n);
        OFFSET(p) = off;
        if (val_size) {
            p[n] = FULL_KEY;
            bufp = __add_ovflpage(hashp, bufp);
            if (!bufp)
                return (-1);
            cp = bufp->page;
            p = (uint16 *)cp;
        }
        else
            p[n] = FULL_KEY_DATA;
        bufp->flags |= BUF_MOD;
    }
    return (0);
}