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