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*50997Sbostic static char sccsid[] = "@(#)hash_bigkey.c 5.6 (Berkeley) 09/04/91"; 1346364Sbostic #endif /* LIBC_SCCS and not lint */ 1446364Sbostic 15*50997Sbostic /* 16*50997Sbostic * PACKAGE: hash 17*50997Sbostic * DESCRIPTION: 18*50997Sbostic * Big key/data handling for the hashing package. 19*50997Sbostic * 20*50997Sbostic * ROUTINES: 21*50997Sbostic * External 22*50997Sbostic * __big_keydata 23*50997Sbostic * __big_split 24*50997Sbostic * __big_insert 25*50997Sbostic * __big_return 26*50997Sbostic * __big_delete 27*50997Sbostic * __find_last_page 28*50997Sbostic * Internal 29*50997Sbostic * collect_key 30*50997Sbostic * collect_data 31*50997Sbostic */ 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> 39*50997Sbostic #ifdef DEBUG 40*50997Sbostic #include <assert.h> 41*50997Sbostic #endif 4246364Sbostic #include "hash.h" 4346364Sbostic #include "page.h" 44*50997Sbostic #include "extern.h" 4546364Sbostic 46*50997Sbostic static int collect_key __P((BUFHEAD *, int, DBT *, int)); 47*50997Sbostic static int collect_data __P((BUFHEAD *, int, int)); 4846364Sbostic 4946364Sbostic /* 50*50997Sbostic * Big_insert 51*50997Sbostic * 52*50997Sbostic * You need to do an insert and the key/data pair is too big 53*50997Sbostic * 54*50997Sbostic * Returns: 55*50997Sbostic * 0 ==> OK 56*50997Sbostic *-1 ==> ERROR 57*50997Sbostic */ 5846364Sbostic extern int 59*50997Sbostic __big_insert(bufp, key, val) 60*50997Sbostic BUFHEAD *bufp; 61*50997Sbostic const DBT *key, *val; 6246364Sbostic { 63*50997Sbostic register u_short *p; 64*50997Sbostic int key_size, n, val_size; 65*50997Sbostic u_short space, move_bytes, off; 66*50997Sbostic char *cp, *key_data, *val_data; 6746364Sbostic 68*50997Sbostic cp = bufp->page; /* Character pointer of p. */ 69*50997Sbostic p = (u_short *)cp; 7046364Sbostic 71*50997Sbostic key_data = (char *)key->data; 72*50997Sbostic key_size = key->size; 73*50997Sbostic val_data = (char *)val->data; 74*50997Sbostic val_size = val->size; 75*50997Sbostic 76*50997Sbostic /* First move the Key */ 77*50997Sbostic for (space = FREESPACE(p) - BIGOVERHEAD; key_size; 78*50997Sbostic space = FREESPACE(p) - BIGOVERHEAD) { 79*50997Sbostic move_bytes = MIN(space, key_size); 80*50997Sbostic off = OFFSET(p) - move_bytes; 81*50997Sbostic bcopy(key_data, cp + off, move_bytes); 82*50997Sbostic key_size -= move_bytes; 83*50997Sbostic key_data += move_bytes; 84*50997Sbostic n = p[0]; 85*50997Sbostic p[++n] = off; 86*50997Sbostic p[0] = ++n; 87*50997Sbostic FREESPACE(p) = off - PAGE_META(n); 88*50997Sbostic OFFSET(p) = off; 89*50997Sbostic p[n] = PARTIAL_KEY; 90*50997Sbostic bufp = __add_ovflpage(bufp); 91*50997Sbostic if (!bufp) 92*50997Sbostic return (-1); 93*50997Sbostic n = p[0]; 94*50997Sbostic if (!key_size) 95*50997Sbostic if (FREESPACE(p)) { 96*50997Sbostic move_bytes = MIN(FREESPACE(p), val_size); 97*50997Sbostic off = OFFSET(p) - move_bytes; 98*50997Sbostic p[n] = off; 99*50997Sbostic bcopy(val_data, cp + off, move_bytes); 100*50997Sbostic val_data += move_bytes; 101*50997Sbostic val_size -= move_bytes; 102*50997Sbostic p[n - 2] = FULL_KEY_DATA; 103*50997Sbostic FREESPACE(p) = FREESPACE(p) - move_bytes; 104*50997Sbostic OFFSET(p) = off; 105*50997Sbostic } else 106*50997Sbostic p[n - 2] = FULL_KEY; 107*50997Sbostic p = (u_short *)bufp->page; 108*50997Sbostic cp = bufp->page; 109*50997Sbostic bufp->flags |= BUF_MOD; 11046364Sbostic } 111*50997Sbostic 112*50997Sbostic /* Now move the data */ 113*50997Sbostic for (space = FREESPACE(p) - BIGOVERHEAD; val_size; 114*50997Sbostic space = FREESPACE(p) - BIGOVERHEAD) { 115*50997Sbostic move_bytes = MIN(space, val_size); 116*50997Sbostic /* 117*50997Sbostic * Here's the hack to make sure that if the data ends on the 118*50997Sbostic * same page as the key ends, FREESPACE is at least one. 119*50997Sbostic */ 120*50997Sbostic if (space == val_size && val_size == val->size) 121*50997Sbostic move_bytes--; 12246364Sbostic off = OFFSET(p) - move_bytes; 123*50997Sbostic bcopy(val_data, cp + off, move_bytes); 124*50997Sbostic val_size -= move_bytes; 12546364Sbostic val_data += move_bytes; 126*50997Sbostic n = p[0]; 127*50997Sbostic p[++n] = off; 128*50997Sbostic p[0] = ++n; 129*50997Sbostic FREESPACE(p) = off - PAGE_META(n); 13046364Sbostic OFFSET(p) = off; 131*50997Sbostic if (val_size) { 132*50997Sbostic p[n] = FULL_KEY; 133*50997Sbostic bufp = __add_ovflpage(bufp); 134*50997Sbostic if (!bufp) 135*50997Sbostic return (-1); 136*50997Sbostic cp = bufp->page; 137*50997Sbostic p = (u_short *)cp; 138*50997Sbostic } else 139*50997Sbostic p[n] = FULL_KEY_DATA; 140*50997Sbostic bufp->flags |= BUF_MOD; 14146364Sbostic } 142*50997Sbostic return (0); 14346364Sbostic } 14446364Sbostic 14546364Sbostic /* 146*50997Sbostic * Called when bufp's page contains a partial key (index should be 1) 147*50997Sbostic * 148*50997Sbostic * All pages in the big key/data pair except bufp are freed. We cannot 149*50997Sbostic * free bufp because the page pointing to it is lost and we can't get rid 150*50997Sbostic * of its pointer. 151*50997Sbostic * 152*50997Sbostic * Returns: 153*50997Sbostic * 0 => OK 154*50997Sbostic *-1 => ERROR 155*50997Sbostic */ 15646364Sbostic extern int 157*50997Sbostic __big_delete(bufp, ndx) 158*50997Sbostic BUFHEAD *bufp; 159*50997Sbostic int ndx; 16046364Sbostic { 161*50997Sbostic register BUFHEAD *last_bfp, *rbufp; 162*50997Sbostic u_short *bp, pageno; 163*50997Sbostic int key_done, n; 16446364Sbostic 165*50997Sbostic rbufp = bufp; 166*50997Sbostic last_bfp = NULL; 167*50997Sbostic bp = (u_short *)bufp->page; 168*50997Sbostic pageno = 0; 169*50997Sbostic key_done = 0; 170*50997Sbostic 17146364Sbostic while (!key_done || (bp[2] != FULL_KEY_DATA)) { 172*50997Sbostic if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) 173*50997Sbostic key_done = 1; 17446364Sbostic 175*50997Sbostic /* 176*50997Sbostic * If there is freespace left on a FULL_KEY_DATA page, then 177*50997Sbostic * the data is short and fits entirely on this page, and this 178*50997Sbostic * is the last page. 179*50997Sbostic */ 180*50997Sbostic if (bp[2] == FULL_KEY_DATA && FREESPACE(bp)) 181*50997Sbostic break; 182*50997Sbostic pageno = bp[bp[0] - 1]; 183*50997Sbostic rbufp->flags |= BUF_MOD; 184*50997Sbostic rbufp = __get_buf(pageno, rbufp, 0); 185*50997Sbostic if (last_bfp) 186*50997Sbostic __free_ovflpage(last_bfp); 187*50997Sbostic last_bfp = rbufp; 188*50997Sbostic if (!rbufp) 189*50997Sbostic return (-1); /* Error. */ 190*50997Sbostic bp = (u_short *)rbufp->page; 19146364Sbostic } 19246364Sbostic 193*50997Sbostic /* 194*50997Sbostic * If we get here then rbufp points to the last page of the big 195*50997Sbostic * key/data pair. Bufp points to the first one -- it should now be 196*50997Sbostic * empty pointing to the next page after this pair. Can't free it 197*50997Sbostic * because we don't have the page pointing to it. 198*50997Sbostic */ 19946364Sbostic 200*50997Sbostic /* This is information from the last page of the pair. */ 20146364Sbostic n = bp[0]; 202*50997Sbostic pageno = bp[n - 1]; 20346364Sbostic 204*50997Sbostic /* Now, bp is the first page of the pair. */ 20546364Sbostic bp = (u_short *)bufp->page; 206*50997Sbostic if (n > 2) { 207*50997Sbostic /* There is an overflow page. */ 208*50997Sbostic bp[1] = pageno; 209*50997Sbostic bp[2] = OVFLPAGE; 210*50997Sbostic bufp->ovfl = rbufp->ovfl; 211*50997Sbostic } else 212*50997Sbostic /* This is the last page. */ 213*50997Sbostic bufp->ovfl = NULL; 21446364Sbostic n -= 2; 21546364Sbostic bp[0] = n; 21646364Sbostic FREESPACE(bp) = hashp->BSIZE - PAGE_META(n); 21746364Sbostic OFFSET(bp) = hashp->BSIZE - 1; 21846364Sbostic 21946364Sbostic bufp->flags |= BUF_MOD; 220*50997Sbostic if (rbufp) 221*50997Sbostic __free_ovflpage(rbufp); 222*50997Sbostic if (last_bfp != rbufp) 223*50997Sbostic __free_ovflpage(last_bfp); 22446364Sbostic 22546364Sbostic hashp->NKEYS--; 226*50997Sbostic return (0); 22746364Sbostic } 22846364Sbostic /* 229*50997Sbostic * Returns: 230*50997Sbostic * 0 = key not found 231*50997Sbostic * -1 = get next overflow page 232*50997Sbostic * -2 means key not found and this is big key/data 233*50997Sbostic * -3 error 234*50997Sbostic */ 23546364Sbostic extern int 236*50997Sbostic __find_bigpair(bufp, ndx, key, size) 237*50997Sbostic BUFHEAD *bufp; 238*50997Sbostic int ndx; 239*50997Sbostic char *key; 240*50997Sbostic int size; 24146364Sbostic { 242*50997Sbostic register u_short *bp; 243*50997Sbostic register char *p; 244*50997Sbostic int ksize; 245*50997Sbostic u_short bytes; 246*50997Sbostic char *kkey; 24746364Sbostic 248*50997Sbostic bp = (u_short *)bufp->page; 249*50997Sbostic p = bufp->page; 250*50997Sbostic ksize = size; 251*50997Sbostic kkey = key; 25246364Sbostic 253*50997Sbostic for (bytes = hashp->BSIZE - bp[ndx]; 254*50997Sbostic bytes <= size && bp[ndx + 1] == PARTIAL_KEY; 255*50997Sbostic bytes = hashp->BSIZE - bp[ndx]) { 256*50997Sbostic if (bcmp(p + bp[ndx], kkey, bytes)) 257*50997Sbostic return (-2); 258*50997Sbostic kkey += bytes; 259*50997Sbostic ksize -= bytes; 260*50997Sbostic bufp = __get_buf(bp[ndx + 2], bufp, 0); 261*50997Sbostic if (!bufp) 262*50997Sbostic return (-3); 263*50997Sbostic p = bufp->page; 264*50997Sbostic bp = (u_short *)p; 265*50997Sbostic ndx = 1; 26646364Sbostic } 26746364Sbostic 268*50997Sbostic if (bytes != ksize || bcmp(p + bp[ndx], kkey, bytes)) { 26946364Sbostic #ifdef HASH_STATISTICS 270*50997Sbostic ++hash_collisions; 27146364Sbostic #endif 272*50997Sbostic return (-2); 273*50997Sbostic } else 274*50997Sbostic return (ndx); 27546364Sbostic } 27646364Sbostic 27746364Sbostic /* 278*50997Sbostic * Given the buffer pointer of the first overflow page of a big pair, 279*50997Sbostic * find the end of the big pair 280*50997Sbostic * 281*50997Sbostic * This will set bpp to the buffer header of the last page of the big pair. 282*50997Sbostic * It will return the pageno of the overflow page following the last page 283*50997Sbostic * of the pair; 0 if there isn't any (i.e. big pair is the last key in the 284*50997Sbostic * bucket) 285*50997Sbostic */ 28646364Sbostic extern u_short 287*50997Sbostic __find_last_page(bpp) 288*50997Sbostic BUFHEAD **bpp; 28946364Sbostic { 290*50997Sbostic BUFHEAD *bufp; 291*50997Sbostic u_short *bp, pageno; 292*50997Sbostic int n; 29346364Sbostic 294*50997Sbostic bufp = *bpp; 295*50997Sbostic bp = (u_short *)bufp->page; 296*50997Sbostic for (;;) { 297*50997Sbostic n = bp[0]; 29846364Sbostic 299*50997Sbostic /* 300*50997Sbostic * This is the last page if: the tag is FULL_KEY_DATA and 301*50997Sbostic * either only 2 entries OVFLPAGE marker is explicit there 302*50997Sbostic * is freespace on the page. 303*50997Sbostic */ 304*50997Sbostic if (bp[2] == FULL_KEY_DATA && 305*50997Sbostic ((n == 2) || (bp[n] == OVFLPAGE) || (FREESPACE(bp)))) 306*50997Sbostic break; 30746364Sbostic 308*50997Sbostic pageno = bp[n - 1]; 309*50997Sbostic bufp = __get_buf(pageno, bufp, 0); 310*50997Sbostic if (!bufp) 311*50997Sbostic return (0); /* Need to indicate an error! */ 312*50997Sbostic bp = (u_short *)bufp->page; 31346364Sbostic } 31446364Sbostic 31546364Sbostic *bpp = bufp; 316*50997Sbostic if (bp[0] > 2) 317*50997Sbostic return (bp[3]); 318*50997Sbostic else 319*50997Sbostic return (0); 32046364Sbostic } 32146364Sbostic 32246364Sbostic /* 323*50997Sbostic * Return the data for the key/data pair that begins on this page at this 324*50997Sbostic * index (index should always be 1). 325*50997Sbostic */ 32646364Sbostic extern int 327*50997Sbostic __big_return(bufp, ndx, val, set_current) 328*50997Sbostic BUFHEAD *bufp; 329*50997Sbostic int ndx; 330*50997Sbostic DBT *val; 331*50997Sbostic int set_current; 33246364Sbostic { 333*50997Sbostic BUFHEAD *save_p; 334*50997Sbostic u_short *bp, len, off, save_addr; 335*50997Sbostic char *tp; 33646364Sbostic 33746364Sbostic bp = (u_short *)bufp->page; 338*50997Sbostic while (bp[ndx + 1] == PARTIAL_KEY) { 339*50997Sbostic bufp = __get_buf(bp[bp[0] - 1], bufp, 0); 340*50997Sbostic if (!bufp) 341*50997Sbostic return (-1); 342*50997Sbostic bp = (u_short *)bufp->page; 343*50997Sbostic ndx = 1; 344*50997Sbostic } 34546364Sbostic 346*50997Sbostic if (bp[ndx + 1] == FULL_KEY) { 347*50997Sbostic bufp = __get_buf(bp[bp[0] - 1], bufp, 0); 348*50997Sbostic if (!bufp) 349*50997Sbostic return (-1); 350*50997Sbostic bp = (u_short *)bufp->page; 351*50997Sbostic save_p = bufp; 352*50997Sbostic save_addr = save_p->addr; 353*50997Sbostic off = bp[1]; 354*50997Sbostic len = 0; 355*50997Sbostic } else 356*50997Sbostic if (!FREESPACE(bp)) { 357*50997Sbostic /* 358*50997Sbostic * This is a hack. We can't distinguish between 359*50997Sbostic * FULL_KEY_DATA that contains complete data or 360*50997Sbostic * incomplete data, so we require that if the data 361*50997Sbostic * is complete, there is at least 1 byte of free 362*50997Sbostic * space left. 363*50997Sbostic */ 364*50997Sbostic off = bp[bp[0]]; 365*50997Sbostic len = bp[1] - off; 366*50997Sbostic save_p = bufp; 367*50997Sbostic save_addr = bufp->addr; 368*50997Sbostic bufp = __get_buf(bp[bp[0] - 1], bufp, 0); 369*50997Sbostic if (!bufp) 370*50997Sbostic return (-1); 371*50997Sbostic bp = (u_short *)bufp->page; 372*50997Sbostic } else { 373*50997Sbostic /* The data is all on one page. */ 374*50997Sbostic tp = (char *)bp; 375*50997Sbostic off = bp[bp[0]]; 376*50997Sbostic val->data = (u_char *)tp + off; 377*50997Sbostic val->size = bp[1] - off; 378*50997Sbostic if (set_current) { 379*50997Sbostic if (bp[0] == 2) { /* No more buckets in 380*50997Sbostic * chain */ 381*50997Sbostic hashp->cpage = NULL; 382*50997Sbostic hashp->cbucket++; 383*50997Sbostic hashp->cndx = 1; 384*50997Sbostic } else { 385*50997Sbostic hashp->cpage = 386*50997Sbostic __get_buf(bp[bp[0] - 1], bufp, 0); 387*50997Sbostic if (!hashp->cpage) 388*50997Sbostic return (-1); 389*50997Sbostic hashp->cndx = 1; 390*50997Sbostic if (!((u_short *) 391*50997Sbostic hashp->cpage->page)[0]) { 392*50997Sbostic hashp->cbucket++; 393*50997Sbostic hashp->cpage = NULL; 394*50997Sbostic } 395*50997Sbostic } 396*50997Sbostic } 397*50997Sbostic return (0); 39846364Sbostic } 399*50997Sbostic 400*50997Sbostic val->size = collect_data(bufp, len, set_current); 401*50997Sbostic if (val->size == -1) 402*50997Sbostic return (-1); 403*50997Sbostic if (save_p->addr != save_addr) { 404*50997Sbostic /* We are pretty short on buffers. */ 405*50997Sbostic errno = EINVAL; /* OUT OF BUFFERS */ 406*50997Sbostic return (-1); 40746364Sbostic } 408*50997Sbostic bcopy((save_p->page) + off, hashp->tmp_buf, len); 409*50997Sbostic val->data = (u_char *)hashp->tmp_buf; 410*50997Sbostic return (0); 41146364Sbostic } 41246364Sbostic /* 413*50997Sbostic * Count how big the total datasize is by recursing through the pages. Then 414*50997Sbostic * allocate a buffer and copy the data as you recurse up. 415*50997Sbostic */ 41646364Sbostic static int 417*50997Sbostic collect_data(bufp, len, set) 418*50997Sbostic BUFHEAD *bufp; 419*50997Sbostic int len, set; 42046364Sbostic { 421*50997Sbostic register u_short *bp; 422*50997Sbostic register char *p; 423*50997Sbostic BUFHEAD *xbp; 424*50997Sbostic u_short save_addr; 425*50997Sbostic int mylen, totlen; 42646364Sbostic 427*50997Sbostic p = bufp->page; 428*50997Sbostic bp = (u_short *)p; 429*50997Sbostic mylen = hashp->BSIZE - bp[1]; 430*50997Sbostic save_addr = bufp->addr; 43146364Sbostic 432*50997Sbostic if (bp[2] == FULL_KEY_DATA) { /* End of Data */ 433*50997Sbostic totlen = len + mylen; 434*50997Sbostic if (hashp->tmp_buf) 435*50997Sbostic free(hashp->tmp_buf); 436*50997Sbostic hashp->tmp_buf = malloc(totlen); 437*50997Sbostic if (!hashp->tmp_buf) 438*50997Sbostic return (-1); 439*50997Sbostic if (set) { 440*50997Sbostic hashp->cndx = 1; 441*50997Sbostic if (bp[0] == 2) { /* No more buckets in chain */ 442*50997Sbostic hashp->cpage = NULL; 443*50997Sbostic hashp->cbucket++; 444*50997Sbostic } else { 445*50997Sbostic hashp->cpage = 446*50997Sbostic __get_buf(bp[bp[0] - 1], bufp, 0); 447*50997Sbostic if (!hashp->cpage) 448*50997Sbostic return (-1); 449*50997Sbostic else if (!((u_short *)hashp->cpage->page)[0]) { 450*50997Sbostic hashp->cbucket++; 451*50997Sbostic hashp->cpage = NULL; 452*50997Sbostic } 453*50997Sbostic } 45446364Sbostic } 455*50997Sbostic } else { 456*50997Sbostic xbp = __get_buf(bp[bp[0] - 1], bufp, 0); 457*50997Sbostic if (!xbp || 458*50997Sbostic ((totlen = collect_data(xbp, len + mylen, set)) < 1)) 459*50997Sbostic return (-1); 46046364Sbostic } 461*50997Sbostic if (bufp->addr != save_addr) { 462*50997Sbostic errno = EINVAL; /* Out of buffers. */ 463*50997Sbostic return (-1); 46446364Sbostic } 465*50997Sbostic bcopy((bufp->page) + bp[1], &hashp->tmp_buf[len], mylen); 466*50997Sbostic return (totlen); 46746364Sbostic } 46846364Sbostic 46946364Sbostic /* 470*50997Sbostic * Fill in the key and data for this big pair. 471*50997Sbostic */ 47246364Sbostic extern int 473*50997Sbostic __big_keydata(bufp, ndx, key, val, set) 474*50997Sbostic BUFHEAD *bufp; 475*50997Sbostic int ndx; 476*50997Sbostic DBT *key, *val; 477*50997Sbostic int set; 47846364Sbostic { 479*50997Sbostic key->size = collect_key(bufp, 0, val, set); 480*50997Sbostic if (key->size == -1) 481*50997Sbostic return (-1); 482*50997Sbostic key->data = (u_char *)hashp->tmp_key; 483*50997Sbostic return (0); 48446364Sbostic } 48546364Sbostic 48646364Sbostic /* 487*50997Sbostic * Count how big the total key size is by recursing through the pages. Then 488*50997Sbostic * collect the data, allocate a buffer and copy the key as you recurse up. 489*50997Sbostic */ 49046364Sbostic static int 491*50997Sbostic collect_key(bufp, len, val, set) 492*50997Sbostic BUFHEAD *bufp; 493*50997Sbostic int len; 494*50997Sbostic DBT *val; 495*50997Sbostic int set; 49646364Sbostic { 497*50997Sbostic BUFHEAD *xbp; 498*50997Sbostic char *p; 499*50997Sbostic int mylen, totlen; 500*50997Sbostic u_short *bp, save_addr; 50146364Sbostic 502*50997Sbostic p = bufp->page; 503*50997Sbostic bp = (u_short *)p; 504*50997Sbostic mylen = hashp->BSIZE - bp[1]; 50546364Sbostic 506*50997Sbostic save_addr = bufp->addr; 507*50997Sbostic totlen = len + mylen; 508*50997Sbostic if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) { /* End of Key. */ 509*50997Sbostic if (hashp->tmp_key) 510*50997Sbostic free(hashp->tmp_key); 511*50997Sbostic hashp->tmp_key = malloc(totlen); 512*50997Sbostic if (!hashp->tmp_key) 513*50997Sbostic return (-1); 514*50997Sbostic __big_return(bufp, 1, val, set); 515*50997Sbostic } else { 516*50997Sbostic xbp = __get_buf(bp[bp[0] - 1], bufp, 0); 517*50997Sbostic if (!xbp || 518*50997Sbostic ((totlen = collect_key(xbp, totlen, val, set)) < 1)) 519*50997Sbostic return (-1); 52046364Sbostic } 521*50997Sbostic if (bufp->addr != save_addr) { 522*50997Sbostic errno = EINVAL; /* MIS -- OUT OF BUFFERS */ 523*50997Sbostic return (-1); 52446364Sbostic } 525*50997Sbostic bcopy((bufp->page) + bp[1], &hashp->tmp_key[len], mylen); 526*50997Sbostic return (totlen); 52746364Sbostic } 52846364Sbostic 52946364Sbostic /* 530*50997Sbostic * Returns: 531*50997Sbostic * 0 => OK 532*50997Sbostic * -1 => error 533*50997Sbostic */ 53446364Sbostic extern int 535*50997Sbostic __big_split(op, np, big_keyp, addr, obucket, ret) 536*50997Sbostic BUFHEAD *op; /* Pointer to where to put keys that go in old bucket */ 537*50997Sbostic BUFHEAD *np; /* Pointer to new bucket page */ 538*50997Sbostic /* Pointer to first page containing the big key/data */ 539*50997Sbostic BUFHEAD *big_keyp; 540*50997Sbostic int addr; /* Address of big_keyp */ 541*50997Sbostic u_int obucket;/* Old Bucket */ 542*50997Sbostic SPLIT_RETURN *ret; 54346364Sbostic { 544*50997Sbostic register BUFHEAD *tmpp; 545*50997Sbostic register u_short *tp; 546*50997Sbostic BUFHEAD *bp; 547*50997Sbostic DBT key, val; 548*50997Sbostic u_int change; 549*50997Sbostic u_short free_space, n, off; 55046364Sbostic 551*50997Sbostic bp = big_keyp; 55246364Sbostic 553*50997Sbostic /* Now figure out where the big key/data goes */ 554*50997Sbostic if (__big_keydata(big_keyp, 1, &key, &val, 0)) 555*50997Sbostic return (-1); 556*50997Sbostic change = (__call_hash(key.data, key.size) != obucket); 55746364Sbostic 558*50997Sbostic if (ret->next_addr = __find_last_page(&big_keyp)) { 559*50997Sbostic if (!(ret->nextp = __get_buf(ret->next_addr, big_keyp, 0))) 560*50997Sbostic return (-1);; 561*50997Sbostic } else 562*50997Sbostic ret->nextp = NULL; 56346364Sbostic 564*50997Sbostic /* Now make one of np/op point to the big key/data pair */ 565*50997Sbostic #ifdef DEBUG 566*50997Sbostic assert(np->ovfl == NULL); 567*50997Sbostic #endif 568*50997Sbostic if (change) 569*50997Sbostic tmpp = np; 570*50997Sbostic else 571*50997Sbostic tmpp = op; 57246364Sbostic 573*50997Sbostic tmpp->flags |= BUF_MOD; 57446364Sbostic #ifdef DEBUG1 575*50997Sbostic (void)fprintf(stderr, 576*50997Sbostic "BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr, 577*50997Sbostic (tmpp->ovfl ? tmpp->ovfl->addr : 0), (bp ? bp->addr : 0)); 57846364Sbostic #endif 579*50997Sbostic tmpp->ovfl = bp; /* one of op/np point to big_keyp */ 580*50997Sbostic tp = (u_short *)tmpp->page; 581*50997Sbostic #ifdef DEBUG 582*50997Sbostic assert(FREESPACE(tp) >= OVFLSIZE); 583*50997Sbostic #endif 584*50997Sbostic n = tp[0]; 585*50997Sbostic off = OFFSET(tp); 586*50997Sbostic free_space = FREESPACE(tp); 587*50997Sbostic tp[++n] = (u_short)addr; 588*50997Sbostic tp[++n] = OVFLPAGE; 589*50997Sbostic tp[0] = n; 590*50997Sbostic OFFSET(tp) = off; 591*50997Sbostic FREESPACE(tp) = free_space - OVFLSIZE; 59246364Sbostic 593*50997Sbostic /* 594*50997Sbostic * Finally, set the new and old return values. BIG_KEYP contains a 595*50997Sbostic * pointer to the last page of the big key_data pair. Make sure that 596*50997Sbostic * big_keyp has no following page (2 elements) or create an empty 597*50997Sbostic * following page. 598*50997Sbostic */ 59946364Sbostic 600*50997Sbostic ret->newp = np; 601*50997Sbostic ret->oldp = op; 60246364Sbostic 603*50997Sbostic tp = (u_short *)big_keyp->page; 604*50997Sbostic big_keyp->flags |= BUF_MOD; 605*50997Sbostic if (tp[0] > 2) { 606*50997Sbostic /* 607*50997Sbostic * There may be either one or two offsets on this page. If 608*50997Sbostic * there is one, then the overflow page is linked on normally 609*50997Sbostic * and tp[4] is OVFLPAGE. If there are two, tp[4] contains 610*50997Sbostic * the second offset and needs to get stuffed in after the 611*50997Sbostic * next overflow page is added. 612*50997Sbostic */ 613*50997Sbostic n = tp[4]; 614*50997Sbostic free_space = FREESPACE(tp); 615*50997Sbostic off = OFFSET(tp); 616*50997Sbostic tp[0] -= 2; 617*50997Sbostic FREESPACE(tp) = free_space + OVFLSIZE; 618*50997Sbostic OFFSET(tp) = off; 619*50997Sbostic tmpp = __add_ovflpage(big_keyp); 620*50997Sbostic if (!tmpp) 621*50997Sbostic return (-1); 622*50997Sbostic tp[4] = n; 623*50997Sbostic } else 624*50997Sbostic tmpp = big_keyp; 62546364Sbostic 626*50997Sbostic if (change) 627*50997Sbostic ret->newp = tmpp; 628*50997Sbostic else 629*50997Sbostic ret->oldp = tmpp; 630*50997Sbostic return (0); 63146364Sbostic } 632