146364Sbostic /*- 246364Sbostic * Copyright (c) 1990 The Regents of the University of California. 346364Sbostic * 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*58016Sbostic static char sccsid[] = "@(#)hash_bigkey.c 5.10 (Berkeley) 02/16/93"; 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; 85*58016Sbostic 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; 103*58016Sbostic 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; 127*58016Sbostic 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]) { 261*58016Sbostic 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 273*58016Sbostic 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 } 415*58016Sbostic 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 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); 44450997Sbostic hashp->tmp_buf = malloc(totlen); 44550997Sbostic if (!hashp->tmp_buf) 44650997Sbostic return (-1); 44750997Sbostic if (set) { 44850997Sbostic hashp->cndx = 1; 44950997Sbostic if (bp[0] == 2) { /* No more buckets in chain */ 45050997Sbostic hashp->cpage = NULL; 45150997Sbostic hashp->cbucket++; 45250997Sbostic } else { 45350997Sbostic hashp->cpage = 45457586Sbostic __get_buf(hashp, bp[bp[0] - 1], bufp, 0); 45550997Sbostic if (!hashp->cpage) 45650997Sbostic return (-1); 45750997Sbostic else if (!((u_short *)hashp->cpage->page)[0]) { 45850997Sbostic hashp->cbucket++; 45950997Sbostic hashp->cpage = NULL; 46050997Sbostic } 46150997Sbostic } 46246364Sbostic } 46350997Sbostic } else { 46457586Sbostic xbp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0); 46557586Sbostic if (!xbp || ((totlen = 46657586Sbostic collect_data(hashp, xbp, len + mylen, set)) < 1)) 46750997Sbostic return (-1); 46846364Sbostic } 46950997Sbostic if (bufp->addr != save_addr) { 47050997Sbostic errno = EINVAL; /* Out of buffers. */ 47150997Sbostic return (-1); 47246364Sbostic } 473*58016Sbostic memmove(&hashp->tmp_buf[len], (bufp->page) + bp[1], mylen); 47450997Sbostic return (totlen); 47546364Sbostic } 47646364Sbostic 47746364Sbostic /* 47850997Sbostic * Fill in the key and data for this big pair. 47950997Sbostic */ 48046364Sbostic extern int 48157586Sbostic __big_keydata(hashp, bufp, key, val, set) 48257586Sbostic HTAB *hashp; 48350997Sbostic BUFHEAD *bufp; 48450997Sbostic DBT *key, *val; 48550997Sbostic int set; 48646364Sbostic { 48757586Sbostic key->size = collect_key(hashp, bufp, 0, val, set); 48850997Sbostic if (key->size == -1) 48950997Sbostic return (-1); 49050997Sbostic key->data = (u_char *)hashp->tmp_key; 49150997Sbostic return (0); 49246364Sbostic } 49346364Sbostic 49446364Sbostic /* 49550997Sbostic * Count how big the total key size is by recursing through the pages. Then 49650997Sbostic * collect the data, allocate a buffer and copy the key as you recurse up. 49750997Sbostic */ 49846364Sbostic static int 49957586Sbostic collect_key(hashp, bufp, len, val, set) 50057586Sbostic HTAB *hashp; 50150997Sbostic BUFHEAD *bufp; 50250997Sbostic int len; 50350997Sbostic DBT *val; 50450997Sbostic int set; 50546364Sbostic { 50650997Sbostic BUFHEAD *xbp; 50750997Sbostic char *p; 50850997Sbostic int mylen, totlen; 50950997Sbostic u_short *bp, save_addr; 51046364Sbostic 51150997Sbostic p = bufp->page; 51250997Sbostic bp = (u_short *)p; 51350997Sbostic mylen = hashp->BSIZE - bp[1]; 51446364Sbostic 51550997Sbostic save_addr = bufp->addr; 51650997Sbostic totlen = len + mylen; 51750997Sbostic if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) { /* End of Key. */ 51850997Sbostic if (hashp->tmp_key) 51950997Sbostic free(hashp->tmp_key); 52050997Sbostic hashp->tmp_key = malloc(totlen); 52150997Sbostic if (!hashp->tmp_key) 52250997Sbostic return (-1); 52357586Sbostic if (__big_return(hashp, bufp, 1, val, set)) 52451046Sbostic return (-1); 52550997Sbostic } else { 52657586Sbostic xbp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0); 52757586Sbostic if (!xbp || ((totlen = 52857586Sbostic collect_key(hashp, xbp, totlen, val, set)) < 1)) 52950997Sbostic return (-1); 53046364Sbostic } 53150997Sbostic if (bufp->addr != save_addr) { 53250997Sbostic errno = EINVAL; /* MIS -- OUT OF BUFFERS */ 53350997Sbostic return (-1); 53446364Sbostic } 535*58016Sbostic memmove(&hashp->tmp_key[len], (bufp->page) + bp[1], mylen); 53650997Sbostic return (totlen); 53746364Sbostic } 53846364Sbostic 53946364Sbostic /* 54050997Sbostic * Returns: 54150997Sbostic * 0 => OK 54250997Sbostic * -1 => error 54350997Sbostic */ 54446364Sbostic extern int 54557586Sbostic __big_split(hashp, op, np, big_keyp, addr, obucket, ret) 54657586Sbostic HTAB *hashp; 54750997Sbostic BUFHEAD *op; /* Pointer to where to put keys that go in old bucket */ 54850997Sbostic BUFHEAD *np; /* Pointer to new bucket page */ 54950997Sbostic /* Pointer to first page containing the big key/data */ 55050997Sbostic BUFHEAD *big_keyp; 55150997Sbostic int addr; /* Address of big_keyp */ 55250997Sbostic u_int obucket;/* Old Bucket */ 55350997Sbostic SPLIT_RETURN *ret; 55446364Sbostic { 55550997Sbostic register BUFHEAD *tmpp; 55650997Sbostic register u_short *tp; 55750997Sbostic BUFHEAD *bp; 55850997Sbostic DBT key, val; 55950997Sbostic u_int change; 56050997Sbostic u_short free_space, n, off; 56146364Sbostic 56250997Sbostic bp = big_keyp; 56346364Sbostic 56450997Sbostic /* Now figure out where the big key/data goes */ 56557586Sbostic if (__big_keydata(hashp, big_keyp, &key, &val, 0)) 56650997Sbostic return (-1); 56757586Sbostic change = (__call_hash(hashp, key.data, key.size) != obucket); 56846364Sbostic 56957586Sbostic if (ret->next_addr = __find_last_page(hashp, &big_keyp)) { 57057586Sbostic if (!(ret->nextp = 57157586Sbostic __get_buf(hashp, ret->next_addr, big_keyp, 0))) 57250997Sbostic return (-1);; 57350997Sbostic } else 57450997Sbostic ret->nextp = NULL; 57546364Sbostic 57650997Sbostic /* Now make one of np/op point to the big key/data pair */ 57750997Sbostic #ifdef DEBUG 57850997Sbostic assert(np->ovfl == NULL); 57950997Sbostic #endif 58050997Sbostic if (change) 58150997Sbostic tmpp = np; 58250997Sbostic else 58350997Sbostic tmpp = op; 58446364Sbostic 58550997Sbostic tmpp->flags |= BUF_MOD; 58646364Sbostic #ifdef DEBUG1 58750997Sbostic (void)fprintf(stderr, 58850997Sbostic "BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr, 58950997Sbostic (tmpp->ovfl ? tmpp->ovfl->addr : 0), (bp ? bp->addr : 0)); 59046364Sbostic #endif 59150997Sbostic tmpp->ovfl = bp; /* one of op/np point to big_keyp */ 59250997Sbostic tp = (u_short *)tmpp->page; 59350997Sbostic #ifdef DEBUG 59450997Sbostic assert(FREESPACE(tp) >= OVFLSIZE); 59550997Sbostic #endif 59650997Sbostic n = tp[0]; 59750997Sbostic off = OFFSET(tp); 59850997Sbostic free_space = FREESPACE(tp); 59950997Sbostic tp[++n] = (u_short)addr; 60050997Sbostic tp[++n] = OVFLPAGE; 60150997Sbostic tp[0] = n; 60250997Sbostic OFFSET(tp) = off; 60350997Sbostic FREESPACE(tp) = free_space - OVFLSIZE; 60446364Sbostic 60550997Sbostic /* 60650997Sbostic * Finally, set the new and old return values. BIG_KEYP contains a 60750997Sbostic * pointer to the last page of the big key_data pair. Make sure that 60850997Sbostic * big_keyp has no following page (2 elements) or create an empty 60950997Sbostic * following page. 61050997Sbostic */ 61146364Sbostic 61250997Sbostic ret->newp = np; 61350997Sbostic ret->oldp = op; 61446364Sbostic 61550997Sbostic tp = (u_short *)big_keyp->page; 61650997Sbostic big_keyp->flags |= BUF_MOD; 61750997Sbostic if (tp[0] > 2) { 61850997Sbostic /* 61950997Sbostic * There may be either one or two offsets on this page. If 62050997Sbostic * there is one, then the overflow page is linked on normally 62150997Sbostic * and tp[4] is OVFLPAGE. If there are two, tp[4] contains 62250997Sbostic * the second offset and needs to get stuffed in after the 62350997Sbostic * next overflow page is added. 62450997Sbostic */ 62550997Sbostic n = tp[4]; 62650997Sbostic free_space = FREESPACE(tp); 62750997Sbostic off = OFFSET(tp); 62850997Sbostic tp[0] -= 2; 62950997Sbostic FREESPACE(tp) = free_space + OVFLSIZE; 63050997Sbostic OFFSET(tp) = off; 63157586Sbostic tmpp = __add_ovflpage(hashp, big_keyp); 63250997Sbostic if (!tmpp) 63350997Sbostic return (-1); 63450997Sbostic tp[4] = n; 63550997Sbostic } else 63650997Sbostic tmpp = big_keyp; 63746364Sbostic 63850997Sbostic if (change) 63950997Sbostic ret->newp = tmpp; 64050997Sbostic else 64150997Sbostic ret->oldp = tmpp; 64250997Sbostic return (0); 64346364Sbostic } 644