andre@3: /*- andre@3: * Copyright (c) 1990, 1993, 1994 andre@3: * The Regents of the University of California. All rights reserved. andre@3: * andre@3: * This code is derived from software contributed to Berkeley by andre@3: * Margo Seltzer. andre@3: * andre@3: * Redistribution and use in source and binary forms, with or without andre@3: * modification, are permitted provided that the following conditions andre@3: * are met: andre@3: * 1. Redistributions of source code must retain the above copyright andre@3: * notice, this list of conditions and the following disclaimer. andre@3: * 2. Redistributions in binary form must reproduce the above copyright andre@3: * notice, this list of conditions and the following disclaimer in the andre@3: * documentation and/or other materials provided with the distribution. andre@3: * 3. ***REMOVED*** - see andre@3: * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change andre@3: * 4. Neither the name of the University nor the names of its contributors andre@3: * may be used to endorse or promote products derived from this software andre@3: * without specific prior written permission. andre@3: * andre@3: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND andre@3: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE andre@3: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE andre@3: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE andre@3: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL andre@3: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS andre@3: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) andre@3: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT andre@3: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY andre@3: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF andre@3: * SUCH DAMAGE. andre@3: */ andre@3: andre@3: #if defined(LIBC_SCCS) && !defined(lint) andre@3: static char sccsid[] = "@(#)hash_bigkey.c 8.3 (Berkeley) 5/31/94"; andre@3: #endif /* LIBC_SCCS and not lint */ andre@3: andre@3: /* andre@3: * PACKAGE: hash andre@3: * DESCRIPTION: andre@3: * Big key/data handling for the hashing package. andre@3: * andre@3: * ROUTINES: andre@3: * External andre@3: * __big_keydata andre@3: * __big_split andre@3: * __big_insert andre@3: * __big_return andre@3: * __big_delete andre@3: * __find_last_page andre@3: * Internal andre@3: * collect_key andre@3: * collect_data andre@3: */ andre@3: andre@3: #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh) andre@3: #include andre@3: #endif andre@3: andre@3: #include andre@3: #include andre@3: #include andre@3: #include andre@3: andre@3: #ifdef DEBUG andre@3: #include andre@3: #endif andre@3: andre@3: #include "mcom_db.h" andre@3: #include "hash.h" andre@3: #include "page.h" andre@3: /* #include "extern.h" */ andre@3: andre@3: static int collect_key __P((HTAB *, BUFHEAD *, int, DBT *, int)); andre@3: static int collect_data __P((HTAB *, BUFHEAD *, int, int)); andre@3: andre@3: /* andre@3: * Big_insert andre@3: * andre@3: * You need to do an insert and the key/data pair is too big andre@3: * andre@3: * Returns: andre@3: * 0 ==> OK andre@3: *-1 ==> ERROR andre@3: */ andre@3: extern int andre@3: __big_insert(HTAB *hashp, BUFHEAD *bufp, const DBT *key, const DBT *val) andre@3: { andre@3: register uint16 *p; andre@3: uint key_size, n, val_size; andre@3: uint16 space, move_bytes, off; andre@3: char *cp, *key_data, *val_data; andre@3: andre@3: cp = bufp->page; /* Character pointer of p. */ andre@3: p = (uint16 *)cp; andre@3: andre@3: key_data = (char *)key->data; andre@3: key_size = key->size; andre@3: val_data = (char *)val->data; andre@3: val_size = val->size; andre@3: andre@3: /* First move the Key */ andre@3: for (space = FREESPACE(p) - BIGOVERHEAD; key_size; andre@3: space = FREESPACE(p) - BIGOVERHEAD) { andre@3: move_bytes = PR_MIN(space, key_size); andre@3: off = OFFSET(p) - move_bytes; andre@3: memmove(cp + off, key_data, move_bytes); andre@3: key_size -= move_bytes; andre@3: key_data += move_bytes; andre@3: n = p[0]; andre@3: p[++n] = off; andre@3: p[0] = ++n; andre@3: FREESPACE(p) = off - PAGE_META(n); andre@3: OFFSET(p) = off; andre@3: p[n] = PARTIAL_KEY; andre@3: bufp = __add_ovflpage(hashp, bufp); andre@3: if (!bufp) andre@3: return (-1); andre@3: n = p[0]; andre@3: if (!key_size) { andre@3: if (FREESPACE(p)) { andre@3: move_bytes = PR_MIN(FREESPACE(p), val_size); andre@3: off = OFFSET(p) - move_bytes; andre@3: p[n] = off; andre@3: memmove(cp + off, val_data, move_bytes); andre@3: val_data += move_bytes; andre@3: val_size -= move_bytes; andre@3: p[n - 2] = FULL_KEY_DATA; andre@3: FREESPACE(p) = FREESPACE(p) - move_bytes; andre@3: OFFSET(p) = off; andre@3: } else andre@3: p[n - 2] = FULL_KEY; andre@3: } andre@3: p = (uint16 *)bufp->page; andre@3: cp = bufp->page; andre@3: bufp->flags |= BUF_MOD; andre@3: } andre@3: andre@3: /* Now move the data */ andre@3: for (space = FREESPACE(p) - BIGOVERHEAD; val_size; andre@3: space = FREESPACE(p) - BIGOVERHEAD) { andre@3: move_bytes = PR_MIN(space, val_size); andre@3: /* andre@3: * Here's the hack to make sure that if the data ends on the andre@3: * same page as the key ends, FREESPACE is at least one. andre@3: */ andre@3: if (space == val_size && val_size == val->size) andre@3: move_bytes--; andre@3: off = OFFSET(p) - move_bytes; andre@3: memmove(cp + off, val_data, move_bytes); andre@3: val_size -= move_bytes; andre@3: val_data += move_bytes; andre@3: n = p[0]; andre@3: p[++n] = off; andre@3: p[0] = ++n; andre@3: FREESPACE(p) = off - PAGE_META(n); andre@3: OFFSET(p) = off; andre@3: if (val_size) { andre@3: p[n] = FULL_KEY; andre@3: bufp = __add_ovflpage(hashp, bufp); andre@3: if (!bufp) andre@3: return (-1); andre@3: cp = bufp->page; andre@3: p = (uint16 *)cp; andre@3: } else andre@3: p[n] = FULL_KEY_DATA; andre@3: bufp->flags |= BUF_MOD; andre@3: } andre@3: return (0); andre@3: } andre@3: andre@3: /* andre@3: * Called when bufp's page contains a partial key (index should be 1) andre@3: * andre@3: * All pages in the big key/data pair except bufp are freed. We cannot andre@3: * free bufp because the page pointing to it is lost and we can't get rid andre@3: * of its pointer. andre@3: * andre@3: * Returns: andre@3: * 0 => OK andre@3: *-1 => ERROR andre@3: */ andre@3: extern int andre@3: __big_delete(HTAB *hashp, BUFHEAD *bufp) andre@3: { andre@3: register BUFHEAD *last_bfp, *rbufp; andre@3: uint16 *bp, pageno; andre@3: int key_done, n; andre@3: andre@3: rbufp = bufp; andre@3: last_bfp = NULL; andre@3: bp = (uint16 *)bufp->page; andre@3: pageno = 0; andre@3: key_done = 0; andre@3: andre@3: while (!key_done || (bp[2] != FULL_KEY_DATA)) { andre@3: if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) andre@3: key_done = 1; andre@3: andre@3: /* andre@3: * If there is freespace left on a FULL_KEY_DATA page, then andre@3: * the data is short and fits entirely on this page, and this andre@3: * is the last page. andre@3: */ andre@3: if (bp[2] == FULL_KEY_DATA && FREESPACE(bp)) andre@3: break; andre@3: pageno = bp[bp[0] - 1]; andre@3: rbufp->flags |= BUF_MOD; andre@3: rbufp = __get_buf(hashp, pageno, rbufp, 0); andre@3: if (last_bfp) andre@3: __free_ovflpage(hashp, last_bfp); andre@3: last_bfp = rbufp; andre@3: if (!rbufp) andre@3: return (-1); /* Error. */ andre@3: bp = (uint16 *)rbufp->page; andre@3: } andre@3: andre@3: /* andre@3: * If we get here then rbufp points to the last page of the big andre@3: * key/data pair. Bufp points to the first one -- it should now be andre@3: * empty pointing to the next page after this pair. Can't free it andre@3: * because we don't have the page pointing to it. andre@3: */ andre@3: andre@3: /* This is information from the last page of the pair. */ andre@3: n = bp[0]; andre@3: pageno = bp[n - 1]; andre@3: andre@3: /* Now, bp is the first page of the pair. */ andre@3: bp = (uint16 *)bufp->page; andre@3: if (n > 2) { andre@3: /* There is an overflow page. */ andre@3: bp[1] = pageno; andre@3: bp[2] = OVFLPAGE; andre@3: bufp->ovfl = rbufp->ovfl; andre@3: } else andre@3: /* This is the last page. */ andre@3: bufp->ovfl = NULL; andre@3: n -= 2; andre@3: bp[0] = n; andre@3: FREESPACE(bp) = hashp->BSIZE - PAGE_META(n); andre@3: OFFSET(bp) = hashp->BSIZE - 1; andre@3: andre@3: bufp->flags |= BUF_MOD; andre@3: if (rbufp) andre@3: __free_ovflpage(hashp, rbufp); andre@3: if (last_bfp != rbufp) andre@3: __free_ovflpage(hashp, last_bfp); andre@3: andre@3: hashp->NKEYS--; andre@3: return (0); andre@3: } andre@3: /* andre@3: * Returns: andre@3: * 0 = key not found andre@3: * -1 = get next overflow page andre@3: * -2 means key not found and this is big key/data andre@3: * -3 error andre@3: */ andre@3: extern int andre@3: __find_bigpair(HTAB *hashp, BUFHEAD *bufp, int ndx, char *key, int size) andre@3: { andre@3: register uint16 *bp; andre@3: register char *p; andre@3: int ksize; andre@3: uint16 bytes; andre@3: char *kkey; andre@3: andre@3: bp = (uint16 *)bufp->page; andre@3: p = bufp->page; andre@3: ksize = size; andre@3: kkey = key; andre@3: andre@3: for (bytes = hashp->BSIZE - bp[ndx]; andre@3: bytes <= size && bp[ndx + 1] == PARTIAL_KEY; andre@3: bytes = hashp->BSIZE - bp[ndx]) { andre@3: if (memcmp(p + bp[ndx], kkey, bytes)) andre@3: return (-2); andre@3: kkey += bytes; andre@3: ksize -= bytes; andre@3: bufp = __get_buf(hashp, bp[ndx + 2], bufp, 0); andre@3: if (!bufp) andre@3: return (-3); andre@3: p = bufp->page; andre@3: bp = (uint16 *)p; andre@3: ndx = 1; andre@3: } andre@3: andre@3: if (bytes != ksize || memcmp(p + bp[ndx], kkey, bytes)) { andre@3: #ifdef HASH_STATISTICS andre@3: ++hash_collisions; andre@3: #endif andre@3: return (-2); andre@3: } else andre@3: return (ndx); andre@3: } andre@3: andre@3: /* andre@3: * Given the buffer pointer of the first overflow page of a big pair, andre@3: * find the end of the big pair andre@3: * andre@3: * This will set bpp to the buffer header of the last page of the big pair. andre@3: * It will return the pageno of the overflow page following the last page andre@3: * of the pair; 0 if there isn't any (i.e. big pair is the last key in the andre@3: * bucket) andre@3: */ andre@3: extern uint16 andre@3: __find_last_page(HTAB *hashp, BUFHEAD **bpp) andre@3: { andre@3: BUFHEAD *bufp; andre@3: uint16 *bp, pageno; andre@3: uint n; andre@3: andre@3: bufp = *bpp; andre@3: bp = (uint16 *)bufp->page; andre@3: for (;;) { andre@3: n = bp[0]; andre@3: andre@3: /* andre@3: * This is the last page if: the tag is FULL_KEY_DATA and andre@3: * either only 2 entries OVFLPAGE marker is explicit there andre@3: * is freespace on the page. andre@3: */ andre@3: if (bp[2] == FULL_KEY_DATA && andre@3: ((n == 2) || (bp[n] == OVFLPAGE) || (FREESPACE(bp)))) andre@3: break; andre@3: andre@3: /* LJM bound the size of n to reasonable limits andre@3: */ andre@3: if(n > hashp->BSIZE/sizeof(uint16)) andre@3: return(0); andre@3: andre@3: pageno = bp[n - 1]; andre@3: bufp = __get_buf(hashp, pageno, bufp, 0); andre@3: if (!bufp) andre@3: return (0); /* Need to indicate an error! */ andre@3: bp = (uint16 *)bufp->page; andre@3: } andre@3: andre@3: *bpp = bufp; andre@3: if (bp[0] > 2) andre@3: return (bp[3]); andre@3: else andre@3: return (0); andre@3: } andre@3: andre@3: /* andre@3: * Return the data for the key/data pair that begins on this page at this andre@3: * index (index should always be 1). andre@3: */ andre@3: extern int andre@3: __big_return( andre@3: HTAB *hashp, andre@3: BUFHEAD *bufp, andre@3: int ndx, andre@3: DBT *val, andre@3: int set_current) andre@3: { andre@3: BUFHEAD *save_p; andre@3: uint16 *bp, len, off, save_addr; andre@3: char *tp; andre@3: int save_flags; andre@3: andre@3: bp = (uint16 *)bufp->page; andre@3: while (bp[ndx + 1] == PARTIAL_KEY) { andre@3: bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0); andre@3: if (!bufp) andre@3: return (-1); andre@3: bp = (uint16 *)bufp->page; andre@3: ndx = 1; andre@3: } andre@3: andre@3: if (bp[ndx + 1] == FULL_KEY) { andre@3: bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0); andre@3: if (!bufp) andre@3: return (-1); andre@3: bp = (uint16 *)bufp->page; andre@3: save_p = bufp; andre@3: save_addr = save_p->addr; andre@3: off = bp[1]; andre@3: len = 0; andre@3: } else andre@3: if (!FREESPACE(bp)) { andre@3: /* andre@3: * This is a hack. We can't distinguish between andre@3: * FULL_KEY_DATA that contains complete data or andre@3: * incomplete data, so we require that if the data andre@3: * is complete, there is at least 1 byte of free andre@3: * space left. andre@3: */ andre@3: off = bp[bp[0]]; andre@3: len = bp[1] - off; andre@3: save_p = bufp; andre@3: save_addr = bufp->addr; andre@3: bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0); andre@3: if (!bufp) andre@3: return (-1); andre@3: bp = (uint16 *)bufp->page; andre@3: } else { andre@3: /* The data is all on one page. */ andre@3: tp = (char *)bp; andre@3: off = bp[bp[0]]; andre@3: val->data = (uint8 *)tp + off; andre@3: val->size = bp[1] - off; andre@3: if (set_current) { andre@3: if (bp[0] == 2) { /* No more buckets in andre@3: * chain */ andre@3: hashp->cpage = NULL; andre@3: hashp->cbucket++; andre@3: hashp->cndx = 1; andre@3: } else { andre@3: hashp->cpage = __get_buf(hashp, andre@3: bp[bp[0] - 1], bufp, 0); andre@3: if (!hashp->cpage) andre@3: return (-1); andre@3: hashp->cndx = 1; andre@3: if (!((uint16 *) andre@3: hashp->cpage->page)[0]) { andre@3: hashp->cbucket++; andre@3: hashp->cpage = NULL; andre@3: } andre@3: } andre@3: } andre@3: return (0); andre@3: } andre@3: andre@3: /* pin our saved buf so that we don't lose if andre@3: * we run out of buffers */ andre@3: save_flags = save_p->flags; andre@3: save_p->flags |= BUF_PIN; andre@3: val->size = collect_data(hashp, bufp, (int)len, set_current); andre@3: save_p->flags = save_flags; andre@3: if (val->size == (size_t)-1) andre@3: return (-1); andre@3: if (save_p->addr != save_addr) { andre@3: /* We are pretty short on buffers. */ andre@3: errno = EINVAL; /* OUT OF BUFFERS */ andre@3: return (-1); andre@3: } andre@3: memmove(hashp->tmp_buf, (save_p->page) + off, len); andre@3: val->data = (uint8 *)hashp->tmp_buf; andre@3: return (0); andre@3: } andre@3: andre@3: andre@3: /* andre@3: * Count how big the total datasize is by looping through the pages. Then andre@3: * allocate a buffer and copy the data in the second loop. NOTE: Our caller andre@3: * may already have a bp which it is holding onto. The caller is andre@3: * responsible for copying that bp into our temp buffer. 'len' is how much andre@3: * space to reserve for that buffer. andre@3: */ andre@3: static int andre@3: collect_data( andre@3: HTAB *hashp, andre@3: BUFHEAD *bufp, andre@3: int len, int set) andre@3: { andre@3: register uint16 *bp; andre@3: BUFHEAD *save_bufp; andre@3: int save_flags; andre@3: int mylen, totlen; andre@3: andre@3: /* andre@3: * save the input buf head because we need to walk the list twice. andre@3: * pin it to make sure it doesn't leave the buffer pool. andre@3: * This has the effect of growing the buffer pool if necessary. andre@3: */ andre@3: save_bufp = bufp; andre@3: save_flags = save_bufp->flags; andre@3: save_bufp->flags |= BUF_PIN; andre@3: andre@3: /* read the length of the buffer */ andre@3: for (totlen = len; bufp ; bufp = __get_buf(hashp, bp[bp[0]-1], bufp, 0)) { andre@3: bp = (uint16 *)bufp->page; andre@3: mylen = hashp->BSIZE - bp[1]; andre@3: andre@3: /* if mylen ever goes negative it means that the andre@3: * page is screwed up. andre@3: */ andre@3: if (mylen < 0) { andre@3: save_bufp->flags = save_flags; andre@3: return (-1); andre@3: } andre@3: totlen += mylen; andre@3: if (bp[2] == FULL_KEY_DATA) { /* End of Data */ andre@3: break; andre@3: } andre@3: } andre@3: andre@3: if (!bufp) { andre@3: save_bufp->flags = save_flags; andre@3: return (-1); andre@3: } andre@3: andre@3: /* allocate a temp buf */ andre@3: if (hashp->tmp_buf) andre@3: free(hashp->tmp_buf); andre@3: if ((hashp->tmp_buf = (char *)malloc((size_t)totlen)) == NULL) { andre@3: save_bufp->flags = save_flags; andre@3: return (-1); andre@3: } andre@3: andre@3: /* copy the buffers back into temp buf */ andre@3: for (bufp = save_bufp; bufp ; andre@3: bufp = __get_buf(hashp, bp[bp[0]-1], bufp, 0)) { andre@3: bp = (uint16 *)bufp->page; andre@3: mylen = hashp->BSIZE - bp[1]; andre@3: memmove(&hashp->tmp_buf[len], (bufp->page) + bp[1], (size_t)mylen); andre@3: len += mylen; andre@3: if (bp[2] == FULL_KEY_DATA) { andre@3: break; andre@3: } andre@3: } andre@3: andre@3: /* 'clear' the pin flags */ andre@3: save_bufp->flags = save_flags; andre@3: andre@3: /* update the database cursor */ andre@3: if (set) { andre@3: hashp->cndx = 1; andre@3: if (bp[0] == 2) { /* No more buckets in chain */ andre@3: hashp->cpage = NULL; andre@3: hashp->cbucket++; andre@3: } else { andre@3: hashp->cpage = __get_buf(hashp, bp[bp[0] - 1], bufp, 0); andre@3: if (!hashp->cpage) andre@3: return (-1); andre@3: else if (!((uint16 *)hashp->cpage->page)[0]) { andre@3: hashp->cbucket++; andre@3: hashp->cpage = NULL; andre@3: } andre@3: } andre@3: } andre@3: return (totlen); andre@3: } andre@3: andre@3: /* andre@3: * Fill in the key and data for this big pair. andre@3: */ andre@3: extern int andre@3: __big_keydata( andre@3: HTAB *hashp, andre@3: BUFHEAD *bufp, andre@3: DBT *key, DBT *val, andre@3: int set) andre@3: { andre@3: key->size = collect_key(hashp, bufp, 0, val, set); andre@3: if (key->size == (size_t)-1) andre@3: return (-1); andre@3: key->data = (uint8 *)hashp->tmp_key; andre@3: return (0); andre@3: } andre@3: andre@3: /* andre@3: * Count how big the total key size is by recursing through the pages. Then andre@3: * collect the data, allocate a buffer and copy the key as you recurse up. andre@3: */ andre@3: static int andre@3: collect_key( andre@3: HTAB *hashp, andre@3: BUFHEAD *bufp, andre@3: int len, andre@3: DBT *val, andre@3: int set) andre@3: { andre@3: BUFHEAD *xbp; andre@3: char *p; andre@3: int mylen, totlen; andre@3: uint16 *bp, save_addr; andre@3: andre@3: p = bufp->page; andre@3: bp = (uint16 *)p; andre@3: mylen = hashp->BSIZE - bp[1]; andre@3: andre@3: save_addr = bufp->addr; andre@3: totlen = len + mylen; andre@3: if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) { /* End of Key. */ andre@3: if (hashp->tmp_key != NULL) andre@3: free(hashp->tmp_key); andre@3: if ((hashp->tmp_key = (char *)malloc((size_t)totlen)) == NULL) andre@3: return (-1); andre@3: if (__big_return(hashp, bufp, 1, val, set)) andre@3: return (-1); andre@3: } else { andre@3: xbp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0); andre@3: if (!xbp || ((totlen = andre@3: collect_key(hashp, xbp, totlen, val, set)) < 1)) andre@3: return (-1); andre@3: } andre@3: if (bufp->addr != save_addr) { andre@3: errno = EINVAL; /* MIS -- OUT OF BUFFERS */ andre@3: return (-1); andre@3: } andre@3: memmove(&hashp->tmp_key[len], (bufp->page) + bp[1], (size_t)mylen); andre@3: return (totlen); andre@3: } andre@3: andre@3: /* andre@3: * Returns: andre@3: * 0 => OK andre@3: * -1 => error andre@3: */ andre@3: extern int andre@3: __big_split( andre@3: HTAB *hashp, andre@3: BUFHEAD *op, /* Pointer to where to put keys that go in old bucket */ andre@3: BUFHEAD *np, /* Pointer to new bucket page */ andre@3: /* Pointer to first page containing the big key/data */ andre@3: BUFHEAD *big_keyp, andre@3: uint32 addr, /* Address of big_keyp */ andre@3: uint32 obucket,/* Old Bucket */ andre@3: SPLIT_RETURN *ret) andre@3: { andre@3: register BUFHEAD *tmpp; andre@3: register uint16 *tp; andre@3: BUFHEAD *bp; andre@3: DBT key, val; andre@3: uint32 change; andre@3: uint16 free_space, n, off; andre@3: andre@3: bp = big_keyp; andre@3: andre@3: /* Now figure out where the big key/data goes */ andre@3: if (__big_keydata(hashp, big_keyp, &key, &val, 0)) andre@3: return (-1); andre@3: change = (__call_hash(hashp,(char*) key.data, key.size) != obucket); andre@3: andre@3: if ((ret->next_addr = __find_last_page(hashp, &big_keyp))) { andre@3: if (!(ret->nextp = andre@3: __get_buf(hashp, ret->next_addr, big_keyp, 0))) andre@3: return (-1);; andre@3: } else andre@3: ret->nextp = NULL; andre@3: andre@3: /* Now make one of np/op point to the big key/data pair */ andre@3: #ifdef DEBUG andre@3: assert(np->ovfl == NULL); andre@3: #endif andre@3: if (change) andre@3: tmpp = np; andre@3: else andre@3: tmpp = op; andre@3: andre@3: tmpp->flags |= BUF_MOD; andre@3: #ifdef DEBUG1 andre@3: (void)fprintf(stderr, andre@3: "BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr, andre@3: (tmpp->ovfl ? tmpp->ovfl->addr : 0), (bp ? bp->addr : 0)); andre@3: #endif andre@3: tmpp->ovfl = bp; /* one of op/np point to big_keyp */ andre@3: tp = (uint16 *)tmpp->page; andre@3: andre@3: andre@3: #if 0 /* this get's tripped on database corrupted error */ andre@3: assert(FREESPACE(tp) >= OVFLSIZE); andre@3: #endif andre@3: if(FREESPACE(tp) < OVFLSIZE) andre@3: return(DATABASE_CORRUPTED_ERROR); andre@3: andre@3: n = tp[0]; andre@3: off = OFFSET(tp); andre@3: free_space = FREESPACE(tp); andre@3: tp[++n] = (uint16)addr; andre@3: tp[++n] = OVFLPAGE; andre@3: tp[0] = n; andre@3: OFFSET(tp) = off; andre@3: FREESPACE(tp) = free_space - OVFLSIZE; andre@3: andre@3: /* andre@3: * Finally, set the new and old return values. BIG_KEYP contains a andre@3: * pointer to the last page of the big key_data pair. Make sure that andre@3: * big_keyp has no following page (2 elements) or create an empty andre@3: * following page. andre@3: */ andre@3: andre@3: ret->newp = np; andre@3: ret->oldp = op; andre@3: andre@3: tp = (uint16 *)big_keyp->page; andre@3: big_keyp->flags |= BUF_MOD; andre@3: if (tp[0] > 2) { andre@3: /* andre@3: * There may be either one or two offsets on this page. If andre@3: * there is one, then the overflow page is linked on normally andre@3: * and tp[4] is OVFLPAGE. If there are two, tp[4] contains andre@3: * the second offset and needs to get stuffed in after the andre@3: * next overflow page is added. andre@3: */ andre@3: n = tp[4]; andre@3: free_space = FREESPACE(tp); andre@3: off = OFFSET(tp); andre@3: tp[0] -= 2; andre@3: FREESPACE(tp) = free_space + OVFLSIZE; andre@3: OFFSET(tp) = off; andre@3: tmpp = __add_ovflpage(hashp, big_keyp); andre@3: if (!tmpp) andre@3: return (-1); andre@3: tp[4] = n; andre@3: } else andre@3: tmpp = big_keyp; andre@3: andre@3: if (change) andre@3: ret->newp = tmpp; andre@3: else andre@3: ret->oldp = tmpp; andre@3: return (0); andre@3: }