xref: /csrg-svn/lib/libc/db/hash/hash.c (revision 47251)
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*47251Sbostic static char sccsid[] = "@(#)hash.c	5.13 (Berkeley) 03/12/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>
1946366Sbostic #include <assert.h>
2046366Sbostic #include <db.h>
2146562Sbostic #include <stdio.h>
2246562Sbostic #include <stdlib.h>
2346500Sbostic #include <unistd.h>
2446562Sbostic #include <string.h>
2546366Sbostic #include "hash.h"
2646366Sbostic 
2746366Sbostic /* Fast arithmetic, relying on powers of 2, */
2846366Sbostic 
2946366Sbostic #define MOD(x,y)		((x) & ((y)-1))
3046366Sbostic #define RETURN_ERROR(ERR,LOC)	{ save_errno = ERR; goto LOC; }
3146366Sbostic 
3246366Sbostic /* Return values */
3346366Sbostic 
3446366Sbostic #define	SUCCESS	0
3546366Sbostic #define	ERROR	-1
3646366Sbostic #define	ABNORMAL 1
3746366Sbostic 
3846366Sbostic /* page.c */
3946366Sbostic extern int __get_page();
4046366Sbostic extern int __split_page();
4146366Sbostic extern int __addel();
4246366Sbostic extern int __delpair();
4346366Sbostic extern u_long *__init_bitmap();
4446366Sbostic 
4546366Sbostic /* big.c */
46*47251Sbostic extern int __big_return();
4746366Sbostic extern int __big_keydata();
4846366Sbostic extern u_short __find_last_page();
4946366Sbostic 
5046366Sbostic /* buf.c */
5146366Sbostic extern BUFHEAD	*__get_buf();
5246366Sbostic extern void __buf_init();
5346366Sbostic extern int __buf_free();
5446366Sbostic 
5546366Sbostic /* hash function */
5646366Sbostic extern int (*default_hash)();
5746366Sbostic 
5846366Sbostic /* My externals */
5946366Sbostic extern int __expand_table();
60*47251Sbostic extern u_int __call_hash();
6146366Sbostic 
6246366Sbostic /* Internal routines */
6346366Sbostic static HTAB *init_hash();
6446366Sbostic static int hash_access();
6546366Sbostic static int flush_meta();
6646366Sbostic static int alloc_segs();
6746366Sbostic static int init_htab();
6846366Sbostic static char *hash_realloc();
6946366Sbostic static int hdestroy();
7046366Sbostic static int hash_put();
7146366Sbostic static int hash_delete();
7246366Sbostic static int hash_get();
7346366Sbostic static int hash_sync();
7446366Sbostic static int hash_close();
7546366Sbostic static int hash_seq();
7646366Sbostic static void swap_header_copy();
7746366Sbostic static void swap_header();
7846366Sbostic 
7946366Sbostic /* Local data */
8046366Sbostic 
8146366Sbostic HTAB *hashp = NULL;
8246366Sbostic 
8346366Sbostic #ifdef HASH_STATISTICS
8446366Sbostic long hash_accesses, hash_collisions, hash_expansions, hash_overflows;
8546366Sbostic #endif
8646366Sbostic 
8746366Sbostic /************************** INTERFACE ROUTINES **********************/
8846366Sbostic /* OPEN/CLOSE */
8946366Sbostic 
9046366Sbostic extern	DB *
9146366Sbostic hash_open ( file, flags, mode, info )
9246534Sbostic const char	*file;
9346366Sbostic int	flags;
9446366Sbostic int	mode;
9546534Sbostic const HASHINFO	*info;		/* Special directives for create */
9646366Sbostic {
9746366Sbostic     int		buckets;
9846366Sbostic     int		bpages;
9946366Sbostic     int		hdrsize;
10046366Sbostic     int		i;
10146366Sbostic     int		new_table = 0;
10246366Sbostic     int		nkey;
10346366Sbostic     int		nsegs;
10446366Sbostic     int		save_errno;
10546366Sbostic     struct	stat statbuf;
10646366Sbostic     DB		*dbp;
10746366Sbostic 
10846366Sbostic 
10946366Sbostic     if ( !(hashp = (HTAB *) calloc( 1, sizeof(HTAB) ))) {
11046366Sbostic 	/* calloc should set errno */
11146366Sbostic 	return(0);
11246366Sbostic     }
11346457Sbostic     hashp->fp = -1;
11446366Sbostic     /*
11546366Sbostic 	Select flags relevant to us.
11646366Sbostic 	Even if user wants write only, we need to be able to read
11746366Sbostic 	the actual file, so we need to open it read/write.  But, the
11846366Sbostic 	field in the hashp structure needs to be accurate so that
11946366Sbostic 	we can check accesses.
12046366Sbostic     */
12146366Sbostic     flags = flags & (O_CREAT | O_EXCL | O_RDONLY | O_RDWR | O_TRUNC | O_WRONLY);
12246366Sbostic     hashp->flags = flags;
12346366Sbostic     if ( flags & O_WRONLY )  flags = (flags & ~O_WRONLY) | O_RDWR;
12446366Sbostic 
12546366Sbostic     if ( !file ||
12646366Sbostic 	 (flags & O_TRUNC) ||
12746366Sbostic 	 (stat ( file, &statbuf ) && (errno == ENOENT)) ) {
12846503Sbostic 	 if ( errno == ENOENT ) {
12946503Sbostic 	    errno = 0;		/* Just in case someone looks at errno */
13046503Sbostic 	 }
13146366Sbostic 	 new_table = 1;
13246366Sbostic     }
13346366Sbostic 
13446485Sbostic     if ( file ) {
13546485Sbostic 	if ((hashp->fp = open ( file, flags, mode )) == -1) {
13646485Sbostic 	    RETURN_ERROR (errno, error0);
13746485Sbostic 	}
13846485Sbostic 	(void)fcntl(hashp->fp, F_SETFD, 1);
13946366Sbostic     }
14046366Sbostic 
14146366Sbostic     if ( new_table ) {
14246366Sbostic 	if ( !(hashp = init_hash( info )) ) {
14346366Sbostic 	    RETURN_ERROR(errno,error1);
14446366Sbostic 	}
14546366Sbostic     } else {
14646366Sbostic 	/* Table already exists */
14746366Sbostic 	if ( info && info->hash ) hashp->hash = info->hash;
14846366Sbostic 	else hashp->hash = default_hash;
14946366Sbostic 
15046366Sbostic 	hdrsize = read ( hashp->fp, &hashp->hdr, sizeof(HASHHDR) );
15146366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
15246366Sbostic 	swap_header ( );
15346366Sbostic #endif
15446366Sbostic 	if ( hdrsize == -1 ) {
15546366Sbostic 	    RETURN_ERROR(errno, error1);
15646366Sbostic 	}
15746366Sbostic 	if ( hdrsize != sizeof(HASHHDR) ) {
15846366Sbostic 	    RETURN_ERROR(EFTYPE, error1);
15946366Sbostic 	}
16046366Sbostic 
16146366Sbostic 	/* Verify file type, versions and hash function */
16246366Sbostic 	if ( hashp->MAGIC != HASHMAGIC )
16346366Sbostic 	    RETURN_ERROR ( EFTYPE, error1 );
16446366Sbostic 	if ( hashp->VERSION != VERSION_NO )
16546366Sbostic 	    RETURN_ERROR ( EFTYPE, error1 );
16646366Sbostic 	if (hashp->hash ( CHARKEY, sizeof(CHARKEY) ) != hashp->H_CHARKEY ) {
16746366Sbostic 	    RETURN_ERROR ( EFTYPE, error1 );
16846366Sbostic 	}
16946366Sbostic 
17046366Sbostic 	/*
17146366Sbostic 	    Figure out how many segments we need.
17246366Sbostic 	*/
17346366Sbostic 	nsegs = (hashp->MAX_BUCKET + hashp->SGSIZE -1)/ hashp->SGSIZE;
17446366Sbostic 	hashp->nsegs = 0;
17546366Sbostic 	if (alloc_segs( nsegs )) {
17646366Sbostic 	    /*
17746366Sbostic 		If alloc_segs fails, table will have been destroyed
17846366Sbostic 		and errno will have been set.
17946366Sbostic 	    */
18046366Sbostic 	    return( (DB *) NULL );
18146366Sbostic 	}
18246366Sbostic 
18346366Sbostic 	/* Read in bitmaps */
18446366Sbostic 	bpages = (hashp->SPARES[__log2(hashp->MAX_BUCKET)] +
18546366Sbostic 		  (hashp->BSIZE << BYTE_SHIFT) - 1) >>
18646366Sbostic 		  (hashp->BSHIFT + BYTE_SHIFT);
18746366Sbostic 
18846503Sbostic 	hashp->nmaps = bpages;
189*47251Sbostic 	memset ( &hashp->mapp[0], 0, bpages * sizeof ( u_long *) );
19046366Sbostic     }
19146366Sbostic 
19246366Sbostic     /* Initialize Buffer Manager */
193*47251Sbostic     if ( info && info->cachesize ) {
194*47251Sbostic 	__buf_init (info->cachesize);
19546366Sbostic     } else {
19646366Sbostic 	__buf_init (DEF_BUFSIZE);
19746366Sbostic     }
19846366Sbostic 
19946366Sbostic     hashp->new_file = new_table;
200*47251Sbostic     hashp->save_file = file && (hashp->flags & (O_WRONLY|O_RDWR));
20146366Sbostic     hashp->cbucket = -1;
20246366Sbostic     if ( !(dbp = (DB *)malloc ( sizeof (DB) )) ) {
20346366Sbostic 	save_errno = errno;
20446366Sbostic 	hdestroy();
20546366Sbostic 	errno = save_errno;
20646366Sbostic 	return ( NULL );
20746366Sbostic     }
20846366Sbostic     dbp->internal = (char *)hashp;
20946366Sbostic     dbp->close = hash_close;
21046534Sbostic     dbp->del = hash_delete;
21146366Sbostic     dbp->get = hash_get;
21246366Sbostic     dbp->put = hash_put;
21346366Sbostic     dbp->seq = hash_seq;
21446366Sbostic     dbp->sync = hash_sync;
21546366Sbostic 
21646366Sbostic #ifdef DEBUG
21746366Sbostic 	(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",
21846366Sbostic 		"init_htab:",
21946366Sbostic 		"TABLE POINTER   ", hashp,
22046366Sbostic 		"BUCKET SIZE     ", hashp->BSIZE,
22146366Sbostic 		"BUCKET SHIFT    ", hashp->BSHIFT,
22246366Sbostic 		"DIRECTORY SIZE  ", hashp->DSIZE,
22346366Sbostic 		"SEGMENT SIZE    ", hashp->SGSIZE,
22446366Sbostic 		"SEGMENT SHIFT   ", hashp->SSHIFT,
22546366Sbostic 		"FILL FACTOR     ", hashp->FFACTOR,
22646366Sbostic 		"MAX BUCKET      ", hashp->MAX_BUCKET,
22746366Sbostic 		"HIGH MASK       ", hashp->HIGH_MASK,
22846366Sbostic 		"LOW  MASK       ", hashp->LOW_MASK,
22946366Sbostic 		"NSEGS           ", hashp->nsegs,
23046366Sbostic 		"NKEYS           ", hashp->NKEYS );
23146366Sbostic #endif
23246366Sbostic #ifdef HASH_STATISTICS
23346366Sbostic 	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
23446366Sbostic #endif
23546366Sbostic     return (dbp);
23646366Sbostic 
23746366Sbostic error2:
23846366Sbostic     (void)hdestroy();
23946366Sbostic     errno = save_errno;
24046366Sbostic     return ( (DB *)NULL );
24146366Sbostic 
24246366Sbostic error1:
24346366Sbostic     (void) close ( hashp->fp );
24446366Sbostic 
24546366Sbostic error0:
24646366Sbostic     free ( hashp );
24746366Sbostic     errno = save_errno;
24846366Sbostic     return ( (DB *) NULL );
24946366Sbostic }
25046366Sbostic 
25146366Sbostic static int
25246366Sbostic hash_close (dbp)
25346366Sbostic DB	*dbp;
25446366Sbostic {
25546457Sbostic 	int	retval;
25646457Sbostic 
25746366Sbostic 	if ( !dbp ) {
25846366Sbostic 	    return(ERROR);
25946366Sbostic 	}
26046366Sbostic 	hashp = (HTAB *)dbp->internal;
26146457Sbostic 	retval = hdestroy();
26246457Sbostic 	(void)free ( dbp );
26346457Sbostic 	return ( retval );
26446366Sbostic }
26546366Sbostic 
26646366Sbostic 
26746366Sbostic /************************** LOCAL CREATION ROUTINES **********************/
26846366Sbostic static HTAB *
26946366Sbostic init_hash( info )
27046366Sbostic HASHINFO *info;
27146366Sbostic {
27246366Sbostic 	int	nelem;
27346366Sbostic 
27446366Sbostic 	nelem = 1;
27546366Sbostic 
27646366Sbostic 	hashp->LORDER	= BYTE_ORDER;
27746366Sbostic 	hashp->BSIZE    = DEF_BUCKET_SIZE;
27846366Sbostic 	hashp->BSHIFT   = DEF_BUCKET_SHIFT;
27946366Sbostic 	hashp->SGSIZE   = DEF_SEGSIZE;
28046366Sbostic 	hashp->SSHIFT   = DEF_SEGSIZE_SHIFT;
28146366Sbostic 	hashp->DSIZE    = DEF_DIRSIZE;
28246366Sbostic 	hashp->FFACTOR  = DEF_FFACTOR;
28346366Sbostic 	hashp->hash     = default_hash;
28446366Sbostic 	bzero (hashp->SPARES, sizeof (hashp->SPARES));
28546366Sbostic 
28646366Sbostic 	if ( info ) {
28746366Sbostic 	    if ( info->bsize )   {
28846366Sbostic 		/* Round pagesize up to power of 2 */
28946366Sbostic 		hashp->BSHIFT  = __log2(info->bsize);
29046366Sbostic 		hashp->BSIZE   = 1 << hashp->BSHIFT;
29146366Sbostic 		if ( hashp->BSIZE > MAX_BSIZE ) {
29246366Sbostic 		    errno = EINVAL;
29346366Sbostic 		    return(0);
29446366Sbostic 		}
29546366Sbostic 	    }
29646366Sbostic 	    if ( info->ffactor )  hashp->FFACTOR = info->ffactor;
29746366Sbostic 	    if ( info->hash ) hashp->hash    = info->hash;
29846366Sbostic 	    if ( info->nelem ) nelem = info->nelem;
29946366Sbostic 	    if ( info->lorder ) {
30046366Sbostic 		if ( info->lorder != BIG_ENDIAN &&
30146366Sbostic 		     info->lorder != LITTLE_ENDIAN) {
30246366Sbostic 		    errno = EINVAL;
30346366Sbostic 		    return(0);
30446366Sbostic 		}
30546366Sbostic 		hashp->LORDER = info->lorder;
30646366Sbostic 	    }
30746366Sbostic 	}
30846366Sbostic 
30946366Sbostic 	/* init_htab should destroy the table and set errno if it fails */
31046366Sbostic 	if ( init_htab ( nelem ) ) {
31146366Sbostic 	    return(0);
31246366Sbostic 	} else {
31346366Sbostic 	    return(hashp);
31446366Sbostic 	}
31546366Sbostic }
31646366Sbostic 
31746366Sbostic /*
31846366Sbostic     This calls alloc_segs which may run out of memory.
31946366Sbostic     Alloc_segs will destroy the table and set errno,
32046366Sbostic     so we just pass the error information along.
32146366Sbostic 
32246366Sbostic     Returns 0 on No Error
32346366Sbostic 
32446366Sbostic */
32546366Sbostic static int
32646366Sbostic init_htab ( nelem )
32746366Sbostic int	nelem;
32846366Sbostic {
32946366Sbostic 	register SEGMENT	*segp;
33046366Sbostic 	register int nbuckets;
33146366Sbostic 	register int nsegs;
33246366Sbostic 	int	l2;
33346366Sbostic 
33446366Sbostic  /*
33546366Sbostic   * Divide number of elements by the fill factor and determine a desired
33646366Sbostic   * number of buckets.  Allocate space for the next greater power of
33746366Sbostic   * two number of buckets
33846366Sbostic   */
33946366Sbostic 	nelem = (nelem - 1) / hashp->FFACTOR + 1;
34046366Sbostic 
34146366Sbostic 	l2 = __log2(nelem);
34246366Sbostic 	nbuckets = 1 << l2;
34346366Sbostic 	nbuckets = MAX ( nbuckets, 2 );
34446366Sbostic 
34546366Sbostic 	hashp->SPARES[l2] = l2 + 1;
34646366Sbostic 	hashp->SPARES[l2+1] = l2 + 1;
34746366Sbostic 	/*
34846366Sbostic 	    First bitmap page is at:
34946366Sbostic 		splitpoint l2
35046366Sbostic 		page offset 1
35146366Sbostic 	*/
35246366Sbostic 	__init_bitmap ( OADDR_OF(l2,1), l2+1, 0 );
35346366Sbostic 
35446366Sbostic 	hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
35546366Sbostic 	hashp->HIGH_MASK = (nbuckets << 1) - 1;
35646366Sbostic 	hashp->HDRPAGES = ((MAX(sizeof(HASHHDR),MINHDRSIZE) - 1) >>
35746366Sbostic 			  hashp->BSHIFT) + 1;
35846366Sbostic 
35946366Sbostic 	nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
36046366Sbostic 	nsegs = 1 << __log2(nsegs);
36146366Sbostic 
36246366Sbostic 	if ( nsegs > hashp->DSIZE ) {
36346366Sbostic 	    hashp->DSIZE  = nsegs;
36446366Sbostic 	}
36546366Sbostic 
36646366Sbostic 	return (alloc_segs ( nsegs ) );
36746366Sbostic }
36846366Sbostic 
36946366Sbostic /********************** DESTROY/CLOSE ROUTINES ************************/
37046366Sbostic 
37146366Sbostic /*
37246366Sbostic     Flushes any changes to the file if necessary and
37346366Sbostic     destroys the hashp structure, freeing all allocated
37446366Sbostic     space.
37546366Sbostic */
37646366Sbostic static int
37746366Sbostic hdestroy()
37846366Sbostic {
37946366Sbostic 	int	save_errno;
38046366Sbostic 	int	i;
38146366Sbostic 
38246366Sbostic 	save_errno = 0;
38346366Sbostic 
38446366Sbostic 	if (hashp != NULL) {
38546366Sbostic #ifdef HASH_STATISTICS
38646366Sbostic 	 (void)	fprintf(stderr,	"hdestroy: accesses %ld collisions %ld\n",
38746366Sbostic 			hash_accesses, hash_collisions);
38846366Sbostic 	 (void)	fprintf(stderr, "hdestroy: expansions %ld\n",
38946366Sbostic 			hash_expansions);
39046366Sbostic 	 (void)	fprintf(stderr, "hdestroy: overflows %ld\n",
39146366Sbostic 			hash_overflows);
39246366Sbostic 	 (void)	fprintf(stderr,	"keys %ld maxp %d segmentcount %d\n",
39346366Sbostic 			hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
39446366Sbostic 
39546366Sbostic 	for ( i = 0; i < NCACHED; i++ ) {
39646366Sbostic 	    (void) fprintf ( stderr, "spares[%d] = %d\n", i, hashp->SPARES[i] );
39746366Sbostic 	}
39846366Sbostic #endif
39946366Sbostic 
40046366Sbostic 		/*
40146366Sbostic 		    Call on buffer manager to free buffers, and if
40246366Sbostic 		    required, write them to disk
40346366Sbostic 		*/
40446366Sbostic 		if (__buf_free(1, hashp->save_file)) {
40546366Sbostic 		    save_errno = errno;
40646366Sbostic 		}
40746366Sbostic 		if ( hashp->dir ) {
40846366Sbostic 		    (void)free(*hashp->dir);	/* Free initial segments */
40946366Sbostic 		    /* Free extra segments */
41046366Sbostic 		    while ( hashp->exsegs-- ) {
41146366Sbostic 			(void)free ( hashp->dir[--hashp->nsegs] );
41246366Sbostic 		    }
41346366Sbostic 		    (void)free(hashp->dir);
41446366Sbostic 		}
41546366Sbostic 		if (flush_meta() && !save_errno) {
41646366Sbostic 		    save_errno = errno;
41746366Sbostic 		}
41846503Sbostic 
419*47251Sbostic 		/* Free Bigmaps */
420*47251Sbostic 		for ( i = 0; i < hashp->nmaps; i++ ) {
421*47251Sbostic 		    if ( hashp->mapp[i] ) {
422*47251Sbostic 			(void) free ( hashp->mapp[i] );
423*47251Sbostic 		    }
42446503Sbostic 		}
42546503Sbostic 
42646457Sbostic 		if ( hashp->fp != -1 ) {
42746457Sbostic 			(void)close (hashp->fp);
42846457Sbostic 		}
42946366Sbostic 		(void)free(hashp);
43046366Sbostic 		hashp = NULL;
43146366Sbostic 	}
43246366Sbostic 	if ( save_errno ) {
43346366Sbostic 	    errno = save_errno;
43446366Sbostic 	    return(ERROR);
43546366Sbostic 	} else {
43646366Sbostic 	    return(SUCCESS);
43746366Sbostic 	}
43846366Sbostic }
43946366Sbostic 
44046366Sbostic /*
44146366Sbostic     Write modified pages to disk
44246366Sbostic     0 == OK
44346366Sbostic     -1 ERROR
44446366Sbostic */
44546366Sbostic static int
44646366Sbostic hash_sync(dbp)
44746366Sbostic DB	*dbp;
44846366Sbostic {
44946366Sbostic 	if ( !dbp ) {
45046366Sbostic 	    return (ERROR);
45146366Sbostic 	}
45246366Sbostic 
45346366Sbostic 	hashp = (HTAB *)dbp->internal;
45446366Sbostic 
45546366Sbostic 	if (!hashp->save_file) return(0);
45646366Sbostic 	if ( __buf_free ( 0, 1 )  || flush_meta()) {
45746366Sbostic 	    return(ERROR);
45846366Sbostic 	}
45946366Sbostic 	hashp->new_file = 0;
46046366Sbostic 	return(0);
46146366Sbostic }
46246366Sbostic 
46346366Sbostic /*
46446366Sbostic 0 == OK
46546366Sbostic -1 indicates that errno should be set
46646366Sbostic */
46746366Sbostic static int
46846366Sbostic flush_meta()
46946366Sbostic {
47046366Sbostic     	int	fp;
47146366Sbostic 	int	hdrsize;
47246366Sbostic 	int	i;
47346366Sbostic 	int	wsize;
47446366Sbostic 	HASHHDR	*whdrp;
47546366Sbostic 	HASHHDR	whdr;
47646366Sbostic 
47746366Sbostic 	if (!hashp->save_file) return(0);
47846366Sbostic 	hashp->MAGIC = HASHMAGIC;
47946366Sbostic 	hashp->VERSION = VERSION_NO;
48046366Sbostic 	hashp->H_CHARKEY = hashp->hash ( CHARKEY, sizeof(CHARKEY));
48146366Sbostic 
48246366Sbostic 	fp = hashp->fp;
48346366Sbostic 	whdrp = &hashp->hdr;
48446366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
48546366Sbostic 	whdrp = &whdr;
48646366Sbostic 	swap_header_copy( &hashp->hdr, whdrp );
48746366Sbostic #endif
48846500Sbostic 	if ( (lseek (fp, 0, SEEK_SET) == -1 ) ||
48946366Sbostic 	     ((wsize = write ( fp, whdrp, sizeof(HASHHDR))) == -1)) {
49046366Sbostic 	    return(-1);
49146366Sbostic 	} else if ( wsize != sizeof(HASHHDR) ) {
49246366Sbostic 	    errno = EFTYPE;
49346366Sbostic 	    hashp->errno = errno;
49446366Sbostic 	    return(-1);
49546366Sbostic 	}
49646366Sbostic 	for ( i = 0; i < NCACHED; i++ ) {
49746366Sbostic 	    if ( hashp->mapp[i] ) {
49846366Sbostic 		if (!__put_page((char *)hashp->mapp[i],
49946366Sbostic 		    hashp->BITMAPS[i], 0, 1)){
50046366Sbostic 		    return(-1);
50146366Sbostic 		}
50246366Sbostic 	    }
50346366Sbostic 	}
50446366Sbostic 	return(0);
50546366Sbostic }
50646366Sbostic /*******************************SEARCH ROUTINES *****************************/
50746366Sbostic /*
50846366Sbostic     All the access routines return
50946366Sbostic 	0 on SUCCESS
51046366Sbostic 	1 to indicate an external ERROR (i.e. key not found, etc)
51146366Sbostic 	-1 to indicate an internal ERROR (i.e. out of memory, etc)
51246366Sbostic */
51346366Sbostic static int
51446571Sbostic hash_get ( dbp, key, data, flag )
51546366Sbostic DB	*dbp;
51646571Sbostic DBT	*key, *data;
517*47251Sbostic u_int	flag;
51846366Sbostic {
51946571Sbostic #ifdef lint
52046571Sbostic     flag = flag;
52146571Sbostic #endif
52246571Sbostic 
52346366Sbostic     if ( !dbp ) {
52446366Sbostic 	return (ERROR);
52546366Sbostic     }
52646366Sbostic     hashp = (HTAB *)dbp->internal;
52746366Sbostic     if ( hashp->flags & O_WRONLY ) {
52846366Sbostic 	errno = EBADF;
52946366Sbostic 	hashp->errno = errno;
53046366Sbostic 	return ( ERROR );
53146366Sbostic     }
53246366Sbostic     return ( hash_access ( HASH_GET, key, data ) );
53346366Sbostic }
53446366Sbostic 
53546366Sbostic static int
53646366Sbostic hash_put ( dbp, key, data, flag )
53746366Sbostic DB	*dbp;
53846366Sbostic DBT 	*key, *data;
539*47251Sbostic u_int	flag;
54046366Sbostic {
54146366Sbostic     if ( !dbp ) {
54246366Sbostic 	return (ERROR);
54346366Sbostic     }
54446366Sbostic     hashp = (HTAB *)dbp->internal;
54546366Sbostic     if ( (hashp->flags & O_ACCMODE) == O_RDONLY ) {
54646366Sbostic 	errno = EBADF;
54746366Sbostic 	hashp->errno = errno;
54846366Sbostic 	return ( ERROR );
54946366Sbostic     }
55046366Sbostic     if ( flag == R_NOOVERWRITE ) {
55146366Sbostic 	return ( hash_access ( HASH_PUTNEW, key, data ) );
55246366Sbostic     } else {
55346366Sbostic 	return ( hash_access ( HASH_PUT, key, data ) );
55446366Sbostic     }
55546366Sbostic }
55646366Sbostic 
55746366Sbostic static int
55846571Sbostic hash_delete ( dbp, key, flag )
55946366Sbostic DB	*dbp;
56046366Sbostic DBT 	*key;
561*47251Sbostic u_int	flag;		/* Ignored */
56246366Sbostic {
56346571Sbostic #ifdef lint
56446571Sbostic     flag = flag;
56546571Sbostic #endif
56646366Sbostic     if ( !dbp ) {
56746366Sbostic 	return (ERROR);
56846366Sbostic     }
56946366Sbostic     hashp = (HTAB *)dbp->internal;
57046366Sbostic     if ( (hashp->flags & O_ACCMODE) == O_RDONLY ) {
57146366Sbostic 	errno = EBADF;
57246366Sbostic 	hashp->errno = errno;
57346366Sbostic 	return ( ERROR );
57446366Sbostic     }
57546366Sbostic     return ( hash_access ( HASH_DELETE, key, NULL ) );
57646366Sbostic }
57746366Sbostic 
57846366Sbostic /*
57946366Sbostic     Assume that hashp has been set in wrapper routine
58046366Sbostic */
58146366Sbostic static int
58246366Sbostic hash_access(action, key, val)
58346366Sbostic ACTION action;
58446366Sbostic DBT *key, *val;
58546366Sbostic {
58646366Sbostic 	register	BUFHEAD	*rbufp;
58746366Sbostic 	register	u_short	*bp;
58846366Sbostic 	register	int	ndx;
58946366Sbostic 	register 	int n;
59046366Sbostic 	register 	int off = hashp->BSIZE;
59146366Sbostic 	register	int		size;
59246366Sbostic 	register	char	*kp;
59346366Sbostic 	BUFHEAD	*bufp;
59446457Sbostic 	BUFHEAD	*save_bufp;
59546366Sbostic 	u_short	pageno;
59646366Sbostic 
59746366Sbostic #ifdef HASH_STATISTICS
59846366Sbostic 	hash_accesses++;
59946366Sbostic #endif
60046366Sbostic 
60146366Sbostic 	size = key->size;
60246950Sbostic 	kp = (char *)key->data;
60346457Sbostic 	rbufp = __get_buf ( __call_hash(kp, size), NULL, 0 );
60446366Sbostic 	if ( !rbufp ) return(ERROR);
60546457Sbostic 	save_bufp = rbufp;
60646366Sbostic 
60746457Sbostic 	/* Pin the bucket chain */
60846457Sbostic 	rbufp->flags |= BUF_PIN;
60946366Sbostic 	for ( bp = (u_short *)rbufp->page, n = *bp++, ndx = 1; ndx < n;  ) {
61046366Sbostic 	    if ( bp[1] >= REAL_KEY ) {
61146366Sbostic 		/* Real key/data pair */
61246366Sbostic 		if (size == off - *bp &&
61346366Sbostic 		    bcmp(kp, rbufp->page + *bp, size) == 0) {
61446366Sbostic 		    goto found;
61546366Sbostic 		}
61646366Sbostic 		off = bp[1];
61746366Sbostic #ifdef HASH_STATISTICS
61846366Sbostic 		hash_collisions++;
61946366Sbostic #endif
62046366Sbostic 	        bp += 2;
62146366Sbostic 	        ndx += 2;
62246366Sbostic 	    } else if ( bp[1] == OVFLPAGE ) {
62346366Sbostic 		rbufp = __get_buf ( *bp, rbufp, 0 );
62446457Sbostic 		if ( !rbufp ) {
62546457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
62646457Sbostic 		    return (ERROR);
62746457Sbostic 		}
62846366Sbostic 		/* FOR LOOP INIT */
62946366Sbostic 		bp = (u_short *)rbufp->page;
63046366Sbostic 		n = *bp++;
63146366Sbostic 		ndx = 1;
63246366Sbostic 		off = hashp->BSIZE;
63346366Sbostic 	    } else if ( bp[1] < REAL_KEY ) {
63446366Sbostic 		if ( (ndx = __find_bigpair(rbufp, ndx, kp, size )) > 0 ) {
63546366Sbostic 		    goto found;
63646366Sbostic 		} else if ( ndx == -2 ) {
63746366Sbostic 		    bufp = rbufp;
63846366Sbostic 		    if ( !(pageno = __find_last_page ( &bufp )) ) {
63946366Sbostic 			ndx = 0;
64046366Sbostic 			rbufp = bufp;
64146366Sbostic 			break;	/* FOR */
64246366Sbostic 		    }
64346366Sbostic 		    rbufp = __get_buf ( pageno, bufp, 0 );
64446457Sbostic 		    if ( !rbufp ) {
64546457Sbostic 			save_bufp->flags &= ~BUF_PIN;
64646457Sbostic 			return (ERROR);
64746457Sbostic 		    }
64846366Sbostic 		    /* FOR LOOP INIT */
64946366Sbostic 		    bp = (u_short *)rbufp->page;
65046366Sbostic 		    n = *bp++;
65146366Sbostic 		    ndx = 1;
65246366Sbostic 		    off = hashp->BSIZE;
65346366Sbostic 		} else  {
65446457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
65546366Sbostic 		    return(ERROR);
65646366Sbostic 		}
65746366Sbostic 	    }
65846366Sbostic 	}
65946366Sbostic 
66046366Sbostic 	/* Not found */
66146366Sbostic 	switch ( action ) {
66246366Sbostic 	    case HASH_PUT:
66346366Sbostic 	    case HASH_PUTNEW:
66446366Sbostic 		if (__addel(rbufp, key, val)) {
66546457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
66646366Sbostic 		    return(ERROR);
66746366Sbostic 		} else {
66846457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
66946366Sbostic 		    return(SUCCESS);
67046366Sbostic 		}
67146366Sbostic 	    case HASH_GET:
67246366Sbostic 	    case HASH_DELETE:
67346366Sbostic 	    default:
67446457Sbostic 		save_bufp->flags &= ~BUF_PIN;
67546366Sbostic 		return(ABNORMAL);
67646366Sbostic 	}
67746366Sbostic 
67846366Sbostic found:
67946366Sbostic 	switch (action) {
68046366Sbostic 	    case HASH_PUTNEW:
68146457Sbostic 		save_bufp->flags &= ~BUF_PIN;
68246366Sbostic 		return(ABNORMAL);
68346366Sbostic 	    case HASH_GET:
68446366Sbostic 		bp = (u_short *)rbufp->page;
68546366Sbostic 		if (bp[ndx+1] < REAL_KEY) __big_return(rbufp, ndx, val, 0);
68646366Sbostic 		else {
68746950Sbostic 		    val->data = (u_char *)rbufp->page + (int) bp[ndx + 1];
68846366Sbostic 		    val->size = bp[ndx] - bp[ndx + 1];
68946366Sbostic 		}
69046366Sbostic 		break;
69146366Sbostic 	    case HASH_PUT:
69246457Sbostic 		if ((__delpair (rbufp, ndx)) || (__addel (rbufp, key, val)) ) {
69346457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
69446457Sbostic 		    return(ERROR);
69546457Sbostic 		}
69646366Sbostic 		break;
69746366Sbostic 	    case HASH_DELETE:
69846366Sbostic 		if (__delpair (rbufp, ndx))return(ERROR);
69946366Sbostic 		break;
70046366Sbostic 	}
70146457Sbostic 	save_bufp->flags &= ~BUF_PIN;
70246366Sbostic 	return (SUCCESS);
70346366Sbostic }
70446366Sbostic 
70546366Sbostic static int
70646366Sbostic hash_seq(dbp, key, data, flag)
70746366Sbostic DB	*dbp;
70846366Sbostic DBT 	*key, *data;
709*47251Sbostic u_int	flag;
71046366Sbostic {
711*47251Sbostic 	register	u_int bucket;
71246366Sbostic 	register	BUFHEAD	*bufp;
71346457Sbostic 	BUFHEAD	*save_bufp;
71446366Sbostic 	u_short	*bp;
71546366Sbostic 	u_short	ndx;
71646366Sbostic 	u_short	pageno;
71746366Sbostic 
71846366Sbostic 	if ( !dbp ) {
71946366Sbostic 	    return (ERROR);
72046366Sbostic 	}
72146366Sbostic 
72246366Sbostic 	hashp = (HTAB *)dbp->internal;
72346366Sbostic 	if ( hashp->flags & O_WRONLY ) {
72446366Sbostic 	    errno = EBADF;
72546366Sbostic 	    hashp->errno = errno;
72646366Sbostic 	    return ( ERROR );
72746366Sbostic 	}
72846366Sbostic #ifdef HASH_STATISTICS
72946366Sbostic 	hash_accesses++;
73046366Sbostic #endif
73146366Sbostic 
73246366Sbostic 	if ( (hashp->cbucket < 0) || (flag == R_FIRST) ) {
73346366Sbostic 	    hashp->cbucket = 0;
73446366Sbostic 	    hashp->cndx = 1;
73546366Sbostic 	    hashp->cpage = NULL;
73646366Sbostic 	}
73746366Sbostic 
73846366Sbostic 	if ( !(bufp = hashp->cpage) ) {
73946366Sbostic 	    for (bucket = hashp->cbucket;
74046366Sbostic 		 bucket <= hashp->MAX_BUCKET;
74146366Sbostic 		 bucket++, hashp->cndx = 1 ) {
74246366Sbostic 
74346366Sbostic 		bufp = __get_buf ( bucket, NULL, 0 );
74446366Sbostic 		if (!bufp) return(ERROR);
74546366Sbostic 		hashp->cpage = bufp;
74646366Sbostic 		bp = (u_short *)bufp->page;
74746366Sbostic 		if (bp[0]) break;
74846366Sbostic 	    }
74946366Sbostic 	    hashp->cbucket = bucket;
75046366Sbostic 	    if ( hashp->cbucket > hashp->MAX_BUCKET ) {
75146366Sbostic 		hashp->cbucket = -1;
75246366Sbostic 		return ( ABNORMAL );
75346366Sbostic 	    }
75446366Sbostic 	} else {
75546366Sbostic 	    bp  = (u_short *)hashp->cpage->page;
75646366Sbostic 	}
75746366Sbostic 
75846366Sbostic #ifdef DEBUG
75946366Sbostic 	assert (bp);
76046366Sbostic 	assert (bufp);
76146366Sbostic #endif
76246366Sbostic 	while ( bp[hashp->cndx+1] == OVFLPAGE ) {
76346366Sbostic 	    bufp = hashp->cpage = __get_buf ( bp[hashp->cndx], bufp, 0 );
76446366Sbostic 	    if (!bufp) return(ERROR);
76546366Sbostic 	    bp = (u_short *)(bufp->page);
76646366Sbostic 	    hashp->cndx = 1;
76746366Sbostic 	}
76846366Sbostic 	ndx = hashp->cndx;
76946366Sbostic 	if (bp[ndx+1] < REAL_KEY) {
77046366Sbostic 	    if (__big_keydata(bufp, ndx, key, data, 1)) {
77146366Sbostic 		return(ERROR);
77246366Sbostic 	    }
77346366Sbostic 	} else {
77446950Sbostic 	    key->data = (u_char *)hashp->cpage->page + bp[ndx];
77546366Sbostic 	    key->size = (ndx > 1 ? bp[ndx-1] : hashp->BSIZE) - bp[ndx];
77646950Sbostic 	    data->data = (u_char *)hashp->cpage->page + bp[ndx + 1];
77746366Sbostic 	    data->size = bp[ndx] - bp[ndx + 1];
77846366Sbostic 	    ndx += 2;
77946366Sbostic 	    if ( ndx > bp[0] ) {
78046366Sbostic 		hashp->cpage = NULL;
78146366Sbostic 		hashp->cbucket++;
78246366Sbostic 		hashp->cndx=1;
78346366Sbostic 	    } else hashp->cndx = ndx;
78446366Sbostic 	}
78546366Sbostic 	return (SUCCESS);
78646366Sbostic }
78746366Sbostic 
78846366Sbostic /********************************* UTILITIES ************************/
78946366Sbostic /*
79046366Sbostic     0 ==> OK
79146366Sbostic     -1 ==> Error
79246366Sbostic */
79346366Sbostic extern int
79446366Sbostic __expand_table()
79546366Sbostic {
796*47251Sbostic 	u_int	old_bucket, new_bucket;
79746366Sbostic 	int	new_segnum;
79846366Sbostic 	int	dirsize;
79946366Sbostic 	int	spare_ndx;
80046366Sbostic 	register	char **old, **new;
80146366Sbostic #ifdef HASH_STATISTICS
80246366Sbostic 	hash_expansions++;
80346366Sbostic #endif
80446366Sbostic 
80546366Sbostic 	new_bucket = ++hashp->MAX_BUCKET;
80646366Sbostic 	old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
80746366Sbostic 
80846366Sbostic 	new_segnum = new_bucket >> hashp->SSHIFT;
80946366Sbostic 
81046366Sbostic 	/* Check if we need a new segment */
81146366Sbostic 	if ( new_segnum >= hashp->nsegs ) {
81246366Sbostic 
81346366Sbostic 	    /* Check if we need to expand directory */
81446366Sbostic 	    if ( new_segnum >= hashp->DSIZE ) {
81546366Sbostic 
81646366Sbostic 		/* Reallocate directory */
81746366Sbostic 		dirsize = hashp->DSIZE * sizeof ( SEGMENT * );
81846366Sbostic 		if (!hash_realloc ( &hashp->dir, dirsize, (dirsize << 1 ) )) {
81946366Sbostic 		    return(-1);
82046366Sbostic 		}
82146366Sbostic 		hashp->DSIZE = dirsize << 1;
82246366Sbostic 	    }
82346366Sbostic 	    if (!(hashp->dir[new_segnum] =
82446366Sbostic 		    (SEGMENT)calloc ( hashp->SGSIZE, sizeof(SEGMENT)))) {
82546366Sbostic 		    return(-1);
82646366Sbostic 	    }
82746366Sbostic 	    hashp->exsegs++;
82846366Sbostic 	    hashp->nsegs++;
82946366Sbostic 	}
83046366Sbostic 
83146366Sbostic 	/*
83246366Sbostic 	    If the split point is increasing (MAX_BUCKET's log
83346366Sbostic 	    base 2 increases), we need to copy the current contents
83446366Sbostic 	    of the spare split bucket to the next bucket
83546366Sbostic 	*/
83646366Sbostic 	spare_ndx = __log2(hashp->MAX_BUCKET);
83746366Sbostic 	if ( spare_ndx != (__log2(hashp->MAX_BUCKET - 1))) {
83846366Sbostic 	    hashp->SPARES[spare_ndx] = hashp->SPARES[spare_ndx-1];
83946366Sbostic 	}
84046366Sbostic 
84146366Sbostic 	if ( new_bucket > hashp->HIGH_MASK ) {
84246366Sbostic 	    /* Starting a new doubling */
84346366Sbostic 	    hashp->LOW_MASK = hashp->HIGH_MASK;
84446366Sbostic 	    hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
84546366Sbostic 	}
84646366Sbostic 
84746366Sbostic 	/*
84846366Sbostic 	 * Relocate records to the new bucket
84946366Sbostic 	 */
85046366Sbostic 	return(__split_page ( old_bucket, new_bucket ));
85146366Sbostic }
85246366Sbostic /*
85346366Sbostic     If realloc guarantees that the pointer is not destroyed
85446366Sbostic     if the realloc fails, then this routine can go away
85546366Sbostic */
85646366Sbostic static char *
85746366Sbostic hash_realloc ( p_ptr, oldsize, newsize )
85846366Sbostic char	**p_ptr;
85946366Sbostic int	oldsize;
86046366Sbostic int	newsize;
86146366Sbostic {
86246366Sbostic 	register char	*p;
86346366Sbostic 
86446366Sbostic 	if (p = (char *)malloc ( newsize ) ) {
86546366Sbostic 		bcopy ( *p_ptr, p, oldsize );
86646366Sbostic 		bzero ( *p_ptr + oldsize, newsize-oldsize );
86746366Sbostic 		free(*p_ptr);
86846366Sbostic 		*p_ptr = p;
86946366Sbostic 	}
87046366Sbostic 	return (p);
87146366Sbostic }
87246366Sbostic 
873*47251Sbostic extern u_int
87446366Sbostic __call_hash ( k, len )
87546366Sbostic char	*k;
87646366Sbostic int	len;
87746366Sbostic {
87846366Sbostic 	int	n, bucket;
87946366Sbostic 	n = hashp->hash(k, len);
88046366Sbostic 
88146366Sbostic 	bucket = n & hashp->HIGH_MASK;
88246366Sbostic 	if ( bucket > hashp->MAX_BUCKET ) {
88346366Sbostic 	    bucket = bucket & hashp->LOW_MASK;
88446366Sbostic 	}
88546366Sbostic 
88646366Sbostic 	return(bucket);
88746366Sbostic }
88846366Sbostic 
88946366Sbostic /*
89046366Sbostic     Allocate segment table.  On error, destroy the table
89146366Sbostic     and set errno.
89246366Sbostic 
89346366Sbostic     Returns 0 on success
89446366Sbostic */
89546366Sbostic static int
89646366Sbostic alloc_segs ( nsegs )
89746366Sbostic int	nsegs;
89846366Sbostic {
89946366Sbostic     register int	i;
90046366Sbostic     register SEGMENT	store;
90146366Sbostic 
90246366Sbostic     int	save_errno;
90346366Sbostic 
90446366Sbostic     if (!(hashp->dir = (SEGMENT *)calloc(hashp->DSIZE, sizeof(SEGMENT *)))) {
90546366Sbostic 	save_errno = errno;
90646366Sbostic 	(void)hdestroy();
90746366Sbostic 	errno = save_errno;
90846366Sbostic 	return(-1);
90946366Sbostic     }
91046366Sbostic 
91146366Sbostic     /* Allocate segments */
91246366Sbostic     store = (SEGMENT)calloc ( nsegs << hashp->SSHIFT, sizeof (SEGMENT) );
91346366Sbostic     if ( !store ) {
91446366Sbostic 	save_errno = errno;
91546366Sbostic 	(void)hdestroy();
91646366Sbostic 	errno = save_errno;
91746366Sbostic 	return(-1);
91846366Sbostic     }
91946366Sbostic 
92046366Sbostic     for ( i=0; i < nsegs; i++, hashp->nsegs++ ) {
92146366Sbostic 	hashp->dir[i] = &store[i<<hashp->SSHIFT];
92246366Sbostic     }
92346366Sbostic     return(0);
92446366Sbostic }
92546366Sbostic 
92646366Sbostic /*
92746366Sbostic     Hashp->hdr needs to be byteswapped.
92846366Sbostic */
92946366Sbostic static void
93046366Sbostic swap_header_copy ( srcp, destp )
93146366Sbostic HASHHDR	*srcp;
93246366Sbostic HASHHDR	*destp;
93346366Sbostic {
93446366Sbostic     int i;
93546366Sbostic 
93646366Sbostic     BLSWAP_COPY(srcp->magic, destp->magic);
93746366Sbostic     BLSWAP_COPY(srcp->version, destp->version);
93846366Sbostic     BLSWAP_COPY(srcp->lorder, destp->lorder);
93946366Sbostic     BLSWAP_COPY(srcp->bsize, destp->bsize);
94046366Sbostic     BLSWAP_COPY(srcp->bshift, destp->bshift);
94146366Sbostic     BLSWAP_COPY(srcp->dsize, destp->dsize);
94246366Sbostic     BLSWAP_COPY(srcp->ssize, destp->ssize);
94346366Sbostic     BLSWAP_COPY(srcp->sshift, destp->sshift);
94446366Sbostic     BLSWAP_COPY(srcp->max_bucket, destp->max_bucket);
94546366Sbostic     BLSWAP_COPY(srcp->high_mask, destp->high_mask);
94646366Sbostic     BLSWAP_COPY(srcp->low_mask, destp->low_mask);
94746366Sbostic     BLSWAP_COPY(srcp->ffactor, destp->ffactor);
94846366Sbostic     BLSWAP_COPY(srcp->nkeys, destp->nkeys);
94946366Sbostic     BLSWAP_COPY(srcp->hdrpages, destp->hdrpages);
95046366Sbostic     BLSWAP_COPY(srcp->h_charkey, destp->h_charkey);
95146366Sbostic     for ( i=0; i < NCACHED; i++ ) {
95246366Sbostic 	BLSWAP_COPY ( srcp->spares[i] , destp->spares[i]);
95346366Sbostic 	BSSWAP_COPY ( srcp->bitmaps[i] , destp->bitmaps[i]);
95446366Sbostic     }
95546366Sbostic     return;
95646366Sbostic }
95746366Sbostic 
95846366Sbostic static void
95946366Sbostic swap_header ( )
96046366Sbostic {
96146366Sbostic     HASHHDR	*hdrp;
96246366Sbostic     int	i;
96346366Sbostic 
96446366Sbostic     hdrp = &hashp->hdr;
96546366Sbostic 
96646366Sbostic     BLSWAP(hdrp->magic);
96746366Sbostic     BLSWAP(hdrp->version);
96846366Sbostic     BLSWAP(hdrp->lorder);
96946366Sbostic     BLSWAP(hdrp->bsize);
97046366Sbostic     BLSWAP(hdrp->bshift);
97146366Sbostic     BLSWAP(hdrp->dsize);
97246366Sbostic     BLSWAP(hdrp->ssize);
97346366Sbostic     BLSWAP(hdrp->sshift);
97446366Sbostic     BLSWAP(hdrp->max_bucket);
97546366Sbostic     BLSWAP(hdrp->high_mask);
97646366Sbostic     BLSWAP(hdrp->low_mask);
97746366Sbostic     BLSWAP(hdrp->ffactor);
97846366Sbostic     BLSWAP(hdrp->nkeys);
97946366Sbostic     BLSWAP(hdrp->hdrpages);
98046366Sbostic     BLSWAP(hdrp->h_charkey);
98146366Sbostic     for ( i=0; i < NCACHED; i++ ) {
98246366Sbostic 	BLSWAP ( hdrp->spares[i] );
98346366Sbostic 	BSSWAP ( hdrp->bitmaps[i] );
98446366Sbostic     }
98546366Sbostic     return;
98646366Sbostic }
987