1*46364Sbostic /*- 2*46364Sbostic * Copyright (c) 1990 The Regents of the University of California. 3*46364Sbostic * All rights reserved. 4*46364Sbostic * 5*46364Sbostic * This code is derived from software contributed to Berkeley by 6*46364Sbostic * Margo Seltzer. 7*46364Sbostic * 8*46364Sbostic * %sccs.include.redist.c% 9*46364Sbostic */ 10*46364Sbostic 11*46364Sbostic #if defined(LIBC_SCCS) && !defined(lint) 12*46364Sbostic static char sccsid[] = "@(#)hash_bigkey.c 5.1 (Berkeley) 02/12/91"; 13*46364Sbostic #endif /* LIBC_SCCS and not lint */ 14*46364Sbostic 15*46364Sbostic /****************************************************************************** 16*46364Sbostic 17*46364Sbostic PACKAGE: hash 18*46364Sbostic 19*46364Sbostic DESCRIPTION: 20*46364Sbostic Big key/data handling for the hashing package. 21*46364Sbostic 22*46364Sbostic ROUTINES: 23*46364Sbostic External 24*46364Sbostic __big_keydata 25*46364Sbostic __big_split 26*46364Sbostic __big_insert 27*46364Sbostic __big_return 28*46364Sbostic __big_delete 29*46364Sbostic __find_last_page 30*46364Sbostic Internal 31*46364Sbostic collect_key 32*46364Sbostic collect_data 33*46364Sbostic ******************************************************************************/ 34*46364Sbostic /* Includes */ 35*46364Sbostic #include <sys/param.h> 36*46364Sbostic #include <sys/file.h> 37*46364Sbostic #include <assert.h> 38*46364Sbostic #include <errno.h> 39*46364Sbostic #include <db.h> 40*46364Sbostic #include <stdio.h> 41*46364Sbostic #include "hash.h" 42*46364Sbostic #include "page.h" 43*46364Sbostic 44*46364Sbostic /* Externals */ 45*46364Sbostic /* buf.c */ 46*46364Sbostic extern BUFHEAD *__get_buf(); 47*46364Sbostic 48*46364Sbostic /* page.c */ 49*46364Sbostic extern BUFHEAD *__add_ovflpage(); 50*46364Sbostic 51*46364Sbostic /* My externals */ 52*46364Sbostic extern int __big_keydata(); 53*46364Sbostic extern int __big_split(); 54*46364Sbostic extern int __big_insert(); 55*46364Sbostic extern int __big_return(); 56*46364Sbostic extern int __big_delete(); 57*46364Sbostic extern u_short __find_last_page(); 58*46364Sbostic extern int __find_bigpair(); 59*46364Sbostic 60*46364Sbostic /* My internals */ 61*46364Sbostic static int collect_key(); 62*46364Sbostic static int collect_data(); 63*46364Sbostic 64*46364Sbostic #ifdef HASH_STATISTICS 65*46364Sbostic extern long hash_accesses, hash_collisions, hash_expansions, hash_overflows; 66*46364Sbostic #endif 67*46364Sbostic /* 68*46364Sbostic Big_insert 69*46364Sbostic 70*46364Sbostic You need to do an insert and the key/data pair is too big 71*46364Sbostic 0 ==> OK 72*46364Sbostic -1 ==> ERROR 73*46364Sbostic */ 74*46364Sbostic extern int 75*46364Sbostic __big_insert ( bufp, key, val ) 76*46364Sbostic BUFHEAD *bufp; 77*46364Sbostic DBT *key, *val; 78*46364Sbostic { 79*46364Sbostic char *cp = bufp->page; /* Character pointer of p */ 80*46364Sbostic register u_short *p = (u_short *)cp; 81*46364Sbostic char *key_data, *val_data; 82*46364Sbostic int key_size, val_size; 83*46364Sbostic int n; 84*46364Sbostic u_short space, move_bytes, off; 85*46364Sbostic 86*46364Sbostic key_data = key->data; 87*46364Sbostic key_size = key->size; 88*46364Sbostic val_data = val->data; 89*46364Sbostic val_size = val->size; 90*46364Sbostic 91*46364Sbostic /* First move the Key */ 92*46364Sbostic for ( space = FREESPACE(p) - BIGOVERHEAD; 93*46364Sbostic key_size; 94*46364Sbostic space = FREESPACE(p) - BIGOVERHEAD ) { 95*46364Sbostic move_bytes = MIN(space, key_size); 96*46364Sbostic off = OFFSET(p) - move_bytes; 97*46364Sbostic bcopy (key_data, cp+off, move_bytes ); 98*46364Sbostic key_size -= move_bytes; 99*46364Sbostic key_data += move_bytes; 100*46364Sbostic n = p[0]; 101*46364Sbostic p[++n] = off; 102*46364Sbostic p[0] = ++n; 103*46364Sbostic FREESPACE(p) = off - PAGE_META(n); 104*46364Sbostic OFFSET(p) = off; 105*46364Sbostic p[n] = PARTIAL_KEY; 106*46364Sbostic bufp = __add_ovflpage(bufp); 107*46364Sbostic if ( !bufp ) { 108*46364Sbostic return(-1); 109*46364Sbostic } 110*46364Sbostic n = p[0]; 111*46364Sbostic if ( !key_size ) { 112*46364Sbostic if ( FREESPACE(p) ) { 113*46364Sbostic move_bytes = MIN (FREESPACE(p), val_size); 114*46364Sbostic off = OFFSET(p) - move_bytes; 115*46364Sbostic p[n] = off; 116*46364Sbostic bcopy ( val_data, cp + off, move_bytes ); 117*46364Sbostic val_data += move_bytes; 118*46364Sbostic val_size -= move_bytes; 119*46364Sbostic p[n-2] = FULL_KEY_DATA; 120*46364Sbostic FREESPACE(p) = FREESPACE(p) - move_bytes; 121*46364Sbostic OFFSET(p) = off; 122*46364Sbostic } 123*46364Sbostic else p[n-2] = FULL_KEY; 124*46364Sbostic } 125*46364Sbostic p = (u_short *)bufp->page; 126*46364Sbostic cp = bufp->page; 127*46364Sbostic bufp->flags |= BUF_MOD; 128*46364Sbostic } 129*46364Sbostic 130*46364Sbostic /* Now move the data */ 131*46364Sbostic for ( space = FREESPACE(p) - BIGOVERHEAD; 132*46364Sbostic val_size; 133*46364Sbostic space = FREESPACE(p) - BIGOVERHEAD ) { 134*46364Sbostic move_bytes = MIN(space, val_size); 135*46364Sbostic /* 136*46364Sbostic Here's the hack to make sure that if the data ends 137*46364Sbostic on the same page as the key ends, FREESPACE is 138*46364Sbostic at least one 139*46364Sbostic */ 140*46364Sbostic if ( space == val_size && val_size == val->size ) { 141*46364Sbostic move_bytes--; 142*46364Sbostic } 143*46364Sbostic off = OFFSET(p) - move_bytes; 144*46364Sbostic bcopy (val_data, cp+off, move_bytes ); 145*46364Sbostic val_size -= move_bytes; 146*46364Sbostic val_data += move_bytes; 147*46364Sbostic n = p[0]; 148*46364Sbostic p[++n] = off; 149*46364Sbostic p[0] = ++n; 150*46364Sbostic FREESPACE(p) = off - PAGE_META(n); 151*46364Sbostic OFFSET(p) = off; 152*46364Sbostic if ( val_size ) { 153*46364Sbostic p[n] = FULL_KEY; 154*46364Sbostic bufp = __add_ovflpage (bufp); 155*46364Sbostic if ( !bufp ) { 156*46364Sbostic return(-1); 157*46364Sbostic } 158*46364Sbostic cp = bufp->page; 159*46364Sbostic p = (u_short *)cp; 160*46364Sbostic } else { 161*46364Sbostic p[n] = FULL_KEY_DATA; 162*46364Sbostic } 163*46364Sbostic bufp->flags |= BUF_MOD; 164*46364Sbostic } 165*46364Sbostic return(0); 166*46364Sbostic } 167*46364Sbostic 168*46364Sbostic /* 169*46364Sbostic Called when bufp's page contains a partial key (index should be 1) 170*46364Sbostic 171*46364Sbostic All pages in the big key/data pair except bufp are freed. We cannot 172*46364Sbostic free bufp because the page pointing to it is lost and we can't 173*46364Sbostic get rid of its pointer. 174*46364Sbostic 175*46364Sbostic Returns 0 => OK 176*46364Sbostic -1 => ERROR 177*46364Sbostic */ 178*46364Sbostic extern int 179*46364Sbostic __big_delete (bufp, ndx) 180*46364Sbostic BUFHEAD *bufp; 181*46364Sbostic int ndx; 182*46364Sbostic { 183*46364Sbostic register BUFHEAD *rbufp = bufp; 184*46364Sbostic register BUFHEAD *last_bfp = NULL; 185*46364Sbostic char *cp; 186*46364Sbostic u_short *bp = (u_short *)bufp->page; 187*46364Sbostic u_short *xbp; 188*46364Sbostic u_short pageno = 0; 189*46364Sbostic u_short off, free_sp; 190*46364Sbostic int key_done = 0; 191*46364Sbostic int n; 192*46364Sbostic 193*46364Sbostic while (!key_done || (bp[2] != FULL_KEY_DATA)) { 194*46364Sbostic if ( bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA ) key_done = 1; 195*46364Sbostic 196*46364Sbostic /* 197*46364Sbostic If there is freespace left on a FULL_KEY_DATA page, 198*46364Sbostic then the data is short and fits entirely on this 199*46364Sbostic page, and this is the last page. 200*46364Sbostic */ 201*46364Sbostic if ( bp[2] == FULL_KEY_DATA && FREESPACE(bp) ) break; 202*46364Sbostic pageno = bp[bp[0]-1]; 203*46364Sbostic rbufp->flags |= BUF_MOD; 204*46364Sbostic rbufp = __get_buf ( pageno, rbufp, 0 ); 205*46364Sbostic if ( last_bfp ) __free_ovflpage(last_bfp); 206*46364Sbostic last_bfp = rbufp; 207*46364Sbostic if ( !rbufp ) return(-1); /* Error */ 208*46364Sbostic bp = (u_short *)rbufp->page; 209*46364Sbostic } 210*46364Sbostic 211*46364Sbostic /* 212*46364Sbostic If we get here then rbufp points to the last page of 213*46364Sbostic the big key/data pair. Bufp points to the first 214*46364Sbostic one -- it should now be empty pointing to the next 215*46364Sbostic page after this pair. Can't free it because we don't 216*46364Sbostic have the page pointing to it. 217*46364Sbostic */ 218*46364Sbostic 219*46364Sbostic /* This is information from the last page of the pair */ 220*46364Sbostic n = bp[0]; 221*46364Sbostic pageno = bp[n-1]; 222*46364Sbostic 223*46364Sbostic /* Now, bp is the first page of the pair */ 224*46364Sbostic bp = (u_short *)bufp->page; 225*46364Sbostic if ( n > 2 ) { 226*46364Sbostic /* There is an overflow page */ 227*46364Sbostic bp[1] = pageno; 228*46364Sbostic bp[2] = OVFLPAGE; 229*46364Sbostic bufp->ovfl = rbufp->ovfl; 230*46364Sbostic } else { 231*46364Sbostic /* This is the last page */ 232*46364Sbostic bufp->ovfl = NULL; 233*46364Sbostic } 234*46364Sbostic n -= 2; 235*46364Sbostic bp[0] = n; 236*46364Sbostic FREESPACE(bp) = hashp->BSIZE - PAGE_META(n); 237*46364Sbostic OFFSET(bp) = hashp->BSIZE - 1; 238*46364Sbostic 239*46364Sbostic bufp->flags |= BUF_MOD; 240*46364Sbostic if ( rbufp ) __free_ovflpage(rbufp); 241*46364Sbostic if ( last_bfp != rbufp ) __free_ovflpage(last_bfp); 242*46364Sbostic 243*46364Sbostic hashp->NKEYS--; 244*46364Sbostic return(0); 245*46364Sbostic } 246*46364Sbostic 247*46364Sbostic /* 248*46364Sbostic 0 = key not found 249*46364Sbostic -1 = get next overflow page 250*46364Sbostic -2 means key not found and this is big key/data 251*46364Sbostic -3 error 252*46364Sbostic */ 253*46364Sbostic extern int 254*46364Sbostic __find_bigpair(bufp, ndx, key, size ) 255*46364Sbostic BUFHEAD *bufp; 256*46364Sbostic int ndx; 257*46364Sbostic char *key; 258*46364Sbostic int size; 259*46364Sbostic { 260*46364Sbostic register u_short *bp = (u_short *)bufp->page; 261*46364Sbostic register char *p = bufp->page; 262*46364Sbostic int ksize = size; 263*46364Sbostic char *kkey = key; 264*46364Sbostic u_short bytes; 265*46364Sbostic 266*46364Sbostic 267*46364Sbostic for ( bytes = hashp->BSIZE - bp[ndx]; 268*46364Sbostic bytes <= size && bp[ndx+1] == PARTIAL_KEY; 269*46364Sbostic bytes = hashp->BSIZE - bp[ndx] ) { 270*46364Sbostic 271*46364Sbostic if ( bcmp ( p+bp[ndx], kkey, bytes ))return(-2); 272*46364Sbostic kkey += bytes; 273*46364Sbostic ksize -= bytes; 274*46364Sbostic bufp = __get_buf ( bp[ndx+2], bufp, 0 ); 275*46364Sbostic if ( !bufp ) { 276*46364Sbostic return(-3); 277*46364Sbostic } 278*46364Sbostic p = bufp->page; 279*46364Sbostic bp = (u_short *)p; 280*46364Sbostic ndx = 1; 281*46364Sbostic } 282*46364Sbostic 283*46364Sbostic if ( (bytes != ksize) || bcmp ( p+bp[ndx], kkey, bytes )) { 284*46364Sbostic #ifdef HASH_STATISTICS 285*46364Sbostic hash_collisions++; 286*46364Sbostic #endif 287*46364Sbostic return(-2); 288*46364Sbostic } 289*46364Sbostic else return (ndx); 290*46364Sbostic } 291*46364Sbostic 292*46364Sbostic 293*46364Sbostic /* 294*46364Sbostic Given the buffer pointer of the first overflow page of a big pair, 295*46364Sbostic find the end of the big pair 296*46364Sbostic 297*46364Sbostic This will set bpp to the buffer header of the last page of the big pair. 298*46364Sbostic It will return the pageno of the overflow page following the last page of 299*46364Sbostic the pair; 0 if there isn't any (i.e. big pair is the last key in the 300*46364Sbostic bucket) 301*46364Sbostic */ 302*46364Sbostic extern u_short 303*46364Sbostic __find_last_page ( bpp ) 304*46364Sbostic BUFHEAD **bpp; 305*46364Sbostic { 306*46364Sbostic int n; 307*46364Sbostic u_short pageno; 308*46364Sbostic BUFHEAD *bufp = *bpp; 309*46364Sbostic u_short *bp = (u_short *)bufp->page; 310*46364Sbostic 311*46364Sbostic while ( 1 ) { 312*46364Sbostic n = bp[0]; 313*46364Sbostic 314*46364Sbostic /* 315*46364Sbostic This is the last page if: 316*46364Sbostic the tag is FULL_KEY_DATA and either 317*46364Sbostic only 2 entries 318*46364Sbostic OVFLPAGE marker is explicit 319*46364Sbostic there is freespace on the page 320*46364Sbostic */ 321*46364Sbostic if ( bp[2] == FULL_KEY_DATA && 322*46364Sbostic ((n == 2) || (bp[n] == OVFLPAGE) || (FREESPACE(bp)) ) ) break; 323*46364Sbostic 324*46364Sbostic pageno = bp[n-1]; 325*46364Sbostic bufp = __get_buf ( pageno, bufp, 0 ); 326*46364Sbostic if ( !bufp ) return (0); /* Need to indicate an error! */ 327*46364Sbostic bp = (u_short *)bufp->page; 328*46364Sbostic } 329*46364Sbostic 330*46364Sbostic *bpp = bufp; 331*46364Sbostic if ( bp[0] > 2 ) return ( bp[3] ); 332*46364Sbostic else return(0); 333*46364Sbostic } 334*46364Sbostic 335*46364Sbostic 336*46364Sbostic /* 337*46364Sbostic Return the data for the key/data pair 338*46364Sbostic that begins on this page at this index 339*46364Sbostic (index should always be 1) 340*46364Sbostic */ 341*46364Sbostic extern int 342*46364Sbostic __big_return ( bufp, ndx, val, set_current ) 343*46364Sbostic BUFHEAD *bufp; 344*46364Sbostic int ndx; 345*46364Sbostic DBT *val; 346*46364Sbostic int set_current; 347*46364Sbostic { 348*46364Sbostic BUFHEAD *save_p; 349*46364Sbostic u_short save_addr; 350*46364Sbostic u_short *bp = (u_short *)bufp->page; 351*46364Sbostic u_short off, len; 352*46364Sbostic char *cp, *tp; 353*46364Sbostic 354*46364Sbostic while ( bp[ndx+1] == PARTIAL_KEY ) { 355*46364Sbostic bufp = __get_buf ( bp[bp[0]-1], bufp, 0 ); 356*46364Sbostic if ( !bufp ) return(-1); 357*46364Sbostic bp = (u_short *)bufp->page; 358*46364Sbostic ndx = 1; 359*46364Sbostic } 360*46364Sbostic 361*46364Sbostic if ( bp[ndx+1] == FULL_KEY ) { 362*46364Sbostic bufp = __get_buf ( bp[bp[0]-1], bufp, 0 ); 363*46364Sbostic if ( !bufp ) return(-1); 364*46364Sbostic bp = (u_short *)bufp->page; 365*46364Sbostic save_p = bufp; 366*46364Sbostic save_addr = save_p->addr; 367*46364Sbostic off = bp[1]; 368*46364Sbostic len = 0; 369*46364Sbostic } else if (!FREESPACE(bp)) { 370*46364Sbostic /* 371*46364Sbostic This is a hack. We can't distinguish between 372*46364Sbostic FULL_KEY_DATA that contains complete data or 373*46364Sbostic incomplete data, so we require that if the 374*46364Sbostic data is complete, there is at least 1 byte 375*46364Sbostic of free space left. 376*46364Sbostic */ 377*46364Sbostic off = bp[bp[0]]; 378*46364Sbostic len = bp[1] - off; 379*46364Sbostic save_p = bufp; 380*46364Sbostic save_addr = bufp->addr; 381*46364Sbostic bufp = __get_buf ( bp[bp[0]-1], bufp, 0 ); 382*46364Sbostic if ( !bufp ) return(-1); 383*46364Sbostic bp = (u_short *)bufp->page; 384*46364Sbostic } else { 385*46364Sbostic /* The data is all on one page */ 386*46364Sbostic tp = (char *)bp; 387*46364Sbostic off = bp[bp[0]]; 388*46364Sbostic val->data = tp + off; 389*46364Sbostic val->size = bp[1] - off; 390*46364Sbostic if ( set_current ) { 391*46364Sbostic if ( bp[0] == 2 ) { /* No more buckets in chain */ 392*46364Sbostic hashp->cpage = NULL; 393*46364Sbostic hashp->cbucket++; 394*46364Sbostic hashp->cndx=1; 395*46364Sbostic } else { 396*46364Sbostic hashp->cpage = __get_buf ( bp[bp[0]-1], bufp, 0 ); 397*46364Sbostic if ( !hashp->cpage )return(-1); 398*46364Sbostic hashp->cndx = 1; 399*46364Sbostic if ( !((u_short *)hashp->cpage->page)[0] ) { 400*46364Sbostic hashp->cbucket++; 401*46364Sbostic hashp->cpage = NULL; 402*46364Sbostic } 403*46364Sbostic } 404*46364Sbostic } 405*46364Sbostic return(0); 406*46364Sbostic } 407*46364Sbostic 408*46364Sbostic val->size = collect_data ( bufp, len, set_current ); 409*46364Sbostic if ( val->size == -1 ) { 410*46364Sbostic return(-1); 411*46364Sbostic } 412*46364Sbostic if ( save_p->addr != save_addr ) { 413*46364Sbostic /* We are pretty short on buffers */ 414*46364Sbostic errno = EINVAL; /* OUT OF BUFFERS */ 415*46364Sbostic return(-1); 416*46364Sbostic } 417*46364Sbostic bcopy ( (save_p->page)+off, hashp->tmp_buf, len ); 418*46364Sbostic val->data = hashp->tmp_buf; 419*46364Sbostic return(0); 420*46364Sbostic } 421*46364Sbostic 422*46364Sbostic /* 423*46364Sbostic Count how big the total datasize is by 424*46364Sbostic recursing through the pages. Then allocate 425*46364Sbostic a buffer and copy the data as you recurse up. 426*46364Sbostic */ 427*46364Sbostic static int 428*46364Sbostic collect_data ( bufp, len, set ) 429*46364Sbostic BUFHEAD *bufp; 430*46364Sbostic int len; 431*46364Sbostic int set; 432*46364Sbostic { 433*46364Sbostic register char *p = bufp->page; 434*46364Sbostic register u_short *bp = (u_short *)p; 435*46364Sbostic u_short save_addr; 436*46364Sbostic int mylen, totlen; 437*46364Sbostic BUFHEAD *xbp; 438*46364Sbostic 439*46364Sbostic mylen = hashp->BSIZE - bp[1]; 440*46364Sbostic save_addr = bufp->addr; 441*46364Sbostic 442*46364Sbostic if ( bp[2] == FULL_KEY_DATA ) { /* End of Data */ 443*46364Sbostic totlen = len + mylen; 444*46364Sbostic if ( hashp->tmp_buf ) free (hashp->tmp_buf); 445*46364Sbostic hashp->tmp_buf = (char *)malloc ( totlen ); 446*46364Sbostic if ( !hashp->tmp_buf ) { 447*46364Sbostic return(-1); 448*46364Sbostic } 449*46364Sbostic if ( set ) { 450*46364Sbostic hashp->cndx = 1; 451*46364Sbostic if ( bp[0] == 2 ) { /* No more buckets in chain */ 452*46364Sbostic hashp->cpage = NULL; 453*46364Sbostic hashp->cbucket++; 454*46364Sbostic } else { 455*46364Sbostic hashp->cpage = __get_buf ( bp[bp[0]-1], bufp, 0 ); 456*46364Sbostic if (!hashp->cpage) { 457*46364Sbostic return(-1); 458*46364Sbostic } else if ( !((u_short *)hashp->cpage->page)[0] ) { 459*46364Sbostic hashp->cbucket++; 460*46364Sbostic hashp->cpage = NULL; 461*46364Sbostic } 462*46364Sbostic } 463*46364Sbostic } 464*46364Sbostic } else { 465*46364Sbostic xbp = __get_buf ( bp[bp[0]-1], bufp, 0 ); 466*46364Sbostic if ( !xbp || ((totlen = collect_data ( xbp, len + mylen, set )) < 1) ) { 467*46364Sbostic return(-1); 468*46364Sbostic } 469*46364Sbostic } 470*46364Sbostic if ( bufp->addr != save_addr ) { 471*46364Sbostic errno = EINVAL; /* Out of buffers */ 472*46364Sbostic return(-1); 473*46364Sbostic } 474*46364Sbostic bcopy ( (bufp->page) + bp[1], &hashp->tmp_buf[len], mylen ); 475*46364Sbostic return ( totlen ); 476*46364Sbostic } 477*46364Sbostic 478*46364Sbostic /* 479*46364Sbostic Fill in the key and data 480*46364Sbostic for this big pair 481*46364Sbostic */ 482*46364Sbostic extern int 483*46364Sbostic __big_keydata ( bufp, ndx, key, val, set ) 484*46364Sbostic BUFHEAD *bufp; 485*46364Sbostic int ndx; 486*46364Sbostic DBT *key, *val; 487*46364Sbostic int set; 488*46364Sbostic { 489*46364Sbostic key->size = collect_key ( bufp, 0, val, set ); 490*46364Sbostic if ( key->size == -1 ) { 491*46364Sbostic return (-1); 492*46364Sbostic } 493*46364Sbostic key->data = hashp->tmp_key; 494*46364Sbostic return(0); 495*46364Sbostic } 496*46364Sbostic 497*46364Sbostic /* 498*46364Sbostic Count how big the total key size is by 499*46364Sbostic recursing through the pages. Then collect 500*46364Sbostic the data, allocate a buffer and copy the key as 501*46364Sbostic you recurse up. 502*46364Sbostic */ 503*46364Sbostic static int 504*46364Sbostic collect_key ( bufp, len, val, set ) 505*46364Sbostic BUFHEAD *bufp; 506*46364Sbostic int len; 507*46364Sbostic DBT *val; 508*46364Sbostic int set; 509*46364Sbostic { 510*46364Sbostic char *p = bufp->page; 511*46364Sbostic u_short *bp = (u_short *)p; 512*46364Sbostic u_short save_addr; 513*46364Sbostic int mylen, totlen; 514*46364Sbostic BUFHEAD *xbp; 515*46364Sbostic 516*46364Sbostic mylen = hashp->BSIZE - bp[1]; 517*46364Sbostic 518*46364Sbostic save_addr = bufp->addr; 519*46364Sbostic totlen = len + mylen; 520*46364Sbostic if ( bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA ) {/* End of Key */ 521*46364Sbostic if ( hashp->tmp_key ) free (hashp->tmp_key); 522*46364Sbostic hashp->tmp_key = (char *)malloc ( totlen ); 523*46364Sbostic if ( !hashp->tmp_key ) { 524*46364Sbostic return(-1); 525*46364Sbostic } 526*46364Sbostic __big_return ( bufp, 1, val, set ); 527*46364Sbostic } else { 528*46364Sbostic xbp = __get_buf (bp[bp[0]-1], bufp, 0); 529*46364Sbostic if ( !xbp || ((totlen = collect_key (xbp, totlen, val, set)) < 1 ) ) { 530*46364Sbostic return(-1); 531*46364Sbostic } 532*46364Sbostic } 533*46364Sbostic if ( bufp->addr != save_addr ) { 534*46364Sbostic errno = EINVAL; /* MIS -- OUT OF BUFFERS */ 535*46364Sbostic return (-1); 536*46364Sbostic } 537*46364Sbostic bcopy ( (bufp->page) + bp[1], &hashp->tmp_key[len], mylen ); 538*46364Sbostic return ( totlen ); 539*46364Sbostic } 540*46364Sbostic 541*46364Sbostic 542*46364Sbostic /* 543*46364Sbostic return 0 => OK 544*46364Sbostic -1 => error 545*46364Sbostic */ 546*46364Sbostic extern int 547*46364Sbostic __big_split ( op, np, big_keyp, addr, obucket, ret ) 548*46364Sbostic BUFHEAD *op; /* Pointer to where to put keys that go in old bucket */ 549*46364Sbostic BUFHEAD *np; /* Pointer to new bucket page */ 550*46364Sbostic BUFHEAD *big_keyp; /* Pointer to first page containing the big key/data */ 551*46364Sbostic u_short addr; /* Address of big_keyp */ 552*46364Sbostic int obucket; /* Old Bucket */ 553*46364Sbostic SPLIT_RETURN *ret; 554*46364Sbostic { 555*46364Sbostic register u_short *prev_pagep; 556*46364Sbostic register BUFHEAD *tmpp; 557*46364Sbostic register u_short *tp; 558*46364Sbostic BUFHEAD *bp = big_keyp; 559*46364Sbostic u_short off, free_space; 560*46364Sbostic u_short n; 561*46364Sbostic 562*46364Sbostic DBT key, val; 563*46364Sbostic 564*46364Sbostic int change; 565*46364Sbostic 566*46364Sbostic /* Now figure out where the big key/data goes */ 567*46364Sbostic if (__big_keydata ( big_keyp, 1, &key, &val, 0 )) { 568*46364Sbostic return(-1); 569*46364Sbostic } 570*46364Sbostic change = (__call_hash ( key.data, key.size ) != obucket ); 571*46364Sbostic 572*46364Sbostic if ( ret->next_addr = __find_last_page ( &big_keyp ) ) { 573*46364Sbostic if (!(ret->nextp = __get_buf ( ret->next_addr, big_keyp, 0 ))) { 574*46364Sbostic return(-1);; 575*46364Sbostic } 576*46364Sbostic } else { 577*46364Sbostic ret->nextp = NULL; 578*46364Sbostic } 579*46364Sbostic 580*46364Sbostic /* Now make one of np/op point to the big key/data pair */ 581*46364Sbostic assert(np->ovfl == NULL); 582*46364Sbostic if ( change ) tmpp = np; 583*46364Sbostic else tmpp = op; 584*46364Sbostic 585*46364Sbostic tmpp->flags |= BUF_MOD; 586*46364Sbostic #ifdef DEBUG1 587*46364Sbostic fprintf ( stderr, "BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr, 588*46364Sbostic (tmpp->ovfl?tmpp->ovfl->addr:0), 589*46364Sbostic (bp?bp->addr:0) ); 590*46364Sbostic #endif 591*46364Sbostic tmpp->ovfl = bp; /* one of op/np point to big_keyp */ 592*46364Sbostic tp = (u_short *)tmpp->page; 593*46364Sbostic assert ( FREESPACE(tp) >= OVFLSIZE); 594*46364Sbostic n = tp[0]; 595*46364Sbostic off = OFFSET(tp); 596*46364Sbostic free_space = FREESPACE(tp); 597*46364Sbostic tp[++n] = addr; 598*46364Sbostic tp[++n] = OVFLPAGE; 599*46364Sbostic tp[0] = n; 600*46364Sbostic OFFSET(tp) = off; 601*46364Sbostic FREESPACE(tp) = free_space - OVFLSIZE; 602*46364Sbostic 603*46364Sbostic /* 604*46364Sbostic Finally, set the new and old return values. 605*46364Sbostic BIG_KEYP contains a pointer to the last page of the big key_data pair. 606*46364Sbostic Make sure that big_keyp has no following page (2 elements) or create 607*46364Sbostic an empty following page. 608*46364Sbostic */ 609*46364Sbostic 610*46364Sbostic ret->newp = np; 611*46364Sbostic ret->oldp = op; 612*46364Sbostic 613*46364Sbostic tp = (u_short *)big_keyp->page; 614*46364Sbostic big_keyp->flags |= BUF_MOD; 615*46364Sbostic if ( tp[0] > 2 ) { 616*46364Sbostic /* 617*46364Sbostic There may be either one or two offsets on this page 618*46364Sbostic If there is one, then the overflow page is linked on 619*46364Sbostic normally and tp[4] is OVFLPAGE. If there are two, tp[4] 620*46364Sbostic contains the second offset and needs to get stuffed in 621*46364Sbostic after the next overflow page is added 622*46364Sbostic */ 623*46364Sbostic n = tp[4]; 624*46364Sbostic free_space = FREESPACE(tp); 625*46364Sbostic off = OFFSET(tp); 626*46364Sbostic tp[0] -= 2; 627*46364Sbostic FREESPACE(tp) = free_space + OVFLSIZE; 628*46364Sbostic OFFSET(tp) = off; 629*46364Sbostic tmpp = __add_ovflpage ( big_keyp ); 630*46364Sbostic if ( !tmpp ) { 631*46364Sbostic return(-1); 632*46364Sbostic } 633*46364Sbostic tp[4] = n; 634*46364Sbostic } else { 635*46364Sbostic tmpp = big_keyp; 636*46364Sbostic } 637*46364Sbostic 638*46364Sbostic if ( change ) ret->newp = tmpp; 639*46364Sbostic else ret->oldp = tmpp; 640*46364Sbostic 641*46364Sbostic return(0); 642*46364Sbostic } 643