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