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