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.c 5.26 (Berkeley) 10/04/92"; 13 #endif /* LIBC_SCCS and not lint */ 14 15 #include <sys/param.h> 16 #include <sys/stat.h> 17 18 #include <fcntl.h> 19 #include <errno.h> 20 #ifdef DEBUG 21 #include <assert.h> 22 #endif 23 #include <db.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <unistd.h> 27 #include <string.h> 28 #include "hash.h" 29 #include "page.h" 30 #include "extern.h" 31 32 static int alloc_segs __P((int)); 33 static int flush_meta __P((void)); 34 static int hash_access __P((ACTION, DBT *, DBT *)); 35 static int hash_close __P((DB *)); 36 static int hash_delete __P((const DB *, const DBT *, u_int)); 37 static int hash_get __P((const DB *, const DBT *, DBT *, u_int)); 38 static int hash_put __P((const DB *, const DBT *, const DBT *, u_int)); 39 static void *hash_realloc __P((SEGMENT **, int, int)); 40 static int hash_seq __P((const DB *, DBT *, DBT *, u_int)); 41 static int hash_sync __P((const DB *)); 42 static int hdestroy __P((void)); 43 static HTAB *init_hash __P((HASHINFO *)); 44 static int init_htab __P((int)); 45 #if BYTE_ORDER == LITTLE_ENDIAN 46 static void swap_header __P((void)); 47 static void swap_header_copy __P((HASHHDR *, HASHHDR *)); 48 #endif 49 50 /* Fast arithmetic, relying on powers of 2, */ 51 #define MOD(x, y) ((x) & ((y) - 1)) 52 53 #define RETURN_ERROR(ERR, LOC) { save_errno = ERR; goto LOC; } 54 55 /* Return values */ 56 #define SUCCESS (0) 57 #define ERROR (-1) 58 #define ABNORMAL (1) 59 60 /* Local data */ 61 HTAB *hashp = NULL; 62 63 #ifdef HASH_STATISTICS 64 long hash_accesses, hash_collisions, hash_expansions, hash_overflows; 65 #endif 66 67 /************************** INTERFACE ROUTINES ***************************/ 68 /* OPEN/CLOSE */ 69 70 extern DB * 71 __hash_open(file, flags, mode, info) 72 const char *file; 73 int flags, mode; 74 const HASHINFO *info; /* Special directives for create */ 75 { 76 struct stat statbuf; 77 DB *dbp; 78 int bpages, hdrsize, new_table, nsegs, save_errno; 79 80 if (flags & O_WRONLY) { 81 errno = EINVAL; 82 return (NULL); 83 } 84 85 if (!(hashp = calloc(1, sizeof(HTAB)))) 86 return (NULL); 87 hashp->fp = -1; 88 /* 89 * Select flags relevant to us. Even if user wants write only, we need 90 * to be able to read the actual file, so we need to open it read/write. 91 * But, the field in the hashp structure needs to be accurate so that 92 * we can check accesses. 93 */ 94 hashp->flags = flags = flags & (O_CREAT | O_EXCL | O_EXLOCK | 95 O_RDONLY | O_RDWR | O_SHLOCK | O_TRUNC); 96 97 new_table = 0; 98 if (!file || (flags & O_TRUNC) || 99 (stat(file, &statbuf) && (errno == ENOENT))) { 100 if (errno == ENOENT) 101 errno = 0; /* Just in case someone looks at errno */ 102 new_table = 1; 103 } 104 if (file) { 105 if ((hashp->fp = open(file, flags, mode)) == -1) 106 RETURN_ERROR(errno, error0); 107 (void)fcntl(hashp->fp, F_SETFD, 1); 108 } 109 if (new_table) { 110 if (!(hashp = init_hash((HASHINFO *)info))) 111 RETURN_ERROR(errno, error1); 112 } else { 113 /* Table already exists */ 114 if (info && info->hash) 115 hashp->hash = info->hash; 116 else 117 hashp->hash = default_hash; 118 119 hdrsize = read(hashp->fp, &hashp->hdr, sizeof(HASHHDR)); 120 #if BYTE_ORDER == LITTLE_ENDIAN 121 swap_header(); 122 #endif 123 if (hdrsize == -1) 124 RETURN_ERROR(errno, error1); 125 if (hdrsize != sizeof(HASHHDR)) 126 RETURN_ERROR(EFTYPE, error1); 127 /* Verify file type, versions and hash function */ 128 if (hashp->MAGIC != HASHMAGIC) 129 RETURN_ERROR(EFTYPE, error1); 130 if (hashp->VERSION != HASHVERSION) 131 RETURN_ERROR(EFTYPE, error1); 132 if (hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY) 133 RETURN_ERROR(EFTYPE, error1); 134 /* 135 * Figure out how many segments we need. Max_Bucket is the 136 * maximum bucket number, so the number of buckets is 137 * max_bucket + 1. 138 */ 139 nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) / 140 hashp->SGSIZE; 141 hashp->nsegs = 0; 142 if (alloc_segs(nsegs)) 143 /* 144 * If alloc_segs fails, table will have been destroyed 145 * and errno will have been set. 146 */ 147 return (NULL); 148 /* Read in bitmaps */ 149 bpages = (hashp->SPARES[hashp->OVFL_POINT] + 150 (hashp->BSIZE << BYTE_SHIFT) - 1) >> 151 (hashp->BSHIFT + BYTE_SHIFT); 152 153 hashp->nmaps = bpages; 154 (void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_long *)); 155 } 156 157 /* Initialize Buffer Manager */ 158 if (info && info->cachesize) 159 __buf_init(info->cachesize); 160 else 161 __buf_init(DEF_BUFSIZE); 162 163 hashp->new_file = new_table; 164 hashp->save_file = file && (hashp->flags & O_RDWR); 165 hashp->cbucket = -1; 166 if (!(dbp = malloc(sizeof(DB)))) { 167 save_errno = errno; 168 hdestroy(); 169 errno = save_errno; 170 return (NULL); 171 } 172 dbp->internal = (char *)hashp; 173 dbp->close = hash_close; 174 dbp->del = hash_delete; 175 dbp->get = hash_get; 176 dbp->put = hash_put; 177 dbp->seq = hash_seq; 178 dbp->sync = hash_sync; 179 dbp->type = DB_HASH; 180 181 #ifdef DEBUG 182 (void)fprintf(stderr, 183 "%s\n%s%x\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n", 184 "init_htab:", 185 "TABLE POINTER ", hashp, 186 "BUCKET SIZE ", hashp->BSIZE, 187 "BUCKET SHIFT ", hashp->BSHIFT, 188 "DIRECTORY SIZE ", hashp->DSIZE, 189 "SEGMENT SIZE ", hashp->SGSIZE, 190 "SEGMENT SHIFT ", hashp->SSHIFT, 191 "FILL FACTOR ", hashp->FFACTOR, 192 "MAX BUCKET ", hashp->MAX_BUCKET, 193 "OVFL POINT ", hashp->OVFL_POINT, 194 "LAST FREED ", hashp->LAST_FREED, 195 "HIGH MASK ", hashp->HIGH_MASK, 196 "LOW MASK ", hashp->LOW_MASK, 197 "NSEGS ", hashp->nsegs, 198 "NKEYS ", hashp->NKEYS); 199 #endif 200 #ifdef HASH_STATISTICS 201 hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0; 202 #endif 203 return (dbp); 204 205 error1: 206 if (hashp != NULL) 207 (void)close(hashp->fp); 208 209 error0: 210 free(hashp); 211 errno = save_errno; 212 return (NULL); 213 } 214 215 static int 216 hash_close(dbp) 217 DB *dbp; 218 { 219 int retval; 220 221 if (!dbp) 222 return (ERROR); 223 hashp = (HTAB *)dbp->internal; 224 retval = hdestroy(); 225 free(dbp); 226 return (retval); 227 } 228 229 /************************** LOCAL CREATION ROUTINES **********************/ 230 static HTAB * 231 init_hash(info) 232 HASHINFO *info; 233 { 234 int nelem; 235 236 nelem = 1; 237 hashp->NKEYS = 0; 238 hashp->LORDER = BYTE_ORDER; 239 hashp->BSIZE = DEF_BUCKET_SIZE; 240 hashp->BSHIFT = DEF_BUCKET_SHIFT; 241 hashp->SGSIZE = DEF_SEGSIZE; 242 hashp->SSHIFT = DEF_SEGSIZE_SHIFT; 243 hashp->DSIZE = DEF_DIRSIZE; 244 hashp->FFACTOR = DEF_FFACTOR; 245 hashp->hash = default_hash; 246 bzero(hashp->SPARES, sizeof(hashp->SPARES)); 247 bzero (hashp->BITMAPS, sizeof (hashp->BITMAPS)); 248 249 if (info) { 250 if (info->bsize) { 251 /* Round pagesize up to power of 2 */ 252 hashp->BSHIFT = __log2(info->bsize); 253 hashp->BSIZE = 1 << hashp->BSHIFT; 254 if (hashp->BSIZE > MAX_BSIZE) { 255 errno = EINVAL; 256 return (NULL); 257 } 258 } 259 if (info->ffactor) 260 hashp->FFACTOR = info->ffactor; 261 if (info->hash) 262 hashp->hash = info->hash; 263 if (info->nelem) 264 nelem = info->nelem; 265 if (info->lorder) { 266 if (info->lorder != BIG_ENDIAN && 267 info->lorder != LITTLE_ENDIAN) { 268 errno = EINVAL; 269 return (NULL); 270 } 271 hashp->LORDER = info->lorder; 272 } 273 } 274 /* init_htab should destroy the table and set errno if it fails */ 275 if (init_htab(nelem)) 276 return (NULL); 277 else 278 return (hashp); 279 } 280 /* 281 * This calls alloc_segs which may run out of memory. Alloc_segs will destroy 282 * the table and set errno, so we just pass the error information along. 283 * 284 * Returns 0 on No Error 285 */ 286 static int 287 init_htab(nelem) 288 int nelem; 289 { 290 register int nbuckets, nsegs; 291 int l2; 292 293 /* 294 * Divide number of elements by the fill factor and determine a 295 * desired number of buckets. Allocate space for the next greater 296 * power of two number of buckets. 297 */ 298 nelem = (nelem - 1) / hashp->FFACTOR + 1; 299 300 l2 = __log2(MAX(nelem, 2)); 301 nbuckets = 1 << l2; 302 303 hashp->SPARES[l2] = l2 + 1; 304 hashp->SPARES[l2 + 1] = l2 + 1; 305 hashp->OVFL_POINT = l2; 306 hashp->LAST_FREED = 2; 307 308 /* First bitmap page is at: splitpoint l2 page offset 1 */ 309 if (__init_bitmap(OADDR_OF(l2, 1), l2 + 1, 0)) 310 return (-1); 311 312 hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1; 313 hashp->HIGH_MASK = (nbuckets << 1) - 1; 314 hashp->HDRPAGES = ((MAX(sizeof(HASHHDR), MINHDRSIZE) - 1) >> 315 hashp->BSHIFT) + 1; 316 317 nsegs = (nbuckets - 1) / hashp->SGSIZE + 1; 318 nsegs = 1 << __log2(nsegs); 319 320 if (nsegs > hashp->DSIZE) 321 hashp->DSIZE = nsegs; 322 return (alloc_segs(nsegs)); 323 } 324 325 /********************** DESTROY/CLOSE ROUTINES ************************/ 326 327 /* 328 * Flushes any changes to the file if necessary and destroys the hashp 329 * structure, freeing all allocated space. 330 */ 331 static int 332 hdestroy() 333 { 334 int i, save_errno; 335 336 save_errno = 0; 337 338 if (hashp != NULL) { 339 #ifdef HASH_STATISTICS 340 (void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n", 341 hash_accesses, hash_collisions); 342 (void)fprintf(stderr, "hdestroy: expansions %ld\n", 343 hash_expansions); 344 (void)fprintf(stderr, "hdestroy: overflows %ld\n", 345 hash_overflows); 346 (void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n", 347 hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs); 348 349 for (i = 0; i < NCACHED; i++) 350 (void)fprintf(stderr, 351 "spares[%d] = %d\n", i, hashp->SPARES[i]); 352 #endif 353 /* 354 * Call on buffer manager to free buffers, and if required, 355 * write them to disk. 356 */ 357 if (__buf_free(1, hashp->save_file)) 358 save_errno = errno; 359 if (hashp->dir) { 360 free(*hashp->dir); /* Free initial segments */ 361 /* Free extra segments */ 362 while (hashp->exsegs--) 363 free(hashp->dir[--hashp->nsegs]); 364 free(hashp->dir); 365 } 366 if (flush_meta() && !save_errno) 367 save_errno = errno; 368 /* Free Bigmaps */ 369 for (i = 0; i < hashp->nmaps; i++) 370 if (hashp->mapp[i]) 371 free(hashp->mapp[i]); 372 373 if (hashp->fp != -1) 374 (void)close(hashp->fp); 375 free(hashp); 376 hashp = NULL; 377 } 378 if (save_errno) { 379 errno = save_errno; 380 return (ERROR); 381 } 382 return (SUCCESS); 383 } 384 /* 385 * Write modified pages to disk 386 * 387 * Returns: 388 * 0 == OK 389 * -1 ERROR 390 */ 391 static int 392 hash_sync(dbp) 393 const DB *dbp; 394 { 395 if (!dbp) 396 return (ERROR); 397 hashp = (HTAB *)dbp->internal; 398 399 if (!hashp->save_file) 400 return (0); 401 if (__buf_free(0, 1) || flush_meta()) 402 return (ERROR); 403 hashp->new_file = 0; 404 return (0); 405 } 406 407 /* 408 * Returns: 409 * 0 == OK 410 * -1 indicates that errno should be set 411 */ 412 static int 413 flush_meta() 414 { 415 HASHHDR *whdrp; 416 #if BYTE_ORDER == LITTLE_ENDIAN 417 HASHHDR whdr; 418 #endif 419 int fp, i, wsize; 420 421 if (!hashp->save_file) 422 return (0); 423 hashp->MAGIC = HASHMAGIC; 424 hashp->VERSION = HASHVERSION; 425 hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY)); 426 427 fp = hashp->fp; 428 whdrp = &hashp->hdr; 429 #if BYTE_ORDER == LITTLE_ENDIAN 430 whdrp = &whdr; 431 swap_header_copy(&hashp->hdr, whdrp); 432 #endif 433 if ((lseek(fp, 0, SEEK_SET) == -1) || 434 ((wsize = write(fp, whdrp, sizeof(HASHHDR))) == -1)) 435 return (-1); 436 else 437 if (wsize != sizeof(HASHHDR)) { 438 errno = EFTYPE; 439 hashp->errno = errno; 440 return (-1); 441 } 442 for (i = 0; i < NCACHED; i++) 443 if (hashp->mapp[i]) 444 if (__put_page((char *)hashp->mapp[i], 445 hashp->BITMAPS[i], 0, 1)) 446 return (-1); 447 return (0); 448 } 449 450 /*******************************SEARCH ROUTINES *****************************/ 451 /* 452 * All the access routines return 453 * 454 * Returns: 455 * 0 on SUCCESS 456 * 1 to indicate an external ERROR (i.e. key not found, etc) 457 * -1 to indicate an internal ERROR (i.e. out of memory, etc) 458 */ 459 static int 460 hash_get(dbp, key, data, flag) 461 const DB *dbp; 462 const DBT *key; 463 DBT *data; 464 u_int flag; 465 { 466 if (flag) { 467 hashp->errno = errno = EINVAL; 468 return (ERROR); 469 } 470 hashp = (HTAB *)dbp->internal; 471 return (hash_access(HASH_GET, (DBT *)key, data)); 472 } 473 474 static int 475 hash_put(dbp, key, data, flag) 476 const DB *dbp; 477 const DBT *key, *data; 478 u_int flag; 479 { 480 if (flag && flag != R_NOOVERWRITE) { 481 hashp->errno = errno = EINVAL; 482 return (ERROR); 483 } 484 hashp = (HTAB *)dbp->internal; 485 if ((hashp->flags & O_ACCMODE) == O_RDONLY) { 486 hashp->errno = errno = EPERM; 487 return (ERROR); 488 } 489 return (hash_access(flag == R_NOOVERWRITE ? 490 HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data)); 491 } 492 493 static int 494 hash_delete(dbp, key, flag) 495 const DB *dbp; 496 const DBT *key; 497 u_int flag; /* Ignored */ 498 { 499 if (flag && flag != R_CURSOR) { 500 hashp->errno = errno = EINVAL; 501 return (ERROR); 502 } 503 hashp = (HTAB *)dbp->internal; 504 if ((hashp->flags & O_ACCMODE) == O_RDONLY) { 505 hashp->errno = errno = EPERM; 506 return (ERROR); 507 } 508 return (hash_access(HASH_DELETE, (DBT *)key, NULL)); 509 } 510 511 /* 512 * Assume that hashp has been set in wrapper routine. 513 */ 514 static int 515 hash_access(action, key, val) 516 ACTION action; 517 DBT *key, *val; 518 { 519 register BUFHEAD *rbufp; 520 BUFHEAD *bufp, *save_bufp; 521 register u_short *bp; 522 register int n, ndx, off, size; 523 register char *kp; 524 u_short pageno; 525 526 #ifdef HASH_STATISTICS 527 hash_accesses++; 528 #endif 529 530 off = hashp->BSIZE; 531 size = key->size; 532 kp = (char *)key->data; 533 rbufp = __get_buf(__call_hash(kp, size), NULL, 0); 534 if (!rbufp) 535 return (ERROR); 536 save_bufp = rbufp; 537 538 /* Pin the bucket chain */ 539 rbufp->flags |= BUF_PIN; 540 for (bp = (u_short *)rbufp->page, n = *bp++, ndx = 1; ndx < n;) 541 if (bp[1] >= REAL_KEY) { 542 /* Real key/data pair */ 543 if (size == off - *bp && 544 bcmp(kp, rbufp->page + *bp, size) == 0) 545 goto found; 546 off = bp[1]; 547 #ifdef HASH_STATISTICS 548 hash_collisions++; 549 #endif 550 bp += 2; 551 ndx += 2; 552 } else if (bp[1] == OVFLPAGE) { 553 rbufp = __get_buf(*bp, rbufp, 0); 554 if (!rbufp) { 555 save_bufp->flags &= ~BUF_PIN; 556 return (ERROR); 557 } 558 /* FOR LOOP INIT */ 559 bp = (u_short *)rbufp->page; 560 n = *bp++; 561 ndx = 1; 562 off = hashp->BSIZE; 563 } else if (bp[1] < REAL_KEY) { 564 if ((ndx = __find_bigpair(rbufp, ndx, kp, size)) > 0) 565 goto found; 566 if (ndx == -2) { 567 bufp = rbufp; 568 if (!(pageno = __find_last_page(&bufp))) { 569 ndx = 0; 570 rbufp = bufp; 571 break; /* FOR */ 572 } 573 rbufp = __get_buf(pageno, bufp, 0); 574 if (!rbufp) { 575 save_bufp->flags &= ~BUF_PIN; 576 return (ERROR); 577 } 578 /* FOR LOOP INIT */ 579 bp = (u_short *)rbufp->page; 580 n = *bp++; 581 ndx = 1; 582 off = hashp->BSIZE; 583 } else { 584 save_bufp->flags &= ~BUF_PIN; 585 return (ERROR); 586 } 587 } 588 589 /* Not found */ 590 switch (action) { 591 case HASH_PUT: 592 case HASH_PUTNEW: 593 if (__addel(rbufp, key, val)) { 594 save_bufp->flags &= ~BUF_PIN; 595 return (ERROR); 596 } else { 597 save_bufp->flags &= ~BUF_PIN; 598 return (SUCCESS); 599 } 600 case HASH_GET: 601 case HASH_DELETE: 602 default: 603 save_bufp->flags &= ~BUF_PIN; 604 return (ABNORMAL); 605 } 606 607 found: 608 switch (action) { 609 case HASH_PUTNEW: 610 save_bufp->flags &= ~BUF_PIN; 611 return (ABNORMAL); 612 case HASH_GET: 613 bp = (u_short *)rbufp->page; 614 if (bp[ndx + 1] < REAL_KEY) { 615 if (__big_return(rbufp, ndx, val, 0)) 616 return (ERROR); 617 } else { 618 val->data = (u_char *)rbufp->page + (int)bp[ndx + 1]; 619 val->size = bp[ndx] - bp[ndx + 1]; 620 } 621 break; 622 case HASH_PUT: 623 if ((__delpair(rbufp, ndx)) || (__addel(rbufp, key, val))) { 624 save_bufp->flags &= ~BUF_PIN; 625 return (ERROR); 626 } 627 break; 628 case HASH_DELETE: 629 if (__delpair(rbufp, ndx)) 630 return (ERROR); 631 break; 632 } 633 save_bufp->flags &= ~BUF_PIN; 634 return (SUCCESS); 635 } 636 637 static int 638 hash_seq(dbp, key, data, flag) 639 const DB *dbp; 640 DBT *key, *data; 641 u_int flag; 642 { 643 register u_int bucket; 644 register BUFHEAD *bufp; 645 u_short *bp, ndx; 646 647 if (flag && flag != R_FIRST && flag != R_NEXT) { 648 hashp->errno = errno = EINVAL; 649 return (ERROR); 650 } 651 hashp = (HTAB *)dbp->internal; 652 #ifdef HASH_STATISTICS 653 hash_accesses++; 654 #endif 655 if ((hashp->cbucket < 0) || (flag == R_FIRST)) { 656 hashp->cbucket = 0; 657 hashp->cndx = 1; 658 hashp->cpage = NULL; 659 } 660 661 for (bp = NULL; !bp || !bp[0]; ) { 662 if (!(bufp = hashp->cpage)) { 663 for (bucket = hashp->cbucket; 664 bucket <= hashp->MAX_BUCKET; 665 bucket++, hashp->cndx = 1) { 666 bufp = __get_buf(bucket, NULL, 0); 667 if (!bufp) 668 return (ERROR); 669 hashp->cpage = bufp; 670 bp = (u_short *)bufp->page; 671 if (bp[0]) 672 break; 673 } 674 hashp->cbucket = bucket; 675 if (hashp->cbucket > hashp->MAX_BUCKET) { 676 hashp->cbucket = -1; 677 return (ABNORMAL); 678 } 679 } else 680 bp = (u_short *)hashp->cpage->page; 681 682 #ifdef DEBUG 683 assert(bp); 684 assert(bufp); 685 #endif 686 while (bp[hashp->cndx + 1] == OVFLPAGE) { 687 bufp = hashp->cpage = 688 __get_buf(bp[hashp->cndx], bufp, 0); 689 if (!bufp) 690 return (ERROR); 691 bp = (u_short *)(bufp->page); 692 hashp->cndx = 1; 693 } 694 if (!bp[0]) { 695 hashp->cpage = NULL; 696 ++hashp->cbucket; 697 } 698 } 699 ndx = hashp->cndx; 700 if (bp[ndx + 1] < REAL_KEY) { 701 if (__big_keydata(bufp, key, data, 1)) 702 return (ERROR); 703 } else { 704 key->data = (u_char *)hashp->cpage->page + bp[ndx]; 705 key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx]; 706 data->data = (u_char *)hashp->cpage->page + bp[ndx + 1]; 707 data->size = bp[ndx] - bp[ndx + 1]; 708 ndx += 2; 709 if (ndx > bp[0]) { 710 hashp->cpage = NULL; 711 hashp->cbucket++; 712 hashp->cndx = 1; 713 } else 714 hashp->cndx = ndx; 715 } 716 return (SUCCESS); 717 } 718 719 /********************************* UTILITIES ************************/ 720 721 /* 722 * Returns: 723 * 0 ==> OK 724 * -1 ==> Error 725 */ 726 extern int 727 __expand_table() 728 { 729 u_int old_bucket, new_bucket; 730 int dirsize, new_segnum, spare_ndx; 731 732 #ifdef HASH_STATISTICS 733 hash_expansions++; 734 #endif 735 new_bucket = ++hashp->MAX_BUCKET; 736 old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK); 737 738 new_segnum = new_bucket >> hashp->SSHIFT; 739 740 /* Check if we need a new segment */ 741 if (new_segnum >= hashp->nsegs) { 742 /* Check if we need to expand directory */ 743 if (new_segnum >= hashp->DSIZE) { 744 /* Reallocate directory */ 745 dirsize = hashp->DSIZE * sizeof(SEGMENT *); 746 if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1)) 747 return (-1); 748 hashp->DSIZE = dirsize << 1; 749 } 750 if (!(hashp->dir[new_segnum] = 751 calloc(hashp->SGSIZE, sizeof(SEGMENT)))) 752 return (-1); 753 hashp->exsegs++; 754 hashp->nsegs++; 755 } 756 /* 757 * If the split point is increasing (MAX_BUCKET's log base 2 758 * * increases), we need to copy the current contents of the spare 759 * split bucket to the next bucket. 760 */ 761 spare_ndx = __log2(hashp->MAX_BUCKET + 1); 762 if (spare_ndx > hashp->OVFL_POINT) { 763 hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT]; 764 hashp->OVFL_POINT = spare_ndx; 765 } 766 767 if (new_bucket > hashp->HIGH_MASK) { 768 /* Starting a new doubling */ 769 hashp->LOW_MASK = hashp->HIGH_MASK; 770 hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK; 771 } 772 /* Relocate records to the new bucket */ 773 return (__split_page(old_bucket, new_bucket)); 774 } 775 776 /* 777 * If realloc guarantees that the pointer is not destroyed if the realloc 778 * fails, then this routine can go away. 779 */ 780 static void * 781 hash_realloc(p_ptr, oldsize, newsize) 782 SEGMENT **p_ptr; 783 int oldsize, newsize; 784 { 785 register void *p; 786 787 if (p = malloc(newsize)) { 788 bcopy(*p_ptr, p, oldsize); 789 bzero(*p_ptr + oldsize, newsize - oldsize); 790 free(*p_ptr); 791 *p_ptr = p; 792 } 793 return (p); 794 } 795 796 extern u_int 797 __call_hash(k, len) 798 char *k; 799 int len; 800 { 801 int n, bucket; 802 803 n = hashp->hash(k, len); 804 bucket = n & hashp->HIGH_MASK; 805 if (bucket > hashp->MAX_BUCKET) 806 bucket = bucket & hashp->LOW_MASK; 807 return (bucket); 808 } 809 810 /* 811 * Allocate segment table. On error, destroy the table and set errno. 812 * 813 * Returns 0 on success 814 */ 815 static int 816 alloc_segs(nsegs) 817 int nsegs; 818 { 819 register int i; 820 register SEGMENT store; 821 822 int save_errno; 823 824 if (!(hashp->dir = calloc(hashp->DSIZE, sizeof(SEGMENT *)))) { 825 save_errno = errno; 826 (void)hdestroy(); 827 errno = save_errno; 828 return (-1); 829 } 830 /* Allocate segments */ 831 store = calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT)); 832 if (!store) { 833 save_errno = errno; 834 (void)hdestroy(); 835 errno = save_errno; 836 return (-1); 837 } 838 for (i = 0; i < nsegs; i++, hashp->nsegs++) 839 hashp->dir[i] = &store[i << hashp->SSHIFT]; 840 return (0); 841 } 842 843 #if BYTE_ORDER == LITTLE_ENDIAN 844 /* 845 * Hashp->hdr needs to be byteswapped. 846 */ 847 static void 848 swap_header_copy(srcp, destp) 849 HASHHDR *srcp, *destp; 850 { 851 int i; 852 853 BLSWAP_COPY(srcp->magic, destp->magic); 854 BLSWAP_COPY(srcp->version, destp->version); 855 BLSWAP_COPY(srcp->lorder, destp->lorder); 856 BLSWAP_COPY(srcp->bsize, destp->bsize); 857 BLSWAP_COPY(srcp->bshift, destp->bshift); 858 BLSWAP_COPY(srcp->dsize, destp->dsize); 859 BLSWAP_COPY(srcp->ssize, destp->ssize); 860 BLSWAP_COPY(srcp->sshift, destp->sshift); 861 BLSWAP_COPY(srcp->ovfl_point, destp->ovfl_point); 862 BLSWAP_COPY(srcp->last_freed, destp->last_freed); 863 BLSWAP_COPY(srcp->max_bucket, destp->max_bucket); 864 BLSWAP_COPY(srcp->high_mask, destp->high_mask); 865 BLSWAP_COPY(srcp->low_mask, destp->low_mask); 866 BLSWAP_COPY(srcp->ffactor, destp->ffactor); 867 BLSWAP_COPY(srcp->nkeys, destp->nkeys); 868 BLSWAP_COPY(srcp->hdrpages, destp->hdrpages); 869 BLSWAP_COPY(srcp->h_charkey, destp->h_charkey); 870 for (i = 0; i < NCACHED; i++) { 871 BLSWAP_COPY(srcp->spares[i], destp->spares[i]); 872 BSSWAP_COPY(srcp->bitmaps[i], destp->bitmaps[i]); 873 } 874 } 875 876 static void 877 swap_header() 878 { 879 HASHHDR *hdrp; 880 int i; 881 882 hdrp = &hashp->hdr; 883 884 BLSWAP(hdrp->magic); 885 BLSWAP(hdrp->version); 886 BLSWAP(hdrp->lorder); 887 BLSWAP(hdrp->bsize); 888 BLSWAP(hdrp->bshift); 889 BLSWAP(hdrp->dsize); 890 BLSWAP(hdrp->ssize); 891 BLSWAP(hdrp->sshift); 892 BLSWAP(hdrp->ovfl_point); 893 BLSWAP(hdrp->last_freed); 894 BLSWAP(hdrp->max_bucket); 895 BLSWAP(hdrp->high_mask); 896 BLSWAP(hdrp->low_mask); 897 BLSWAP(hdrp->ffactor); 898 BLSWAP(hdrp->nkeys); 899 BLSWAP(hdrp->hdrpages); 900 BLSWAP(hdrp->h_charkey); 901 for (i = 0; i < NCACHED; i++) { 902 BLSWAP(hdrp->spares[i]); 903 BSSWAP(hdrp->bitmaps[i]); 904 } 905 } 906 #endif 907