xref: /csrg-svn/lib/libc/db/hash/hash.c (revision 46457)
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*46457Sbostic static char sccsid[] = "@(#)hash.c	5.3 (Berkeley) 02/19/91";
1346366Sbostic #endif /* LIBC_SCCS and not lint */
1446366Sbostic 
1546366Sbostic #include <sys/param.h>
1646366Sbostic #include <sys/file.h>
1746366Sbostic #include <sys/stat.h>
1846366Sbostic #include <errno.h>
1946366Sbostic #include <assert.h>
2046366Sbostic #include <db.h>
2146366Sbostic #include "hash.h"
2246366Sbostic #include <string.h>
2346366Sbostic 
2446366Sbostic /* For systems that do not have O_ACCMODE */
2546366Sbostic #ifndef O_ACCMODE
2646366Sbostic #define O_ACCMODE       (O_RDONLY|O_WRONLY|O_RDWR)
2746366Sbostic #endif
2846366Sbostic 
2946366Sbostic /* Fast arithmetic, relying on powers of 2, */
3046366Sbostic 
3146366Sbostic #define MOD(x,y)		((x) & ((y)-1))
3246366Sbostic #define RETURN_ERROR(ERR,LOC)	{ save_errno = ERR; goto LOC; }
3346366Sbostic 
3446366Sbostic /* Return values */
3546366Sbostic 
3646366Sbostic #define	SUCCESS	0
3746366Sbostic #define	ERROR	-1
3846366Sbostic #define	ABNORMAL 1
3946366Sbostic 
4046366Sbostic /* external routines */
4146366Sbostic extern char *calloc();
4246366Sbostic 
4346366Sbostic /* page.c */
4446366Sbostic extern int __get_page();
4546366Sbostic extern int __split_page();
4646366Sbostic extern int __addel();
4746366Sbostic extern int __delpair();
4846366Sbostic extern u_long *__init_bitmap();
4946366Sbostic 
5046366Sbostic /* big.c */
5146366Sbostic extern void __big_return();
5246366Sbostic extern int __big_keydata();
5346366Sbostic extern u_short __find_last_page();
5446366Sbostic 
5546366Sbostic /* buf.c */
5646366Sbostic extern BUFHEAD	*__get_buf();
5746366Sbostic extern void __buf_init();
5846366Sbostic extern int __buf_free();
5946366Sbostic 
6046366Sbostic /* hash function */
6146366Sbostic extern int (*default_hash)();
6246366Sbostic 
6346366Sbostic /* My externals */
6446366Sbostic extern int __expand_table();
6546366Sbostic extern int __call_hash();
6646366Sbostic 
6746366Sbostic /* Internal routines */
6846366Sbostic static HTAB *init_hash();
6946366Sbostic static int hash_access();
7046366Sbostic static int flush_meta();
7146366Sbostic static int alloc_segs();
7246366Sbostic static int init_htab();
7346366Sbostic static char *hash_realloc();
7446366Sbostic static int hdestroy();
7546366Sbostic static int hash_put();
7646366Sbostic static int hash_delete();
7746366Sbostic static int hash_get();
7846366Sbostic static int hash_sync();
7946366Sbostic static int hash_close();
8046366Sbostic static int hash_seq();
8146366Sbostic static void swap_header_copy();
8246366Sbostic static void swap_header();
8346366Sbostic 
8446366Sbostic /* Local data */
8546366Sbostic 
8646366Sbostic HTAB *hashp = NULL;
8746366Sbostic 
8846366Sbostic #ifdef HASH_STATISTICS
8946366Sbostic long hash_accesses, hash_collisions, hash_expansions, hash_overflows;
9046366Sbostic #endif
9146366Sbostic 
9246366Sbostic /************************** INTERFACE ROUTINES **********************/
9346366Sbostic /* OPEN/CLOSE */
9446366Sbostic 
9546366Sbostic extern	DB *
9646366Sbostic hash_open ( file, flags, mode, info )
9746366Sbostic char	*file;
9846366Sbostic int	flags;
9946366Sbostic int	mode;
10046366Sbostic HASHINFO	*info;		/* Special directives for create */
10146366Sbostic {
10246366Sbostic     int		buckets;
10346366Sbostic     int		bpages;
10446366Sbostic     int		hdrsize;
10546366Sbostic     int		i;
10646366Sbostic     int		new_table = 0;
10746366Sbostic     int		nkey;
10846366Sbostic     int		nsegs;
10946366Sbostic     int		save_errno;
11046366Sbostic     struct	stat statbuf;
11146366Sbostic     DB		*dbp;
11246366Sbostic 
11346366Sbostic 
11446366Sbostic     if ( !(hashp = (HTAB *) calloc( 1, sizeof(HTAB) ))) {
11546366Sbostic 	/* calloc should set errno */
11646366Sbostic 	return(0);
11746366Sbostic     }
118*46457Sbostic     hashp->fp = -1;
11946366Sbostic     /*
12046366Sbostic 	Select flags relevant to us.
12146366Sbostic 	Even if user wants write only, we need to be able to read
12246366Sbostic 	the actual file, so we need to open it read/write.  But, the
12346366Sbostic 	field in the hashp structure needs to be accurate so that
12446366Sbostic 	we can check accesses.
12546366Sbostic     */
12646366Sbostic     flags = flags & (O_CREAT | O_EXCL | O_RDONLY | O_RDWR | O_TRUNC | O_WRONLY);
12746366Sbostic     hashp->flags = flags;
12846366Sbostic     if ( flags & O_WRONLY )  flags = (flags & ~O_WRONLY) | O_RDWR;
12946366Sbostic 
13046366Sbostic     if ( !file ||
13146366Sbostic 	 (flags & O_TRUNC) ||
13246366Sbostic 	 (stat ( file, &statbuf ) && (errno == ENOENT)) ) {
13346366Sbostic 	 new_table = 1;
13446366Sbostic     }
13546366Sbostic 
13646366Sbostic     if ( file && ((hashp->fp = open ( file, flags, mode )) == -1)) {
13746366Sbostic 	RETURN_ERROR (errno, error0);
13846366Sbostic     }
13946416Sbostic     (void)fcntl(hashp->fp, F_SETFD, 1);
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 
18846366Sbostic 	hashp->mapp[0] = (u_long *)malloc(bpages<<hashp->BSHIFT);
18946366Sbostic 	if ( !hashp->mapp[0] ) {
19046366Sbostic 	    RETURN_ERROR(errno, error2);
19146366Sbostic 	}
19246366Sbostic 	for ( i = 0; i < bpages; i++ ) {
19346366Sbostic 	    hashp->mapp[i] = &hashp->mapp[0][i<<hashp->BSHIFT];
19446366Sbostic 	    if (__get_page ((char *)hashp->mapp[i],
19546366Sbostic 		hashp->BITMAPS[i], 0, 1, 1)) {
19646366Sbostic 		    RETURN_ERROR(errno, error2);
19746366Sbostic 	    }
19846366Sbostic 	}
19946366Sbostic 
20046366Sbostic     }
20146366Sbostic 
20246366Sbostic     /* Initialize Buffer Manager */
20346366Sbostic     if ( info && info->ncached ) {
20446366Sbostic 	__buf_init (info->ncached);
20546366Sbostic     } else {
20646366Sbostic 	__buf_init (DEF_BUFSIZE);
20746366Sbostic     }
20846366Sbostic 
20946366Sbostic     hashp->new_file = new_table;
210*46457Sbostic     hashp->save_file = file && !(hashp->flags&O_RDONLY);
21146366Sbostic     hashp->cbucket = -1;
21246366Sbostic     if ( !(dbp = (DB *)malloc ( sizeof (DB) )) ) {
21346366Sbostic 	save_errno = errno;
21446366Sbostic 	hdestroy();
21546366Sbostic 	errno = save_errno;
21646366Sbostic 	return ( NULL );
21746366Sbostic     }
21846366Sbostic     dbp->internal = (char *)hashp;
21946366Sbostic     dbp->close = hash_close;
22046366Sbostic     dbp->delete = hash_delete;
22146366Sbostic     dbp->get = hash_get;
22246366Sbostic     dbp->put = hash_put;
22346366Sbostic     dbp->seq = hash_seq;
22446366Sbostic     dbp->sync = hash_sync;
22546366Sbostic 
22646366Sbostic #ifdef DEBUG
22746366Sbostic 	(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",
22846366Sbostic 		"init_htab:",
22946366Sbostic 		"TABLE POINTER   ", hashp,
23046366Sbostic 		"BUCKET SIZE     ", hashp->BSIZE,
23146366Sbostic 		"BUCKET SHIFT    ", hashp->BSHIFT,
23246366Sbostic 		"DIRECTORY SIZE  ", hashp->DSIZE,
23346366Sbostic 		"SEGMENT SIZE    ", hashp->SGSIZE,
23446366Sbostic 		"SEGMENT SHIFT   ", hashp->SSHIFT,
23546366Sbostic 		"FILL FACTOR     ", hashp->FFACTOR,
23646366Sbostic 		"MAX BUCKET      ", hashp->MAX_BUCKET,
23746366Sbostic 		"HIGH MASK       ", hashp->HIGH_MASK,
23846366Sbostic 		"LOW  MASK       ", hashp->LOW_MASK,
23946366Sbostic 		"NSEGS           ", hashp->nsegs,
24046366Sbostic 		"NKEYS           ", hashp->NKEYS );
24146366Sbostic #endif
24246366Sbostic #ifdef HASH_STATISTICS
24346366Sbostic 	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
24446366Sbostic #endif
24546366Sbostic     return (dbp);
24646366Sbostic 
24746366Sbostic error2:
24846366Sbostic     (void)hdestroy();
24946366Sbostic     errno = save_errno;
25046366Sbostic     return ( (DB *)NULL );
25146366Sbostic 
25246366Sbostic error1:
25346366Sbostic     (void) close ( hashp->fp );
25446366Sbostic 
25546366Sbostic error0:
25646366Sbostic     free ( hashp );
25746366Sbostic     errno = save_errno;
25846366Sbostic     return ( (DB *) NULL );
25946366Sbostic }
26046366Sbostic 
26146366Sbostic static int
26246366Sbostic hash_close (dbp)
26346366Sbostic DB	*dbp;
26446366Sbostic {
265*46457Sbostic 	int	retval;
266*46457Sbostic 
26746366Sbostic 	if ( !dbp ) {
26846366Sbostic 	    return(ERROR);
26946366Sbostic 	}
27046366Sbostic 	hashp = (HTAB *)dbp->internal;
271*46457Sbostic 	retval = hdestroy();
272*46457Sbostic 	(void)free ( dbp );
273*46457Sbostic 	return ( retval );
27446366Sbostic }
27546366Sbostic 
27646366Sbostic 
27746366Sbostic /************************** LOCAL CREATION ROUTINES **********************/
27846366Sbostic static HTAB *
27946366Sbostic init_hash( info )
28046366Sbostic HASHINFO *info;
28146366Sbostic {
28246366Sbostic 	int	nelem;
28346366Sbostic 
28446366Sbostic 	nelem = 1;
28546366Sbostic 
28646366Sbostic 	hashp->LORDER	= BYTE_ORDER;
28746366Sbostic 	hashp->BSIZE    = DEF_BUCKET_SIZE;
28846366Sbostic 	hashp->BSHIFT   = DEF_BUCKET_SHIFT;
28946366Sbostic 	hashp->SGSIZE   = DEF_SEGSIZE;
29046366Sbostic 	hashp->SSHIFT   = DEF_SEGSIZE_SHIFT;
29146366Sbostic 	hashp->DSIZE    = DEF_DIRSIZE;
29246366Sbostic 	hashp->FFACTOR  = DEF_FFACTOR;
29346366Sbostic 	hashp->hash     = default_hash;
29446366Sbostic 	bzero (hashp->SPARES, sizeof (hashp->SPARES));
29546366Sbostic 
29646366Sbostic 	if ( info ) {
29746366Sbostic 	    if ( info->bsize )   {
29846366Sbostic 		/* Round pagesize up to power of 2 */
29946366Sbostic 		hashp->BSHIFT  = __log2(info->bsize);
30046366Sbostic 		hashp->BSIZE   = 1 << hashp->BSHIFT;
30146366Sbostic 		if ( hashp->BSIZE > MAX_BSIZE ) {
30246366Sbostic 		    errno = EINVAL;
30346366Sbostic 		    return(0);
30446366Sbostic 		}
30546366Sbostic 	    }
30646366Sbostic 	    if ( info->ffactor )  hashp->FFACTOR = info->ffactor;
30746366Sbostic 	    if ( info->hash ) hashp->hash    = info->hash;
30846366Sbostic 	    if ( info->nelem ) nelem = info->nelem;
30946366Sbostic 	    if ( info->lorder ) {
31046366Sbostic 		if ( info->lorder != BIG_ENDIAN &&
31146366Sbostic 		     info->lorder != LITTLE_ENDIAN) {
31246366Sbostic 		    errno = EINVAL;
31346366Sbostic 		    return(0);
31446366Sbostic 		}
31546366Sbostic 		hashp->LORDER = info->lorder;
31646366Sbostic 	    }
31746366Sbostic 	}
31846366Sbostic 
31946366Sbostic 	/* init_htab should destroy the table and set errno if it fails */
32046366Sbostic 	if ( init_htab ( nelem ) ) {
32146366Sbostic 	    return(0);
32246366Sbostic 	} else {
32346366Sbostic 	    return(hashp);
32446366Sbostic 	}
32546366Sbostic }
32646366Sbostic 
32746366Sbostic /*
32846366Sbostic     This calls alloc_segs which may run out of memory.
32946366Sbostic     Alloc_segs will destroy the table and set errno,
33046366Sbostic     so we just pass the error information along.
33146366Sbostic 
33246366Sbostic     Returns 0 on No Error
33346366Sbostic 
33446366Sbostic */
33546366Sbostic static int
33646366Sbostic init_htab ( nelem )
33746366Sbostic int	nelem;
33846366Sbostic {
33946366Sbostic 	register SEGMENT	*segp;
34046366Sbostic 	register int nbuckets;
34146366Sbostic 	register int nsegs;
34246366Sbostic 	int	l2;
34346366Sbostic 
34446366Sbostic  /*
34546366Sbostic   * Divide number of elements by the fill factor and determine a desired
34646366Sbostic   * number of buckets.  Allocate space for the next greater power of
34746366Sbostic   * two number of buckets
34846366Sbostic   */
34946366Sbostic 	nelem = (nelem - 1) / hashp->FFACTOR + 1;
35046366Sbostic 
35146366Sbostic 	l2 = __log2(nelem);
35246366Sbostic 	nbuckets = 1 << l2;
35346366Sbostic 	nbuckets = MAX ( nbuckets, 2 );
35446366Sbostic 
35546366Sbostic 	hashp->SPARES[l2] = l2 + 1;
35646366Sbostic 	hashp->SPARES[l2+1] = l2 + 1;
35746366Sbostic 	/*
35846366Sbostic 	    First bitmap page is at:
35946366Sbostic 		splitpoint l2
36046366Sbostic 		page offset 1
36146366Sbostic 	*/
36246366Sbostic 	__init_bitmap ( OADDR_OF(l2,1), l2+1, 0 );
36346366Sbostic 
36446366Sbostic 	hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
36546366Sbostic 	hashp->HIGH_MASK = (nbuckets << 1) - 1;
36646366Sbostic 	hashp->HDRPAGES = ((MAX(sizeof(HASHHDR),MINHDRSIZE) - 1) >>
36746366Sbostic 			  hashp->BSHIFT) + 1;
36846366Sbostic 
36946366Sbostic 	nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
37046366Sbostic 	nsegs = 1 << __log2(nsegs);
37146366Sbostic 
37246366Sbostic 	if ( nsegs > hashp->DSIZE ) {
37346366Sbostic 	    hashp->DSIZE  = nsegs;
37446366Sbostic 	}
37546366Sbostic 
37646366Sbostic 	return (alloc_segs ( nsegs ) );
37746366Sbostic }
37846366Sbostic 
37946366Sbostic /********************** DESTROY/CLOSE ROUTINES ************************/
38046366Sbostic 
38146366Sbostic /*
38246366Sbostic     Flushes any changes to the file if necessary and
38346366Sbostic     destroys the hashp structure, freeing all allocated
38446366Sbostic     space.
38546366Sbostic */
38646366Sbostic static int
38746366Sbostic hdestroy()
38846366Sbostic {
38946366Sbostic 	int	save_errno;
39046366Sbostic 	int	i;
39146366Sbostic 
39246366Sbostic 	save_errno = 0;
39346366Sbostic 
39446366Sbostic 	if (hashp != NULL) {
39546366Sbostic #ifdef HASH_STATISTICS
39646366Sbostic 	 (void)	fprintf(stderr,	"hdestroy: accesses %ld collisions %ld\n",
39746366Sbostic 			hash_accesses, hash_collisions);
39846366Sbostic 	 (void)	fprintf(stderr, "hdestroy: expansions %ld\n",
39946366Sbostic 			hash_expansions);
40046366Sbostic 	 (void)	fprintf(stderr, "hdestroy: overflows %ld\n",
40146366Sbostic 			hash_overflows);
40246366Sbostic 	 (void)	fprintf(stderr,	"keys %ld maxp %d segmentcount %d\n",
40346366Sbostic 			hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
40446366Sbostic 
40546366Sbostic 	for ( i = 0; i < NCACHED; i++ ) {
40646366Sbostic 	    (void) fprintf ( stderr, "spares[%d] = %d\n", i, hashp->SPARES[i] );
40746366Sbostic 	}
40846366Sbostic #endif
40946366Sbostic 
41046366Sbostic 		/*
41146366Sbostic 		    Call on buffer manager to free buffers, and if
41246366Sbostic 		    required, write them to disk
41346366Sbostic 		*/
41446366Sbostic 		if (__buf_free(1, hashp->save_file)) {
41546366Sbostic 		    save_errno = errno;
41646366Sbostic 		}
41746366Sbostic 		if ( hashp->dir ) {
41846366Sbostic 		    (void)free(*hashp->dir);	/* Free initial segments */
41946366Sbostic 		    /* Free extra segments */
42046366Sbostic 		    while ( hashp->exsegs-- ) {
42146366Sbostic 			(void)free ( hashp->dir[--hashp->nsegs] );
42246366Sbostic 		    }
42346366Sbostic 		    (void)free(hashp->dir);
42446366Sbostic 		}
42546366Sbostic 		if (flush_meta() && !save_errno) {
42646366Sbostic 		    save_errno = errno;
42746366Sbostic 		}
428*46457Sbostic 		if ( hashp->fp != -1 ) {
429*46457Sbostic 			(void)close (hashp->fp);
430*46457Sbostic 		}
43146366Sbostic 		(void)free(hashp);
43246366Sbostic 		hashp = NULL;
43346366Sbostic 	}
43446366Sbostic 	if ( save_errno ) {
43546366Sbostic 	    errno = save_errno;
43646366Sbostic 	    return(ERROR);
43746366Sbostic 	} else {
43846366Sbostic 	    return(SUCCESS);
43946366Sbostic 	}
44046366Sbostic }
44146366Sbostic 
44246366Sbostic /*
44346366Sbostic     Write modified pages to disk
44446366Sbostic     0 == OK
44546366Sbostic     -1 ERROR
44646366Sbostic */
44746366Sbostic static int
44846366Sbostic hash_sync(dbp)
44946366Sbostic DB	*dbp;
45046366Sbostic {
45146366Sbostic 	if ( !dbp ) {
45246366Sbostic 	    return (ERROR);
45346366Sbostic 	}
45446366Sbostic 
45546366Sbostic 	hashp = (HTAB *)dbp->internal;
45646366Sbostic 
45746366Sbostic 	if (!hashp->save_file) return(0);
45846366Sbostic 	if ( __buf_free ( 0, 1 )  || flush_meta()) {
45946366Sbostic 	    return(ERROR);
46046366Sbostic 	}
46146366Sbostic 	hashp->new_file = 0;
46246366Sbostic 	return(0);
46346366Sbostic }
46446366Sbostic 
46546366Sbostic /*
46646366Sbostic 0 == OK
46746366Sbostic -1 indicates that errno should be set
46846366Sbostic */
46946366Sbostic static int
47046366Sbostic flush_meta()
47146366Sbostic {
47246366Sbostic     	int	fp;
47346366Sbostic 	int	hdrsize;
47446366Sbostic 	int	i;
47546366Sbostic 	int	wsize;
47646366Sbostic 	HASHHDR	*whdrp;
47746366Sbostic 	HASHHDR	whdr;
47846366Sbostic 
47946366Sbostic 	if (!hashp->save_file) return(0);
48046366Sbostic 	hashp->MAGIC = HASHMAGIC;
48146366Sbostic 	hashp->VERSION = VERSION_NO;
48246366Sbostic 	hashp->H_CHARKEY = hashp->hash ( CHARKEY, sizeof(CHARKEY));
48346366Sbostic 
48446366Sbostic 	fp = hashp->fp;
48546366Sbostic 	whdrp = &hashp->hdr;
48646366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
48746366Sbostic 	whdrp = &whdr;
48846366Sbostic 	swap_header_copy( &hashp->hdr, whdrp );
48946366Sbostic #endif
49046366Sbostic 	if ( (lseek (fp, 0, L_SET) == -1 ) ||
49146366Sbostic 	     ((wsize = write ( fp, whdrp, sizeof(HASHHDR))) == -1)) {
49246366Sbostic 	    return(-1);
49346366Sbostic 	} else if ( wsize != sizeof(HASHHDR) ) {
49446366Sbostic 	    errno = EFTYPE;
49546366Sbostic 	    hashp->errno = errno;
49646366Sbostic 	    return(-1);
49746366Sbostic 	}
49846366Sbostic 	for ( i = 0; i < NCACHED; i++ ) {
49946366Sbostic 	    if ( hashp->mapp[i] ) {
50046366Sbostic 		if (!__put_page((char *)hashp->mapp[i],
50146366Sbostic 		    hashp->BITMAPS[i], 0, 1)){
50246366Sbostic 		    return(-1);
50346366Sbostic 		}
50446366Sbostic 	    }
50546366Sbostic 	}
50646366Sbostic 	return(0);
50746366Sbostic }
50846366Sbostic /*******************************SEARCH ROUTINES *****************************/
50946366Sbostic /*
51046366Sbostic     All the access routines return
51146366Sbostic 	0 on SUCCESS
51246366Sbostic 	1 to indicate an external ERROR (i.e. key not found, etc)
51346366Sbostic 	-1 to indicate an internal ERROR (i.e. out of memory, etc)
51446366Sbostic */
51546366Sbostic static int
51646366Sbostic hash_get ( dbp, key, data )
51746366Sbostic DB	*dbp;
51846366Sbostic DBT *key, *data;
51946366Sbostic {
52046366Sbostic     if ( !dbp ) {
52146366Sbostic 	return (ERROR);
52246366Sbostic     }
52346366Sbostic     hashp = (HTAB *)dbp->internal;
52446366Sbostic     if ( hashp->flags & O_WRONLY ) {
52546366Sbostic 	errno = EBADF;
52646366Sbostic 	hashp->errno = errno;
52746366Sbostic 	return ( ERROR );
52846366Sbostic     }
52946366Sbostic     return ( hash_access ( HASH_GET, key, data ) );
53046366Sbostic }
53146366Sbostic 
53246366Sbostic static int
53346366Sbostic hash_put ( dbp, key, data, flag )
53446366Sbostic DB	*dbp;
53546366Sbostic DBT 	*key, *data;
53646366Sbostic int	flag;
53746366Sbostic {
53846366Sbostic     if ( !dbp ) {
53946366Sbostic 	return (ERROR);
54046366Sbostic     }
54146366Sbostic     hashp = (HTAB *)dbp->internal;
54246366Sbostic     if ( (hashp->flags & O_ACCMODE) == O_RDONLY ) {
54346366Sbostic 	errno = EBADF;
54446366Sbostic 	hashp->errno = errno;
54546366Sbostic 	return ( ERROR );
54646366Sbostic     }
54746366Sbostic     if ( flag == R_NOOVERWRITE ) {
54846366Sbostic 	return ( hash_access ( HASH_PUTNEW, key, data ) );
54946366Sbostic     } else {
55046366Sbostic 	return ( hash_access ( HASH_PUT, key, data ) );
55146366Sbostic     }
55246366Sbostic }
55346366Sbostic 
55446366Sbostic static int
55546366Sbostic hash_delete ( dbp, key, flags )
55646366Sbostic DB	*dbp;
55746366Sbostic DBT 	*key;
55846366Sbostic int	flags;		/* Ignored */
55946366Sbostic {
56046366Sbostic     if ( !dbp ) {
56146366Sbostic 	return (ERROR);
56246366Sbostic     }
56346366Sbostic     hashp = (HTAB *)dbp->internal;
56446366Sbostic     if ( (hashp->flags & O_ACCMODE) == O_RDONLY ) {
56546366Sbostic 	errno = EBADF;
56646366Sbostic 	hashp->errno = errno;
56746366Sbostic 	return ( ERROR );
56846366Sbostic     }
56946366Sbostic     return ( hash_access ( HASH_DELETE, key, NULL ) );
57046366Sbostic }
57146366Sbostic 
57246366Sbostic /*
57346366Sbostic     Assume that hashp has been set in wrapper routine
57446366Sbostic */
57546366Sbostic static int
57646366Sbostic hash_access(action, key, val)
57746366Sbostic ACTION action;
57846366Sbostic DBT *key, *val;
57946366Sbostic {
58046366Sbostic 	register	BUFHEAD	*rbufp;
58146366Sbostic 	register	u_short	*bp;
58246366Sbostic 	register	int	ndx;
58346366Sbostic 	register 	int n;
58446366Sbostic 	register 	int off = hashp->BSIZE;
58546366Sbostic 	register	int		size;
58646366Sbostic 	register	char	*kp;
58746366Sbostic 	BUFHEAD	*bufp;
588*46457Sbostic 	BUFHEAD	*save_bufp;
58946366Sbostic 	u_short	pageno;
59046366Sbostic 
59146366Sbostic #ifdef HASH_STATISTICS
59246366Sbostic 	hash_accesses++;
59346366Sbostic #endif
59446366Sbostic 
59546366Sbostic 	size = key->size;
59646366Sbostic 	kp = key->data;
597*46457Sbostic 	rbufp = __get_buf ( __call_hash(kp, size), NULL, 0 );
59846366Sbostic 	if ( !rbufp ) return(ERROR);
599*46457Sbostic 	save_bufp = rbufp;
60046366Sbostic 
601*46457Sbostic 	/* Pin the bucket chain */
602*46457Sbostic 	rbufp->flags |= BUF_PIN;
60346366Sbostic 	for ( bp = (u_short *)rbufp->page, n = *bp++, ndx = 1; ndx < n;  ) {
60446366Sbostic 	    if ( bp[1] >= REAL_KEY ) {
60546366Sbostic 		/* Real key/data pair */
60646366Sbostic 		if (size == off - *bp &&
60746366Sbostic 		    bcmp(kp, rbufp->page + *bp, size) == 0) {
60846366Sbostic 		    goto found;
60946366Sbostic 		}
61046366Sbostic 		off = bp[1];
61146366Sbostic #ifdef HASH_STATISTICS
61246366Sbostic 		hash_collisions++;
61346366Sbostic #endif
61446366Sbostic 	        bp += 2;
61546366Sbostic 	        ndx += 2;
61646366Sbostic 	    } else if ( bp[1] == OVFLPAGE ) {
61746366Sbostic 		rbufp = __get_buf ( *bp, rbufp, 0 );
618*46457Sbostic 		if ( !rbufp ) {
619*46457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
620*46457Sbostic 		    return (ERROR);
621*46457Sbostic 		}
62246366Sbostic 		/* FOR LOOP INIT */
62346366Sbostic 		bp = (u_short *)rbufp->page;
62446366Sbostic 		n = *bp++;
62546366Sbostic 		ndx = 1;
62646366Sbostic 		off = hashp->BSIZE;
62746366Sbostic 	    } else if ( bp[1] < REAL_KEY ) {
62846366Sbostic 		if ( (ndx = __find_bigpair(rbufp, ndx, kp, size )) > 0 ) {
62946366Sbostic 		    goto found;
63046366Sbostic 		} else if ( ndx == -2 ) {
63146366Sbostic 		    bufp = rbufp;
63246366Sbostic 		    if ( !(pageno = __find_last_page ( &bufp )) ) {
63346366Sbostic 			ndx = 0;
63446366Sbostic 			rbufp = bufp;
63546366Sbostic 			break;	/* FOR */
63646366Sbostic 		    }
63746366Sbostic 		    rbufp = __get_buf ( pageno, bufp, 0 );
638*46457Sbostic 		    if ( !rbufp ) {
639*46457Sbostic 			save_bufp->flags &= ~BUF_PIN;
640*46457Sbostic 			return (ERROR);
641*46457Sbostic 		    }
64246366Sbostic 		    /* FOR LOOP INIT */
64346366Sbostic 		    bp = (u_short *)rbufp->page;
64446366Sbostic 		    n = *bp++;
64546366Sbostic 		    ndx = 1;
64646366Sbostic 		    off = hashp->BSIZE;
64746366Sbostic 		} else  {
648*46457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
64946366Sbostic 		    return(ERROR);
65046366Sbostic 		}
65146366Sbostic 	    }
65246366Sbostic 	}
65346366Sbostic 
65446366Sbostic 	/* Not found */
65546366Sbostic 	switch ( action ) {
65646366Sbostic 	    case HASH_PUT:
65746366Sbostic 	    case HASH_PUTNEW:
65846366Sbostic 		if (__addel(rbufp, key, val)) {
659*46457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
66046366Sbostic 		    return(ERROR);
66146366Sbostic 		} else {
662*46457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
66346366Sbostic 		    return(SUCCESS);
66446366Sbostic 		}
66546366Sbostic 	    case HASH_GET:
66646366Sbostic 	    case HASH_DELETE:
66746366Sbostic 	    default:
668*46457Sbostic 		save_bufp->flags &= ~BUF_PIN;
66946366Sbostic 		return(ABNORMAL);
67046366Sbostic 	}
67146366Sbostic 
67246366Sbostic found:
67346366Sbostic 	switch (action) {
67446366Sbostic 	    case HASH_PUTNEW:
675*46457Sbostic 		save_bufp->flags &= ~BUF_PIN;
67646366Sbostic 		return(ABNORMAL);
67746366Sbostic 	    case HASH_GET:
67846366Sbostic 		bp = (u_short *)rbufp->page;
67946366Sbostic 		if (bp[ndx+1] < REAL_KEY) __big_return(rbufp, ndx, val, 0);
68046366Sbostic 		else {
68146366Sbostic 		    val->data = rbufp->page + (int) bp[ndx + 1];
68246366Sbostic 		    val->size = bp[ndx] - bp[ndx + 1];
68346366Sbostic 		}
68446366Sbostic 		break;
68546366Sbostic 	    case HASH_PUT:
686*46457Sbostic 		if ((__delpair (rbufp, ndx)) || (__addel (rbufp, key, val)) ) {
687*46457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
688*46457Sbostic 		    return(ERROR);
689*46457Sbostic 		}
69046366Sbostic 		break;
69146366Sbostic 	    case HASH_DELETE:
69246366Sbostic 		if (__delpair (rbufp, ndx))return(ERROR);
69346366Sbostic 		break;
69446366Sbostic 	}
695*46457Sbostic 	save_bufp->flags &= ~BUF_PIN;
69646366Sbostic 	return (SUCCESS);
69746366Sbostic }
69846366Sbostic 
69946366Sbostic static int
70046366Sbostic hash_seq(dbp, key, data, flag)
70146366Sbostic DB	*dbp;
70246366Sbostic DBT 	*key, *data;
70346366Sbostic int flag;
70446366Sbostic {
70546366Sbostic 	register	int bucket;
70646366Sbostic 	register	BUFHEAD	*bufp;
707*46457Sbostic 	BUFHEAD	*save_bufp;
70846366Sbostic 	u_short	*bp;
70946366Sbostic 	u_short	ndx;
71046366Sbostic 	u_short	pageno;
71146366Sbostic 
71246366Sbostic 	if ( !dbp ) {
71346366Sbostic 	    return (ERROR);
71446366Sbostic 	}
71546366Sbostic 
71646366Sbostic 	hashp = (HTAB *)dbp->internal;
71746366Sbostic 	if ( hashp->flags & O_WRONLY ) {
71846366Sbostic 	    errno = EBADF;
71946366Sbostic 	    hashp->errno = errno;
72046366Sbostic 	    return ( ERROR );
72146366Sbostic 	}
72246366Sbostic #ifdef HASH_STATISTICS
72346366Sbostic 	hash_accesses++;
72446366Sbostic #endif
72546366Sbostic 
72646366Sbostic 	if ( (hashp->cbucket < 0) || (flag == R_FIRST) ) {
72746366Sbostic 	    hashp->cbucket = 0;
72846366Sbostic 	    hashp->cndx = 1;
72946366Sbostic 	    hashp->cpage = NULL;
73046366Sbostic 	}
73146366Sbostic 
73246366Sbostic 	if ( !(bufp = hashp->cpage) ) {
73346366Sbostic 	    for (bucket = hashp->cbucket;
73446366Sbostic 		 bucket <= hashp->MAX_BUCKET;
73546366Sbostic 		 bucket++, hashp->cndx = 1 ) {
73646366Sbostic 
73746366Sbostic 		bufp = __get_buf ( bucket, NULL, 0 );
73846366Sbostic 		if (!bufp) return(ERROR);
73946366Sbostic 		hashp->cpage = bufp;
74046366Sbostic 		bp = (u_short *)bufp->page;
74146366Sbostic 		if (bp[0]) break;
74246366Sbostic 	    }
74346366Sbostic 	    hashp->cbucket = bucket;
74446366Sbostic 	    if ( hashp->cbucket > hashp->MAX_BUCKET ) {
74546366Sbostic 		hashp->cbucket = -1;
74646366Sbostic 		return ( ABNORMAL );
74746366Sbostic 	    }
74846366Sbostic 	} else {
74946366Sbostic 	    bp  = (u_short *)hashp->cpage->page;
75046366Sbostic 	}
75146366Sbostic 
75246366Sbostic #ifdef DEBUG
75346366Sbostic 	assert (bp);
75446366Sbostic 	assert (bufp);
75546366Sbostic #endif
75646366Sbostic 	while ( bp[hashp->cndx+1] == OVFLPAGE ) {
75746366Sbostic 	    bufp = hashp->cpage = __get_buf ( bp[hashp->cndx], bufp, 0 );
75846366Sbostic 	    if (!bufp) return(ERROR);
75946366Sbostic 	    bp = (u_short *)(bufp->page);
76046366Sbostic 	    hashp->cndx = 1;
76146366Sbostic 	}
76246366Sbostic 	ndx = hashp->cndx;
76346366Sbostic 	if (bp[ndx+1] < REAL_KEY) {
76446366Sbostic 	    if (__big_keydata(bufp, ndx, key, data, 1)) {
76546366Sbostic 		return(ERROR);
76646366Sbostic 	    }
76746366Sbostic 	} else {
76846366Sbostic 	    key->data = hashp->cpage->page + bp[ndx];
76946366Sbostic 	    key->size = (ndx > 1 ? bp[ndx-1] : hashp->BSIZE) - bp[ndx];
77046366Sbostic 	    data->data = hashp->cpage->page + bp[ndx + 1];
77146366Sbostic 	    data->size = bp[ndx] - bp[ndx + 1];
77246366Sbostic 	    ndx += 2;
77346366Sbostic 	    if ( ndx > bp[0] ) {
77446366Sbostic 		hashp->cpage = NULL;
77546366Sbostic 		hashp->cbucket++;
77646366Sbostic 		hashp->cndx=1;
77746366Sbostic 	    } else hashp->cndx = ndx;
77846366Sbostic 	}
77946366Sbostic 	return (SUCCESS);
78046366Sbostic }
78146366Sbostic 
78246366Sbostic /********************************* UTILITIES ************************/
78346366Sbostic /*
78446366Sbostic     0 ==> OK
78546366Sbostic     -1 ==> Error
78646366Sbostic */
78746366Sbostic extern int
78846366Sbostic __expand_table()
78946366Sbostic {
79046366Sbostic 	int	old_bucket, new_bucket;
79146366Sbostic 	int	new_segnum;
79246366Sbostic 	int	dirsize;
79346366Sbostic 	int	spare_ndx;
79446366Sbostic 	register	char **old, **new;
79546366Sbostic #ifdef HASH_STATISTICS
79646366Sbostic 	hash_expansions++;
79746366Sbostic #endif
79846366Sbostic 
79946366Sbostic 	new_bucket = ++hashp->MAX_BUCKET;
80046366Sbostic 	old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
80146366Sbostic 
80246366Sbostic 	new_segnum = new_bucket >> hashp->SSHIFT;
80346366Sbostic 
80446366Sbostic 	/* Check if we need a new segment */
80546366Sbostic 	if ( new_segnum >= hashp->nsegs ) {
80646366Sbostic 
80746366Sbostic 	    /* Check if we need to expand directory */
80846366Sbostic 	    if ( new_segnum >= hashp->DSIZE ) {
80946366Sbostic 
81046366Sbostic 		/* Reallocate directory */
81146366Sbostic 		dirsize = hashp->DSIZE * sizeof ( SEGMENT * );
81246366Sbostic 		if (!hash_realloc ( &hashp->dir, dirsize, (dirsize << 1 ) )) {
81346366Sbostic 		    return(-1);
81446366Sbostic 		}
81546366Sbostic 		hashp->DSIZE = dirsize << 1;
81646366Sbostic 	    }
81746366Sbostic 	    if (!(hashp->dir[new_segnum] =
81846366Sbostic 		    (SEGMENT)calloc ( hashp->SGSIZE, sizeof(SEGMENT)))) {
81946366Sbostic 		    return(-1);
82046366Sbostic 	    }
82146366Sbostic 	    hashp->exsegs++;
82246366Sbostic 	    hashp->nsegs++;
82346366Sbostic 	}
82446366Sbostic 
82546366Sbostic 	/*
82646366Sbostic 	    If the split point is increasing (MAX_BUCKET's log
82746366Sbostic 	    base 2 increases), we need to copy the current contents
82846366Sbostic 	    of the spare split bucket to the next bucket
82946366Sbostic 	*/
83046366Sbostic 	spare_ndx = __log2(hashp->MAX_BUCKET);
83146366Sbostic 	if ( spare_ndx != (__log2(hashp->MAX_BUCKET - 1))) {
83246366Sbostic 	    hashp->SPARES[spare_ndx] = hashp->SPARES[spare_ndx-1];
83346366Sbostic 	}
83446366Sbostic 
83546366Sbostic 	if ( new_bucket > hashp->HIGH_MASK ) {
83646366Sbostic 	    /* Starting a new doubling */
83746366Sbostic 	    hashp->LOW_MASK = hashp->HIGH_MASK;
83846366Sbostic 	    hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
83946366Sbostic 	}
84046366Sbostic 
84146366Sbostic 	/*
84246366Sbostic 	 * Relocate records to the new bucket
84346366Sbostic 	 */
84446366Sbostic 	return(__split_page ( old_bucket, new_bucket ));
84546366Sbostic }
84646366Sbostic /*
84746366Sbostic     If realloc guarantees that the pointer is not destroyed
84846366Sbostic     if the realloc fails, then this routine can go away
84946366Sbostic */
85046366Sbostic static char *
85146366Sbostic hash_realloc ( p_ptr, oldsize, newsize )
85246366Sbostic char	**p_ptr;
85346366Sbostic int	oldsize;
85446366Sbostic int	newsize;
85546366Sbostic {
85646366Sbostic 	register char	*p;
85746366Sbostic 
85846366Sbostic 	if (p = (char *)malloc ( newsize ) ) {
85946366Sbostic 		bcopy ( *p_ptr, p, oldsize );
86046366Sbostic 		bzero ( *p_ptr + oldsize, newsize-oldsize );
86146366Sbostic 		free(*p_ptr);
86246366Sbostic 		*p_ptr = p;
86346366Sbostic 	}
86446366Sbostic 	return (p);
86546366Sbostic }
86646366Sbostic 
86746366Sbostic extern int
86846366Sbostic __call_hash ( k, len )
86946366Sbostic char	*k;
87046366Sbostic int	len;
87146366Sbostic {
87246366Sbostic 	int	n, bucket;
87346366Sbostic 	n = hashp->hash(k, len);
87446366Sbostic 
87546366Sbostic 	bucket = n & hashp->HIGH_MASK;
87646366Sbostic 	if ( bucket > hashp->MAX_BUCKET ) {
87746366Sbostic 	    bucket = bucket & hashp->LOW_MASK;
87846366Sbostic 	}
87946366Sbostic 
88046366Sbostic 	return(bucket);
88146366Sbostic }
88246366Sbostic 
88346366Sbostic /*
88446366Sbostic     Allocate segment table.  On error, destroy the table
88546366Sbostic     and set errno.
88646366Sbostic 
88746366Sbostic     Returns 0 on success
88846366Sbostic */
88946366Sbostic static int
89046366Sbostic alloc_segs ( nsegs )
89146366Sbostic int	nsegs;
89246366Sbostic {
89346366Sbostic     register int	i;
89446366Sbostic     register SEGMENT	store;
89546366Sbostic 
89646366Sbostic     int	save_errno;
89746366Sbostic 
89846366Sbostic     if (!(hashp->dir = (SEGMENT *)calloc(hashp->DSIZE, sizeof(SEGMENT *)))) {
89946366Sbostic 	save_errno = errno;
90046366Sbostic 	(void)hdestroy();
90146366Sbostic 	errno = save_errno;
90246366Sbostic 	return(-1);
90346366Sbostic     }
90446366Sbostic 
90546366Sbostic     /* Allocate segments */
90646366Sbostic     store = (SEGMENT)calloc ( nsegs << hashp->SSHIFT, sizeof (SEGMENT) );
90746366Sbostic     if ( !store ) {
90846366Sbostic 	save_errno = errno;
90946366Sbostic 	(void)hdestroy();
91046366Sbostic 	errno = save_errno;
91146366Sbostic 	return(-1);
91246366Sbostic     }
91346366Sbostic 
91446366Sbostic     for ( i=0; i < nsegs; i++, hashp->nsegs++ ) {
91546366Sbostic 	hashp->dir[i] = &store[i<<hashp->SSHIFT];
91646366Sbostic     }
91746366Sbostic     return(0);
91846366Sbostic }
91946366Sbostic 
92046366Sbostic /*
92146366Sbostic     Hashp->hdr needs to be byteswapped.
92246366Sbostic */
92346366Sbostic static void
92446366Sbostic swap_header_copy ( srcp, destp )
92546366Sbostic HASHHDR	*srcp;
92646366Sbostic HASHHDR	*destp;
92746366Sbostic {
92846366Sbostic     int i;
92946366Sbostic 
93046366Sbostic     BLSWAP_COPY(srcp->magic, destp->magic);
93146366Sbostic     BLSWAP_COPY(srcp->version, destp->version);
93246366Sbostic     BLSWAP_COPY(srcp->lorder, destp->lorder);
93346366Sbostic     BLSWAP_COPY(srcp->bsize, destp->bsize);
93446366Sbostic     BLSWAP_COPY(srcp->bshift, destp->bshift);
93546366Sbostic     BLSWAP_COPY(srcp->dsize, destp->dsize);
93646366Sbostic     BLSWAP_COPY(srcp->ssize, destp->ssize);
93746366Sbostic     BLSWAP_COPY(srcp->sshift, destp->sshift);
93846366Sbostic     BLSWAP_COPY(srcp->max_bucket, destp->max_bucket);
93946366Sbostic     BLSWAP_COPY(srcp->high_mask, destp->high_mask);
94046366Sbostic     BLSWAP_COPY(srcp->low_mask, destp->low_mask);
94146366Sbostic     BLSWAP_COPY(srcp->ffactor, destp->ffactor);
94246366Sbostic     BLSWAP_COPY(srcp->nkeys, destp->nkeys);
94346366Sbostic     BLSWAP_COPY(srcp->hdrpages, destp->hdrpages);
94446366Sbostic     BLSWAP_COPY(srcp->h_charkey, destp->h_charkey);
94546366Sbostic     for ( i=0; i < NCACHED; i++ ) {
94646366Sbostic 	BLSWAP_COPY ( srcp->spares[i] , destp->spares[i]);
94746366Sbostic 	BSSWAP_COPY ( srcp->bitmaps[i] , destp->bitmaps[i]);
94846366Sbostic     }
94946366Sbostic     return;
95046366Sbostic }
95146366Sbostic 
95246366Sbostic static void
95346366Sbostic swap_header ( )
95446366Sbostic {
95546366Sbostic     HASHHDR	*hdrp;
95646366Sbostic     int	i;
95746366Sbostic 
95846366Sbostic     hdrp = &hashp->hdr;
95946366Sbostic 
96046366Sbostic     BLSWAP(hdrp->magic);
96146366Sbostic     BLSWAP(hdrp->version);
96246366Sbostic     BLSWAP(hdrp->lorder);
96346366Sbostic     BLSWAP(hdrp->bsize);
96446366Sbostic     BLSWAP(hdrp->bshift);
96546366Sbostic     BLSWAP(hdrp->dsize);
96646366Sbostic     BLSWAP(hdrp->ssize);
96746366Sbostic     BLSWAP(hdrp->sshift);
96846366Sbostic     BLSWAP(hdrp->max_bucket);
96946366Sbostic     BLSWAP(hdrp->high_mask);
97046366Sbostic     BLSWAP(hdrp->low_mask);
97146366Sbostic     BLSWAP(hdrp->ffactor);
97246366Sbostic     BLSWAP(hdrp->nkeys);
97346366Sbostic     BLSWAP(hdrp->hdrpages);
97446366Sbostic     BLSWAP(hdrp->h_charkey);
97546366Sbostic     for ( i=0; i < NCACHED; i++ ) {
97646366Sbostic 	BLSWAP ( hdrp->spares[i] );
97746366Sbostic 	BSSWAP ( hdrp->bitmaps[i] );
97846366Sbostic     }
97946366Sbostic     return;
98046366Sbostic }
981