xref: /csrg-svn/lib/libc/db/hash/hash.c (revision 46950)
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*46950Sbostic static char sccsid[] = "@(#)hash.c	5.12 (Berkeley) 03/03/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 */
4646366Sbostic extern void __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();
6046366Sbostic extern 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;
18946366Sbostic 	hashp->mapp[0] = (u_long *)malloc(bpages<<hashp->BSHIFT);
19046366Sbostic 	if ( !hashp->mapp[0] ) {
19146366Sbostic 	    RETURN_ERROR(errno, error2);
19246366Sbostic 	}
19346366Sbostic 	for ( i = 0; i < bpages; i++ ) {
19446366Sbostic 	    hashp->mapp[i] = &hashp->mapp[0][i<<hashp->BSHIFT];
19546366Sbostic 	    if (__get_page ((char *)hashp->mapp[i],
19646366Sbostic 		hashp->BITMAPS[i], 0, 1, 1)) {
19746366Sbostic 		    RETURN_ERROR(errno, error2);
19846366Sbostic 	    }
19946366Sbostic 	}
20046366Sbostic 
20146366Sbostic     }
20246366Sbostic 
20346366Sbostic     /* Initialize Buffer Manager */
20446366Sbostic     if ( info && info->ncached ) {
20546366Sbostic 	__buf_init (info->ncached);
20646366Sbostic     } else {
20746366Sbostic 	__buf_init (DEF_BUFSIZE);
20846366Sbostic     }
20946366Sbostic 
21046366Sbostic     hashp->new_file = new_table;
21146457Sbostic     hashp->save_file = file && !(hashp->flags&O_RDONLY);
21246366Sbostic     hashp->cbucket = -1;
21346366Sbostic     if ( !(dbp = (DB *)malloc ( sizeof (DB) )) ) {
21446366Sbostic 	save_errno = errno;
21546366Sbostic 	hdestroy();
21646366Sbostic 	errno = save_errno;
21746366Sbostic 	return ( NULL );
21846366Sbostic     }
21946366Sbostic     dbp->internal = (char *)hashp;
22046366Sbostic     dbp->close = hash_close;
22146534Sbostic     dbp->del = hash_delete;
22246366Sbostic     dbp->get = hash_get;
22346366Sbostic     dbp->put = hash_put;
22446366Sbostic     dbp->seq = hash_seq;
22546366Sbostic     dbp->sync = hash_sync;
22646366Sbostic 
22746366Sbostic #ifdef DEBUG
22846366Sbostic 	(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",
22946366Sbostic 		"init_htab:",
23046366Sbostic 		"TABLE POINTER   ", hashp,
23146366Sbostic 		"BUCKET SIZE     ", hashp->BSIZE,
23246366Sbostic 		"BUCKET SHIFT    ", hashp->BSHIFT,
23346366Sbostic 		"DIRECTORY SIZE  ", hashp->DSIZE,
23446366Sbostic 		"SEGMENT SIZE    ", hashp->SGSIZE,
23546366Sbostic 		"SEGMENT SHIFT   ", hashp->SSHIFT,
23646366Sbostic 		"FILL FACTOR     ", hashp->FFACTOR,
23746366Sbostic 		"MAX BUCKET      ", hashp->MAX_BUCKET,
23846366Sbostic 		"HIGH MASK       ", hashp->HIGH_MASK,
23946366Sbostic 		"LOW  MASK       ", hashp->LOW_MASK,
24046366Sbostic 		"NSEGS           ", hashp->nsegs,
24146366Sbostic 		"NKEYS           ", hashp->NKEYS );
24246366Sbostic #endif
24346366Sbostic #ifdef HASH_STATISTICS
24446366Sbostic 	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
24546366Sbostic #endif
24646366Sbostic     return (dbp);
24746366Sbostic 
24846366Sbostic error2:
24946366Sbostic     (void)hdestroy();
25046366Sbostic     errno = save_errno;
25146366Sbostic     return ( (DB *)NULL );
25246366Sbostic 
25346366Sbostic error1:
25446366Sbostic     (void) close ( hashp->fp );
25546366Sbostic 
25646366Sbostic error0:
25746366Sbostic     free ( hashp );
25846366Sbostic     errno = save_errno;
25946366Sbostic     return ( (DB *) NULL );
26046366Sbostic }
26146366Sbostic 
26246366Sbostic static int
26346366Sbostic hash_close (dbp)
26446366Sbostic DB	*dbp;
26546366Sbostic {
26646457Sbostic 	int	retval;
26746457Sbostic 
26846366Sbostic 	if ( !dbp ) {
26946366Sbostic 	    return(ERROR);
27046366Sbostic 	}
27146366Sbostic 	hashp = (HTAB *)dbp->internal;
27246457Sbostic 	retval = hdestroy();
27346457Sbostic 	(void)free ( dbp );
27446457Sbostic 	return ( retval );
27546366Sbostic }
27646366Sbostic 
27746366Sbostic 
27846366Sbostic /************************** LOCAL CREATION ROUTINES **********************/
27946366Sbostic static HTAB *
28046366Sbostic init_hash( info )
28146366Sbostic HASHINFO *info;
28246366Sbostic {
28346366Sbostic 	int	nelem;
28446366Sbostic 
28546366Sbostic 	nelem = 1;
28646366Sbostic 
28746366Sbostic 	hashp->LORDER	= BYTE_ORDER;
28846366Sbostic 	hashp->BSIZE    = DEF_BUCKET_SIZE;
28946366Sbostic 	hashp->BSHIFT   = DEF_BUCKET_SHIFT;
29046366Sbostic 	hashp->SGSIZE   = DEF_SEGSIZE;
29146366Sbostic 	hashp->SSHIFT   = DEF_SEGSIZE_SHIFT;
29246366Sbostic 	hashp->DSIZE    = DEF_DIRSIZE;
29346366Sbostic 	hashp->FFACTOR  = DEF_FFACTOR;
29446366Sbostic 	hashp->hash     = default_hash;
29546366Sbostic 	bzero (hashp->SPARES, sizeof (hashp->SPARES));
29646366Sbostic 
29746366Sbostic 	if ( info ) {
29846366Sbostic 	    if ( info->bsize )   {
29946366Sbostic 		/* Round pagesize up to power of 2 */
30046366Sbostic 		hashp->BSHIFT  = __log2(info->bsize);
30146366Sbostic 		hashp->BSIZE   = 1 << hashp->BSHIFT;
30246366Sbostic 		if ( hashp->BSIZE > MAX_BSIZE ) {
30346366Sbostic 		    errno = EINVAL;
30446366Sbostic 		    return(0);
30546366Sbostic 		}
30646366Sbostic 	    }
30746366Sbostic 	    if ( info->ffactor )  hashp->FFACTOR = info->ffactor;
30846366Sbostic 	    if ( info->hash ) hashp->hash    = info->hash;
30946366Sbostic 	    if ( info->nelem ) nelem = info->nelem;
31046366Sbostic 	    if ( info->lorder ) {
31146366Sbostic 		if ( info->lorder != BIG_ENDIAN &&
31246366Sbostic 		     info->lorder != LITTLE_ENDIAN) {
31346366Sbostic 		    errno = EINVAL;
31446366Sbostic 		    return(0);
31546366Sbostic 		}
31646366Sbostic 		hashp->LORDER = info->lorder;
31746366Sbostic 	    }
31846366Sbostic 	}
31946366Sbostic 
32046366Sbostic 	/* init_htab should destroy the table and set errno if it fails */
32146366Sbostic 	if ( init_htab ( nelem ) ) {
32246366Sbostic 	    return(0);
32346366Sbostic 	} else {
32446366Sbostic 	    return(hashp);
32546366Sbostic 	}
32646366Sbostic }
32746366Sbostic 
32846366Sbostic /*
32946366Sbostic     This calls alloc_segs which may run out of memory.
33046366Sbostic     Alloc_segs will destroy the table and set errno,
33146366Sbostic     so we just pass the error information along.
33246366Sbostic 
33346366Sbostic     Returns 0 on No Error
33446366Sbostic 
33546366Sbostic */
33646366Sbostic static int
33746366Sbostic init_htab ( nelem )
33846366Sbostic int	nelem;
33946366Sbostic {
34046366Sbostic 	register SEGMENT	*segp;
34146366Sbostic 	register int nbuckets;
34246366Sbostic 	register int nsegs;
34346366Sbostic 	int	l2;
34446366Sbostic 
34546366Sbostic  /*
34646366Sbostic   * Divide number of elements by the fill factor and determine a desired
34746366Sbostic   * number of buckets.  Allocate space for the next greater power of
34846366Sbostic   * two number of buckets
34946366Sbostic   */
35046366Sbostic 	nelem = (nelem - 1) / hashp->FFACTOR + 1;
35146366Sbostic 
35246366Sbostic 	l2 = __log2(nelem);
35346366Sbostic 	nbuckets = 1 << l2;
35446366Sbostic 	nbuckets = MAX ( nbuckets, 2 );
35546366Sbostic 
35646366Sbostic 	hashp->SPARES[l2] = l2 + 1;
35746366Sbostic 	hashp->SPARES[l2+1] = l2 + 1;
35846366Sbostic 	/*
35946366Sbostic 	    First bitmap page is at:
36046366Sbostic 		splitpoint l2
36146366Sbostic 		page offset 1
36246366Sbostic 	*/
36346366Sbostic 	__init_bitmap ( OADDR_OF(l2,1), l2+1, 0 );
36446366Sbostic 
36546366Sbostic 	hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
36646366Sbostic 	hashp->HIGH_MASK = (nbuckets << 1) - 1;
36746366Sbostic 	hashp->HDRPAGES = ((MAX(sizeof(HASHHDR),MINHDRSIZE) - 1) >>
36846366Sbostic 			  hashp->BSHIFT) + 1;
36946366Sbostic 
37046366Sbostic 	nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
37146366Sbostic 	nsegs = 1 << __log2(nsegs);
37246366Sbostic 
37346366Sbostic 	if ( nsegs > hashp->DSIZE ) {
37446366Sbostic 	    hashp->DSIZE  = nsegs;
37546366Sbostic 	}
37646366Sbostic 
37746366Sbostic 	return (alloc_segs ( nsegs ) );
37846366Sbostic }
37946366Sbostic 
38046366Sbostic /********************** DESTROY/CLOSE ROUTINES ************************/
38146366Sbostic 
38246366Sbostic /*
38346366Sbostic     Flushes any changes to the file if necessary and
38446366Sbostic     destroys the hashp structure, freeing all allocated
38546366Sbostic     space.
38646366Sbostic */
38746366Sbostic static int
38846366Sbostic hdestroy()
38946366Sbostic {
39046366Sbostic 	int	save_errno;
39146366Sbostic 	int	i;
39246503Sbostic 	u_long	**mapp;
39346366Sbostic 
39446366Sbostic 	save_errno = 0;
39546366Sbostic 
39646366Sbostic 	if (hashp != NULL) {
39746366Sbostic #ifdef HASH_STATISTICS
39846366Sbostic 	 (void)	fprintf(stderr,	"hdestroy: accesses %ld collisions %ld\n",
39946366Sbostic 			hash_accesses, hash_collisions);
40046366Sbostic 	 (void)	fprintf(stderr, "hdestroy: expansions %ld\n",
40146366Sbostic 			hash_expansions);
40246366Sbostic 	 (void)	fprintf(stderr, "hdestroy: overflows %ld\n",
40346366Sbostic 			hash_overflows);
40446366Sbostic 	 (void)	fprintf(stderr,	"keys %ld maxp %d segmentcount %d\n",
40546366Sbostic 			hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
40646366Sbostic 
40746366Sbostic 	for ( i = 0; i < NCACHED; i++ ) {
40846366Sbostic 	    (void) fprintf ( stderr, "spares[%d] = %d\n", i, hashp->SPARES[i] );
40946366Sbostic 	}
41046366Sbostic #endif
41146366Sbostic 
41246366Sbostic 		/*
41346366Sbostic 		    Call on buffer manager to free buffers, and if
41446366Sbostic 		    required, write them to disk
41546366Sbostic 		*/
41646366Sbostic 		if (__buf_free(1, hashp->save_file)) {
41746366Sbostic 		    save_errno = errno;
41846366Sbostic 		}
41946366Sbostic 		if ( hashp->dir ) {
42046366Sbostic 		    (void)free(*hashp->dir);	/* Free initial segments */
42146366Sbostic 		    /* Free extra segments */
42246366Sbostic 		    while ( hashp->exsegs-- ) {
42346366Sbostic 			(void)free ( hashp->dir[--hashp->nsegs] );
42446366Sbostic 		    }
42546366Sbostic 		    (void)free(hashp->dir);
42646366Sbostic 		}
42746366Sbostic 		if (flush_meta() && !save_errno) {
42846366Sbostic 		    save_errno = errno;
42946366Sbostic 		}
43046503Sbostic 
43146503Sbostic 		/* Free Initial Bigmaps */
43246503Sbostic 		if ( hashp->nmaps ) {
43346503Sbostic 		    (void)free(hashp->mapp[0]);
43446503Sbostic 		}
43546503Sbostic 
43646503Sbostic 		/* Free extra bitmaps */
43746503Sbostic 		for ( mapp = &hashp->mapp[hashp->nmaps];
43846503Sbostic 		      hashp->exmaps--;
43946503Sbostic 		      mapp++ ) {
44046503Sbostic 		      (void) free ( *mapp );
44146503Sbostic 		}
44246503Sbostic 
44346457Sbostic 		if ( hashp->fp != -1 ) {
44446457Sbostic 			(void)close (hashp->fp);
44546457Sbostic 		}
44646366Sbostic 		(void)free(hashp);
44746366Sbostic 		hashp = NULL;
44846366Sbostic 	}
44946366Sbostic 	if ( save_errno ) {
45046366Sbostic 	    errno = save_errno;
45146366Sbostic 	    return(ERROR);
45246366Sbostic 	} else {
45346366Sbostic 	    return(SUCCESS);
45446366Sbostic 	}
45546366Sbostic }
45646366Sbostic 
45746366Sbostic /*
45846366Sbostic     Write modified pages to disk
45946366Sbostic     0 == OK
46046366Sbostic     -1 ERROR
46146366Sbostic */
46246366Sbostic static int
46346366Sbostic hash_sync(dbp)
46446366Sbostic DB	*dbp;
46546366Sbostic {
46646366Sbostic 	if ( !dbp ) {
46746366Sbostic 	    return (ERROR);
46846366Sbostic 	}
46946366Sbostic 
47046366Sbostic 	hashp = (HTAB *)dbp->internal;
47146366Sbostic 
47246366Sbostic 	if (!hashp->save_file) return(0);
47346366Sbostic 	if ( __buf_free ( 0, 1 )  || flush_meta()) {
47446366Sbostic 	    return(ERROR);
47546366Sbostic 	}
47646366Sbostic 	hashp->new_file = 0;
47746366Sbostic 	return(0);
47846366Sbostic }
47946366Sbostic 
48046366Sbostic /*
48146366Sbostic 0 == OK
48246366Sbostic -1 indicates that errno should be set
48346366Sbostic */
48446366Sbostic static int
48546366Sbostic flush_meta()
48646366Sbostic {
48746366Sbostic     	int	fp;
48846366Sbostic 	int	hdrsize;
48946366Sbostic 	int	i;
49046366Sbostic 	int	wsize;
49146366Sbostic 	HASHHDR	*whdrp;
49246366Sbostic 	HASHHDR	whdr;
49346366Sbostic 
49446366Sbostic 	if (!hashp->save_file) return(0);
49546366Sbostic 	hashp->MAGIC = HASHMAGIC;
49646366Sbostic 	hashp->VERSION = VERSION_NO;
49746366Sbostic 	hashp->H_CHARKEY = hashp->hash ( CHARKEY, sizeof(CHARKEY));
49846366Sbostic 
49946366Sbostic 	fp = hashp->fp;
50046366Sbostic 	whdrp = &hashp->hdr;
50146366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
50246366Sbostic 	whdrp = &whdr;
50346366Sbostic 	swap_header_copy( &hashp->hdr, whdrp );
50446366Sbostic #endif
50546500Sbostic 	if ( (lseek (fp, 0, SEEK_SET) == -1 ) ||
50646366Sbostic 	     ((wsize = write ( fp, whdrp, sizeof(HASHHDR))) == -1)) {
50746366Sbostic 	    return(-1);
50846366Sbostic 	} else if ( wsize != sizeof(HASHHDR) ) {
50946366Sbostic 	    errno = EFTYPE;
51046366Sbostic 	    hashp->errno = errno;
51146366Sbostic 	    return(-1);
51246366Sbostic 	}
51346366Sbostic 	for ( i = 0; i < NCACHED; i++ ) {
51446366Sbostic 	    if ( hashp->mapp[i] ) {
51546366Sbostic 		if (!__put_page((char *)hashp->mapp[i],
51646366Sbostic 		    hashp->BITMAPS[i], 0, 1)){
51746366Sbostic 		    return(-1);
51846366Sbostic 		}
51946366Sbostic 	    }
52046366Sbostic 	}
52146366Sbostic 	return(0);
52246366Sbostic }
52346366Sbostic /*******************************SEARCH ROUTINES *****************************/
52446366Sbostic /*
52546366Sbostic     All the access routines return
52646366Sbostic 	0 on SUCCESS
52746366Sbostic 	1 to indicate an external ERROR (i.e. key not found, etc)
52846366Sbostic 	-1 to indicate an internal ERROR (i.e. out of memory, etc)
52946366Sbostic */
53046366Sbostic static int
53146571Sbostic hash_get ( dbp, key, data, flag )
53246366Sbostic DB	*dbp;
53346571Sbostic DBT	*key, *data;
53446571Sbostic u_long	flag;
53546366Sbostic {
53646571Sbostic #ifdef lint
53746571Sbostic     flag = flag;
53846571Sbostic #endif
53946571Sbostic 
54046366Sbostic     if ( !dbp ) {
54146366Sbostic 	return (ERROR);
54246366Sbostic     }
54346366Sbostic     hashp = (HTAB *)dbp->internal;
54446366Sbostic     if ( hashp->flags & O_WRONLY ) {
54546366Sbostic 	errno = EBADF;
54646366Sbostic 	hashp->errno = errno;
54746366Sbostic 	return ( ERROR );
54846366Sbostic     }
54946366Sbostic     return ( hash_access ( HASH_GET, key, data ) );
55046366Sbostic }
55146366Sbostic 
55246366Sbostic static int
55346366Sbostic hash_put ( dbp, key, data, flag )
55446366Sbostic DB	*dbp;
55546366Sbostic DBT 	*key, *data;
55646571Sbostic u_long	flag;
55746366Sbostic {
55846366Sbostic     if ( !dbp ) {
55946366Sbostic 	return (ERROR);
56046366Sbostic     }
56146366Sbostic     hashp = (HTAB *)dbp->internal;
56246366Sbostic     if ( (hashp->flags & O_ACCMODE) == O_RDONLY ) {
56346366Sbostic 	errno = EBADF;
56446366Sbostic 	hashp->errno = errno;
56546366Sbostic 	return ( ERROR );
56646366Sbostic     }
56746366Sbostic     if ( flag == R_NOOVERWRITE ) {
56846366Sbostic 	return ( hash_access ( HASH_PUTNEW, key, data ) );
56946366Sbostic     } else {
57046366Sbostic 	return ( hash_access ( HASH_PUT, key, data ) );
57146366Sbostic     }
57246366Sbostic }
57346366Sbostic 
57446366Sbostic static int
57546571Sbostic hash_delete ( dbp, key, flag )
57646366Sbostic DB	*dbp;
57746366Sbostic DBT 	*key;
57846571Sbostic u_long	flag;		/* Ignored */
57946366Sbostic {
58046571Sbostic #ifdef lint
58146571Sbostic     flag = flag;
58246571Sbostic #endif
58346366Sbostic     if ( !dbp ) {
58446366Sbostic 	return (ERROR);
58546366Sbostic     }
58646366Sbostic     hashp = (HTAB *)dbp->internal;
58746366Sbostic     if ( (hashp->flags & O_ACCMODE) == O_RDONLY ) {
58846366Sbostic 	errno = EBADF;
58946366Sbostic 	hashp->errno = errno;
59046366Sbostic 	return ( ERROR );
59146366Sbostic     }
59246366Sbostic     return ( hash_access ( HASH_DELETE, key, NULL ) );
59346366Sbostic }
59446366Sbostic 
59546366Sbostic /*
59646366Sbostic     Assume that hashp has been set in wrapper routine
59746366Sbostic */
59846366Sbostic static int
59946366Sbostic hash_access(action, key, val)
60046366Sbostic ACTION action;
60146366Sbostic DBT *key, *val;
60246366Sbostic {
60346366Sbostic 	register	BUFHEAD	*rbufp;
60446366Sbostic 	register	u_short	*bp;
60546366Sbostic 	register	int	ndx;
60646366Sbostic 	register 	int n;
60746366Sbostic 	register 	int off = hashp->BSIZE;
60846366Sbostic 	register	int		size;
60946366Sbostic 	register	char	*kp;
61046366Sbostic 	BUFHEAD	*bufp;
61146457Sbostic 	BUFHEAD	*save_bufp;
61246366Sbostic 	u_short	pageno;
61346366Sbostic 
61446366Sbostic #ifdef HASH_STATISTICS
61546366Sbostic 	hash_accesses++;
61646366Sbostic #endif
61746366Sbostic 
61846366Sbostic 	size = key->size;
619*46950Sbostic 	kp = (char *)key->data;
62046457Sbostic 	rbufp = __get_buf ( __call_hash(kp, size), NULL, 0 );
62146366Sbostic 	if ( !rbufp ) return(ERROR);
62246457Sbostic 	save_bufp = rbufp;
62346366Sbostic 
62446457Sbostic 	/* Pin the bucket chain */
62546457Sbostic 	rbufp->flags |= BUF_PIN;
62646366Sbostic 	for ( bp = (u_short *)rbufp->page, n = *bp++, ndx = 1; ndx < n;  ) {
62746366Sbostic 	    if ( bp[1] >= REAL_KEY ) {
62846366Sbostic 		/* Real key/data pair */
62946366Sbostic 		if (size == off - *bp &&
63046366Sbostic 		    bcmp(kp, rbufp->page + *bp, size) == 0) {
63146366Sbostic 		    goto found;
63246366Sbostic 		}
63346366Sbostic 		off = bp[1];
63446366Sbostic #ifdef HASH_STATISTICS
63546366Sbostic 		hash_collisions++;
63646366Sbostic #endif
63746366Sbostic 	        bp += 2;
63846366Sbostic 	        ndx += 2;
63946366Sbostic 	    } else if ( bp[1] == OVFLPAGE ) {
64046366Sbostic 		rbufp = __get_buf ( *bp, rbufp, 0 );
64146457Sbostic 		if ( !rbufp ) {
64246457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
64346457Sbostic 		    return (ERROR);
64446457Sbostic 		}
64546366Sbostic 		/* FOR LOOP INIT */
64646366Sbostic 		bp = (u_short *)rbufp->page;
64746366Sbostic 		n = *bp++;
64846366Sbostic 		ndx = 1;
64946366Sbostic 		off = hashp->BSIZE;
65046366Sbostic 	    } else if ( bp[1] < REAL_KEY ) {
65146366Sbostic 		if ( (ndx = __find_bigpair(rbufp, ndx, kp, size )) > 0 ) {
65246366Sbostic 		    goto found;
65346366Sbostic 		} else if ( ndx == -2 ) {
65446366Sbostic 		    bufp = rbufp;
65546366Sbostic 		    if ( !(pageno = __find_last_page ( &bufp )) ) {
65646366Sbostic 			ndx = 0;
65746366Sbostic 			rbufp = bufp;
65846366Sbostic 			break;	/* FOR */
65946366Sbostic 		    }
66046366Sbostic 		    rbufp = __get_buf ( pageno, bufp, 0 );
66146457Sbostic 		    if ( !rbufp ) {
66246457Sbostic 			save_bufp->flags &= ~BUF_PIN;
66346457Sbostic 			return (ERROR);
66446457Sbostic 		    }
66546366Sbostic 		    /* FOR LOOP INIT */
66646366Sbostic 		    bp = (u_short *)rbufp->page;
66746366Sbostic 		    n = *bp++;
66846366Sbostic 		    ndx = 1;
66946366Sbostic 		    off = hashp->BSIZE;
67046366Sbostic 		} else  {
67146457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
67246366Sbostic 		    return(ERROR);
67346366Sbostic 		}
67446366Sbostic 	    }
67546366Sbostic 	}
67646366Sbostic 
67746366Sbostic 	/* Not found */
67846366Sbostic 	switch ( action ) {
67946366Sbostic 	    case HASH_PUT:
68046366Sbostic 	    case HASH_PUTNEW:
68146366Sbostic 		if (__addel(rbufp, key, val)) {
68246457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
68346366Sbostic 		    return(ERROR);
68446366Sbostic 		} else {
68546457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
68646366Sbostic 		    return(SUCCESS);
68746366Sbostic 		}
68846366Sbostic 	    case HASH_GET:
68946366Sbostic 	    case HASH_DELETE:
69046366Sbostic 	    default:
69146457Sbostic 		save_bufp->flags &= ~BUF_PIN;
69246366Sbostic 		return(ABNORMAL);
69346366Sbostic 	}
69446366Sbostic 
69546366Sbostic found:
69646366Sbostic 	switch (action) {
69746366Sbostic 	    case HASH_PUTNEW:
69846457Sbostic 		save_bufp->flags &= ~BUF_PIN;
69946366Sbostic 		return(ABNORMAL);
70046366Sbostic 	    case HASH_GET:
70146366Sbostic 		bp = (u_short *)rbufp->page;
70246366Sbostic 		if (bp[ndx+1] < REAL_KEY) __big_return(rbufp, ndx, val, 0);
70346366Sbostic 		else {
704*46950Sbostic 		    val->data = (u_char *)rbufp->page + (int) bp[ndx + 1];
70546366Sbostic 		    val->size = bp[ndx] - bp[ndx + 1];
70646366Sbostic 		}
70746366Sbostic 		break;
70846366Sbostic 	    case HASH_PUT:
70946457Sbostic 		if ((__delpair (rbufp, ndx)) || (__addel (rbufp, key, val)) ) {
71046457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
71146457Sbostic 		    return(ERROR);
71246457Sbostic 		}
71346366Sbostic 		break;
71446366Sbostic 	    case HASH_DELETE:
71546366Sbostic 		if (__delpair (rbufp, ndx))return(ERROR);
71646366Sbostic 		break;
71746366Sbostic 	}
71846457Sbostic 	save_bufp->flags &= ~BUF_PIN;
71946366Sbostic 	return (SUCCESS);
72046366Sbostic }
72146366Sbostic 
72246366Sbostic static int
72346366Sbostic hash_seq(dbp, key, data, flag)
72446366Sbostic DB	*dbp;
72546366Sbostic DBT 	*key, *data;
72646571Sbostic u_long	flag;
72746366Sbostic {
72846366Sbostic 	register	int bucket;
72946366Sbostic 	register	BUFHEAD	*bufp;
73046457Sbostic 	BUFHEAD	*save_bufp;
73146366Sbostic 	u_short	*bp;
73246366Sbostic 	u_short	ndx;
73346366Sbostic 	u_short	pageno;
73446366Sbostic 
73546366Sbostic 	if ( !dbp ) {
73646366Sbostic 	    return (ERROR);
73746366Sbostic 	}
73846366Sbostic 
73946366Sbostic 	hashp = (HTAB *)dbp->internal;
74046366Sbostic 	if ( hashp->flags & O_WRONLY ) {
74146366Sbostic 	    errno = EBADF;
74246366Sbostic 	    hashp->errno = errno;
74346366Sbostic 	    return ( ERROR );
74446366Sbostic 	}
74546366Sbostic #ifdef HASH_STATISTICS
74646366Sbostic 	hash_accesses++;
74746366Sbostic #endif
74846366Sbostic 
74946366Sbostic 	if ( (hashp->cbucket < 0) || (flag == R_FIRST) ) {
75046366Sbostic 	    hashp->cbucket = 0;
75146366Sbostic 	    hashp->cndx = 1;
75246366Sbostic 	    hashp->cpage = NULL;
75346366Sbostic 	}
75446366Sbostic 
75546366Sbostic 	if ( !(bufp = hashp->cpage) ) {
75646366Sbostic 	    for (bucket = hashp->cbucket;
75746366Sbostic 		 bucket <= hashp->MAX_BUCKET;
75846366Sbostic 		 bucket++, hashp->cndx = 1 ) {
75946366Sbostic 
76046366Sbostic 		bufp = __get_buf ( bucket, NULL, 0 );
76146366Sbostic 		if (!bufp) return(ERROR);
76246366Sbostic 		hashp->cpage = bufp;
76346366Sbostic 		bp = (u_short *)bufp->page;
76446366Sbostic 		if (bp[0]) break;
76546366Sbostic 	    }
76646366Sbostic 	    hashp->cbucket = bucket;
76746366Sbostic 	    if ( hashp->cbucket > hashp->MAX_BUCKET ) {
76846366Sbostic 		hashp->cbucket = -1;
76946366Sbostic 		return ( ABNORMAL );
77046366Sbostic 	    }
77146366Sbostic 	} else {
77246366Sbostic 	    bp  = (u_short *)hashp->cpage->page;
77346366Sbostic 	}
77446366Sbostic 
77546366Sbostic #ifdef DEBUG
77646366Sbostic 	assert (bp);
77746366Sbostic 	assert (bufp);
77846366Sbostic #endif
77946366Sbostic 	while ( bp[hashp->cndx+1] == OVFLPAGE ) {
78046366Sbostic 	    bufp = hashp->cpage = __get_buf ( bp[hashp->cndx], bufp, 0 );
78146366Sbostic 	    if (!bufp) return(ERROR);
78246366Sbostic 	    bp = (u_short *)(bufp->page);
78346366Sbostic 	    hashp->cndx = 1;
78446366Sbostic 	}
78546366Sbostic 	ndx = hashp->cndx;
78646366Sbostic 	if (bp[ndx+1] < REAL_KEY) {
78746366Sbostic 	    if (__big_keydata(bufp, ndx, key, data, 1)) {
78846366Sbostic 		return(ERROR);
78946366Sbostic 	    }
79046366Sbostic 	} else {
791*46950Sbostic 	    key->data = (u_char *)hashp->cpage->page + bp[ndx];
79246366Sbostic 	    key->size = (ndx > 1 ? bp[ndx-1] : hashp->BSIZE) - bp[ndx];
793*46950Sbostic 	    data->data = (u_char *)hashp->cpage->page + bp[ndx + 1];
79446366Sbostic 	    data->size = bp[ndx] - bp[ndx + 1];
79546366Sbostic 	    ndx += 2;
79646366Sbostic 	    if ( ndx > bp[0] ) {
79746366Sbostic 		hashp->cpage = NULL;
79846366Sbostic 		hashp->cbucket++;
79946366Sbostic 		hashp->cndx=1;
80046366Sbostic 	    } else hashp->cndx = ndx;
80146366Sbostic 	}
80246366Sbostic 	return (SUCCESS);
80346366Sbostic }
80446366Sbostic 
80546366Sbostic /********************************* UTILITIES ************************/
80646366Sbostic /*
80746366Sbostic     0 ==> OK
80846366Sbostic     -1 ==> Error
80946366Sbostic */
81046366Sbostic extern int
81146366Sbostic __expand_table()
81246366Sbostic {
81346366Sbostic 	int	old_bucket, new_bucket;
81446366Sbostic 	int	new_segnum;
81546366Sbostic 	int	dirsize;
81646366Sbostic 	int	spare_ndx;
81746366Sbostic 	register	char **old, **new;
81846366Sbostic #ifdef HASH_STATISTICS
81946366Sbostic 	hash_expansions++;
82046366Sbostic #endif
82146366Sbostic 
82246366Sbostic 	new_bucket = ++hashp->MAX_BUCKET;
82346366Sbostic 	old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
82446366Sbostic 
82546366Sbostic 	new_segnum = new_bucket >> hashp->SSHIFT;
82646366Sbostic 
82746366Sbostic 	/* Check if we need a new segment */
82846366Sbostic 	if ( new_segnum >= hashp->nsegs ) {
82946366Sbostic 
83046366Sbostic 	    /* Check if we need to expand directory */
83146366Sbostic 	    if ( new_segnum >= hashp->DSIZE ) {
83246366Sbostic 
83346366Sbostic 		/* Reallocate directory */
83446366Sbostic 		dirsize = hashp->DSIZE * sizeof ( SEGMENT * );
83546366Sbostic 		if (!hash_realloc ( &hashp->dir, dirsize, (dirsize << 1 ) )) {
83646366Sbostic 		    return(-1);
83746366Sbostic 		}
83846366Sbostic 		hashp->DSIZE = dirsize << 1;
83946366Sbostic 	    }
84046366Sbostic 	    if (!(hashp->dir[new_segnum] =
84146366Sbostic 		    (SEGMENT)calloc ( hashp->SGSIZE, sizeof(SEGMENT)))) {
84246366Sbostic 		    return(-1);
84346366Sbostic 	    }
84446366Sbostic 	    hashp->exsegs++;
84546366Sbostic 	    hashp->nsegs++;
84646366Sbostic 	}
84746366Sbostic 
84846366Sbostic 	/*
84946366Sbostic 	    If the split point is increasing (MAX_BUCKET's log
85046366Sbostic 	    base 2 increases), we need to copy the current contents
85146366Sbostic 	    of the spare split bucket to the next bucket
85246366Sbostic 	*/
85346366Sbostic 	spare_ndx = __log2(hashp->MAX_BUCKET);
85446366Sbostic 	if ( spare_ndx != (__log2(hashp->MAX_BUCKET - 1))) {
85546366Sbostic 	    hashp->SPARES[spare_ndx] = hashp->SPARES[spare_ndx-1];
85646366Sbostic 	}
85746366Sbostic 
85846366Sbostic 	if ( new_bucket > hashp->HIGH_MASK ) {
85946366Sbostic 	    /* Starting a new doubling */
86046366Sbostic 	    hashp->LOW_MASK = hashp->HIGH_MASK;
86146366Sbostic 	    hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
86246366Sbostic 	}
86346366Sbostic 
86446366Sbostic 	/*
86546366Sbostic 	 * Relocate records to the new bucket
86646366Sbostic 	 */
86746366Sbostic 	return(__split_page ( old_bucket, new_bucket ));
86846366Sbostic }
86946366Sbostic /*
87046366Sbostic     If realloc guarantees that the pointer is not destroyed
87146366Sbostic     if the realloc fails, then this routine can go away
87246366Sbostic */
87346366Sbostic static char *
87446366Sbostic hash_realloc ( p_ptr, oldsize, newsize )
87546366Sbostic char	**p_ptr;
87646366Sbostic int	oldsize;
87746366Sbostic int	newsize;
87846366Sbostic {
87946366Sbostic 	register char	*p;
88046366Sbostic 
88146366Sbostic 	if (p = (char *)malloc ( newsize ) ) {
88246366Sbostic 		bcopy ( *p_ptr, p, oldsize );
88346366Sbostic 		bzero ( *p_ptr + oldsize, newsize-oldsize );
88446366Sbostic 		free(*p_ptr);
88546366Sbostic 		*p_ptr = p;
88646366Sbostic 	}
88746366Sbostic 	return (p);
88846366Sbostic }
88946366Sbostic 
89046366Sbostic extern int
89146366Sbostic __call_hash ( k, len )
89246366Sbostic char	*k;
89346366Sbostic int	len;
89446366Sbostic {
89546366Sbostic 	int	n, bucket;
89646366Sbostic 	n = hashp->hash(k, len);
89746366Sbostic 
89846366Sbostic 	bucket = n & hashp->HIGH_MASK;
89946366Sbostic 	if ( bucket > hashp->MAX_BUCKET ) {
90046366Sbostic 	    bucket = bucket & hashp->LOW_MASK;
90146366Sbostic 	}
90246366Sbostic 
90346366Sbostic 	return(bucket);
90446366Sbostic }
90546366Sbostic 
90646366Sbostic /*
90746366Sbostic     Allocate segment table.  On error, destroy the table
90846366Sbostic     and set errno.
90946366Sbostic 
91046366Sbostic     Returns 0 on success
91146366Sbostic */
91246366Sbostic static int
91346366Sbostic alloc_segs ( nsegs )
91446366Sbostic int	nsegs;
91546366Sbostic {
91646366Sbostic     register int	i;
91746366Sbostic     register SEGMENT	store;
91846366Sbostic 
91946366Sbostic     int	save_errno;
92046366Sbostic 
92146366Sbostic     if (!(hashp->dir = (SEGMENT *)calloc(hashp->DSIZE, sizeof(SEGMENT *)))) {
92246366Sbostic 	save_errno = errno;
92346366Sbostic 	(void)hdestroy();
92446366Sbostic 	errno = save_errno;
92546366Sbostic 	return(-1);
92646366Sbostic     }
92746366Sbostic 
92846366Sbostic     /* Allocate segments */
92946366Sbostic     store = (SEGMENT)calloc ( nsegs << hashp->SSHIFT, sizeof (SEGMENT) );
93046366Sbostic     if ( !store ) {
93146366Sbostic 	save_errno = errno;
93246366Sbostic 	(void)hdestroy();
93346366Sbostic 	errno = save_errno;
93446366Sbostic 	return(-1);
93546366Sbostic     }
93646366Sbostic 
93746366Sbostic     for ( i=0; i < nsegs; i++, hashp->nsegs++ ) {
93846366Sbostic 	hashp->dir[i] = &store[i<<hashp->SSHIFT];
93946366Sbostic     }
94046366Sbostic     return(0);
94146366Sbostic }
94246366Sbostic 
94346366Sbostic /*
94446366Sbostic     Hashp->hdr needs to be byteswapped.
94546366Sbostic */
94646366Sbostic static void
94746366Sbostic swap_header_copy ( srcp, destp )
94846366Sbostic HASHHDR	*srcp;
94946366Sbostic HASHHDR	*destp;
95046366Sbostic {
95146366Sbostic     int i;
95246366Sbostic 
95346366Sbostic     BLSWAP_COPY(srcp->magic, destp->magic);
95446366Sbostic     BLSWAP_COPY(srcp->version, destp->version);
95546366Sbostic     BLSWAP_COPY(srcp->lorder, destp->lorder);
95646366Sbostic     BLSWAP_COPY(srcp->bsize, destp->bsize);
95746366Sbostic     BLSWAP_COPY(srcp->bshift, destp->bshift);
95846366Sbostic     BLSWAP_COPY(srcp->dsize, destp->dsize);
95946366Sbostic     BLSWAP_COPY(srcp->ssize, destp->ssize);
96046366Sbostic     BLSWAP_COPY(srcp->sshift, destp->sshift);
96146366Sbostic     BLSWAP_COPY(srcp->max_bucket, destp->max_bucket);
96246366Sbostic     BLSWAP_COPY(srcp->high_mask, destp->high_mask);
96346366Sbostic     BLSWAP_COPY(srcp->low_mask, destp->low_mask);
96446366Sbostic     BLSWAP_COPY(srcp->ffactor, destp->ffactor);
96546366Sbostic     BLSWAP_COPY(srcp->nkeys, destp->nkeys);
96646366Sbostic     BLSWAP_COPY(srcp->hdrpages, destp->hdrpages);
96746366Sbostic     BLSWAP_COPY(srcp->h_charkey, destp->h_charkey);
96846366Sbostic     for ( i=0; i < NCACHED; i++ ) {
96946366Sbostic 	BLSWAP_COPY ( srcp->spares[i] , destp->spares[i]);
97046366Sbostic 	BSSWAP_COPY ( srcp->bitmaps[i] , destp->bitmaps[i]);
97146366Sbostic     }
97246366Sbostic     return;
97346366Sbostic }
97446366Sbostic 
97546366Sbostic static void
97646366Sbostic swap_header ( )
97746366Sbostic {
97846366Sbostic     HASHHDR	*hdrp;
97946366Sbostic     int	i;
98046366Sbostic 
98146366Sbostic     hdrp = &hashp->hdr;
98246366Sbostic 
98346366Sbostic     BLSWAP(hdrp->magic);
98446366Sbostic     BLSWAP(hdrp->version);
98546366Sbostic     BLSWAP(hdrp->lorder);
98646366Sbostic     BLSWAP(hdrp->bsize);
98746366Sbostic     BLSWAP(hdrp->bshift);
98846366Sbostic     BLSWAP(hdrp->dsize);
98946366Sbostic     BLSWAP(hdrp->ssize);
99046366Sbostic     BLSWAP(hdrp->sshift);
99146366Sbostic     BLSWAP(hdrp->max_bucket);
99246366Sbostic     BLSWAP(hdrp->high_mask);
99346366Sbostic     BLSWAP(hdrp->low_mask);
99446366Sbostic     BLSWAP(hdrp->ffactor);
99546366Sbostic     BLSWAP(hdrp->nkeys);
99646366Sbostic     BLSWAP(hdrp->hdrpages);
99746366Sbostic     BLSWAP(hdrp->h_charkey);
99846366Sbostic     for ( i=0; i < NCACHED; i++ ) {
99946366Sbostic 	BLSWAP ( hdrp->spares[i] );
100046366Sbostic 	BSSWAP ( hdrp->bitmaps[i] );
100146366Sbostic     }
100246366Sbostic     return;
100346366Sbostic }
1004