146364Sbostic /*-
261202Sbostic * Copyright (c) 1990, 1993
361202Sbostic * The Regents of the University of California. All rights reserved.
446364Sbostic *
546364Sbostic * This code is derived from software contributed to Berkeley by
646364Sbostic * Margo Seltzer.
746364Sbostic *
846364Sbostic * %sccs.include.redist.c%
946364Sbostic */
1046364Sbostic
1146364Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*66215Sbostic static char sccsid[] = "@(#)hash_bigkey.c 8.2 (Berkeley) 02/21/94";
1346364Sbostic #endif /* LIBC_SCCS and not lint */
1446364Sbostic
1550997Sbostic /*
1650997Sbostic * PACKAGE: hash
1750997Sbostic * DESCRIPTION:
1850997Sbostic * Big key/data handling for the hashing package.
1950997Sbostic *
2050997Sbostic * ROUTINES:
2150997Sbostic * External
2250997Sbostic * __big_keydata
2350997Sbostic * __big_split
2450997Sbostic * __big_insert
2550997Sbostic * __big_return
2650997Sbostic * __big_delete
2750997Sbostic * __find_last_page
2850997Sbostic * Internal
2950997Sbostic * collect_key
3050997Sbostic * collect_data
3150997Sbostic */
3246364Sbostic
3346644Sbostic #include <sys/param.h>
3457586Sbostic
3546364Sbostic #include <errno.h>
3646364Sbostic #include <stdio.h>
3746562Sbostic #include <stdlib.h>
3846562Sbostic #include <string.h>
3957586Sbostic
4050997Sbostic #ifdef DEBUG
4150997Sbostic #include <assert.h>
4250997Sbostic #endif
4357586Sbostic
4457932Sbostic #include <db.h>
4546364Sbostic #include "hash.h"
4646364Sbostic #include "page.h"
4750997Sbostic #include "extern.h"
4846364Sbostic
4957586Sbostic static int collect_key __P((HTAB *, BUFHEAD *, int, DBT *, int));
5057586Sbostic static int collect_data __P((HTAB *, BUFHEAD *, int, int));
5146364Sbostic
5246364Sbostic /*
5350997Sbostic * Big_insert
5450997Sbostic *
5550997Sbostic * You need to do an insert and the key/data pair is too big
5650997Sbostic *
5750997Sbostic * Returns:
5850997Sbostic * 0 ==> OK
5950997Sbostic *-1 ==> ERROR
6050997Sbostic */
6146364Sbostic extern int
6257586Sbostic __big_insert(hashp, bufp, key, val)
6357586Sbostic HTAB *hashp;
6450997Sbostic BUFHEAD *bufp;
6550997Sbostic const DBT *key, *val;
6646364Sbostic {
6750997Sbostic register u_short *p;
6850997Sbostic int key_size, n, val_size;
6950997Sbostic u_short space, move_bytes, off;
7050997Sbostic char *cp, *key_data, *val_data;
7146364Sbostic
7250997Sbostic cp = bufp->page; /* Character pointer of p. */
7350997Sbostic p = (u_short *)cp;
7446364Sbostic
7550997Sbostic key_data = (char *)key->data;
7650997Sbostic key_size = key->size;
7750997Sbostic val_data = (char *)val->data;
7850997Sbostic val_size = val->size;
7950997Sbostic
8050997Sbostic /* First move the Key */
8150997Sbostic for (space = FREESPACE(p) - BIGOVERHEAD; key_size;
8250997Sbostic space = FREESPACE(p) - BIGOVERHEAD) {
8350997Sbostic move_bytes = MIN(space, key_size);
8450997Sbostic off = OFFSET(p) - move_bytes;
8558016Sbostic memmove(cp + off, key_data, move_bytes);
8650997Sbostic key_size -= move_bytes;
8750997Sbostic key_data += move_bytes;
8850997Sbostic n = p[0];
8950997Sbostic p[++n] = off;
9050997Sbostic p[0] = ++n;
9150997Sbostic FREESPACE(p) = off - PAGE_META(n);
9250997Sbostic OFFSET(p) = off;
9350997Sbostic p[n] = PARTIAL_KEY;
9457586Sbostic bufp = __add_ovflpage(hashp, bufp);
9550997Sbostic if (!bufp)
9650997Sbostic return (-1);
9750997Sbostic n = p[0];
9850997Sbostic if (!key_size)
9950997Sbostic if (FREESPACE(p)) {
10050997Sbostic move_bytes = MIN(FREESPACE(p), val_size);
10150997Sbostic off = OFFSET(p) - move_bytes;
10250997Sbostic p[n] = off;
10358016Sbostic memmove(cp + off, val_data, move_bytes);
10450997Sbostic val_data += move_bytes;
10550997Sbostic val_size -= move_bytes;
10650997Sbostic p[n - 2] = FULL_KEY_DATA;
10750997Sbostic FREESPACE(p) = FREESPACE(p) - move_bytes;
10850997Sbostic OFFSET(p) = off;
10950997Sbostic } else
11050997Sbostic p[n - 2] = FULL_KEY;
11150997Sbostic p = (u_short *)bufp->page;
11250997Sbostic cp = bufp->page;
11350997Sbostic bufp->flags |= BUF_MOD;
11446364Sbostic }
11550997Sbostic
11650997Sbostic /* Now move the data */
11750997Sbostic for (space = FREESPACE(p) - BIGOVERHEAD; val_size;
11850997Sbostic space = FREESPACE(p) - BIGOVERHEAD) {
11950997Sbostic move_bytes = MIN(space, val_size);
12050997Sbostic /*
12150997Sbostic * Here's the hack to make sure that if the data ends on the
12250997Sbostic * same page as the key ends, FREESPACE is at least one.
12350997Sbostic */
12450997Sbostic if (space == val_size && val_size == val->size)
12550997Sbostic move_bytes--;
12646364Sbostic off = OFFSET(p) - move_bytes;
12758016Sbostic memmove(cp + off, val_data, move_bytes);
12850997Sbostic val_size -= move_bytes;
12946364Sbostic val_data += move_bytes;
13050997Sbostic n = p[0];
13150997Sbostic p[++n] = off;
13250997Sbostic p[0] = ++n;
13350997Sbostic FREESPACE(p) = off - PAGE_META(n);
13446364Sbostic OFFSET(p) = off;
13550997Sbostic if (val_size) {
13650997Sbostic p[n] = FULL_KEY;
13757586Sbostic bufp = __add_ovflpage(hashp, bufp);
13850997Sbostic if (!bufp)
13950997Sbostic return (-1);
14050997Sbostic cp = bufp->page;
14150997Sbostic p = (u_short *)cp;
14250997Sbostic } else
14350997Sbostic p[n] = FULL_KEY_DATA;
14450997Sbostic bufp->flags |= BUF_MOD;
14546364Sbostic }
14650997Sbostic return (0);
14746364Sbostic }
14846364Sbostic
14946364Sbostic /*
15050997Sbostic * Called when bufp's page contains a partial key (index should be 1)
15150997Sbostic *
15250997Sbostic * All pages in the big key/data pair except bufp are freed. We cannot
15350997Sbostic * free bufp because the page pointing to it is lost and we can't get rid
15450997Sbostic * of its pointer.
15550997Sbostic *
15650997Sbostic * Returns:
15750997Sbostic * 0 => OK
15850997Sbostic *-1 => ERROR
15950997Sbostic */
16046364Sbostic extern int
16157586Sbostic __big_delete(hashp, bufp)
16257586Sbostic HTAB *hashp;
16350997Sbostic BUFHEAD *bufp;
16446364Sbostic {
16550997Sbostic register BUFHEAD *last_bfp, *rbufp;
16650997Sbostic u_short *bp, pageno;
16750997Sbostic int key_done, n;
16846364Sbostic
16950997Sbostic rbufp = bufp;
17050997Sbostic last_bfp = NULL;
17150997Sbostic bp = (u_short *)bufp->page;
17250997Sbostic pageno = 0;
17350997Sbostic key_done = 0;
17450997Sbostic
17546364Sbostic while (!key_done || (bp[2] != FULL_KEY_DATA)) {
17650997Sbostic if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA)
17750997Sbostic key_done = 1;
17846364Sbostic
17950997Sbostic /*
18050997Sbostic * If there is freespace left on a FULL_KEY_DATA page, then
18150997Sbostic * the data is short and fits entirely on this page, and this
18250997Sbostic * is the last page.
18350997Sbostic */
18450997Sbostic if (bp[2] == FULL_KEY_DATA && FREESPACE(bp))
18550997Sbostic break;
18650997Sbostic pageno = bp[bp[0] - 1];
18750997Sbostic rbufp->flags |= BUF_MOD;
18857586Sbostic rbufp = __get_buf(hashp, pageno, rbufp, 0);
18950997Sbostic if (last_bfp)
19057586Sbostic __free_ovflpage(hashp, last_bfp);
19150997Sbostic last_bfp = rbufp;
19250997Sbostic if (!rbufp)
19350997Sbostic return (-1); /* Error. */
19450997Sbostic bp = (u_short *)rbufp->page;
19546364Sbostic }
19646364Sbostic
19750997Sbostic /*
19850997Sbostic * If we get here then rbufp points to the last page of the big
19950997Sbostic * key/data pair. Bufp points to the first one -- it should now be
20050997Sbostic * empty pointing to the next page after this pair. Can't free it
20150997Sbostic * because we don't have the page pointing to it.
20250997Sbostic */
20346364Sbostic
20450997Sbostic /* This is information from the last page of the pair. */
20546364Sbostic n = bp[0];
20650997Sbostic pageno = bp[n - 1];
20746364Sbostic
20850997Sbostic /* Now, bp is the first page of the pair. */
20946364Sbostic bp = (u_short *)bufp->page;
21050997Sbostic if (n > 2) {
21150997Sbostic /* There is an overflow page. */
21250997Sbostic bp[1] = pageno;
21350997Sbostic bp[2] = OVFLPAGE;
21450997Sbostic bufp->ovfl = rbufp->ovfl;
21550997Sbostic } else
21650997Sbostic /* This is the last page. */
21750997Sbostic bufp->ovfl = NULL;
21846364Sbostic n -= 2;
21946364Sbostic bp[0] = n;
22046364Sbostic FREESPACE(bp) = hashp->BSIZE - PAGE_META(n);
22146364Sbostic OFFSET(bp) = hashp->BSIZE - 1;
22246364Sbostic
22346364Sbostic bufp->flags |= BUF_MOD;
22450997Sbostic if (rbufp)
22557586Sbostic __free_ovflpage(hashp, rbufp);
22650997Sbostic if (last_bfp != rbufp)
22757586Sbostic __free_ovflpage(hashp, last_bfp);
22846364Sbostic
22946364Sbostic hashp->NKEYS--;
23050997Sbostic return (0);
23146364Sbostic }
23246364Sbostic /*
23350997Sbostic * Returns:
23450997Sbostic * 0 = key not found
23550997Sbostic * -1 = get next overflow page
23650997Sbostic * -2 means key not found and this is big key/data
23750997Sbostic * -3 error
23850997Sbostic */
23946364Sbostic extern int
24057586Sbostic __find_bigpair(hashp, bufp, ndx, key, size)
24157586Sbostic HTAB *hashp;
24250997Sbostic BUFHEAD *bufp;
24350997Sbostic int ndx;
24450997Sbostic char *key;
24550997Sbostic int size;
24646364Sbostic {
24750997Sbostic register u_short *bp;
24850997Sbostic register char *p;
24950997Sbostic int ksize;
25050997Sbostic u_short bytes;
25150997Sbostic char *kkey;
25246364Sbostic
25350997Sbostic bp = (u_short *)bufp->page;
25450997Sbostic p = bufp->page;
25550997Sbostic ksize = size;
25650997Sbostic kkey = key;
25746364Sbostic
25850997Sbostic for (bytes = hashp->BSIZE - bp[ndx];
25950997Sbostic bytes <= size && bp[ndx + 1] == PARTIAL_KEY;
26050997Sbostic bytes = hashp->BSIZE - bp[ndx]) {
26158016Sbostic if (memcmp(p + bp[ndx], kkey, bytes))
26250997Sbostic return (-2);
26350997Sbostic kkey += bytes;
26450997Sbostic ksize -= bytes;
26557586Sbostic bufp = __get_buf(hashp, bp[ndx + 2], bufp, 0);
26650997Sbostic if (!bufp)
26750997Sbostic return (-3);
26850997Sbostic p = bufp->page;
26950997Sbostic bp = (u_short *)p;
27050997Sbostic ndx = 1;
27146364Sbostic }
27246364Sbostic
27358016Sbostic if (bytes != ksize || memcmp(p + bp[ndx], kkey, bytes)) {
27446364Sbostic #ifdef HASH_STATISTICS
27550997Sbostic ++hash_collisions;
27646364Sbostic #endif
27750997Sbostic return (-2);
27850997Sbostic } else
27950997Sbostic return (ndx);
28046364Sbostic }
28146364Sbostic
28246364Sbostic /*
28350997Sbostic * Given the buffer pointer of the first overflow page of a big pair,
28450997Sbostic * find the end of the big pair
28550997Sbostic *
28650997Sbostic * This will set bpp to the buffer header of the last page of the big pair.
28750997Sbostic * It will return the pageno of the overflow page following the last page
28850997Sbostic * of the pair; 0 if there isn't any (i.e. big pair is the last key in the
28950997Sbostic * bucket)
29050997Sbostic */
29146364Sbostic extern u_short
29257586Sbostic __find_last_page(hashp, bpp)
29357586Sbostic HTAB *hashp;
29450997Sbostic BUFHEAD **bpp;
29546364Sbostic {
29650997Sbostic BUFHEAD *bufp;
29750997Sbostic u_short *bp, pageno;
29850997Sbostic int n;
29946364Sbostic
30050997Sbostic bufp = *bpp;
30150997Sbostic bp = (u_short *)bufp->page;
30250997Sbostic for (;;) {
30350997Sbostic n = bp[0];
30446364Sbostic
30550997Sbostic /*
30650997Sbostic * This is the last page if: the tag is FULL_KEY_DATA and
30750997Sbostic * either only 2 entries OVFLPAGE marker is explicit there
30850997Sbostic * is freespace on the page.
30950997Sbostic */
31050997Sbostic if (bp[2] == FULL_KEY_DATA &&
31150997Sbostic ((n == 2) || (bp[n] == OVFLPAGE) || (FREESPACE(bp))))
31250997Sbostic break;
31346364Sbostic
31450997Sbostic pageno = bp[n - 1];
31557586Sbostic bufp = __get_buf(hashp, pageno, bufp, 0);
31650997Sbostic if (!bufp)
31750997Sbostic return (0); /* Need to indicate an error! */
31850997Sbostic bp = (u_short *)bufp->page;
31946364Sbostic }
32046364Sbostic
32146364Sbostic *bpp = bufp;
32250997Sbostic if (bp[0] > 2)
32350997Sbostic return (bp[3]);
32450997Sbostic else
32550997Sbostic return (0);
32646364Sbostic }
32746364Sbostic
32846364Sbostic /*
32950997Sbostic * Return the data for the key/data pair that begins on this page at this
33050997Sbostic * index (index should always be 1).
33150997Sbostic */
33246364Sbostic extern int
33357586Sbostic __big_return(hashp, bufp, ndx, val, set_current)
33457586Sbostic HTAB *hashp;
33550997Sbostic BUFHEAD *bufp;
33650997Sbostic int ndx;
33750997Sbostic DBT *val;
33850997Sbostic int set_current;
33946364Sbostic {
34050997Sbostic BUFHEAD *save_p;
34150997Sbostic u_short *bp, len, off, save_addr;
34250997Sbostic char *tp;
34346364Sbostic
34446364Sbostic bp = (u_short *)bufp->page;
34550997Sbostic while (bp[ndx + 1] == PARTIAL_KEY) {
34657586Sbostic bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
34750997Sbostic if (!bufp)
34850997Sbostic return (-1);
34950997Sbostic bp = (u_short *)bufp->page;
35050997Sbostic ndx = 1;
35150997Sbostic }
35246364Sbostic
35350997Sbostic if (bp[ndx + 1] == FULL_KEY) {
35457586Sbostic bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
35550997Sbostic if (!bufp)
35650997Sbostic return (-1);
35750997Sbostic bp = (u_short *)bufp->page;
35850997Sbostic save_p = bufp;
35950997Sbostic save_addr = save_p->addr;
36050997Sbostic off = bp[1];
36150997Sbostic len = 0;
36250997Sbostic } else
36350997Sbostic if (!FREESPACE(bp)) {
36450997Sbostic /*
36550997Sbostic * This is a hack. We can't distinguish between
36650997Sbostic * FULL_KEY_DATA that contains complete data or
36750997Sbostic * incomplete data, so we require that if the data
36850997Sbostic * is complete, there is at least 1 byte of free
36950997Sbostic * space left.
37050997Sbostic */
37150997Sbostic off = bp[bp[0]];
37250997Sbostic len = bp[1] - off;
37350997Sbostic save_p = bufp;
37450997Sbostic save_addr = bufp->addr;
37557586Sbostic bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
37650997Sbostic if (!bufp)
37750997Sbostic return (-1);
37850997Sbostic bp = (u_short *)bufp->page;
37950997Sbostic } else {
38050997Sbostic /* The data is all on one page. */
38150997Sbostic tp = (char *)bp;
38250997Sbostic off = bp[bp[0]];
38350997Sbostic val->data = (u_char *)tp + off;
38450997Sbostic val->size = bp[1] - off;
38550997Sbostic if (set_current) {
38650997Sbostic if (bp[0] == 2) { /* No more buckets in
38750997Sbostic * chain */
38850997Sbostic hashp->cpage = NULL;
38950997Sbostic hashp->cbucket++;
39050997Sbostic hashp->cndx = 1;
39150997Sbostic } else {
39257586Sbostic hashp->cpage = __get_buf(hashp,
39357586Sbostic bp[bp[0] - 1], bufp, 0);
39450997Sbostic if (!hashp->cpage)
39550997Sbostic return (-1);
39650997Sbostic hashp->cndx = 1;
39750997Sbostic if (!((u_short *)
39850997Sbostic hashp->cpage->page)[0]) {
39950997Sbostic hashp->cbucket++;
40050997Sbostic hashp->cpage = NULL;
40150997Sbostic }
40250997Sbostic }
40350997Sbostic }
40450997Sbostic return (0);
40546364Sbostic }
40650997Sbostic
40757586Sbostic val->size = collect_data(hashp, bufp, (int)len, set_current);
40850997Sbostic if (val->size == -1)
40950997Sbostic return (-1);
41050997Sbostic if (save_p->addr != save_addr) {
41150997Sbostic /* We are pretty short on buffers. */
41250997Sbostic errno = EINVAL; /* OUT OF BUFFERS */
41350997Sbostic return (-1);
41446364Sbostic }
41558016Sbostic memmove(hashp->tmp_buf, (save_p->page) + off, len);
41650997Sbostic val->data = (u_char *)hashp->tmp_buf;
41750997Sbostic return (0);
41846364Sbostic }
41946364Sbostic /*
42050997Sbostic * Count how big the total datasize is by recursing through the pages. Then
42150997Sbostic * allocate a buffer and copy the data as you recurse up.
42250997Sbostic */
42346364Sbostic static int
collect_data(hashp,bufp,len,set)42457586Sbostic collect_data(hashp, bufp, len, set)
42557586Sbostic HTAB *hashp;
42650997Sbostic BUFHEAD *bufp;
42750997Sbostic int len, set;
42846364Sbostic {
42950997Sbostic register u_short *bp;
43050997Sbostic register char *p;
43150997Sbostic BUFHEAD *xbp;
43250997Sbostic u_short save_addr;
43350997Sbostic int mylen, totlen;
43446364Sbostic
43550997Sbostic p = bufp->page;
43650997Sbostic bp = (u_short *)p;
43750997Sbostic mylen = hashp->BSIZE - bp[1];
43850997Sbostic save_addr = bufp->addr;
43946364Sbostic
44050997Sbostic if (bp[2] == FULL_KEY_DATA) { /* End of Data */
44150997Sbostic totlen = len + mylen;
44250997Sbostic if (hashp->tmp_buf)
44350997Sbostic free(hashp->tmp_buf);
444*66215Sbostic if ((hashp->tmp_buf = (char *)malloc(totlen)) == NULL)
44550997Sbostic return (-1);
44650997Sbostic if (set) {
44750997Sbostic hashp->cndx = 1;
44850997Sbostic if (bp[0] == 2) { /* No more buckets in chain */
44950997Sbostic hashp->cpage = NULL;
45050997Sbostic hashp->cbucket++;
45150997Sbostic } else {
45250997Sbostic hashp->cpage =
45357586Sbostic __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
45450997Sbostic if (!hashp->cpage)
45550997Sbostic return (-1);
45650997Sbostic else if (!((u_short *)hashp->cpage->page)[0]) {
45750997Sbostic hashp->cbucket++;
45850997Sbostic hashp->cpage = NULL;
45950997Sbostic }
46050997Sbostic }
46146364Sbostic }
46250997Sbostic } else {
46357586Sbostic xbp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
46457586Sbostic if (!xbp || ((totlen =
46557586Sbostic collect_data(hashp, xbp, len + mylen, set)) < 1))
46650997Sbostic return (-1);
46746364Sbostic }
46850997Sbostic if (bufp->addr != save_addr) {
46950997Sbostic errno = EINVAL; /* Out of buffers. */
47050997Sbostic return (-1);
47146364Sbostic }
47258016Sbostic memmove(&hashp->tmp_buf[len], (bufp->page) + bp[1], mylen);
47350997Sbostic return (totlen);
47446364Sbostic }
47546364Sbostic
47646364Sbostic /*
47750997Sbostic * Fill in the key and data for this big pair.
47850997Sbostic */
47946364Sbostic extern int
48057586Sbostic __big_keydata(hashp, bufp, key, val, set)
48157586Sbostic HTAB *hashp;
48250997Sbostic BUFHEAD *bufp;
48350997Sbostic DBT *key, *val;
48450997Sbostic int set;
48546364Sbostic {
48657586Sbostic key->size = collect_key(hashp, bufp, 0, val, set);
48750997Sbostic if (key->size == -1)
48850997Sbostic return (-1);
48950997Sbostic key->data = (u_char *)hashp->tmp_key;
49050997Sbostic return (0);
49146364Sbostic }
49246364Sbostic
49346364Sbostic /*
49450997Sbostic * Count how big the total key size is by recursing through the pages. Then
49550997Sbostic * collect the data, allocate a buffer and copy the key as you recurse up.
49650997Sbostic */
49746364Sbostic static int
collect_key(hashp,bufp,len,val,set)49857586Sbostic collect_key(hashp, bufp, len, val, set)
49957586Sbostic HTAB *hashp;
50050997Sbostic BUFHEAD *bufp;
50150997Sbostic int len;
50250997Sbostic DBT *val;
50350997Sbostic int set;
50446364Sbostic {
50550997Sbostic BUFHEAD *xbp;
50650997Sbostic char *p;
50750997Sbostic int mylen, totlen;
50850997Sbostic u_short *bp, save_addr;
50946364Sbostic
51050997Sbostic p = bufp->page;
51150997Sbostic bp = (u_short *)p;
51250997Sbostic mylen = hashp->BSIZE - bp[1];
51346364Sbostic
51450997Sbostic save_addr = bufp->addr;
51550997Sbostic totlen = len + mylen;
51650997Sbostic if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) { /* End of Key. */
517*66215Sbostic if (hashp->tmp_key != NULL)
51850997Sbostic free(hashp->tmp_key);
519*66215Sbostic if ((hashp->tmp_key = (char *)malloc(totlen)) == NULL)
52050997Sbostic return (-1);
52157586Sbostic if (__big_return(hashp, bufp, 1, val, set))
52251046Sbostic return (-1);
52350997Sbostic } else {
52457586Sbostic xbp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
52557586Sbostic if (!xbp || ((totlen =
52657586Sbostic collect_key(hashp, xbp, totlen, val, set)) < 1))
52750997Sbostic return (-1);
52846364Sbostic }
52950997Sbostic if (bufp->addr != save_addr) {
53050997Sbostic errno = EINVAL; /* MIS -- OUT OF BUFFERS */
53150997Sbostic return (-1);
53246364Sbostic }
53358016Sbostic memmove(&hashp->tmp_key[len], (bufp->page) + bp[1], mylen);
53450997Sbostic return (totlen);
53546364Sbostic }
53646364Sbostic
53746364Sbostic /*
53850997Sbostic * Returns:
53950997Sbostic * 0 => OK
54050997Sbostic * -1 => error
54150997Sbostic */
54246364Sbostic extern int
54357586Sbostic __big_split(hashp, op, np, big_keyp, addr, obucket, ret)
54457586Sbostic HTAB *hashp;
54550997Sbostic BUFHEAD *op; /* Pointer to where to put keys that go in old bucket */
54650997Sbostic BUFHEAD *np; /* Pointer to new bucket page */
54750997Sbostic /* Pointer to first page containing the big key/data */
54850997Sbostic BUFHEAD *big_keyp;
54950997Sbostic int addr; /* Address of big_keyp */
55050997Sbostic u_int obucket;/* Old Bucket */
55150997Sbostic SPLIT_RETURN *ret;
55246364Sbostic {
55350997Sbostic register BUFHEAD *tmpp;
55450997Sbostic register u_short *tp;
55550997Sbostic BUFHEAD *bp;
55650997Sbostic DBT key, val;
55750997Sbostic u_int change;
55850997Sbostic u_short free_space, n, off;
55946364Sbostic
56050997Sbostic bp = big_keyp;
56146364Sbostic
56250997Sbostic /* Now figure out where the big key/data goes */
56357586Sbostic if (__big_keydata(hashp, big_keyp, &key, &val, 0))
56450997Sbostic return (-1);
56557586Sbostic change = (__call_hash(hashp, key.data, key.size) != obucket);
56646364Sbostic
56757586Sbostic if (ret->next_addr = __find_last_page(hashp, &big_keyp)) {
56857586Sbostic if (!(ret->nextp =
56957586Sbostic __get_buf(hashp, ret->next_addr, big_keyp, 0)))
57050997Sbostic return (-1);;
57150997Sbostic } else
57250997Sbostic ret->nextp = NULL;
57346364Sbostic
57450997Sbostic /* Now make one of np/op point to the big key/data pair */
57550997Sbostic #ifdef DEBUG
57650997Sbostic assert(np->ovfl == NULL);
57750997Sbostic #endif
57850997Sbostic if (change)
57950997Sbostic tmpp = np;
58050997Sbostic else
58150997Sbostic tmpp = op;
58246364Sbostic
58350997Sbostic tmpp->flags |= BUF_MOD;
58446364Sbostic #ifdef DEBUG1
58550997Sbostic (void)fprintf(stderr,
58650997Sbostic "BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr,
58750997Sbostic (tmpp->ovfl ? tmpp->ovfl->addr : 0), (bp ? bp->addr : 0));
58846364Sbostic #endif
58950997Sbostic tmpp->ovfl = bp; /* one of op/np point to big_keyp */
59050997Sbostic tp = (u_short *)tmpp->page;
59150997Sbostic #ifdef DEBUG
59250997Sbostic assert(FREESPACE(tp) >= OVFLSIZE);
59350997Sbostic #endif
59450997Sbostic n = tp[0];
59550997Sbostic off = OFFSET(tp);
59650997Sbostic free_space = FREESPACE(tp);
59750997Sbostic tp[++n] = (u_short)addr;
59850997Sbostic tp[++n] = OVFLPAGE;
59950997Sbostic tp[0] = n;
60050997Sbostic OFFSET(tp) = off;
60150997Sbostic FREESPACE(tp) = free_space - OVFLSIZE;
60246364Sbostic
60350997Sbostic /*
60450997Sbostic * Finally, set the new and old return values. BIG_KEYP contains a
60550997Sbostic * pointer to the last page of the big key_data pair. Make sure that
60650997Sbostic * big_keyp has no following page (2 elements) or create an empty
60750997Sbostic * following page.
60850997Sbostic */
60946364Sbostic
61050997Sbostic ret->newp = np;
61150997Sbostic ret->oldp = op;
61246364Sbostic
61350997Sbostic tp = (u_short *)big_keyp->page;
61450997Sbostic big_keyp->flags |= BUF_MOD;
61550997Sbostic if (tp[0] > 2) {
61650997Sbostic /*
61750997Sbostic * There may be either one or two offsets on this page. If
61850997Sbostic * there is one, then the overflow page is linked on normally
61950997Sbostic * and tp[4] is OVFLPAGE. If there are two, tp[4] contains
62050997Sbostic * the second offset and needs to get stuffed in after the
62150997Sbostic * next overflow page is added.
62250997Sbostic */
62350997Sbostic n = tp[4];
62450997Sbostic free_space = FREESPACE(tp);
62550997Sbostic off = OFFSET(tp);
62650997Sbostic tp[0] -= 2;
62750997Sbostic FREESPACE(tp) = free_space + OVFLSIZE;
62850997Sbostic OFFSET(tp) = off;
62957586Sbostic tmpp = __add_ovflpage(hashp, big_keyp);
63050997Sbostic if (!tmpp)
63150997Sbostic return (-1);
63250997Sbostic tp[4] = n;
63350997Sbostic } else
63450997Sbostic tmpp = big_keyp;
63546364Sbostic
63650997Sbostic if (change)
63750997Sbostic ret->newp = tmpp;
63850997Sbostic else
63950997Sbostic ret->oldp = tmpp;
64050997Sbostic return (0);
64146364Sbostic }
642