146366Sbostic /*- 246366Sbostic * Copyright (c) 1990 The Regents of the University of California. 346366Sbostic * All rights reserved. 446366Sbostic * 546366Sbostic * This code is derived from software contributed to Berkeley by 646366Sbostic * Margo Seltzer. 746366Sbostic * 846366Sbostic * %sccs.include.redist.c% 946366Sbostic */ 1046366Sbostic 1146366Sbostic #if defined(LIBC_SCCS) && !defined(lint) 12*50997Sbostic static char sccsid[] = "@(#)hash.c 5.15 (Berkeley) 09/04/91"; 1346366Sbostic #endif /* LIBC_SCCS and not lint */ 1446366Sbostic 1546366Sbostic #include <sys/param.h> 1646366Sbostic #include <sys/stat.h> 1746562Sbostic #include <fcntl.h> 1846366Sbostic #include <errno.h> 19*50997Sbostic #ifdef DEBUG 2046366Sbostic #include <assert.h> 21*50997Sbostic #endif 2246366Sbostic #include <db.h> 2346562Sbostic #include <stdio.h> 2446562Sbostic #include <stdlib.h> 2546500Sbostic #include <unistd.h> 2646562Sbostic #include <string.h> 2746366Sbostic #include "hash.h" 28*50997Sbostic #include "page.h" 29*50997Sbostic #include "extern.h" 3046366Sbostic 31*50997Sbostic static int alloc_segs __P((int)); 32*50997Sbostic static int flush_meta __P((void)); 33*50997Sbostic static int hash_access __P((ACTION, DBT *, DBT *)); 34*50997Sbostic static int hash_close __P((DB *)); 35*50997Sbostic static int hash_delete __P((const DB *, const DBT *, u_int)); 36*50997Sbostic static int hash_get __P((const DB *, DBT *, DBT *, u_int)); 37*50997Sbostic static int hash_put __P((const DB *, const DBT *, const DBT *, u_int)); 38*50997Sbostic static void *hash_realloc __P((SEGMENT **, int, int)); 39*50997Sbostic static int hash_seq __P((const DB *, DBT *, DBT *, u_int)); 40*50997Sbostic static int hash_sync __P((const DB *)); 41*50997Sbostic static int hdestroy __P((void)); 42*50997Sbostic static HTAB *init_hash __P((HASHINFO *)); 43*50997Sbostic static int init_htab __P((int)); 44*50997Sbostic #if BYTE_ORDER == LITTLE_ENDIAN 45*50997Sbostic static void swap_header __P((void)); 46*50997Sbostic static void swap_header_copy __P((HASHHDR *, HASHHDR *)); 47*50997Sbostic #endif 48*50997Sbostic 4946366Sbostic /* Fast arithmetic, relying on powers of 2, */ 50*50997Sbostic #define MOD(x, y) ((x) & ((y) - 1)) 5146366Sbostic 52*50997Sbostic #define RETURN_ERROR(ERR, LOC) { save_errno = ERR; goto LOC; } 5346366Sbostic 5446366Sbostic /* Return values */ 55*50997Sbostic #define SUCCESS (0) 56*50997Sbostic #define ERROR (-1) 57*50997Sbostic #define ABNORMAL (1) 5846366Sbostic 5946366Sbostic /* Local data */ 6046366Sbostic HTAB *hashp = NULL; 6146366Sbostic 6246366Sbostic #ifdef HASH_STATISTICS 6346366Sbostic long hash_accesses, hash_collisions, hash_expansions, hash_overflows; 6446366Sbostic #endif 6546366Sbostic 66*50997Sbostic /************************** INTERFACE ROUTINES ***************************/ 6746366Sbostic /* OPEN/CLOSE */ 6846366Sbostic 69*50997Sbostic extern DB * 70*50997Sbostic hash_open(file, flags, mode, info) 71*50997Sbostic const char *file; 72*50997Sbostic int flags, mode; 73*50997Sbostic const HASHINFO *info; /* Special directives for create */ 7446366Sbostic { 75*50997Sbostic struct stat statbuf; 76*50997Sbostic DB *dbp; 77*50997Sbostic int bpages, hdrsize, new_table, nsegs, save_errno; 7846366Sbostic 79*50997Sbostic if (!(hashp = calloc(1, sizeof(HTAB)))) 80*50997Sbostic return (NULL); 81*50997Sbostic hashp->fp = -1; 82*50997Sbostic /* 83*50997Sbostic * Select flags relevant to us. Even if user wants write only, we need 84*50997Sbostic * to be able to read the actual file, so we need to open it read/write. 85*50997Sbostic * But, the field in the hashp structure needs to be accurate so that 86*50997Sbostic * we can check accesses. 87*50997Sbostic */ 88*50997Sbostic hashp->flags = flags = 89*50997Sbostic flags & (O_CREAT | O_EXCL | O_RDONLY | O_RDWR | O_TRUNC | O_WRONLY); 90*50997Sbostic if (flags & O_WRONLY) 91*50997Sbostic flags = (flags & ~O_WRONLY) | O_RDWR; 9246366Sbostic 93*50997Sbostic new_table = 0; 94*50997Sbostic if (!file || (flags & O_TRUNC) || 95*50997Sbostic (stat(file, &statbuf) && (errno == ENOENT))) { 96*50997Sbostic if (errno == ENOENT) 97*50997Sbostic errno = 0; /* Just in case someone looks at errno */ 98*50997Sbostic new_table = 1; 9946485Sbostic } 100*50997Sbostic if (file) { 101*50997Sbostic if ((hashp->fp = open(file, flags, mode)) == -1) 102*50997Sbostic RETURN_ERROR(errno, error0); 103*50997Sbostic (void)fcntl(hashp->fp, F_SETFD, 1); 10446366Sbostic } 105*50997Sbostic if (new_table) { 106*50997Sbostic if (!(hashp = init_hash((HASHINFO *)info))) 107*50997Sbostic RETURN_ERROR(errno, error1); 108*50997Sbostic } else { 109*50997Sbostic /* Table already exists */ 110*50997Sbostic if (info && info->hash) 111*50997Sbostic hashp->hash = info->hash; 112*50997Sbostic else 113*50997Sbostic hashp->hash = default_hash; 11446366Sbostic 115*50997Sbostic hdrsize = read(hashp->fp, &hashp->hdr, sizeof(HASHHDR)); 11646366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN 117*50997Sbostic swap_header(); 11846366Sbostic #endif 119*50997Sbostic if (hdrsize == -1) 120*50997Sbostic RETURN_ERROR(errno, error1); 121*50997Sbostic if (hdrsize != sizeof(HASHHDR)) 122*50997Sbostic RETURN_ERROR(EFTYPE, error1); 123*50997Sbostic /* Verify file type, versions and hash function */ 124*50997Sbostic if (hashp->MAGIC != HASHMAGIC) 125*50997Sbostic RETURN_ERROR(EFTYPE, error1); 126*50997Sbostic if (hashp->VERSION != VERSION_NO) 127*50997Sbostic RETURN_ERROR(EFTYPE, error1); 128*50997Sbostic if (hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY) 129*50997Sbostic RETURN_ERROR(EFTYPE, error1); 130*50997Sbostic /* 131*50997Sbostic Figure out how many segments we need. 132*50997Sbostic Max_Bucket it the maximum bucket number, so the 133*50997Sbostic number of buckets is max_bucket+1. 134*50997Sbostic */ 135*50997Sbostic nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) / 136*50997Sbostic hashp->SGSIZE; 137*50997Sbostic hashp->nsegs = 0; 138*50997Sbostic if (alloc_segs(nsegs)) 139*50997Sbostic /* 140*50997Sbostic * If alloc_segs fails, table will have been destroyed 141*50997Sbostic * and errno will have been set. 142*50997Sbostic */ 143*50997Sbostic return (NULL); 144*50997Sbostic /* Read in bitmaps */ 145*50997Sbostic bpages = (hashp->SPARES[__log2(hashp->MAX_BUCKET)] + 146*50997Sbostic (hashp->BSIZE << BYTE_SHIFT) - 1) >> 147*50997Sbostic (hashp->BSHIFT + BYTE_SHIFT); 14846366Sbostic 149*50997Sbostic hashp->nmaps = bpages; 150*50997Sbostic memset(&hashp->mapp[0], 0, bpages * sizeof(u_long *)); 15146366Sbostic } 15246366Sbostic 153*50997Sbostic /* Initialize Buffer Manager */ 154*50997Sbostic if (info && info->cachesize) 155*50997Sbostic __buf_init(info->cachesize); 156*50997Sbostic else 157*50997Sbostic __buf_init(DEF_BUFSIZE); 158*50997Sbostic 159*50997Sbostic hashp->new_file = new_table; 160*50997Sbostic hashp->save_file = file && (hashp->flags & (O_WRONLY | O_RDWR)); 161*50997Sbostic hashp->cbucket = -1; 162*50997Sbostic if (!(dbp = malloc(sizeof(DB)))) { 163*50997Sbostic save_errno = errno; 164*50997Sbostic hdestroy(); 165*50997Sbostic errno = save_errno; 166*50997Sbostic return (NULL); 16746366Sbostic } 168*50997Sbostic dbp->internal = (char *)hashp; 169*50997Sbostic dbp->close = hash_close; 170*50997Sbostic dbp->del = hash_delete; 171*50997Sbostic dbp->get = hash_get; 172*50997Sbostic dbp->put = hash_put; 173*50997Sbostic dbp->seq = hash_seq; 174*50997Sbostic dbp->sync = hash_sync; 175*50997Sbostic dbp->type = DB_HASH; 17646366Sbostic 17746366Sbostic #ifdef DEBUG 178*50997Sbostic (void)fprintf(stderr, 179*50997Sbostic "%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%x\n%s%x\n%s%d\n%s%d\n", 180*50997Sbostic "init_htab:", 181*50997Sbostic "TABLE POINTER ", hashp, 182*50997Sbostic "BUCKET SIZE ", hashp->BSIZE, 183*50997Sbostic "BUCKET SHIFT ", hashp->BSHIFT, 184*50997Sbostic "DIRECTORY SIZE ", hashp->DSIZE, 185*50997Sbostic "SEGMENT SIZE ", hashp->SGSIZE, 186*50997Sbostic "SEGMENT SHIFT ", hashp->SSHIFT, 187*50997Sbostic "FILL FACTOR ", hashp->FFACTOR, 188*50997Sbostic "MAX BUCKET ", hashp->MAX_BUCKET, 189*50997Sbostic "HIGH MASK ", hashp->HIGH_MASK, 190*50997Sbostic "LOW MASK ", hashp->LOW_MASK, 191*50997Sbostic "NSEGS ", hashp->nsegs, 192*50997Sbostic "NKEYS ", hashp->NKEYS); 19346366Sbostic #endif 19446366Sbostic #ifdef HASH_STATISTICS 19546366Sbostic hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0; 19646366Sbostic #endif 197*50997Sbostic return (dbp); 19846366Sbostic 19946366Sbostic error1: 200*50997Sbostic (void)close(hashp->fp); 20146366Sbostic 20246366Sbostic error0: 203*50997Sbostic free(hashp); 204*50997Sbostic errno = save_errno; 205*50997Sbostic return (NULL); 20646366Sbostic } 20746366Sbostic 20846366Sbostic static int 209*50997Sbostic hash_close(dbp) 210*50997Sbostic DB *dbp; 21146366Sbostic { 212*50997Sbostic int retval; 21346457Sbostic 214*50997Sbostic if (!dbp) 215*50997Sbostic return (ERROR); 21646366Sbostic hashp = (HTAB *)dbp->internal; 21746457Sbostic retval = hdestroy(); 218*50997Sbostic free(dbp); 219*50997Sbostic return (retval); 22046366Sbostic } 22146366Sbostic 22246366Sbostic /************************** LOCAL CREATION ROUTINES **********************/ 223*50997Sbostic static HTAB * 224*50997Sbostic init_hash(info) 225*50997Sbostic HASHINFO *info; 22646366Sbostic { 227*50997Sbostic int nelem; 22846366Sbostic 22946366Sbostic nelem = 1; 230*50997Sbostic hashp->LORDER = BYTE_ORDER; 231*50997Sbostic hashp->BSIZE = DEF_BUCKET_SIZE; 232*50997Sbostic hashp->BSHIFT = DEF_BUCKET_SHIFT; 233*50997Sbostic hashp->SGSIZE = DEF_SEGSIZE; 234*50997Sbostic hashp->SSHIFT = DEF_SEGSIZE_SHIFT; 235*50997Sbostic hashp->DSIZE = DEF_DIRSIZE; 236*50997Sbostic hashp->FFACTOR = DEF_FFACTOR; 237*50997Sbostic hashp->hash = default_hash; 238*50997Sbostic bzero(hashp->SPARES, sizeof(hashp->SPARES)); 23946366Sbostic 240*50997Sbostic if (info) { 241*50997Sbostic if (info->bsize) { 242*50997Sbostic /* Round pagesize up to power of 2 */ 243*50997Sbostic hashp->BSHIFT = __log2(info->bsize); 244*50997Sbostic hashp->BSIZE = 1 << hashp->BSHIFT; 245*50997Sbostic if (hashp->BSIZE > MAX_BSIZE) { 246*50997Sbostic errno = EINVAL; 247*50997Sbostic return (NULL); 248*50997Sbostic } 24946366Sbostic } 250*50997Sbostic if (info->ffactor) 251*50997Sbostic hashp->FFACTOR = info->ffactor; 252*50997Sbostic if (info->hash) 253*50997Sbostic hashp->hash = info->hash; 254*50997Sbostic if (info->nelem) 255*50997Sbostic nelem = info->nelem; 256*50997Sbostic if (info->lorder) { 257*50997Sbostic if (info->lorder != BIG_ENDIAN && 258*50997Sbostic info->lorder != LITTLE_ENDIAN) { 259*50997Sbostic errno = EINVAL; 260*50997Sbostic return (NULL); 261*50997Sbostic } 262*50997Sbostic hashp->LORDER = info->lorder; 26346366Sbostic } 26446366Sbostic } 26546366Sbostic /* init_htab should destroy the table and set errno if it fails */ 266*50997Sbostic if (init_htab(nelem)) 267*50997Sbostic return (NULL); 268*50997Sbostic else 269*50997Sbostic return (hashp); 27046366Sbostic } 27146366Sbostic /* 272*50997Sbostic * This calls alloc_segs which may run out of memory. Alloc_segs will destroy 273*50997Sbostic * the table and set errno, so we just pass the error information along. 274*50997Sbostic * 275*50997Sbostic * Returns 0 on No Error 276*50997Sbostic */ 27746366Sbostic static int 278*50997Sbostic init_htab(nelem) 279*50997Sbostic int nelem; 28046366Sbostic { 281*50997Sbostic register int nbuckets, nsegs; 282*50997Sbostic int l2; 28346366Sbostic 284*50997Sbostic /* 285*50997Sbostic * Divide number of elements by the fill factor and determine a 286*50997Sbostic * desired number of buckets. Allocate space for the next greater 287*50997Sbostic * power of two number of buckets. 288*50997Sbostic */ 28946366Sbostic nelem = (nelem - 1) / hashp->FFACTOR + 1; 29046366Sbostic 29146366Sbostic l2 = __log2(nelem); 29246366Sbostic nbuckets = 1 << l2; 293*50997Sbostic nbuckets = MAX(nbuckets, 2); 29446366Sbostic 29546366Sbostic hashp->SPARES[l2] = l2 + 1; 296*50997Sbostic hashp->SPARES[l2 + 1] = l2 + 1; 297*50997Sbostic /* First bitmap page is at: splitpoint l2 page offset 1 */ 298*50997Sbostic __init_bitmap(OADDR_OF(l2, 1), l2 + 1, 0); 29946366Sbostic 30046366Sbostic hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1; 30146366Sbostic hashp->HIGH_MASK = (nbuckets << 1) - 1; 302*50997Sbostic hashp->HDRPAGES = ((MAX(sizeof(HASHHDR), MINHDRSIZE) - 1) >> 303*50997Sbostic hashp->BSHIFT) + 1; 30446366Sbostic 30546366Sbostic nsegs = (nbuckets - 1) / hashp->SGSIZE + 1; 30646366Sbostic nsegs = 1 << __log2(nsegs); 30746366Sbostic 308*50997Sbostic if (nsegs > hashp->DSIZE) 309*50997Sbostic hashp->DSIZE = nsegs; 310*50997Sbostic return (alloc_segs(nsegs)); 31146366Sbostic } 31246366Sbostic 31346366Sbostic /********************** DESTROY/CLOSE ROUTINES ************************/ 31446366Sbostic 31546366Sbostic /* 316*50997Sbostic * Flushes any changes to the file if necessary and destroys the hashp 317*50997Sbostic * structure, freeing all allocated space. 318*50997Sbostic */ 31946366Sbostic static int 32046366Sbostic hdestroy() 32146366Sbostic { 322*50997Sbostic int i, save_errno; 32346366Sbostic 32446366Sbostic save_errno = 0; 32546366Sbostic 32646366Sbostic if (hashp != NULL) { 32746366Sbostic #ifdef HASH_STATISTICS 328*50997Sbostic (void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n", 329*50997Sbostic hash_accesses, hash_collisions); 330*50997Sbostic (void)fprintf(stderr, "hdestroy: expansions %ld\n", 331*50997Sbostic hash_expansions); 332*50997Sbostic (void)fprintf(stderr, "hdestroy: overflows %ld\n", 333*50997Sbostic hash_overflows); 334*50997Sbostic (void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n", 335*50997Sbostic hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs); 33646366Sbostic 337*50997Sbostic for (i = 0; i < NCACHED; i++) 338*50997Sbostic (void)fprintf(stderr, 339*50997Sbostic "spares[%d] = %d\n", i, hashp->SPARES[i]); 34046366Sbostic #endif 341*50997Sbostic /* 342*50997Sbostic * Call on buffer manager to free buffers, and if required, 343*50997Sbostic * write them to disk. 344*50997Sbostic */ 345*50997Sbostic if (__buf_free(1, hashp->save_file)) 346*50997Sbostic save_errno = errno; 347*50997Sbostic if (hashp->dir) { 348*50997Sbostic free(*hashp->dir); /* Free initial segments */ 349*50997Sbostic /* Free extra segments */ 350*50997Sbostic while (hashp->exsegs--) 351*50997Sbostic free(hashp->dir[--hashp->nsegs]); 352*50997Sbostic free(hashp->dir); 35346366Sbostic } 354*50997Sbostic if (flush_meta() && !save_errno) 355*50997Sbostic save_errno = errno; 35647251Sbostic /* Free Bigmaps */ 357*50997Sbostic for (i = 0; i < hashp->nmaps; i++) 358*50997Sbostic if (hashp->mapp[i]) 359*50997Sbostic free(hashp->mapp[i]); 36046503Sbostic 361*50997Sbostic if (hashp->fp != -1) 362*50997Sbostic (void)close(hashp->fp); 363*50997Sbostic free(hashp); 36446366Sbostic hashp = NULL; 36546366Sbostic } 366*50997Sbostic if (save_errno) { 367*50997Sbostic errno = save_errno; 368*50997Sbostic return (ERROR); 36946366Sbostic } 370*50997Sbostic return (SUCCESS); 37146366Sbostic } 372*50997Sbostic /* 373*50997Sbostic * Write modified pages to disk 374*50997Sbostic * 375*50997Sbostic * Returns: 376*50997Sbostic * 0 == OK 377*50997Sbostic * -1 ERROR 378*50997Sbostic */ 37946366Sbostic static int 38046366Sbostic hash_sync(dbp) 381*50997Sbostic const DB *dbp; 38246366Sbostic { 383*50997Sbostic if (!dbp) 384*50997Sbostic return (ERROR); 38546366Sbostic hashp = (HTAB *)dbp->internal; 38646366Sbostic 387*50997Sbostic if (!hashp->save_file) 388*50997Sbostic return (0); 389*50997Sbostic if (__buf_free(0, 1) || flush_meta()) 390*50997Sbostic return (ERROR); 39146366Sbostic hashp->new_file = 0; 392*50997Sbostic return (0); 39346366Sbostic } 39446366Sbostic 39546366Sbostic /* 396*50997Sbostic * Returns: 397*50997Sbostic * 0 == OK 398*50997Sbostic * -1 indicates that errno should be set 399*50997Sbostic */ 40046366Sbostic static int 40146366Sbostic flush_meta() 40246366Sbostic { 403*50997Sbostic HASHHDR *whdrp; 404*50997Sbostic int fp, i, wsize; 40546366Sbostic 406*50997Sbostic if (!hashp->save_file) 407*50997Sbostic return (0); 40846366Sbostic hashp->MAGIC = HASHMAGIC; 40946366Sbostic hashp->VERSION = VERSION_NO; 410*50997Sbostic hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY)); 41146366Sbostic 41246366Sbostic fp = hashp->fp; 41346366Sbostic whdrp = &hashp->hdr; 41446366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN 41546366Sbostic whdrp = &whdr; 416*50997Sbostic swap_header_copy(&hashp->hdr, whdrp); 41746366Sbostic #endif 418*50997Sbostic if ((lseek(fp, 0, SEEK_SET) == -1) || 419*50997Sbostic ((wsize = write(fp, whdrp, sizeof(HASHHDR))) == -1)) 420*50997Sbostic return (-1); 421*50997Sbostic else 422*50997Sbostic if (wsize != sizeof(HASHHDR)) { 423*50997Sbostic errno = EFTYPE; 424*50997Sbostic hashp->errno = errno; 425*50997Sbostic return (-1); 42646366Sbostic } 427*50997Sbostic for (i = 0; i < NCACHED; i++) 428*50997Sbostic if (hashp->mapp[i]) 429*50997Sbostic if (!__put_page((char *)hashp->mapp[i], 430*50997Sbostic hashp->BITMAPS[i], 0, 1)) 431*50997Sbostic return (-1); 432*50997Sbostic return (0); 43346366Sbostic } 434*50997Sbostic 43546366Sbostic /*******************************SEARCH ROUTINES *****************************/ 43646366Sbostic /* 437*50997Sbostic * All the access routines return 438*50997Sbostic * 439*50997Sbostic * Returns: 440*50997Sbostic * 0 on SUCCESS 441*50997Sbostic * 1 to indicate an external ERROR (i.e. key not found, etc) 442*50997Sbostic * -1 to indicate an internal ERROR (i.e. out of memory, etc) 443*50997Sbostic */ 44446366Sbostic static int 445*50997Sbostic hash_get(dbp, key, data, flag) 446*50997Sbostic const DB *dbp; 447*50997Sbostic DBT *key, *data; 448*50997Sbostic u_int flag; 44946366Sbostic { 450*50997Sbostic if (flag) { 451*50997Sbostic hashp->errno = errno = EINVAL; 452*50997Sbostic return (ERROR); 453*50997Sbostic } 454*50997Sbostic hashp = (HTAB *)dbp->internal; 455*50997Sbostic if (hashp->flags & O_WRONLY) { 456*50997Sbostic hashp->errno = errno = EPERM; 457*50997Sbostic return (ERROR); 458*50997Sbostic } 459*50997Sbostic return (hash_access(HASH_GET, key, data)); 46046366Sbostic } 46146366Sbostic 46246366Sbostic static int 463*50997Sbostic hash_put(dbp, key, data, flag) 464*50997Sbostic const DB *dbp; 465*50997Sbostic const DBT *key, *data; 466*50997Sbostic u_int flag; 46746366Sbostic { 468*50997Sbostic if (flag && flag != R_NOOVERWRITE) { 469*50997Sbostic hashp->errno = errno = EINVAL; 470*50997Sbostic return (ERROR); 471*50997Sbostic } 472*50997Sbostic hashp = (HTAB *)dbp->internal; 473*50997Sbostic if ((hashp->flags & O_ACCMODE) == O_RDONLY) { 474*50997Sbostic hashp->errno = errno = EPERM; 475*50997Sbostic return (ERROR); 476*50997Sbostic } 477*50997Sbostic return (hash_access(flag == R_NOOVERWRITE ? 478*50997Sbostic HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data)); 47946366Sbostic } 48046366Sbostic 48146366Sbostic static int 482*50997Sbostic hash_delete(dbp, key, flag) 483*50997Sbostic const DB *dbp; 484*50997Sbostic const DBT *key; 485*50997Sbostic u_int flag; /* Ignored */ 48646366Sbostic { 487*50997Sbostic if (flag && flag != R_CURSOR) { 488*50997Sbostic hashp->errno = errno = EINVAL; 489*50997Sbostic return (ERROR); 490*50997Sbostic } 491*50997Sbostic hashp = (HTAB *)dbp->internal; 492*50997Sbostic if ((hashp->flags & O_ACCMODE) == O_RDONLY) { 493*50997Sbostic hashp->errno = errno = EPERM; 494*50997Sbostic return (ERROR); 495*50997Sbostic } 496*50997Sbostic return (hash_access(HASH_DELETE, (DBT *)key, NULL)); 49746366Sbostic } 49846366Sbostic 49946366Sbostic /* 500*50997Sbostic * Assume that hashp has been set in wrapper routine. 501*50997Sbostic */ 50246366Sbostic static int 50346366Sbostic hash_access(action, key, val) 504*50997Sbostic ACTION action; 505*50997Sbostic DBT *key, *val; 50646366Sbostic { 507*50997Sbostic register BUFHEAD *rbufp; 508*50997Sbostic BUFHEAD *bufp, *save_bufp; 509*50997Sbostic register u_short *bp; 510*50997Sbostic register int n, ndx, off, size; 511*50997Sbostic register char *kp; 512*50997Sbostic u_short pageno; 51346366Sbostic 51446366Sbostic #ifdef HASH_STATISTICS 51546366Sbostic hash_accesses++; 51646366Sbostic #endif 51746366Sbostic 518*50997Sbostic off = hashp->BSIZE; 51946366Sbostic size = key->size; 52046950Sbostic kp = (char *)key->data; 521*50997Sbostic rbufp = __get_buf(__call_hash(kp, size), NULL, 0); 522*50997Sbostic if (!rbufp) 523*50997Sbostic return (ERROR); 52446457Sbostic save_bufp = rbufp; 52546366Sbostic 52646457Sbostic /* Pin the bucket chain */ 52746457Sbostic rbufp->flags |= BUF_PIN; 528*50997Sbostic for (bp = (u_short *)rbufp->page, n = *bp++, ndx = 1; ndx < n;) 529*50997Sbostic if (bp[1] >= REAL_KEY) { 530*50997Sbostic /* Real key/data pair */ 531*50997Sbostic if (size == off - *bp && 532*50997Sbostic bcmp(kp, rbufp->page + *bp, size) == 0) 533*50997Sbostic goto found; 534*50997Sbostic off = bp[1]; 53546366Sbostic #ifdef HASH_STATISTICS 536*50997Sbostic hash_collisions++; 53746366Sbostic #endif 538*50997Sbostic bp += 2; 539*50997Sbostic ndx += 2; 540*50997Sbostic } else if (bp[1] == OVFLPAGE) { 541*50997Sbostic rbufp = __get_buf(*bp, rbufp, 0); 542*50997Sbostic if (!rbufp) { 543*50997Sbostic save_bufp->flags &= ~BUF_PIN; 544*50997Sbostic return (ERROR); 545*50997Sbostic } 546*50997Sbostic /* FOR LOOP INIT */ 547*50997Sbostic bp = (u_short *)rbufp->page; 548*50997Sbostic n = *bp++; 549*50997Sbostic ndx = 1; 550*50997Sbostic off = hashp->BSIZE; 551*50997Sbostic } else if (bp[1] < REAL_KEY) { 552*50997Sbostic if ((ndx = __find_bigpair(rbufp, ndx, kp, size)) > 0) 553*50997Sbostic goto found; 554*50997Sbostic if (ndx == -2) { 555*50997Sbostic bufp = rbufp; 556*50997Sbostic if (!(pageno = __find_last_page(&bufp))) { 557*50997Sbostic ndx = 0; 558*50997Sbostic rbufp = bufp; 559*50997Sbostic break; /* FOR */ 560*50997Sbostic } 561*50997Sbostic rbufp = __get_buf(pageno, bufp, 0); 562*50997Sbostic if (!rbufp) { 563*50997Sbostic save_bufp->flags &= ~BUF_PIN; 564*50997Sbostic return (ERROR); 565*50997Sbostic } 566*50997Sbostic /* FOR LOOP INIT */ 567*50997Sbostic bp = (u_short *)rbufp->page; 568*50997Sbostic n = *bp++; 569*50997Sbostic ndx = 1; 570*50997Sbostic off = hashp->BSIZE; 571*50997Sbostic } else { 572*50997Sbostic save_bufp->flags &= ~BUF_PIN; 573*50997Sbostic return (ERROR); 574*50997Sbostic } 57546457Sbostic } 57646366Sbostic 57746366Sbostic /* Not found */ 578*50997Sbostic switch (action) { 579*50997Sbostic case HASH_PUT: 580*50997Sbostic case HASH_PUTNEW: 58146366Sbostic if (__addel(rbufp, key, val)) { 582*50997Sbostic save_bufp->flags &= ~BUF_PIN; 583*50997Sbostic return (ERROR); 58446366Sbostic } else { 585*50997Sbostic save_bufp->flags &= ~BUF_PIN; 586*50997Sbostic return (SUCCESS); 58746366Sbostic } 588*50997Sbostic case HASH_GET: 589*50997Sbostic case HASH_DELETE: 590*50997Sbostic default: 59146457Sbostic save_bufp->flags &= ~BUF_PIN; 592*50997Sbostic return (ABNORMAL); 59346366Sbostic } 59446366Sbostic 59546366Sbostic found: 59646366Sbostic switch (action) { 597*50997Sbostic case HASH_PUTNEW: 59846457Sbostic save_bufp->flags &= ~BUF_PIN; 599*50997Sbostic return (ABNORMAL); 600*50997Sbostic case HASH_GET: 60146366Sbostic bp = (u_short *)rbufp->page; 602*50997Sbostic if (bp[ndx + 1] < REAL_KEY) 603*50997Sbostic __big_return(rbufp, ndx, val, 0); 60446366Sbostic else { 605*50997Sbostic val->data = (u_char *)rbufp->page + (int)bp[ndx + 1]; 606*50997Sbostic val->size = bp[ndx] - bp[ndx + 1]; 60746366Sbostic } 60846366Sbostic break; 609*50997Sbostic case HASH_PUT: 610*50997Sbostic if ((__delpair(rbufp, ndx)) || (__addel(rbufp, key, val))) { 611*50997Sbostic save_bufp->flags &= ~BUF_PIN; 612*50997Sbostic return (ERROR); 61346457Sbostic } 61446366Sbostic break; 615*50997Sbostic case HASH_DELETE: 616*50997Sbostic if (__delpair(rbufp, ndx)) 617*50997Sbostic return (ERROR); 61846366Sbostic break; 61946366Sbostic } 62046457Sbostic save_bufp->flags &= ~BUF_PIN; 62146366Sbostic return (SUCCESS); 62246366Sbostic } 62346366Sbostic 62446366Sbostic static int 62546366Sbostic hash_seq(dbp, key, data, flag) 626*50997Sbostic const DB *dbp; 627*50997Sbostic DBT *key, *data; 628*50997Sbostic u_int flag; 62946366Sbostic { 630*50997Sbostic register u_int bucket; 631*50997Sbostic register BUFHEAD *bufp; 632*50997Sbostic u_short *bp, ndx; 63346366Sbostic 634*50997Sbostic if (flag && flag != R_FIRST && flag != R_NEXT) { 635*50997Sbostic hashp->errno = errno = EINVAL; 636*50997Sbostic return (ERROR); 63746366Sbostic } 63846366Sbostic hashp = (HTAB *)dbp->internal; 639*50997Sbostic if (hashp->flags & O_WRONLY) { 640*50997Sbostic hashp->errno = errno = EPERM; 641*50997Sbostic return (ERROR); 64246366Sbostic } 64346366Sbostic #ifdef HASH_STATISTICS 64446366Sbostic hash_accesses++; 64546366Sbostic #endif 646*50997Sbostic if ((hashp->cbucket < 0) || (flag == R_FIRST)) { 647*50997Sbostic hashp->cbucket = 0; 648*50997Sbostic hashp->cndx = 1; 649*50997Sbostic hashp->cpage = NULL; 65046366Sbostic } 651*50997Sbostic if (!(bufp = hashp->cpage)) { 652*50997Sbostic for (bucket = hashp->cbucket; bucket <= hashp->MAX_BUCKET; 653*50997Sbostic bucket++, hashp->cndx = 1) { 65446366Sbostic 655*50997Sbostic bufp = __get_buf(bucket, NULL, 0); 656*50997Sbostic if (!bufp) 657*50997Sbostic return (ERROR); 658*50997Sbostic hashp->cpage = bufp; 659*50997Sbostic bp = (u_short *)bufp->page; 660*50997Sbostic if (bp[0]) 661*50997Sbostic break; 662*50997Sbostic } 663*50997Sbostic hashp->cbucket = bucket; 664*50997Sbostic if (hashp->cbucket > hashp->MAX_BUCKET) { 665*50997Sbostic hashp->cbucket = -1; 666*50997Sbostic return (ABNORMAL); 667*50997Sbostic } 668*50997Sbostic } else 669*50997Sbostic bp = (u_short *)hashp->cpage->page; 67046366Sbostic 67146366Sbostic #ifdef DEBUG 672*50997Sbostic assert(bp); 673*50997Sbostic assert(bufp); 67446366Sbostic #endif 675*50997Sbostic while (bp[hashp->cndx + 1] == OVFLPAGE) { 676*50997Sbostic bufp = hashp->cpage = __get_buf(bp[hashp->cndx], bufp, 0); 677*50997Sbostic if (!bufp) 678*50997Sbostic return (ERROR); 679*50997Sbostic bp = (u_short *)(bufp->page); 680*50997Sbostic hashp->cndx = 1; 68146366Sbostic } 68246366Sbostic ndx = hashp->cndx; 683*50997Sbostic if (bp[ndx + 1] < REAL_KEY) { 684*50997Sbostic if (__big_keydata(bufp, ndx, key, data, 1)) 685*50997Sbostic return (ERROR); 68646366Sbostic } else { 687*50997Sbostic key->data = (u_char *)hashp->cpage->page + bp[ndx]; 688*50997Sbostic key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx]; 689*50997Sbostic data->data = (u_char *)hashp->cpage->page + bp[ndx + 1]; 690*50997Sbostic data->size = bp[ndx] - bp[ndx + 1]; 691*50997Sbostic ndx += 2; 692*50997Sbostic if (ndx > bp[0]) { 693*50997Sbostic hashp->cpage = NULL; 694*50997Sbostic hashp->cbucket++; 695*50997Sbostic hashp->cndx = 1; 696*50997Sbostic } else 697*50997Sbostic hashp->cndx = ndx; 69846366Sbostic } 69946366Sbostic return (SUCCESS); 70046366Sbostic } 70146366Sbostic 70246366Sbostic /********************************* UTILITIES ************************/ 703*50997Sbostic 70446366Sbostic /* 705*50997Sbostic * Returns: 706*50997Sbostic * 0 ==> OK 707*50997Sbostic * -1 ==> Error 708*50997Sbostic */ 70946366Sbostic extern int 71046366Sbostic __expand_table() 71146366Sbostic { 712*50997Sbostic u_int old_bucket, new_bucket; 713*50997Sbostic int dirsize, new_segnum, spare_ndx; 714*50997Sbostic 71546366Sbostic #ifdef HASH_STATISTICS 71646366Sbostic hash_expansions++; 71746366Sbostic #endif 71846366Sbostic new_bucket = ++hashp->MAX_BUCKET; 71946366Sbostic old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK); 72046366Sbostic 72146366Sbostic new_segnum = new_bucket >> hashp->SSHIFT; 72246366Sbostic 72346366Sbostic /* Check if we need a new segment */ 724*50997Sbostic if (new_segnum >= hashp->nsegs) { 725*50997Sbostic /* Check if we need to expand directory */ 726*50997Sbostic if (new_segnum >= hashp->DSIZE) { 727*50997Sbostic /* Reallocate directory */ 728*50997Sbostic dirsize = hashp->DSIZE * sizeof(SEGMENT *); 729*50997Sbostic if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1)) 730*50997Sbostic return (-1); 731*50997Sbostic hashp->DSIZE = dirsize << 1; 73246366Sbostic } 733*50997Sbostic if (!(hashp->dir[new_segnum] = 734*50997Sbostic calloc(hashp->SGSIZE, sizeof(SEGMENT)))) 735*50997Sbostic return (-1); 736*50997Sbostic hashp->exsegs++; 737*50997Sbostic hashp->nsegs++; 73846366Sbostic } 73946366Sbostic /* 740*50997Sbostic * If the split point is increasing (MAX_BUCKET's log base 2 741*50997Sbostic * * increases), we need to copy the current contents of the spare 742*50997Sbostic * split bucket to the next bucket. 743*50997Sbostic */ 74446366Sbostic spare_ndx = __log2(hashp->MAX_BUCKET); 745*50997Sbostic if (spare_ndx != (__log2(hashp->MAX_BUCKET - 1))) 746*50997Sbostic hashp->SPARES[spare_ndx] = hashp->SPARES[spare_ndx - 1]; 747*50997Sbostic if (new_bucket > hashp->HIGH_MASK) { 748*50997Sbostic /* Starting a new doubling */ 749*50997Sbostic hashp->LOW_MASK = hashp->HIGH_MASK; 750*50997Sbostic hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK; 75146366Sbostic } 752*50997Sbostic /* Relocate records to the new bucket */ 753*50997Sbostic return (__split_page(old_bucket, new_bucket)); 754*50997Sbostic } 75546366Sbostic 75646366Sbostic /* 757*50997Sbostic * If realloc guarantees that the pointer is not destroyed if the realloc 758*50997Sbostic * fails, then this routine can go away. 759*50997Sbostic */ 760*50997Sbostic static void * 761*50997Sbostic hash_realloc(p_ptr, oldsize, newsize) 762*50997Sbostic SEGMENT **p_ptr; 763*50997Sbostic int oldsize, newsize; 76446366Sbostic { 765*50997Sbostic register void *p; 76646366Sbostic 767*50997Sbostic if (p = malloc(newsize)) { 768*50997Sbostic bcopy(*p_ptr, p, oldsize); 769*50997Sbostic bzero(*p_ptr + oldsize, newsize - oldsize); 77046366Sbostic free(*p_ptr); 77146366Sbostic *p_ptr = p; 77246366Sbostic } 77346366Sbostic return (p); 77446366Sbostic } 77546366Sbostic 77647251Sbostic extern u_int 777*50997Sbostic __call_hash(k, len) 778*50997Sbostic char *k; 779*50997Sbostic int len; 78046366Sbostic { 781*50997Sbostic int n, bucket; 782*50997Sbostic 78346366Sbostic n = hashp->hash(k, len); 78446366Sbostic bucket = n & hashp->HIGH_MASK; 785*50997Sbostic if (bucket > hashp->MAX_BUCKET) 786*50997Sbostic bucket = bucket & hashp->LOW_MASK; 787*50997Sbostic return (bucket); 78846366Sbostic } 78946366Sbostic 79046366Sbostic /* 791*50997Sbostic * Allocate segment table. On error, destroy the table and set errno. 792*50997Sbostic * 793*50997Sbostic * Returns 0 on success 794*50997Sbostic */ 79546366Sbostic static int 796*50997Sbostic alloc_segs(nsegs) 797*50997Sbostic int nsegs; 79846366Sbostic { 799*50997Sbostic register int i; 800*50997Sbostic register SEGMENT store; 80146366Sbostic 802*50997Sbostic int save_errno; 80346366Sbostic 804*50997Sbostic if (!(hashp->dir = calloc(hashp->DSIZE, sizeof(SEGMENT *)))) { 805*50997Sbostic save_errno = errno; 806*50997Sbostic (void)hdestroy(); 807*50997Sbostic errno = save_errno; 808*50997Sbostic return (-1); 809*50997Sbostic } 810*50997Sbostic /* Allocate segments */ 811*50997Sbostic store = calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT)); 812*50997Sbostic if (!store) { 813*50997Sbostic save_errno = errno; 814*50997Sbostic (void)hdestroy(); 815*50997Sbostic errno = save_errno; 816*50997Sbostic return (-1); 817*50997Sbostic } 818*50997Sbostic for (i = 0; i < nsegs; i++, hashp->nsegs++) 819*50997Sbostic hashp->dir[i] = &store[i << hashp->SSHIFT]; 820*50997Sbostic return (0); 82146366Sbostic } 82246366Sbostic 823*50997Sbostic #if BYTE_ORDER == LITTLE_ENDIAN 82446366Sbostic /* 825*50997Sbostic * Hashp->hdr needs to be byteswapped. 826*50997Sbostic */ 82746366Sbostic static void 828*50997Sbostic swap_header_copy(srcp, destp) 829*50997Sbostic HASHHDR *srcp, *destp; 83046366Sbostic { 831*50997Sbostic int i; 83246366Sbostic 833*50997Sbostic BLSWAP_COPY(srcp->magic, destp->magic); 834*50997Sbostic BLSWAP_COPY(srcp->version, destp->version); 835*50997Sbostic BLSWAP_COPY(srcp->lorder, destp->lorder); 836*50997Sbostic BLSWAP_COPY(srcp->bsize, destp->bsize); 837*50997Sbostic BLSWAP_COPY(srcp->bshift, destp->bshift); 838*50997Sbostic BLSWAP_COPY(srcp->dsize, destp->dsize); 839*50997Sbostic BLSWAP_COPY(srcp->ssize, destp->ssize); 840*50997Sbostic BLSWAP_COPY(srcp->sshift, destp->sshift); 841*50997Sbostic BLSWAP_COPY(srcp->max_bucket, destp->max_bucket); 842*50997Sbostic BLSWAP_COPY(srcp->high_mask, destp->high_mask); 843*50997Sbostic BLSWAP_COPY(srcp->low_mask, destp->low_mask); 844*50997Sbostic BLSWAP_COPY(srcp->ffactor, destp->ffactor); 845*50997Sbostic BLSWAP_COPY(srcp->nkeys, destp->nkeys); 846*50997Sbostic BLSWAP_COPY(srcp->hdrpages, destp->hdrpages); 847*50997Sbostic BLSWAP_COPY(srcp->h_charkey, destp->h_charkey); 848*50997Sbostic for (i = 0; i < NCACHED; i++) { 849*50997Sbostic BLSWAP_COPY(srcp->spares[i], destp->spares[i]); 850*50997Sbostic BSSWAP_COPY(srcp->bitmaps[i], destp->bitmaps[i]); 851*50997Sbostic } 85246366Sbostic } 85346366Sbostic 85446366Sbostic static void 855*50997Sbostic swap_header() 85646366Sbostic { 857*50997Sbostic HASHHDR *hdrp; 858*50997Sbostic int i; 85946366Sbostic 860*50997Sbostic hdrp = &hashp->hdr; 86146366Sbostic 862*50997Sbostic BLSWAP(hdrp->magic); 863*50997Sbostic BLSWAP(hdrp->version); 864*50997Sbostic BLSWAP(hdrp->lorder); 865*50997Sbostic BLSWAP(hdrp->bsize); 866*50997Sbostic BLSWAP(hdrp->bshift); 867*50997Sbostic BLSWAP(hdrp->dsize); 868*50997Sbostic BLSWAP(hdrp->ssize); 869*50997Sbostic BLSWAP(hdrp->sshift); 870*50997Sbostic BLSWAP(hdrp->max_bucket); 871*50997Sbostic BLSWAP(hdrp->high_mask); 872*50997Sbostic BLSWAP(hdrp->low_mask); 873*50997Sbostic BLSWAP(hdrp->ffactor); 874*50997Sbostic BLSWAP(hdrp->nkeys); 875*50997Sbostic BLSWAP(hdrp->hdrpages); 876*50997Sbostic BLSWAP(hdrp->h_charkey); 877*50997Sbostic for (i = 0; i < NCACHED; i++) { 878*50997Sbostic BLSWAP(hdrp->spares[i]); 879*50997Sbostic BSSWAP(hdrp->bitmaps[i]); 880*50997Sbostic } 88146366Sbostic } 882*50997Sbostic #endif 883