Пример #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);
}
Пример #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);
}
Пример #3
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);
}
Пример #4
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);
}
Пример #5
0
/*
 * Returns:
 *   0 ==> OK
 *  -1 ==> Error
 */
extern int
__split_page(HTAB *hashp, uint32 obucket, uint32 nbucket)
{
    register BUFHEAD *new_bufp, *old_bufp;
    register uint16 *ino;
    register uint16 *tmp_uint16_array;
    register char *np;
    DBT key, val;
    uint16 n, ndx;
    int retval;
    uint16 copyto, diff, moved;
    size_t off;
    char *op;

    copyto = (uint16)hashp->BSIZE;
    off = (uint16)hashp->BSIZE;
    old_bufp = __get_buf(hashp, obucket, NULL, 0);
    if (old_bufp == NULL)
        return (-1);
    new_bufp = __get_buf(hashp, nbucket, NULL, 0);
    if (new_bufp == NULL)
        return (-1);

    old_bufp->flags |= (BUF_MOD | BUF_PIN);
    new_bufp->flags |= (BUF_MOD | BUF_PIN);

    ino = (uint16 *)(op = old_bufp->page);
    np = new_bufp->page;

    moved = 0;

    for (n = 1, ndx = 1; n < ino[0]; n += 2) {
        if (ino[n + 1] < REAL_KEY) {
            retval = ugly_split(hashp, obucket, old_bufp, new_bufp,
                                (int)copyto, (int)moved);
            old_bufp->flags &= ~BUF_PIN;
            new_bufp->flags &= ~BUF_PIN;
            return (retval);
        }
        key.data = (uint8 *)op + ino[n];

        /* check here for ino[n] being greater than
         * off.  If it is then the database has
         * been corrupted.
         */
        if (ino[n] > off)
            return (DATABASE_CORRUPTED_ERROR);

        key.size = off - ino[n];

#ifdef DEBUG
        /* make sure the size is positive */
        assert(((int)key.size) > -1);
#endif

        if (__call_hash(hashp, (char *)key.data, key.size) == obucket) {
            /* Don't switch page */
            diff = copyto - off;
            if (diff) {
                copyto = ino[n + 1] + diff;
                memmove(op + copyto, op + ino[n + 1],
                        off - ino[n + 1]);
                ino[ndx] = copyto + ino[n] - ino[n + 1];
                ino[ndx + 1] = copyto;
            } else
                copyto = ino[n + 1];
            ndx += 2;
        } else {
            /* Switch page */
            val.data = (uint8 *)op + ino[n + 1];
            val.size = ino[n] - ino[n + 1];

            /* if the pair doesn't fit something is horribly
             * wrong.  LJM
             */
            tmp_uint16_array = (uint16 *)np;
            if (!PAIRFITS(tmp_uint16_array, &key, &val))
                return (DATABASE_CORRUPTED_ERROR);

            putpair(np, &key, &val);
            moved += 2;
        }

        off = ino[n + 1];
    }

    /* Now clean up the page */
    ino[0] -= moved;
    FREESPACE(ino) = copyto - sizeof(uint16) * (ino[0] + 3);
    OFFSET(ino) = copyto;

#ifdef DEBUG3
    (void)fprintf(stderr, "split %d/%d\n",
                  ((uint16 *)np)[0] / 2,
                  ((uint16 *)op)[0] / 2);
#endif
    /* unpin both pages */
    old_bufp->flags &= ~BUF_PIN;
    new_bufp->flags &= ~BUF_PIN;
    return (0);
}