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*46644Sbostic static char sccsid[] = "@(#)hash_bigkey.c 5.3 (Berkeley) 02/24/91"; 1346364Sbostic #endif /* LIBC_SCCS and not lint */ 1446364Sbostic 1546364Sbostic /****************************************************************************** 1646364Sbostic 1746364Sbostic PACKAGE: hash 1846364Sbostic 1946364Sbostic DESCRIPTION: 2046364Sbostic Big key/data handling for the hashing package. 2146364Sbostic 2246364Sbostic ROUTINES: 2346364Sbostic External 2446364Sbostic __big_keydata 2546364Sbostic __big_split 2646364Sbostic __big_insert 2746364Sbostic __big_return 2846364Sbostic __big_delete 2946364Sbostic __find_last_page 3046364Sbostic Internal 3146364Sbostic collect_key 3246364Sbostic collect_data 3346364Sbostic ******************************************************************************/ 3446364Sbostic /* Includes */ 35*46644Sbostic #include <sys/param.h> 3646364Sbostic #include <assert.h> 3746364Sbostic #include <errno.h> 3846364Sbostic #include <db.h> 3946364Sbostic #include <stdio.h> 4046562Sbostic #include <stdlib.h> 4146562Sbostic #include <string.h> 4246364Sbostic #include "hash.h" 4346364Sbostic #include "page.h" 4446364Sbostic 4546364Sbostic /* Externals */ 4646364Sbostic /* buf.c */ 4746364Sbostic extern BUFHEAD *__get_buf(); 4846364Sbostic 4946364Sbostic /* page.c */ 5046364Sbostic extern BUFHEAD *__add_ovflpage(); 5146364Sbostic 5246364Sbostic /* My externals */ 5346364Sbostic extern int __big_keydata(); 5446364Sbostic extern int __big_split(); 5546364Sbostic extern int __big_insert(); 5646364Sbostic extern int __big_return(); 5746364Sbostic extern int __big_delete(); 5846364Sbostic extern u_short __find_last_page(); 5946364Sbostic extern int __find_bigpair(); 6046364Sbostic 6146364Sbostic /* My internals */ 6246364Sbostic static int collect_key(); 6346364Sbostic static int collect_data(); 6446364Sbostic 6546364Sbostic #ifdef HASH_STATISTICS 6646364Sbostic extern long hash_accesses, hash_collisions, hash_expansions, hash_overflows; 6746364Sbostic #endif 6846364Sbostic /* 6946364Sbostic Big_insert 7046364Sbostic 7146364Sbostic You need to do an insert and the key/data pair is too big 7246364Sbostic 0 ==> OK 7346364Sbostic -1 ==> ERROR 7446364Sbostic */ 7546364Sbostic extern int 7646364Sbostic __big_insert ( bufp, key, val ) 7746364Sbostic BUFHEAD *bufp; 7846364Sbostic DBT *key, *val; 7946364Sbostic { 8046364Sbostic char *cp = bufp->page; /* Character pointer of p */ 8146364Sbostic register u_short *p = (u_short *)cp; 8246364Sbostic char *key_data, *val_data; 8346364Sbostic int key_size, val_size; 8446364Sbostic int n; 8546364Sbostic u_short space, move_bytes, off; 8646364Sbostic 8746364Sbostic key_data = key->data; 8846364Sbostic key_size = key->size; 8946364Sbostic val_data = val->data; 9046364Sbostic val_size = val->size; 9146364Sbostic 9246364Sbostic /* First move the Key */ 9346364Sbostic for ( space = FREESPACE(p) - BIGOVERHEAD; 9446364Sbostic key_size; 9546364Sbostic space = FREESPACE(p) - BIGOVERHEAD ) { 9646364Sbostic move_bytes = MIN(space, key_size); 9746364Sbostic off = OFFSET(p) - move_bytes; 9846364Sbostic bcopy (key_data, cp+off, move_bytes ); 9946364Sbostic key_size -= move_bytes; 10046364Sbostic key_data += move_bytes; 10146364Sbostic n = p[0]; 10246364Sbostic p[++n] = off; 10346364Sbostic p[0] = ++n; 10446364Sbostic FREESPACE(p) = off - PAGE_META(n); 10546364Sbostic OFFSET(p) = off; 10646364Sbostic p[n] = PARTIAL_KEY; 10746364Sbostic bufp = __add_ovflpage(bufp); 10846364Sbostic if ( !bufp ) { 10946364Sbostic return(-1); 11046364Sbostic } 11146364Sbostic n = p[0]; 11246364Sbostic if ( !key_size ) { 11346364Sbostic if ( FREESPACE(p) ) { 11446364Sbostic move_bytes = MIN (FREESPACE(p), val_size); 11546364Sbostic off = OFFSET(p) - move_bytes; 11646364Sbostic p[n] = off; 11746364Sbostic bcopy ( val_data, cp + off, move_bytes ); 11846364Sbostic val_data += move_bytes; 11946364Sbostic val_size -= move_bytes; 12046364Sbostic p[n-2] = FULL_KEY_DATA; 12146364Sbostic FREESPACE(p) = FREESPACE(p) - move_bytes; 12246364Sbostic OFFSET(p) = off; 12346364Sbostic } 12446364Sbostic else p[n-2] = FULL_KEY; 12546364Sbostic } 12646364Sbostic p = (u_short *)bufp->page; 12746364Sbostic cp = bufp->page; 12846364Sbostic bufp->flags |= BUF_MOD; 12946364Sbostic } 13046364Sbostic 13146364Sbostic /* Now move the data */ 13246364Sbostic for ( space = FREESPACE(p) - BIGOVERHEAD; 13346364Sbostic val_size; 13446364Sbostic space = FREESPACE(p) - BIGOVERHEAD ) { 13546364Sbostic move_bytes = MIN(space, val_size); 13646364Sbostic /* 13746364Sbostic Here's the hack to make sure that if the data ends 13846364Sbostic on the same page as the key ends, FREESPACE is 13946364Sbostic at least one 14046364Sbostic */ 14146364Sbostic if ( space == val_size && val_size == val->size ) { 14246364Sbostic move_bytes--; 14346364Sbostic } 14446364Sbostic off = OFFSET(p) - move_bytes; 14546364Sbostic bcopy (val_data, cp+off, move_bytes ); 14646364Sbostic val_size -= move_bytes; 14746364Sbostic val_data += move_bytes; 14846364Sbostic n = p[0]; 14946364Sbostic p[++n] = off; 15046364Sbostic p[0] = ++n; 15146364Sbostic FREESPACE(p) = off - PAGE_META(n); 15246364Sbostic OFFSET(p) = off; 15346364Sbostic if ( val_size ) { 15446364Sbostic p[n] = FULL_KEY; 15546364Sbostic bufp = __add_ovflpage (bufp); 15646364Sbostic if ( !bufp ) { 15746364Sbostic return(-1); 15846364Sbostic } 15946364Sbostic cp = bufp->page; 16046364Sbostic p = (u_short *)cp; 16146364Sbostic } else { 16246364Sbostic p[n] = FULL_KEY_DATA; 16346364Sbostic } 16446364Sbostic bufp->flags |= BUF_MOD; 16546364Sbostic } 16646364Sbostic return(0); 16746364Sbostic } 16846364Sbostic 16946364Sbostic /* 17046364Sbostic Called when bufp's page contains a partial key (index should be 1) 17146364Sbostic 17246364Sbostic All pages in the big key/data pair except bufp are freed. We cannot 17346364Sbostic free bufp because the page pointing to it is lost and we can't 17446364Sbostic get rid of its pointer. 17546364Sbostic 17646364Sbostic Returns 0 => OK 17746364Sbostic -1 => ERROR 17846364Sbostic */ 17946364Sbostic extern int 18046364Sbostic __big_delete (bufp, ndx) 18146364Sbostic BUFHEAD *bufp; 18246364Sbostic int ndx; 18346364Sbostic { 18446364Sbostic register BUFHEAD *rbufp = bufp; 18546364Sbostic register BUFHEAD *last_bfp = NULL; 18646364Sbostic char *cp; 18746364Sbostic u_short *bp = (u_short *)bufp->page; 18846364Sbostic u_short *xbp; 18946364Sbostic u_short pageno = 0; 19046364Sbostic u_short off, free_sp; 19146364Sbostic int key_done = 0; 19246364Sbostic int n; 19346364Sbostic 19446364Sbostic while (!key_done || (bp[2] != FULL_KEY_DATA)) { 19546364Sbostic if ( bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA ) key_done = 1; 19646364Sbostic 19746364Sbostic /* 19846364Sbostic If there is freespace left on a FULL_KEY_DATA page, 19946364Sbostic then the data is short and fits entirely on this 20046364Sbostic page, and this is the last page. 20146364Sbostic */ 20246364Sbostic if ( bp[2] == FULL_KEY_DATA && FREESPACE(bp) ) break; 20346364Sbostic pageno = bp[bp[0]-1]; 20446364Sbostic rbufp->flags |= BUF_MOD; 20546364Sbostic rbufp = __get_buf ( pageno, rbufp, 0 ); 20646364Sbostic if ( last_bfp ) __free_ovflpage(last_bfp); 20746364Sbostic last_bfp = rbufp; 20846364Sbostic if ( !rbufp ) return(-1); /* Error */ 20946364Sbostic bp = (u_short *)rbufp->page; 21046364Sbostic } 21146364Sbostic 21246364Sbostic /* 21346364Sbostic If we get here then rbufp points to the last page of 21446364Sbostic the big key/data pair. Bufp points to the first 21546364Sbostic one -- it should now be empty pointing to the next 21646364Sbostic page after this pair. Can't free it because we don't 21746364Sbostic have the page pointing to it. 21846364Sbostic */ 21946364Sbostic 22046364Sbostic /* This is information from the last page of the pair */ 22146364Sbostic n = bp[0]; 22246364Sbostic pageno = bp[n-1]; 22346364Sbostic 22446364Sbostic /* Now, bp is the first page of the pair */ 22546364Sbostic bp = (u_short *)bufp->page; 22646364Sbostic if ( n > 2 ) { 22746364Sbostic /* There is an overflow page */ 22846364Sbostic bp[1] = pageno; 22946364Sbostic bp[2] = OVFLPAGE; 23046364Sbostic bufp->ovfl = rbufp->ovfl; 23146364Sbostic } else { 23246364Sbostic /* This is the last page */ 23346364Sbostic bufp->ovfl = NULL; 23446364Sbostic } 23546364Sbostic n -= 2; 23646364Sbostic bp[0] = n; 23746364Sbostic FREESPACE(bp) = hashp->BSIZE - PAGE_META(n); 23846364Sbostic OFFSET(bp) = hashp->BSIZE - 1; 23946364Sbostic 24046364Sbostic bufp->flags |= BUF_MOD; 24146364Sbostic if ( rbufp ) __free_ovflpage(rbufp); 24246364Sbostic if ( last_bfp != rbufp ) __free_ovflpage(last_bfp); 24346364Sbostic 24446364Sbostic hashp->NKEYS--; 24546364Sbostic return(0); 24646364Sbostic } 24746364Sbostic 24846364Sbostic /* 24946364Sbostic 0 = key not found 25046364Sbostic -1 = get next overflow page 25146364Sbostic -2 means key not found and this is big key/data 25246364Sbostic -3 error 25346364Sbostic */ 25446364Sbostic extern int 25546364Sbostic __find_bigpair(bufp, ndx, key, size ) 25646364Sbostic BUFHEAD *bufp; 25746364Sbostic int ndx; 25846364Sbostic char *key; 25946364Sbostic int size; 26046364Sbostic { 26146364Sbostic register u_short *bp = (u_short *)bufp->page; 26246364Sbostic register char *p = bufp->page; 26346364Sbostic int ksize = size; 26446364Sbostic char *kkey = key; 26546364Sbostic u_short bytes; 26646364Sbostic 26746364Sbostic 26846364Sbostic for ( bytes = hashp->BSIZE - bp[ndx]; 26946364Sbostic bytes <= size && bp[ndx+1] == PARTIAL_KEY; 27046364Sbostic bytes = hashp->BSIZE - bp[ndx] ) { 27146364Sbostic 27246364Sbostic if ( bcmp ( p+bp[ndx], kkey, bytes ))return(-2); 27346364Sbostic kkey += bytes; 27446364Sbostic ksize -= bytes; 27546364Sbostic bufp = __get_buf ( bp[ndx+2], bufp, 0 ); 27646364Sbostic if ( !bufp ) { 27746364Sbostic return(-3); 27846364Sbostic } 27946364Sbostic p = bufp->page; 28046364Sbostic bp = (u_short *)p; 28146364Sbostic ndx = 1; 28246364Sbostic } 28346364Sbostic 28446364Sbostic if ( (bytes != ksize) || bcmp ( p+bp[ndx], kkey, bytes )) { 28546364Sbostic #ifdef HASH_STATISTICS 28646364Sbostic hash_collisions++; 28746364Sbostic #endif 28846364Sbostic return(-2); 28946364Sbostic } 29046364Sbostic else return (ndx); 29146364Sbostic } 29246364Sbostic 29346364Sbostic 29446364Sbostic /* 29546364Sbostic Given the buffer pointer of the first overflow page of a big pair, 29646364Sbostic find the end of the big pair 29746364Sbostic 29846364Sbostic This will set bpp to the buffer header of the last page of the big pair. 29946364Sbostic It will return the pageno of the overflow page following the last page of 30046364Sbostic the pair; 0 if there isn't any (i.e. big pair is the last key in the 30146364Sbostic bucket) 30246364Sbostic */ 30346364Sbostic extern u_short 30446364Sbostic __find_last_page ( bpp ) 30546364Sbostic BUFHEAD **bpp; 30646364Sbostic { 30746364Sbostic int n; 30846364Sbostic u_short pageno; 30946364Sbostic BUFHEAD *bufp = *bpp; 31046364Sbostic u_short *bp = (u_short *)bufp->page; 31146364Sbostic 31246364Sbostic while ( 1 ) { 31346364Sbostic n = bp[0]; 31446364Sbostic 31546364Sbostic /* 31646364Sbostic This is the last page if: 31746364Sbostic the tag is FULL_KEY_DATA and either 31846364Sbostic only 2 entries 31946364Sbostic OVFLPAGE marker is explicit 32046364Sbostic there is freespace on the page 32146364Sbostic */ 32246364Sbostic if ( bp[2] == FULL_KEY_DATA && 32346364Sbostic ((n == 2) || (bp[n] == OVFLPAGE) || (FREESPACE(bp)) ) ) break; 32446364Sbostic 32546364Sbostic pageno = bp[n-1]; 32646364Sbostic bufp = __get_buf ( pageno, bufp, 0 ); 32746364Sbostic if ( !bufp ) return (0); /* Need to indicate an error! */ 32846364Sbostic bp = (u_short *)bufp->page; 32946364Sbostic } 33046364Sbostic 33146364Sbostic *bpp = bufp; 33246364Sbostic if ( bp[0] > 2 ) return ( bp[3] ); 33346364Sbostic else return(0); 33446364Sbostic } 33546364Sbostic 33646364Sbostic 33746364Sbostic /* 33846364Sbostic Return the data for the key/data pair 33946364Sbostic that begins on this page at this index 34046364Sbostic (index should always be 1) 34146364Sbostic */ 34246364Sbostic extern int 34346364Sbostic __big_return ( bufp, ndx, val, set_current ) 34446364Sbostic BUFHEAD *bufp; 34546364Sbostic int ndx; 34646364Sbostic DBT *val; 34746364Sbostic int set_current; 34846364Sbostic { 34946364Sbostic BUFHEAD *save_p; 35046364Sbostic u_short save_addr; 35146364Sbostic u_short *bp = (u_short *)bufp->page; 35246364Sbostic u_short off, len; 35346364Sbostic char *cp, *tp; 35446364Sbostic 35546364Sbostic while ( bp[ndx+1] == PARTIAL_KEY ) { 35646364Sbostic bufp = __get_buf ( bp[bp[0]-1], bufp, 0 ); 35746364Sbostic if ( !bufp ) return(-1); 35846364Sbostic bp = (u_short *)bufp->page; 35946364Sbostic ndx = 1; 36046364Sbostic } 36146364Sbostic 36246364Sbostic if ( bp[ndx+1] == FULL_KEY ) { 36346364Sbostic bufp = __get_buf ( bp[bp[0]-1], bufp, 0 ); 36446364Sbostic if ( !bufp ) return(-1); 36546364Sbostic bp = (u_short *)bufp->page; 36646364Sbostic save_p = bufp; 36746364Sbostic save_addr = save_p->addr; 36846364Sbostic off = bp[1]; 36946364Sbostic len = 0; 37046364Sbostic } else if (!FREESPACE(bp)) { 37146364Sbostic /* 37246364Sbostic This is a hack. We can't distinguish between 37346364Sbostic FULL_KEY_DATA that contains complete data or 37446364Sbostic incomplete data, so we require that if the 37546364Sbostic data is complete, there is at least 1 byte 37646364Sbostic of free space left. 37746364Sbostic */ 37846364Sbostic off = bp[bp[0]]; 37946364Sbostic len = bp[1] - off; 38046364Sbostic save_p = bufp; 38146364Sbostic save_addr = bufp->addr; 38246364Sbostic bufp = __get_buf ( bp[bp[0]-1], bufp, 0 ); 38346364Sbostic if ( !bufp ) return(-1); 38446364Sbostic bp = (u_short *)bufp->page; 38546364Sbostic } else { 38646364Sbostic /* The data is all on one page */ 38746364Sbostic tp = (char *)bp; 38846364Sbostic off = bp[bp[0]]; 38946364Sbostic val->data = tp + off; 39046364Sbostic val->size = bp[1] - off; 39146364Sbostic if ( set_current ) { 39246364Sbostic if ( bp[0] == 2 ) { /* No more buckets in chain */ 39346364Sbostic hashp->cpage = NULL; 39446364Sbostic hashp->cbucket++; 39546364Sbostic hashp->cndx=1; 39646364Sbostic } else { 39746364Sbostic hashp->cpage = __get_buf ( bp[bp[0]-1], bufp, 0 ); 39846364Sbostic if ( !hashp->cpage )return(-1); 39946364Sbostic hashp->cndx = 1; 40046364Sbostic if ( !((u_short *)hashp->cpage->page)[0] ) { 40146364Sbostic hashp->cbucket++; 40246364Sbostic hashp->cpage = NULL; 40346364Sbostic } 40446364Sbostic } 40546364Sbostic } 40646364Sbostic return(0); 40746364Sbostic } 40846364Sbostic 40946364Sbostic val->size = collect_data ( bufp, len, set_current ); 41046364Sbostic if ( val->size == -1 ) { 41146364Sbostic return(-1); 41246364Sbostic } 41346364Sbostic if ( save_p->addr != save_addr ) { 41446364Sbostic /* We are pretty short on buffers */ 41546364Sbostic errno = EINVAL; /* OUT OF BUFFERS */ 41646364Sbostic return(-1); 41746364Sbostic } 41846364Sbostic bcopy ( (save_p->page)+off, hashp->tmp_buf, len ); 41946364Sbostic val->data = hashp->tmp_buf; 42046364Sbostic return(0); 42146364Sbostic } 42246364Sbostic 42346364Sbostic /* 42446364Sbostic Count how big the total datasize is by 42546364Sbostic recursing through the pages. Then allocate 42646364Sbostic a buffer and copy the data as you recurse up. 42746364Sbostic */ 42846364Sbostic static int 42946364Sbostic collect_data ( bufp, len, set ) 43046364Sbostic BUFHEAD *bufp; 43146364Sbostic int len; 43246364Sbostic int set; 43346364Sbostic { 43446364Sbostic register char *p = bufp->page; 43546364Sbostic register u_short *bp = (u_short *)p; 43646364Sbostic u_short save_addr; 43746364Sbostic int mylen, totlen; 43846364Sbostic BUFHEAD *xbp; 43946364Sbostic 44046364Sbostic mylen = hashp->BSIZE - bp[1]; 44146364Sbostic save_addr = bufp->addr; 44246364Sbostic 44346364Sbostic if ( bp[2] == FULL_KEY_DATA ) { /* End of Data */ 44446364Sbostic totlen = len + mylen; 44546364Sbostic if ( hashp->tmp_buf ) free (hashp->tmp_buf); 44646364Sbostic hashp->tmp_buf = (char *)malloc ( totlen ); 44746364Sbostic if ( !hashp->tmp_buf ) { 44846364Sbostic return(-1); 44946364Sbostic } 45046364Sbostic if ( set ) { 45146364Sbostic hashp->cndx = 1; 45246364Sbostic if ( bp[0] == 2 ) { /* No more buckets in chain */ 45346364Sbostic hashp->cpage = NULL; 45446364Sbostic hashp->cbucket++; 45546364Sbostic } else { 45646364Sbostic hashp->cpage = __get_buf ( bp[bp[0]-1], bufp, 0 ); 45746364Sbostic if (!hashp->cpage) { 45846364Sbostic return(-1); 45946364Sbostic } else if ( !((u_short *)hashp->cpage->page)[0] ) { 46046364Sbostic hashp->cbucket++; 46146364Sbostic hashp->cpage = NULL; 46246364Sbostic } 46346364Sbostic } 46446364Sbostic } 46546364Sbostic } else { 46646364Sbostic xbp = __get_buf ( bp[bp[0]-1], bufp, 0 ); 46746364Sbostic if ( !xbp || ((totlen = collect_data ( xbp, len + mylen, set )) < 1) ) { 46846364Sbostic return(-1); 46946364Sbostic } 47046364Sbostic } 47146364Sbostic if ( bufp->addr != save_addr ) { 47246364Sbostic errno = EINVAL; /* Out of buffers */ 47346364Sbostic return(-1); 47446364Sbostic } 47546364Sbostic bcopy ( (bufp->page) + bp[1], &hashp->tmp_buf[len], mylen ); 47646364Sbostic return ( totlen ); 47746364Sbostic } 47846364Sbostic 47946364Sbostic /* 48046364Sbostic Fill in the key and data 48146364Sbostic for this big pair 48246364Sbostic */ 48346364Sbostic extern int 48446364Sbostic __big_keydata ( bufp, ndx, key, val, set ) 48546364Sbostic BUFHEAD *bufp; 48646364Sbostic int ndx; 48746364Sbostic DBT *key, *val; 48846364Sbostic int set; 48946364Sbostic { 49046364Sbostic key->size = collect_key ( bufp, 0, val, set ); 49146364Sbostic if ( key->size == -1 ) { 49246364Sbostic return (-1); 49346364Sbostic } 49446364Sbostic key->data = hashp->tmp_key; 49546364Sbostic return(0); 49646364Sbostic } 49746364Sbostic 49846364Sbostic /* 49946364Sbostic Count how big the total key size is by 50046364Sbostic recursing through the pages. Then collect 50146364Sbostic the data, allocate a buffer and copy the key as 50246364Sbostic you recurse up. 50346364Sbostic */ 50446364Sbostic static int 50546364Sbostic collect_key ( bufp, len, val, set ) 50646364Sbostic BUFHEAD *bufp; 50746364Sbostic int len; 50846364Sbostic DBT *val; 50946364Sbostic int set; 51046364Sbostic { 51146364Sbostic char *p = bufp->page; 51246364Sbostic u_short *bp = (u_short *)p; 51346364Sbostic u_short save_addr; 51446364Sbostic int mylen, totlen; 51546364Sbostic BUFHEAD *xbp; 51646364Sbostic 51746364Sbostic mylen = hashp->BSIZE - bp[1]; 51846364Sbostic 51946364Sbostic save_addr = bufp->addr; 52046364Sbostic totlen = len + mylen; 52146364Sbostic if ( bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA ) {/* End of Key */ 52246364Sbostic if ( hashp->tmp_key ) free (hashp->tmp_key); 52346364Sbostic hashp->tmp_key = (char *)malloc ( totlen ); 52446364Sbostic if ( !hashp->tmp_key ) { 52546364Sbostic return(-1); 52646364Sbostic } 52746364Sbostic __big_return ( bufp, 1, val, set ); 52846364Sbostic } else { 52946364Sbostic xbp = __get_buf (bp[bp[0]-1], bufp, 0); 53046364Sbostic if ( !xbp || ((totlen = collect_key (xbp, totlen, val, set)) < 1 ) ) { 53146364Sbostic return(-1); 53246364Sbostic } 53346364Sbostic } 53446364Sbostic if ( bufp->addr != save_addr ) { 53546364Sbostic errno = EINVAL; /* MIS -- OUT OF BUFFERS */ 53646364Sbostic return (-1); 53746364Sbostic } 53846364Sbostic bcopy ( (bufp->page) + bp[1], &hashp->tmp_key[len], mylen ); 53946364Sbostic return ( totlen ); 54046364Sbostic } 54146364Sbostic 54246364Sbostic 54346364Sbostic /* 54446364Sbostic return 0 => OK 54546364Sbostic -1 => error 54646364Sbostic */ 54746364Sbostic extern int 54846364Sbostic __big_split ( op, np, big_keyp, addr, obucket, ret ) 54946364Sbostic BUFHEAD *op; /* Pointer to where to put keys that go in old bucket */ 55046364Sbostic BUFHEAD *np; /* Pointer to new bucket page */ 55146364Sbostic BUFHEAD *big_keyp; /* Pointer to first page containing the big key/data */ 55246364Sbostic u_short addr; /* Address of big_keyp */ 55346364Sbostic int obucket; /* Old Bucket */ 55446364Sbostic SPLIT_RETURN *ret; 55546364Sbostic { 55646364Sbostic register u_short *prev_pagep; 55746364Sbostic register BUFHEAD *tmpp; 55846364Sbostic register u_short *tp; 55946364Sbostic BUFHEAD *bp = big_keyp; 56046364Sbostic u_short off, free_space; 56146364Sbostic u_short n; 56246364Sbostic 56346364Sbostic DBT key, val; 56446364Sbostic 56546364Sbostic int change; 56646364Sbostic 56746364Sbostic /* Now figure out where the big key/data goes */ 56846364Sbostic if (__big_keydata ( big_keyp, 1, &key, &val, 0 )) { 56946364Sbostic return(-1); 57046364Sbostic } 57146364Sbostic change = (__call_hash ( key.data, key.size ) != obucket ); 57246364Sbostic 57346364Sbostic if ( ret->next_addr = __find_last_page ( &big_keyp ) ) { 57446364Sbostic if (!(ret->nextp = __get_buf ( ret->next_addr, big_keyp, 0 ))) { 57546364Sbostic return(-1);; 57646364Sbostic } 57746364Sbostic } else { 57846364Sbostic ret->nextp = NULL; 57946364Sbostic } 58046364Sbostic 58146364Sbostic /* Now make one of np/op point to the big key/data pair */ 58246364Sbostic assert(np->ovfl == NULL); 58346364Sbostic if ( change ) tmpp = np; 58446364Sbostic else tmpp = op; 58546364Sbostic 58646364Sbostic tmpp->flags |= BUF_MOD; 58746364Sbostic #ifdef DEBUG1 58846364Sbostic fprintf ( stderr, "BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr, 58946364Sbostic (tmpp->ovfl?tmpp->ovfl->addr:0), 59046364Sbostic (bp?bp->addr:0) ); 59146364Sbostic #endif 59246364Sbostic tmpp->ovfl = bp; /* one of op/np point to big_keyp */ 59346364Sbostic tp = (u_short *)tmpp->page; 59446364Sbostic assert ( FREESPACE(tp) >= OVFLSIZE); 59546364Sbostic n = tp[0]; 59646364Sbostic off = OFFSET(tp); 59746364Sbostic free_space = FREESPACE(tp); 59846364Sbostic tp[++n] = addr; 59946364Sbostic tp[++n] = OVFLPAGE; 60046364Sbostic tp[0] = n; 60146364Sbostic OFFSET(tp) = off; 60246364Sbostic FREESPACE(tp) = free_space - OVFLSIZE; 60346364Sbostic 60446364Sbostic /* 60546364Sbostic Finally, set the new and old return values. 60646364Sbostic BIG_KEYP contains a pointer to the last page of the big key_data pair. 60746364Sbostic Make sure that big_keyp has no following page (2 elements) or create 60846364Sbostic an empty following page. 60946364Sbostic */ 61046364Sbostic 61146364Sbostic ret->newp = np; 61246364Sbostic ret->oldp = op; 61346364Sbostic 61446364Sbostic tp = (u_short *)big_keyp->page; 61546364Sbostic big_keyp->flags |= BUF_MOD; 61646364Sbostic if ( tp[0] > 2 ) { 61746364Sbostic /* 61846364Sbostic There may be either one or two offsets on this page 61946364Sbostic If there is one, then the overflow page is linked on 62046364Sbostic normally and tp[4] is OVFLPAGE. If there are two, tp[4] 62146364Sbostic contains the second offset and needs to get stuffed in 62246364Sbostic after the next overflow page is added 62346364Sbostic */ 62446364Sbostic n = tp[4]; 62546364Sbostic free_space = FREESPACE(tp); 62646364Sbostic off = OFFSET(tp); 62746364Sbostic tp[0] -= 2; 62846364Sbostic FREESPACE(tp) = free_space + OVFLSIZE; 62946364Sbostic OFFSET(tp) = off; 63046364Sbostic tmpp = __add_ovflpage ( big_keyp ); 63146364Sbostic if ( !tmpp ) { 63246364Sbostic return(-1); 63346364Sbostic } 63446364Sbostic tp[4] = n; 63546364Sbostic } else { 63646364Sbostic tmpp = big_keyp; 63746364Sbostic } 63846364Sbostic 63946364Sbostic if ( change ) ret->newp = tmpp; 64046364Sbostic else ret->oldp = tmpp; 64146364Sbostic 64246364Sbostic return(0); 64346364Sbostic } 644