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*51046Sbostic static char sccsid[] = "@(#)hash_bigkey.c 5.7 (Berkeley) 09/08/91"; 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> 3446364Sbostic #include <errno.h> 3546364Sbostic #include <db.h> 3646364Sbostic #include <stdio.h> 3746562Sbostic #include <stdlib.h> 3846562Sbostic #include <string.h> 3950997Sbostic #ifdef DEBUG 4050997Sbostic #include <assert.h> 4150997Sbostic #endif 4246364Sbostic #include "hash.h" 4346364Sbostic #include "page.h" 4450997Sbostic #include "extern.h" 4546364Sbostic 4650997Sbostic static int collect_key __P((BUFHEAD *, int, DBT *, int)); 4750997Sbostic static int collect_data __P((BUFHEAD *, int, int)); 4846364Sbostic 4946364Sbostic /* 5050997Sbostic * Big_insert 5150997Sbostic * 5250997Sbostic * You need to do an insert and the key/data pair is too big 5350997Sbostic * 5450997Sbostic * Returns: 5550997Sbostic * 0 ==> OK 5650997Sbostic *-1 ==> ERROR 5750997Sbostic */ 5846364Sbostic extern int 5950997Sbostic __big_insert(bufp, key, val) 6050997Sbostic BUFHEAD *bufp; 6150997Sbostic const DBT *key, *val; 6246364Sbostic { 6350997Sbostic register u_short *p; 6450997Sbostic int key_size, n, val_size; 6550997Sbostic u_short space, move_bytes, off; 6650997Sbostic char *cp, *key_data, *val_data; 6746364Sbostic 6850997Sbostic cp = bufp->page; /* Character pointer of p. */ 6950997Sbostic p = (u_short *)cp; 7046364Sbostic 7150997Sbostic key_data = (char *)key->data; 7250997Sbostic key_size = key->size; 7350997Sbostic val_data = (char *)val->data; 7450997Sbostic val_size = val->size; 7550997Sbostic 7650997Sbostic /* First move the Key */ 7750997Sbostic for (space = FREESPACE(p) - BIGOVERHEAD; key_size; 7850997Sbostic space = FREESPACE(p) - BIGOVERHEAD) { 7950997Sbostic move_bytes = MIN(space, key_size); 8050997Sbostic off = OFFSET(p) - move_bytes; 8150997Sbostic bcopy(key_data, cp + off, move_bytes); 8250997Sbostic key_size -= move_bytes; 8350997Sbostic key_data += move_bytes; 8450997Sbostic n = p[0]; 8550997Sbostic p[++n] = off; 8650997Sbostic p[0] = ++n; 8750997Sbostic FREESPACE(p) = off - PAGE_META(n); 8850997Sbostic OFFSET(p) = off; 8950997Sbostic p[n] = PARTIAL_KEY; 9050997Sbostic bufp = __add_ovflpage(bufp); 9150997Sbostic if (!bufp) 9250997Sbostic return (-1); 9350997Sbostic n = p[0]; 9450997Sbostic if (!key_size) 9550997Sbostic if (FREESPACE(p)) { 9650997Sbostic move_bytes = MIN(FREESPACE(p), val_size); 9750997Sbostic off = OFFSET(p) - move_bytes; 9850997Sbostic p[n] = off; 9950997Sbostic bcopy(val_data, cp + off, move_bytes); 10050997Sbostic val_data += move_bytes; 10150997Sbostic val_size -= move_bytes; 10250997Sbostic p[n - 2] = FULL_KEY_DATA; 10350997Sbostic FREESPACE(p) = FREESPACE(p) - move_bytes; 10450997Sbostic OFFSET(p) = off; 10550997Sbostic } else 10650997Sbostic p[n - 2] = FULL_KEY; 10750997Sbostic p = (u_short *)bufp->page; 10850997Sbostic cp = bufp->page; 10950997Sbostic bufp->flags |= BUF_MOD; 11046364Sbostic } 11150997Sbostic 11250997Sbostic /* Now move the data */ 11350997Sbostic for (space = FREESPACE(p) - BIGOVERHEAD; val_size; 11450997Sbostic space = FREESPACE(p) - BIGOVERHEAD) { 11550997Sbostic move_bytes = MIN(space, val_size); 11650997Sbostic /* 11750997Sbostic * Here's the hack to make sure that if the data ends on the 11850997Sbostic * same page as the key ends, FREESPACE is at least one. 11950997Sbostic */ 12050997Sbostic if (space == val_size && val_size == val->size) 12150997Sbostic move_bytes--; 12246364Sbostic off = OFFSET(p) - move_bytes; 12350997Sbostic bcopy(val_data, cp + off, move_bytes); 12450997Sbostic val_size -= move_bytes; 12546364Sbostic val_data += move_bytes; 12650997Sbostic n = p[0]; 12750997Sbostic p[++n] = off; 12850997Sbostic p[0] = ++n; 12950997Sbostic FREESPACE(p) = off - PAGE_META(n); 13046364Sbostic OFFSET(p) = off; 13150997Sbostic if (val_size) { 13250997Sbostic p[n] = FULL_KEY; 13350997Sbostic bufp = __add_ovflpage(bufp); 13450997Sbostic if (!bufp) 13550997Sbostic return (-1); 13650997Sbostic cp = bufp->page; 13750997Sbostic p = (u_short *)cp; 13850997Sbostic } else 13950997Sbostic p[n] = FULL_KEY_DATA; 14050997Sbostic bufp->flags |= BUF_MOD; 14146364Sbostic } 14250997Sbostic return (0); 14346364Sbostic } 14446364Sbostic 14546364Sbostic /* 14650997Sbostic * Called when bufp's page contains a partial key (index should be 1) 14750997Sbostic * 14850997Sbostic * All pages in the big key/data pair except bufp are freed. We cannot 14950997Sbostic * free bufp because the page pointing to it is lost and we can't get rid 15050997Sbostic * of its pointer. 15150997Sbostic * 15250997Sbostic * Returns: 15350997Sbostic * 0 => OK 15450997Sbostic *-1 => ERROR 15550997Sbostic */ 15646364Sbostic extern int 157*51046Sbostic __big_delete(bufp) 15850997Sbostic BUFHEAD *bufp; 15946364Sbostic { 16050997Sbostic register BUFHEAD *last_bfp, *rbufp; 16150997Sbostic u_short *bp, pageno; 16250997Sbostic int key_done, n; 16346364Sbostic 16450997Sbostic rbufp = bufp; 16550997Sbostic last_bfp = NULL; 16650997Sbostic bp = (u_short *)bufp->page; 16750997Sbostic pageno = 0; 16850997Sbostic key_done = 0; 16950997Sbostic 17046364Sbostic while (!key_done || (bp[2] != FULL_KEY_DATA)) { 17150997Sbostic if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) 17250997Sbostic key_done = 1; 17346364Sbostic 17450997Sbostic /* 17550997Sbostic * If there is freespace left on a FULL_KEY_DATA page, then 17650997Sbostic * the data is short and fits entirely on this page, and this 17750997Sbostic * is the last page. 17850997Sbostic */ 17950997Sbostic if (bp[2] == FULL_KEY_DATA && FREESPACE(bp)) 18050997Sbostic break; 18150997Sbostic pageno = bp[bp[0] - 1]; 18250997Sbostic rbufp->flags |= BUF_MOD; 18350997Sbostic rbufp = __get_buf(pageno, rbufp, 0); 18450997Sbostic if (last_bfp) 18550997Sbostic __free_ovflpage(last_bfp); 18650997Sbostic last_bfp = rbufp; 18750997Sbostic if (!rbufp) 18850997Sbostic return (-1); /* Error. */ 18950997Sbostic bp = (u_short *)rbufp->page; 19046364Sbostic } 19146364Sbostic 19250997Sbostic /* 19350997Sbostic * If we get here then rbufp points to the last page of the big 19450997Sbostic * key/data pair. Bufp points to the first one -- it should now be 19550997Sbostic * empty pointing to the next page after this pair. Can't free it 19650997Sbostic * because we don't have the page pointing to it. 19750997Sbostic */ 19846364Sbostic 19950997Sbostic /* This is information from the last page of the pair. */ 20046364Sbostic n = bp[0]; 20150997Sbostic pageno = bp[n - 1]; 20246364Sbostic 20350997Sbostic /* Now, bp is the first page of the pair. */ 20446364Sbostic bp = (u_short *)bufp->page; 20550997Sbostic if (n > 2) { 20650997Sbostic /* There is an overflow page. */ 20750997Sbostic bp[1] = pageno; 20850997Sbostic bp[2] = OVFLPAGE; 20950997Sbostic bufp->ovfl = rbufp->ovfl; 21050997Sbostic } else 21150997Sbostic /* This is the last page. */ 21250997Sbostic bufp->ovfl = NULL; 21346364Sbostic n -= 2; 21446364Sbostic bp[0] = n; 21546364Sbostic FREESPACE(bp) = hashp->BSIZE - PAGE_META(n); 21646364Sbostic OFFSET(bp) = hashp->BSIZE - 1; 21746364Sbostic 21846364Sbostic bufp->flags |= BUF_MOD; 21950997Sbostic if (rbufp) 22050997Sbostic __free_ovflpage(rbufp); 22150997Sbostic if (last_bfp != rbufp) 22250997Sbostic __free_ovflpage(last_bfp); 22346364Sbostic 22446364Sbostic hashp->NKEYS--; 22550997Sbostic return (0); 22646364Sbostic } 22746364Sbostic /* 22850997Sbostic * Returns: 22950997Sbostic * 0 = key not found 23050997Sbostic * -1 = get next overflow page 23150997Sbostic * -2 means key not found and this is big key/data 23250997Sbostic * -3 error 23350997Sbostic */ 23446364Sbostic extern int 23550997Sbostic __find_bigpair(bufp, ndx, key, size) 23650997Sbostic BUFHEAD *bufp; 23750997Sbostic int ndx; 23850997Sbostic char *key; 23950997Sbostic int size; 24046364Sbostic { 24150997Sbostic register u_short *bp; 24250997Sbostic register char *p; 24350997Sbostic int ksize; 24450997Sbostic u_short bytes; 24550997Sbostic char *kkey; 24646364Sbostic 24750997Sbostic bp = (u_short *)bufp->page; 24850997Sbostic p = bufp->page; 24950997Sbostic ksize = size; 25050997Sbostic kkey = key; 25146364Sbostic 25250997Sbostic for (bytes = hashp->BSIZE - bp[ndx]; 25350997Sbostic bytes <= size && bp[ndx + 1] == PARTIAL_KEY; 25450997Sbostic bytes = hashp->BSIZE - bp[ndx]) { 25550997Sbostic if (bcmp(p + bp[ndx], kkey, bytes)) 25650997Sbostic return (-2); 25750997Sbostic kkey += bytes; 25850997Sbostic ksize -= bytes; 25950997Sbostic bufp = __get_buf(bp[ndx + 2], bufp, 0); 26050997Sbostic if (!bufp) 26150997Sbostic return (-3); 26250997Sbostic p = bufp->page; 26350997Sbostic bp = (u_short *)p; 26450997Sbostic ndx = 1; 26546364Sbostic } 26646364Sbostic 26750997Sbostic if (bytes != ksize || bcmp(p + bp[ndx], kkey, bytes)) { 26846364Sbostic #ifdef HASH_STATISTICS 26950997Sbostic ++hash_collisions; 27046364Sbostic #endif 27150997Sbostic return (-2); 27250997Sbostic } else 27350997Sbostic return (ndx); 27446364Sbostic } 27546364Sbostic 27646364Sbostic /* 27750997Sbostic * Given the buffer pointer of the first overflow page of a big pair, 27850997Sbostic * find the end of the big pair 27950997Sbostic * 28050997Sbostic * This will set bpp to the buffer header of the last page of the big pair. 28150997Sbostic * It will return the pageno of the overflow page following the last page 28250997Sbostic * of the pair; 0 if there isn't any (i.e. big pair is the last key in the 28350997Sbostic * bucket) 28450997Sbostic */ 28546364Sbostic extern u_short 28650997Sbostic __find_last_page(bpp) 28750997Sbostic BUFHEAD **bpp; 28846364Sbostic { 28950997Sbostic BUFHEAD *bufp; 29050997Sbostic u_short *bp, pageno; 29150997Sbostic int n; 29246364Sbostic 29350997Sbostic bufp = *bpp; 29450997Sbostic bp = (u_short *)bufp->page; 29550997Sbostic for (;;) { 29650997Sbostic n = bp[0]; 29746364Sbostic 29850997Sbostic /* 29950997Sbostic * This is the last page if: the tag is FULL_KEY_DATA and 30050997Sbostic * either only 2 entries OVFLPAGE marker is explicit there 30150997Sbostic * is freespace on the page. 30250997Sbostic */ 30350997Sbostic if (bp[2] == FULL_KEY_DATA && 30450997Sbostic ((n == 2) || (bp[n] == OVFLPAGE) || (FREESPACE(bp)))) 30550997Sbostic break; 30646364Sbostic 30750997Sbostic pageno = bp[n - 1]; 30850997Sbostic bufp = __get_buf(pageno, bufp, 0); 30950997Sbostic if (!bufp) 31050997Sbostic return (0); /* Need to indicate an error! */ 31150997Sbostic bp = (u_short *)bufp->page; 31246364Sbostic } 31346364Sbostic 31446364Sbostic *bpp = bufp; 31550997Sbostic if (bp[0] > 2) 31650997Sbostic return (bp[3]); 31750997Sbostic else 31850997Sbostic return (0); 31946364Sbostic } 32046364Sbostic 32146364Sbostic /* 32250997Sbostic * Return the data for the key/data pair that begins on this page at this 32350997Sbostic * index (index should always be 1). 32450997Sbostic */ 32546364Sbostic extern int 32650997Sbostic __big_return(bufp, ndx, val, set_current) 32750997Sbostic BUFHEAD *bufp; 32850997Sbostic int ndx; 32950997Sbostic DBT *val; 33050997Sbostic int set_current; 33146364Sbostic { 33250997Sbostic BUFHEAD *save_p; 33350997Sbostic u_short *bp, len, off, save_addr; 33450997Sbostic char *tp; 33546364Sbostic 33646364Sbostic bp = (u_short *)bufp->page; 33750997Sbostic while (bp[ndx + 1] == PARTIAL_KEY) { 33850997Sbostic bufp = __get_buf(bp[bp[0] - 1], bufp, 0); 33950997Sbostic if (!bufp) 34050997Sbostic return (-1); 34150997Sbostic bp = (u_short *)bufp->page; 34250997Sbostic ndx = 1; 34350997Sbostic } 34446364Sbostic 34550997Sbostic if (bp[ndx + 1] == FULL_KEY) { 34650997Sbostic bufp = __get_buf(bp[bp[0] - 1], bufp, 0); 34750997Sbostic if (!bufp) 34850997Sbostic return (-1); 34950997Sbostic bp = (u_short *)bufp->page; 35050997Sbostic save_p = bufp; 35150997Sbostic save_addr = save_p->addr; 35250997Sbostic off = bp[1]; 35350997Sbostic len = 0; 35450997Sbostic } else 35550997Sbostic if (!FREESPACE(bp)) { 35650997Sbostic /* 35750997Sbostic * This is a hack. We can't distinguish between 35850997Sbostic * FULL_KEY_DATA that contains complete data or 35950997Sbostic * incomplete data, so we require that if the data 36050997Sbostic * is complete, there is at least 1 byte of free 36150997Sbostic * space left. 36250997Sbostic */ 36350997Sbostic off = bp[bp[0]]; 36450997Sbostic len = bp[1] - off; 36550997Sbostic save_p = bufp; 36650997Sbostic save_addr = bufp->addr; 36750997Sbostic bufp = __get_buf(bp[bp[0] - 1], bufp, 0); 36850997Sbostic if (!bufp) 36950997Sbostic return (-1); 37050997Sbostic bp = (u_short *)bufp->page; 37150997Sbostic } else { 37250997Sbostic /* The data is all on one page. */ 37350997Sbostic tp = (char *)bp; 37450997Sbostic off = bp[bp[0]]; 37550997Sbostic val->data = (u_char *)tp + off; 37650997Sbostic val->size = bp[1] - off; 37750997Sbostic if (set_current) { 37850997Sbostic if (bp[0] == 2) { /* No more buckets in 37950997Sbostic * chain */ 38050997Sbostic hashp->cpage = NULL; 38150997Sbostic hashp->cbucket++; 38250997Sbostic hashp->cndx = 1; 38350997Sbostic } else { 38450997Sbostic hashp->cpage = 38550997Sbostic __get_buf(bp[bp[0] - 1], bufp, 0); 38650997Sbostic if (!hashp->cpage) 38750997Sbostic return (-1); 38850997Sbostic hashp->cndx = 1; 38950997Sbostic if (!((u_short *) 39050997Sbostic hashp->cpage->page)[0]) { 39150997Sbostic hashp->cbucket++; 39250997Sbostic hashp->cpage = NULL; 39350997Sbostic } 39450997Sbostic } 39550997Sbostic } 39650997Sbostic return (0); 39746364Sbostic } 39850997Sbostic 399*51046Sbostic val->size = collect_data(bufp, (int)len, set_current); 40050997Sbostic if (val->size == -1) 40150997Sbostic return (-1); 40250997Sbostic if (save_p->addr != save_addr) { 40350997Sbostic /* We are pretty short on buffers. */ 40450997Sbostic errno = EINVAL; /* OUT OF BUFFERS */ 40550997Sbostic return (-1); 40646364Sbostic } 40750997Sbostic bcopy((save_p->page) + off, hashp->tmp_buf, len); 40850997Sbostic val->data = (u_char *)hashp->tmp_buf; 40950997Sbostic return (0); 41046364Sbostic } 41146364Sbostic /* 41250997Sbostic * Count how big the total datasize is by recursing through the pages. Then 41350997Sbostic * allocate a buffer and copy the data as you recurse up. 41450997Sbostic */ 41546364Sbostic static int 41650997Sbostic collect_data(bufp, len, set) 41750997Sbostic BUFHEAD *bufp; 41850997Sbostic int len, set; 41946364Sbostic { 42050997Sbostic register u_short *bp; 42150997Sbostic register char *p; 42250997Sbostic BUFHEAD *xbp; 42350997Sbostic u_short save_addr; 42450997Sbostic int mylen, totlen; 42546364Sbostic 42650997Sbostic p = bufp->page; 42750997Sbostic bp = (u_short *)p; 42850997Sbostic mylen = hashp->BSIZE - bp[1]; 42950997Sbostic save_addr = bufp->addr; 43046364Sbostic 43150997Sbostic if (bp[2] == FULL_KEY_DATA) { /* End of Data */ 43250997Sbostic totlen = len + mylen; 43350997Sbostic if (hashp->tmp_buf) 43450997Sbostic free(hashp->tmp_buf); 43550997Sbostic hashp->tmp_buf = malloc(totlen); 43650997Sbostic if (!hashp->tmp_buf) 43750997Sbostic return (-1); 43850997Sbostic if (set) { 43950997Sbostic hashp->cndx = 1; 44050997Sbostic if (bp[0] == 2) { /* No more buckets in chain */ 44150997Sbostic hashp->cpage = NULL; 44250997Sbostic hashp->cbucket++; 44350997Sbostic } else { 44450997Sbostic hashp->cpage = 44550997Sbostic __get_buf(bp[bp[0] - 1], bufp, 0); 44650997Sbostic if (!hashp->cpage) 44750997Sbostic return (-1); 44850997Sbostic else if (!((u_short *)hashp->cpage->page)[0]) { 44950997Sbostic hashp->cbucket++; 45050997Sbostic hashp->cpage = NULL; 45150997Sbostic } 45250997Sbostic } 45346364Sbostic } 45450997Sbostic } else { 45550997Sbostic xbp = __get_buf(bp[bp[0] - 1], bufp, 0); 45650997Sbostic if (!xbp || 45750997Sbostic ((totlen = collect_data(xbp, len + mylen, set)) < 1)) 45850997Sbostic return (-1); 45946364Sbostic } 46050997Sbostic if (bufp->addr != save_addr) { 46150997Sbostic errno = EINVAL; /* Out of buffers. */ 46250997Sbostic return (-1); 46346364Sbostic } 46450997Sbostic bcopy((bufp->page) + bp[1], &hashp->tmp_buf[len], mylen); 46550997Sbostic return (totlen); 46646364Sbostic } 46746364Sbostic 46846364Sbostic /* 46950997Sbostic * Fill in the key and data for this big pair. 47050997Sbostic */ 47146364Sbostic extern int 472*51046Sbostic __big_keydata(bufp, key, val, set) 47350997Sbostic BUFHEAD *bufp; 47450997Sbostic DBT *key, *val; 47550997Sbostic int set; 47646364Sbostic { 47750997Sbostic key->size = collect_key(bufp, 0, val, set); 47850997Sbostic if (key->size == -1) 47950997Sbostic return (-1); 48050997Sbostic key->data = (u_char *)hashp->tmp_key; 48150997Sbostic return (0); 48246364Sbostic } 48346364Sbostic 48446364Sbostic /* 48550997Sbostic * Count how big the total key size is by recursing through the pages. Then 48650997Sbostic * collect the data, allocate a buffer and copy the key as you recurse up. 48750997Sbostic */ 48846364Sbostic static int 48950997Sbostic collect_key(bufp, len, val, set) 49050997Sbostic BUFHEAD *bufp; 49150997Sbostic int len; 49250997Sbostic DBT *val; 49350997Sbostic int set; 49446364Sbostic { 49550997Sbostic BUFHEAD *xbp; 49650997Sbostic char *p; 49750997Sbostic int mylen, totlen; 49850997Sbostic u_short *bp, save_addr; 49946364Sbostic 50050997Sbostic p = bufp->page; 50150997Sbostic bp = (u_short *)p; 50250997Sbostic mylen = hashp->BSIZE - bp[1]; 50346364Sbostic 50450997Sbostic save_addr = bufp->addr; 50550997Sbostic totlen = len + mylen; 50650997Sbostic if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) { /* End of Key. */ 50750997Sbostic if (hashp->tmp_key) 50850997Sbostic free(hashp->tmp_key); 50950997Sbostic hashp->tmp_key = malloc(totlen); 51050997Sbostic if (!hashp->tmp_key) 51150997Sbostic return (-1); 512*51046Sbostic if (__big_return(bufp, 1, val, set)) 513*51046Sbostic return (-1); 51450997Sbostic } else { 51550997Sbostic xbp = __get_buf(bp[bp[0] - 1], bufp, 0); 51650997Sbostic if (!xbp || 51750997Sbostic ((totlen = collect_key(xbp, totlen, val, set)) < 1)) 51850997Sbostic return (-1); 51946364Sbostic } 52050997Sbostic if (bufp->addr != save_addr) { 52150997Sbostic errno = EINVAL; /* MIS -- OUT OF BUFFERS */ 52250997Sbostic return (-1); 52346364Sbostic } 52450997Sbostic bcopy((bufp->page) + bp[1], &hashp->tmp_key[len], mylen); 52550997Sbostic return (totlen); 52646364Sbostic } 52746364Sbostic 52846364Sbostic /* 52950997Sbostic * Returns: 53050997Sbostic * 0 => OK 53150997Sbostic * -1 => error 53250997Sbostic */ 53346364Sbostic extern int 53450997Sbostic __big_split(op, np, big_keyp, addr, obucket, ret) 53550997Sbostic BUFHEAD *op; /* Pointer to where to put keys that go in old bucket */ 53650997Sbostic BUFHEAD *np; /* Pointer to new bucket page */ 53750997Sbostic /* Pointer to first page containing the big key/data */ 53850997Sbostic BUFHEAD *big_keyp; 53950997Sbostic int addr; /* Address of big_keyp */ 54050997Sbostic u_int obucket;/* Old Bucket */ 54150997Sbostic SPLIT_RETURN *ret; 54246364Sbostic { 54350997Sbostic register BUFHEAD *tmpp; 54450997Sbostic register u_short *tp; 54550997Sbostic BUFHEAD *bp; 54650997Sbostic DBT key, val; 54750997Sbostic u_int change; 54850997Sbostic u_short free_space, n, off; 54946364Sbostic 55050997Sbostic bp = big_keyp; 55146364Sbostic 55250997Sbostic /* Now figure out where the big key/data goes */ 553*51046Sbostic if (__big_keydata(big_keyp, &key, &val, 0)) 55450997Sbostic return (-1); 55550997Sbostic change = (__call_hash(key.data, key.size) != obucket); 55646364Sbostic 55750997Sbostic if (ret->next_addr = __find_last_page(&big_keyp)) { 55850997Sbostic if (!(ret->nextp = __get_buf(ret->next_addr, big_keyp, 0))) 55950997Sbostic return (-1);; 56050997Sbostic } else 56150997Sbostic ret->nextp = NULL; 56246364Sbostic 56350997Sbostic /* Now make one of np/op point to the big key/data pair */ 56450997Sbostic #ifdef DEBUG 56550997Sbostic assert(np->ovfl == NULL); 56650997Sbostic #endif 56750997Sbostic if (change) 56850997Sbostic tmpp = np; 56950997Sbostic else 57050997Sbostic tmpp = op; 57146364Sbostic 57250997Sbostic tmpp->flags |= BUF_MOD; 57346364Sbostic #ifdef DEBUG1 57450997Sbostic (void)fprintf(stderr, 57550997Sbostic "BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr, 57650997Sbostic (tmpp->ovfl ? tmpp->ovfl->addr : 0), (bp ? bp->addr : 0)); 57746364Sbostic #endif 57850997Sbostic tmpp->ovfl = bp; /* one of op/np point to big_keyp */ 57950997Sbostic tp = (u_short *)tmpp->page; 58050997Sbostic #ifdef DEBUG 58150997Sbostic assert(FREESPACE(tp) >= OVFLSIZE); 58250997Sbostic #endif 58350997Sbostic n = tp[0]; 58450997Sbostic off = OFFSET(tp); 58550997Sbostic free_space = FREESPACE(tp); 58650997Sbostic tp[++n] = (u_short)addr; 58750997Sbostic tp[++n] = OVFLPAGE; 58850997Sbostic tp[0] = n; 58950997Sbostic OFFSET(tp) = off; 59050997Sbostic FREESPACE(tp) = free_space - OVFLSIZE; 59146364Sbostic 59250997Sbostic /* 59350997Sbostic * Finally, set the new and old return values. BIG_KEYP contains a 59450997Sbostic * pointer to the last page of the big key_data pair. Make sure that 59550997Sbostic * big_keyp has no following page (2 elements) or create an empty 59650997Sbostic * following page. 59750997Sbostic */ 59846364Sbostic 59950997Sbostic ret->newp = np; 60050997Sbostic ret->oldp = op; 60146364Sbostic 60250997Sbostic tp = (u_short *)big_keyp->page; 60350997Sbostic big_keyp->flags |= BUF_MOD; 60450997Sbostic if (tp[0] > 2) { 60550997Sbostic /* 60650997Sbostic * There may be either one or two offsets on this page. If 60750997Sbostic * there is one, then the overflow page is linked on normally 60850997Sbostic * and tp[4] is OVFLPAGE. If there are two, tp[4] contains 60950997Sbostic * the second offset and needs to get stuffed in after the 61050997Sbostic * next overflow page is added. 61150997Sbostic */ 61250997Sbostic n = tp[4]; 61350997Sbostic free_space = FREESPACE(tp); 61450997Sbostic off = OFFSET(tp); 61550997Sbostic tp[0] -= 2; 61650997Sbostic FREESPACE(tp) = free_space + OVFLSIZE; 61750997Sbostic OFFSET(tp) = off; 61850997Sbostic tmpp = __add_ovflpage(big_keyp); 61950997Sbostic if (!tmpp) 62050997Sbostic return (-1); 62150997Sbostic tp[4] = n; 62250997Sbostic } else 62350997Sbostic tmpp = big_keyp; 62446364Sbostic 62550997Sbostic if (change) 62650997Sbostic ret->newp = tmpp; 62750997Sbostic else 62850997Sbostic ret->oldp = tmpp; 62950997Sbostic return (0); 63046364Sbostic } 631