1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Margo Seltzer. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #if defined(LIBC_SCCS) && !defined(lint) 12 static char sccsid[] = "@(#)hash_page.c 5.1 (Berkeley) 02/12/91"; 13 #endif /* LIBC_SCCS and not lint */ 14 15 /****************************************************************************** 16 PACKAGE: hashing 17 18 DESCRIPTION: 19 Page manipulation for hashing package. 20 21 ROUTINES: 22 External 23 __get_page 24 __add_ovflpage 25 Internal 26 overflow_page 27 open_temp 28 ******************************************************************************/ 29 30 #include <sys/param.h> 31 #include <sys/file.h> 32 #include <assert.h> 33 #include <errno.h> 34 #include <db.h> 35 #include <stdio.h> 36 #include "hash.h" 37 #include "page.h" 38 39 /* Externals */ 40 /* buf.c */ 41 extern BUFHEAD *__get_buf(); 42 extern void __reclaim_buf(); 43 44 /* big.c */ 45 extern int __big_split(); 46 extern int __big_insert(); 47 extern int __big_delete(); 48 extern int __find_bigpair(); 49 50 /* dynahash.c */ 51 extern int __call_hash(); 52 extern int __expand_table(); 53 54 /* my externals */ 55 extern int __get_page(); 56 extern BUFHEAD *__add_ovflpage(); 57 extern int __split_page(); 58 extern int __addel(); 59 60 /* my internals */ 61 static u_short overflow_page(); 62 static int open_temp(); 63 static void squeeze_key(); 64 static void putpair(); 65 66 #ifdef HASH_STATISTICS 67 extern long hash_accesses, hash_collisions, hash_expansions, hash_overflows; 68 #endif 69 #define PAGE_INIT(P) \ 70 { \ 71 ((u_short *)P)[0] = 0; \ 72 ((u_short *)P)[1] = hashp->BSIZE - 3 * sizeof(u_short); \ 73 ((u_short *)P)[2] = hashp->BSIZE; \ 74 } 75 76 /* 77 This is called AFTER we have verified that there is room on the 78 page for the pair (PAIRFITS has returned true) so we go right 79 ahead and start moving stuff on. 80 */ 81 static void 82 putpair(p, key, val) 83 char *p; 84 DBT *key; 85 DBT *val; 86 { 87 register u_short n; 88 register u_short off; 89 register u_short *bp = (u_short *) p; 90 91 /* enter the key first */ 92 n = bp[0]; 93 94 off = OFFSET(bp) - key->size; 95 bcopy( key->data, p+off, key->size ); 96 bp[++n] = off; 97 98 /* now the data */ 99 off -= val->size; 100 bcopy(val->data, p + off, val->size); 101 bp[++n] = off; 102 103 /* adjust page info */ 104 bp[0] = n; 105 bp[n+1] = off - ((n+3)*sizeof(u_short)); 106 bp[n+2] = off; 107 return; 108 } 109 /* 110 0 OK 111 -1 error 112 */ 113 extern int 114 __delpair(bufp, ndx) 115 BUFHEAD *bufp; 116 register int ndx; 117 { 118 register u_short *bp = (u_short *) bufp->page; 119 register int n = bp[0]; 120 register u_short newoff; 121 u_short pairlen; 122 123 if ( bp[ndx+1] < REAL_KEY ) return ( __big_delete ( bufp, ndx ) ); 124 if ( ndx != 1 ) newoff = bp[ndx-1]; 125 else newoff = hashp->BSIZE; 126 pairlen = newoff - bp[ndx+1]; 127 128 if ( ndx != (n-1) ) { 129 /* Hard Case -- need to shuffle keys */ 130 register int i; 131 register char *src = bufp->page + (int)OFFSET(bp); 132 register char *dst = src + (int)pairlen; 133 bcopy ( src, dst, bp[ndx+1] - OFFSET(bp) ); 134 135 /* Now adjust the pointers */ 136 for ( i = ndx+2; i <= n; i += 2 ) { 137 if ( bp[i+1] == OVFLPAGE ) { 138 bp[i-2] = bp[i]; 139 bp[i-1] = bp[i+1]; 140 } else { 141 bp[i-2] = bp[i] + pairlen; 142 bp[i-1] = bp[i+1] + pairlen; 143 } 144 } 145 } 146 147 /* Finally adjust the page data */ 148 bp[n] = OFFSET(bp) + pairlen; 149 bp[n-1] = bp[n+1] + pairlen + 2 * sizeof(u_short); 150 bp[0] = n-2; 151 hashp->NKEYS--; 152 153 bufp->flags |= BUF_MOD; 154 return (0); 155 } 156 /* 157 -1 ==> Error 158 0 ==> OK 159 */ 160 extern int 161 __split_page(obucket, nbucket) 162 int obucket; 163 int nbucket; 164 { 165 DBT key; 166 DBT val; 167 168 register BUFHEAD *new_bufp; 169 register BUFHEAD *old_bufp; 170 register u_short *ino; 171 register char *np; 172 char *op; 173 174 u_short copyto = (u_short)hashp->BSIZE; 175 u_short off = (u_short)hashp->BSIZE; 176 int n; 177 u_short diff; 178 u_short moved; 179 int ndx; 180 181 old_bufp = __get_buf ( obucket, NULL, 0 ); 182 new_bufp = __get_buf ( nbucket, NULL, 0 ); 183 184 old_bufp->flags |= BUF_MOD; 185 new_bufp->flags |= BUF_MOD; 186 187 ino = (u_short *)(op = old_bufp->page); 188 np = new_bufp->page; 189 190 moved = 0; 191 192 for (n = 1, ndx = 1; n < ino[0]; n+=2) { 193 if ( ino[n+1] < REAL_KEY ) { 194 return ( ugly_split( obucket, old_bufp, new_bufp, 195 copyto, moved ) ); 196 } 197 key.data = op + ino[n]; 198 key.size = off - ino[n]; 199 200 if ( __call_hash ( key.data, key.size ) == obucket ) { 201 /* Don't switch page */ 202 diff = copyto - off; 203 if ( diff ) { 204 copyto = ino[n+1] + diff; 205 bcopy ( op + ino[n+1], op + copyto, off-ino[n+1]); 206 ino[ndx] = copyto + ino[n] - ino[n+1]; 207 ino[ndx+1] = copyto; 208 } else copyto = ino[n+1]; 209 ndx += 2; 210 } else { 211 /* Switch page */ 212 val.data = op + ino[n+1]; 213 val.size = ino[n] - ino[n+1]; 214 putpair( np, &key, &val); 215 moved +=2; 216 } 217 218 off = ino[n+1]; 219 } 220 221 /* Now clean up the page */ 222 ino[0] -= moved; 223 FREESPACE(ino) = copyto - sizeof(u_short) * (ino[0]+3); 224 OFFSET(ino) = copyto; 225 226 #ifdef DEBUG3 227 fprintf(stderr, "split %d/%d\n", 228 ((u_short *) np)[0] / 2, 229 ((u_short *) op)[0] / 2); 230 #endif 231 return(0); 232 } 233 /* 234 0 ==> success 235 -1 ==> failure 236 237 Called when we encounter an overflow page during split handling. 238 this is special cased since we have to begin checking whether 239 the key/data pairs fit on their respective pages and because 240 we may need overflow pages for both the old and new pages 241 */ 242 static int 243 ugly_split( obucket, old_bufp, new_bufp, copyto, moved ) 244 int obucket; /* Same as __split_page */ 245 BUFHEAD *old_bufp; 246 BUFHEAD *new_bufp; 247 u_short copyto; /* First byte on page which contains key/data values */ 248 int moved; /* number of pairs moved to new page */ 249 { 250 register BUFHEAD *bufp = old_bufp; /* Buffer header for ino */ 251 register u_short *ino = (u_short *)old_bufp->page; 252 /* Page keys come off of */ 253 register u_short *np = (u_short *)new_bufp->page; /* New page */ 254 register u_short *op = (u_short *)old_bufp->page; 255 /* Page keys go on to if they 256 aren't moving */ 257 258 char *cino; /* Character value of ino */ 259 BUFHEAD *last_bfp = NULL; /* Last buffer header OVFL which 260 needs to be freed */ 261 u_short ov_addr, last_addr = 0; 262 u_short n; 263 u_short off; 264 265 DBT key, val; 266 SPLIT_RETURN ret; 267 268 n = ino[0]-1; 269 while ( n < ino[0] ) { 270 if ( ino[n+1] == OVFLPAGE ) { 271 ov_addr = ino[n]; 272 /* 273 Fix up the old page -- the extra 2 are the fields which 274 contained the overflow information 275 */ 276 ino[0] -= (moved + 2); 277 FREESPACE(ino) = copyto - sizeof(u_short) * (ino[0]+3); 278 OFFSET(ino) = copyto; 279 280 bufp = __get_buf ( ov_addr, bufp, 0 ); 281 if ( !bufp ) return(-1); 282 283 ino = (u_short *)bufp->page; 284 n = 1; 285 copyto = hashp->BSIZE; 286 moved = 0; 287 288 if ( last_bfp ) { 289 __free_ovflpage( last_bfp); 290 } 291 last_bfp = bufp; 292 } 293 294 if ( (ino[2] < REAL_KEY) && (ino[2] != OVFLPAGE) ) { 295 if (__big_split (old_bufp, 296 new_bufp, bufp, ov_addr, obucket, &ret)) { 297 return(-1); 298 } 299 old_bufp = ret.oldp; 300 if ( !old_bufp ) return(-1); 301 op = (u_short *)old_bufp->page; 302 new_bufp = ret.newp; 303 if ( !new_bufp ) return(-1); 304 np = (u_short *)new_bufp->page; 305 bufp = ret.nextp; 306 if ( !bufp ) return(0); 307 cino = (char *)bufp->page; 308 ino = (u_short *)cino; 309 last_bfp = ret.nextp; 310 } 311 312 313 off = hashp->BSIZE; 314 for ( n = 1; (n < ino[0]) && (ino[n+1] >= REAL_KEY); n += 2 ) { 315 cino = (char *)ino; 316 key.data = cino + ino[n]; 317 key.size = off - ino[n]; 318 val.data = cino + ino[n+1]; 319 val.size = ino[n] - ino[n+1]; 320 off = ino[n+1]; 321 322 if ( __call_hash ( key.data, key.size ) == obucket ) { 323 /* Keep on old page */ 324 if (PAIRFITS(op,(&key),(&val))) putpair((char *)op, &key, &val); 325 else { 326 old_bufp = __add_ovflpage ( old_bufp ); 327 if ( !old_bufp ) return(-1); 328 op = (u_short *)old_bufp->page; 329 putpair ((char *)op, &key, &val); 330 } 331 old_bufp->flags |= BUF_MOD; 332 } else { 333 /* Move to new page */ 334 if (PAIRFITS(np,(&key),(&val))) putpair((char *)np, &key, &val); 335 else { 336 new_bufp = __add_ovflpage ( new_bufp ); 337 if ( !new_bufp )return(-1); 338 np = (u_short *)new_bufp->page; 339 putpair ((char *)np, &key, &val); 340 } 341 new_bufp->flags |= BUF_MOD; 342 } 343 } 344 } 345 if ( last_bfp ) { 346 __free_ovflpage(last_bfp); 347 } 348 349 return (0); 350 } 351 /* 352 Add the given pair to the page 353 1 ==> failure 354 0 ==> OK 355 */ 356 extern int 357 __addel(bufp, key, val) 358 BUFHEAD *bufp; 359 DBT *key; 360 DBT *val; 361 { 362 register u_short *bp = (u_short *)bufp->page; 363 register u_short *sop; 364 int do_expand; 365 366 do_expand = 0; 367 while ( bp[0] && (bp[bp[0]] < REAL_KEY) ) { 368 /* Exception case */ 369 if ( bp[2] < REAL_KEY ) { 370 /* This is a big-keydata pair */ 371 bufp = __add_ovflpage(bufp); 372 if ( !bufp ) { 373 return(-1); 374 } 375 bp = (u_short *)bufp->page; 376 } else { 377 /* Try to squeeze key on this page */ 378 if ( FREESPACE(bp) > PAIRSIZE(key,val) ) { 379 squeeze_key ( bp, key, val ); 380 return(0); 381 } else { 382 bufp = __get_buf ( bp[bp[0]-1], bufp, 0 ); 383 if (!bufp) { 384 return(-1); 385 } 386 bp = (u_short *)bufp->page; 387 } 388 } 389 } 390 391 if ( PAIRFITS(bp,key,val) ) putpair (bufp->page, key, val); 392 else { 393 do_expand = 1; 394 bufp = __add_ovflpage ( bufp ); 395 if (!bufp)return(-1); 396 sop = (u_short *) bufp->page; 397 398 if ( PAIRFITS(sop, key, val) ) putpair ( (char *)sop, key, val ); 399 else if ( __big_insert ( bufp, key, val ) ) { 400 return(-1); 401 } 402 } 403 bufp->flags |= BUF_MOD; 404 /* 405 If the average number of keys per bucket exceeds the fill factor, 406 expand the table 407 */ 408 hashp->NKEYS++; 409 if (do_expand || 410 (hashp->NKEYS / (hashp->MAX_BUCKET+1) > hashp->FFACTOR) ) { 411 return(__expand_table()); 412 } 413 return(0); 414 } 415 416 /* 417 returns a pointer, NULL on error 418 */ 419 extern BUFHEAD * 420 __add_ovflpage ( bufp ) 421 BUFHEAD *bufp; 422 { 423 register u_short *sp = (u_short *)bufp->page; 424 425 u_short ovfl_num; 426 u_short ndx, newoff; 427 char *op; 428 DBT okey, oval; 429 #ifdef DEBUG1 430 int tmp1, tmp2; 431 #endif 432 433 bufp->flags |= BUF_MOD; 434 ovfl_num = overflow_page (); 435 #ifdef DEBUG1 436 tmp1 = bufp->addr; 437 tmp2 = bufp->ovfl?bufp->ovfl->addr:0; 438 #endif 439 if (!ovfl_num || !(bufp->ovfl = __get_buf ( ovfl_num, bufp, 1 ))) { 440 return(NULL); 441 } 442 bufp->ovfl->flags |= BUF_MOD; 443 #ifdef DEBUG1 444 fprintf ( stderr, "ADDOVFLPAGE: %d->ovfl was %d is now %d\n", tmp1, tmp2, 445 bufp->ovfl->addr ); 446 #endif 447 ndx = sp[0]; 448 /* 449 Since a pair is allocated on a page only if there's room 450 to add an overflow page, we know that the OVFL information 451 will fit on the page 452 */ 453 sp[ndx+4] = OFFSET(sp); 454 sp[ndx+3] = FREESPACE(sp) - OVFLSIZE; 455 sp[ndx+1] = ovfl_num; 456 sp[ndx+2] = OVFLPAGE; 457 sp[0] = ndx+2; 458 #ifdef HASH_STATISTICS 459 hash_overflows++; 460 #endif 461 return(bufp->ovfl); 462 } 463 464 /* 465 0 indicates SUCCESS 466 -1 indicates FAILURE 467 */ 468 extern int 469 __get_page ( p, bucket, is_bucket, is_disk, is_bitmap ) 470 char *p; 471 int bucket; 472 int is_bucket; 473 int is_disk; 474 int is_bitmap; 475 { 476 register int size; 477 register int fd; 478 register int page; 479 u_short *bp; 480 int rsize; 481 482 fd = hashp->fp; 483 size = hashp->BSIZE; 484 485 if ( !fd || (hashp->new_file && !is_disk) ) { 486 PAGE_INIT(p); 487 return(0); 488 } 489 490 if ( is_bucket) page = BUCKET_TO_PAGE (bucket); 491 else page = OADDR_TO_PAGE (bucket); 492 if ((lseek ( fd, page << hashp->BSHIFT, L_SET ) == -1) || 493 ((rsize = read ( fd, p, size )) == -1 )) { 494 return(-1); 495 } 496 bp = (u_short *)p; 497 if ( !rsize ) { 498 bp[0] = 0; /* We hit the EOF, so initialize a new page */ 499 } else if ( rsize != size ) { 500 errno = EFTYPE; 501 return(-1); 502 } 503 if (!bp[0]) { 504 PAGE_INIT(p); 505 } else if ( hashp->LORDER != BYTE_ORDER ) { 506 register int i; 507 register int max; 508 509 if ( is_bitmap ) { 510 max = hashp->BSIZE >> 2; /* divide by 4 */ 511 for ( i=0; i < max; i++ ) { 512 BLSWAP(((long *)p)[i]); 513 } 514 } else { 515 BSSWAP(bp[0]); 516 max = bp[0] + 2; 517 for ( i=1; i <= max; i++ ) { 518 BSSWAP(bp[i]); 519 } 520 } 521 } 522 return (0); 523 } 524 525 /* 526 Write page p to disk 527 -1==>failure 528 0==> OK 529 */ 530 extern int 531 __put_page ( p, bucket, is_bucket, is_bitmap ) 532 char *p; 533 int bucket; 534 int is_bucket; 535 int is_bitmap; 536 { 537 register int size; 538 register int fd; 539 register int page; 540 int wsize; 541 542 size = hashp->BSIZE; 543 if ( !hashp->fp && open_temp() ) return (1); 544 fd = hashp->fp; 545 546 if ( hashp->LORDER != BYTE_ORDER ) { 547 register int i; 548 register int max; 549 550 if ( is_bitmap ) { 551 max = hashp->BSIZE >> 2; /* divide by 4 */ 552 for ( i=0; i < max; i++ ) { 553 BLSWAP(((long *)p)[i]); 554 } 555 } else { 556 max = ((u_short *)p)[0] + 2; 557 for ( i=0; i <= max; i++ ) { 558 BSSWAP(((u_short *)p)[i]); 559 } 560 } 561 } 562 if (is_bucket ) page = BUCKET_TO_PAGE (bucket); 563 else page = OADDR_TO_PAGE ( bucket ); 564 if ((lseek ( fd, page << hashp->BSHIFT, L_SET ) == -1) || 565 ((wsize = write ( fd, p, size )) == -1 )) { 566 /* Errno is set */ 567 return(-1); 568 } 569 if ( wsize != size ) { 570 errno = EFTYPE; 571 return(-1); 572 } 573 return(0); 574 } 575 #define BYTE_MASK ((1 << INT_BYTE_SHIFT) -1) 576 /* 577 Initialize a new bitmap page. Bitmap pages are left in memory 578 once they are read in. 579 */ 580 extern u_long * 581 __init_bitmap(pnum, nbits, ndx) 582 u_short pnum; 583 int nbits; 584 int ndx; 585 { 586 u_long *ip; 587 int clearints; 588 int clearbytes; 589 590 if ( !(ip = (u_long *)malloc (hashp->BSIZE)) ) return (NULL); 591 clearints = ((nbits - 1) >> INT_BYTE_SHIFT) + 1; 592 clearbytes = clearints << INT_TO_BYTE; 593 memset ((char *)ip, 0, clearbytes ); 594 memset ( ((char *) ip) + clearbytes, 0xFF, 595 hashp->BSIZE-clearbytes ); 596 ip[clearints-1] = ALL_SET << (nbits & BYTE_MASK); 597 SETBIT(ip, 0); 598 hashp->BITMAPS[ndx] = pnum; 599 hashp->mapp[ndx] = ip; 600 return(ip); 601 } 602 static int 603 first_free ( map ) 604 u_long map; 605 { 606 register u_long mask; 607 register u_long i; 608 609 mask = 0x1; 610 for ( i=0; i < BITS_PER_MAP; i++ ) { 611 if ( !(mask & map) ) return(i); 612 mask = mask << 1; 613 } 614 return ( i ); 615 } 616 617 static u_short 618 overflow_page ( ) 619 { 620 register int max_free; 621 register int splitnum; 622 register u_long *freep; 623 register int offset; 624 u_short addr; 625 int in_use_bits; 626 int free_page, free_bit; 627 int i, j, bit; 628 #ifdef DEBUG2 629 int tmp1, tmp2; 630 #endif 631 632 splitnum = __log2(hashp->MAX_BUCKET); 633 max_free = hashp->SPARES[splitnum]; 634 635 free_page = (max_free-1) >> (hashp->BSHIFT + BYTE_SHIFT); 636 free_bit = (max_free-1) & ((hashp->BSIZE << BYTE_SHIFT) - 1); 637 638 /* Look through all the free maps to find the first free block */ 639 for ( i = 0; i <= free_page; i++ ) { 640 if (!(freep = (u_long *)hashp->mapp[i]) ) return(NULL); 641 if ( i == free_page ) in_use_bits = free_bit; 642 else in_use_bits = (hashp->BSIZE << BYTE_SHIFT) -1; 643 644 for (j = 0, bit = 0; bit <= in_use_bits; j++, bit += BITS_PER_MAP ) { 645 if ( freep[j] != ALL_SET ) goto found; 646 } 647 } 648 /* No Free Page Found */ 649 hashp->SPARES[splitnum]++; 650 offset = hashp->SPARES[splitnum] - 651 (splitnum ? hashp->SPARES[splitnum-1] : 0); 652 653 /* Check if we need to allocate a new bitmap page */ 654 if ( free_bit == (hashp->BSIZE << BYTE_SHIFT) - 1 ) { 655 free_page++; 656 if ( free_page >= NCACHED ) { 657 fprintf ( stderr, 658 "HASH: Out of overflow pages. Increase page size\n" ); 659 return(NULL); 660 } 661 /* 662 This is tricky. The 1 indicates that you want the 663 new page allocated with 1 clear bit. Actually, you 664 are going to allocate 2 pages from this map. The first 665 is going to be the map page, the second is the overflow 666 page we were looking for. The init_bitmap routine 667 automatically, sets the first bit of itself to indicate 668 that the bitmap itself is in use. We would explicitly 669 set the second bit, but don't have to if we tell init_bitmap 670 not to leave it clear in the first place. 671 */ 672 __init_bitmap ( OADDR_OF(splitnum, offset), 1, free_page ); 673 hashp->SPARES[splitnum]++; 674 #ifdef DEBUG2 675 free_bit = 2; 676 #endif 677 offset++; 678 } else { 679 /* 680 Free_bit addresses the last used bit. Bump it to 681 address the first available bit. 682 */ 683 free_bit++; 684 SETBIT ( freep, free_bit ); 685 } 686 687 /* Calculate address of the new overflow page */ 688 if ( offset > SPLITMASK ) { 689 fprintf ( stderr, 690 "HASH: Out of overflow pages. Increase page size\n" ); 691 return(NULL); 692 } 693 addr = OADDR_OF(splitnum, offset); 694 #ifdef DEBUG2 695 fprintf ( stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n", 696 addr, free_bit, free_page ); 697 #endif 698 return(addr); 699 700 found: 701 bit = bit + first_free(freep[j]); 702 SETBIT(freep,bit); 703 #ifdef DEBUG2 704 tmp1 = bit; 705 tmp2 = i; 706 #endif 707 /* 708 Bits are addressed starting with 0, but overflow pages are 709 addressed beginning at 1. Bit is a bit addressnumber, so we 710 need to increment it to convert it to a page number. 711 */ 712 bit = 1 + bit + (i * (hashp->BSIZE << BYTE_SHIFT)); 713 714 /* Calculate the split number for this page */ 715 for ( i = 0; (i < splitnum) && (bit > hashp->SPARES[i]); i++ ); 716 offset =(i ? bit - hashp->SPARES[i-1] : bit ); 717 if ( offset >= SPLITMASK ) return(NULL);/* Out of overflow pages */ 718 addr = OADDR_OF(i, offset); 719 #ifdef DEBUG2 720 fprintf ( stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n", 721 addr, tmp1, tmp2 ); 722 #endif 723 724 /* Allocate and return the overflow page */ 725 return (addr); 726 } 727 728 /* 729 Mark this overflow page as free. 730 */ 731 __free_ovflpage ( obufp ) 732 BUFHEAD *obufp; 733 { 734 register u_short addr = obufp->addr; 735 int free_page, free_bit; 736 int bit_address; 737 u_short ndx; 738 u_long *freep; 739 int j; 740 741 #ifdef DEBUG1 742 fprintf ( stderr, "Freeing %d\n", addr ); 743 #endif 744 ndx = (((u_short)addr) >> SPLITSHIFT); 745 bit_address = (ndx ? hashp->SPARES[ndx-1] : 0) + (addr & SPLITMASK) - 1; 746 free_page = (bit_address >> (hashp->BSHIFT + BYTE_SHIFT)); 747 free_bit = bit_address & ((hashp->BSIZE << BYTE_SHIFT) - 1); 748 749 freep = hashp->mapp[free_page]; 750 assert(freep); 751 CLRBIT(freep, free_bit); 752 #ifdef DEBUG2 753 fprintf ( stderr, "FREE_OVFLPAGE: ADDR: %d BIT: %d PAGE %d\n", 754 obufp->addr, free_bit, free_page ); 755 #endif 756 __reclaim_buf ( obufp ); 757 return; 758 } 759 760 /* 761 0 success 762 -1 failure 763 */ 764 static int 765 open_temp() 766 { 767 char *namestr = "_hashXXXXXX"; 768 769 if ((hashp->fp = mkstemp ( namestr )) == -1){ 770 return (-1); 771 } 772 unlink(namestr); /* Make sure file goes away at process exit*/ 773 return(0); 774 } 775 776 /* 777 We have to know that the key will fit, but the 778 last entry on the page is an overflow pair, so we 779 need to shift things. 780 */ 781 static void 782 squeeze_key ( sp, key, val ) 783 u_short *sp; 784 DBT *key; 785 DBT *val; 786 { 787 register char *p = (char *)sp; 788 u_short free_space, off; 789 u_short pageno, n; 790 791 n = sp[0]; 792 free_space = FREESPACE(sp); 793 off = OFFSET(sp); 794 795 pageno = sp[n-1]; 796 off -= key->size; 797 sp[n-1] = off; 798 bcopy ( key->data, p + off, key->size ); 799 off -= val->size; 800 sp[n] = off; 801 bcopy ( val->data, p + off, val->size ); 802 sp[0] = n+2; 803 sp[n+1] = pageno; 804 sp[n+2] = OVFLPAGE; 805 FREESPACE(sp) = free_space - PAIRSIZE(key,val); 806 OFFSET(sp) = off; 807 } 808 809 #ifdef DEBUG4 810 print_chain ( addr ) 811 short addr; 812 { 813 BUFHEAD *bufp; 814 short *bp; 815 short oaddr; 816 817 fprintf ( stderr, "%d ", addr ); 818 bufp = __get_buf ( (int)addr, NULL, 0 ); 819 bp = (short *)bufp->page; 820 while ( bp[0] && 821 ((bp[bp[0]] == OVFLPAGE) || 822 ((bp[0] > 2) && bp[2] < REAL_KEY))) { 823 oaddr = bp[bp[0]-1]; 824 fprintf ( stderr, "%d ", (int)oaddr ); 825 bufp = __get_buf ( (int)oaddr, bufp, 0 ); 826 bp = (short *)bufp->page; 827 } 828 fprintf ( stderr, "\n" ); 829 } 830 #endif 831