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