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