xref: /csrg-svn/lib/libc/db/hash/hash.c (revision 64708)
146366Sbostic /*-
262489Sbostic  * Copyright (c) 1990, 1993
362489Sbostic  *	The Regents of the University of California.  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*64708Sbostic static char sccsid[] = "@(#)hash.c	8.4 (Berkeley) 10/12/93";
1346366Sbostic #endif /* LIBC_SCCS and not lint */
1446366Sbostic 
1546366Sbostic #include <sys/param.h>
1646366Sbostic #include <sys/stat.h>
1755452Sbostic 
1857586Sbostic #include <errno.h>
1946562Sbostic #include <fcntl.h>
2057586Sbostic #include <stdio.h>
2157586Sbostic #include <stdlib.h>
2257586Sbostic #include <string.h>
2357586Sbostic #include <unistd.h>
2450997Sbostic #ifdef DEBUG
2546366Sbostic #include <assert.h>
2650997Sbostic #endif
2757586Sbostic 
2857932Sbostic #include <db.h>
2946366Sbostic #include "hash.h"
3050997Sbostic #include "page.h"
3150997Sbostic #include "extern.h"
3246366Sbostic 
3357586Sbostic static int   alloc_segs __P((HTAB *, int));
3457586Sbostic static int   flush_meta __P((HTAB *));
3557586Sbostic static int   hash_access __P((HTAB *, ACTION, DBT *, DBT *));
3650997Sbostic static int   hash_close __P((DB *));
3750997Sbostic static int   hash_delete __P((const DB *, const DBT *, u_int));
3860247Sbostic static int   hash_fd __P((const DB *));
3951057Sbostic static int   hash_get __P((const DB *, const DBT *, DBT *, u_int));
4056893Sbostic static int   hash_put __P((const DB *, DBT *, const DBT *, u_int));
4150997Sbostic static void *hash_realloc __P((SEGMENT **, int, int));
4250997Sbostic static int   hash_seq __P((const DB *, DBT *, DBT *, u_int));
4360060Sbostic static int   hash_sync __P((const DB *, u_int));
4457586Sbostic static int   hdestroy __P((HTAB *));
4560247Sbostic static HTAB *init_hash __P((HTAB *, const char *, HASHINFO *));
4657586Sbostic static int   init_htab __P((HTAB *, int));
4750997Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
4858127Sralph static void  swap_header __P((HTAB *));
4950997Sbostic static void  swap_header_copy __P((HASHHDR *, HASHHDR *));
5050997Sbostic #endif
5150997Sbostic 
5246366Sbostic /* Fast arithmetic, relying on powers of 2, */
5350997Sbostic #define MOD(x, y)		((x) & ((y) - 1))
5446366Sbostic 
5550997Sbostic #define RETURN_ERROR(ERR, LOC)	{ save_errno = ERR; goto LOC; }
5646366Sbostic 
5746366Sbostic /* Return values */
5850997Sbostic #define	SUCCESS	 (0)
5950997Sbostic #define	ERROR	(-1)
6050997Sbostic #define	ABNORMAL (1)
6146366Sbostic 
6246366Sbostic #ifdef HASH_STATISTICS
6346366Sbostic long hash_accesses, hash_collisions, hash_expansions, hash_overflows;
6446366Sbostic #endif
6546366Sbostic 
6650997Sbostic /************************** INTERFACE ROUTINES ***************************/
6746366Sbostic /* OPEN/CLOSE */
6846366Sbostic 
6950997Sbostic extern DB *
7064466Sbostic __hash_open(file, flags, mode, info, dflags)
7150997Sbostic 	const char *file;
7264466Sbostic 	int flags, mode, dflags;
7350997Sbostic 	const HASHINFO *info;	/* Special directives for create */
7446366Sbostic {
7557586Sbostic 	HTAB *hashp;
7650997Sbostic 	struct stat statbuf;
7750997Sbostic 	DB *dbp;
7850997Sbostic 	int bpages, hdrsize, new_table, nsegs, save_errno;
7946366Sbostic 
8056661Sbostic 	if ((flags & O_ACCMODE) == O_WRONLY) {
8156422Smargo 		errno = EINVAL;
8256422Smargo 		return (NULL);
8356422Smargo 	}
8456422Smargo 
8550997Sbostic 	if (!(hashp = calloc(1, sizeof(HTAB))))
8650997Sbostic 		return (NULL);
8750997Sbostic 	hashp->fp = -1;
8864466Sbostic 
8950997Sbostic 	/*
9064466Sbostic 	 * Even if user wants write only, we need to be able to read
9164466Sbostic 	 * the actual file, so we need to open it read/write. But, the
9264466Sbostic 	 * field in the hashp structure needs to be accurate so that
9350997Sbostic 	 * we can check accesses.
9450997Sbostic 	 */
9564466Sbostic 	hashp->flags = flags;
9646366Sbostic 
9750997Sbostic 	new_table = 0;
9850997Sbostic 	if (!file || (flags & O_TRUNC) ||
9950997Sbostic 	    (stat(file, &statbuf) && (errno == ENOENT))) {
10050997Sbostic 		if (errno == ENOENT)
10150997Sbostic 			errno = 0; /* Just in case someone looks at errno */
10250997Sbostic 		new_table = 1;
10346485Sbostic 	}
10450997Sbostic 	if (file) {
10550997Sbostic 		if ((hashp->fp = open(file, flags, mode)) == -1)
10650997Sbostic 			RETURN_ERROR(errno, error0);
10750997Sbostic 		(void)fcntl(hashp->fp, F_SETFD, 1);
10846366Sbostic 	}
10950997Sbostic 	if (new_table) {
11060247Sbostic 		if (!(hashp = init_hash(hashp, file, (HASHINFO *)info)))
11150997Sbostic 			RETURN_ERROR(errno, error1);
11250997Sbostic 	} else {
11350997Sbostic 		/* Table already exists */
11450997Sbostic 		if (info && info->hash)
11550997Sbostic 			hashp->hash = info->hash;
11650997Sbostic 		else
11757586Sbostic 			hashp->hash = __default_hash;
11846366Sbostic 
11950997Sbostic 		hdrsize = read(hashp->fp, &hashp->hdr, sizeof(HASHHDR));
12046366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
12157586Sbostic 		swap_header(hashp);
12246366Sbostic #endif
12350997Sbostic 		if (hdrsize == -1)
12450997Sbostic 			RETURN_ERROR(errno, error1);
12550997Sbostic 		if (hdrsize != sizeof(HASHHDR))
12650997Sbostic 			RETURN_ERROR(EFTYPE, error1);
12750997Sbostic 		/* Verify file type, versions and hash function */
12850997Sbostic 		if (hashp->MAGIC != HASHMAGIC)
12950997Sbostic 			RETURN_ERROR(EFTYPE, error1);
130*64708Sbostic #define	OLDHASHVERSION	1
131*64708Sbostic 		if (hashp->VERSION != HASHVERSION &&
132*64708Sbostic 		    hashp->VERSION != OLDHASHVERSION)
13350997Sbostic 			RETURN_ERROR(EFTYPE, error1);
13450997Sbostic 		if (hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY)
13550997Sbostic 			RETURN_ERROR(EFTYPE, error1);
13651057Sbostic 		/*
13751057Sbostic 		 * Figure out how many segments we need.  Max_Bucket is the
13851057Sbostic 		 * maximum bucket number, so the number of buckets is
13951057Sbostic 		 * max_bucket + 1.
14051057Sbostic 		 */
14151057Sbostic 		nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) /
14250997Sbostic 			 hashp->SGSIZE;
14350997Sbostic 		hashp->nsegs = 0;
14457586Sbostic 		if (alloc_segs(hashp, nsegs))
14550997Sbostic 			/*
14650997Sbostic 			 * If alloc_segs fails, table will have been destroyed
14750997Sbostic 			 * and errno will have been set.
14850997Sbostic 			 */
14950997Sbostic 			return (NULL);
15050997Sbostic 		/* Read in bitmaps */
15151061Sbostic 		bpages = (hashp->SPARES[hashp->OVFL_POINT] +
15250997Sbostic 		    (hashp->BSIZE << BYTE_SHIFT) - 1) >>
15350997Sbostic 		    (hashp->BSHIFT + BYTE_SHIFT);
15446366Sbostic 
15550997Sbostic 		hashp->nmaps = bpages;
15651057Sbostic 		(void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_long *));
15746366Sbostic 	}
15846366Sbostic 
15950997Sbostic 	/* Initialize Buffer Manager */
16050997Sbostic 	if (info && info->cachesize)
16157586Sbostic 		__buf_init(hashp, info->cachesize);
16250997Sbostic 	else
16357586Sbostic 		__buf_init(hashp, DEF_BUFSIZE);
16450997Sbostic 
16550997Sbostic 	hashp->new_file = new_table;
16656422Smargo 	hashp->save_file = file && (hashp->flags & O_RDWR);
16750997Sbostic 	hashp->cbucket = -1;
16850997Sbostic 	if (!(dbp = malloc(sizeof(DB)))) {
16950997Sbostic 		save_errno = errno;
17057586Sbostic 		hdestroy(hashp);
17150997Sbostic 		errno = save_errno;
17250997Sbostic 		return (NULL);
17346366Sbostic 	}
17457586Sbostic 	dbp->internal = hashp;
17550997Sbostic 	dbp->close = hash_close;
17650997Sbostic 	dbp->del = hash_delete;
17760247Sbostic 	dbp->fd = hash_fd;
17850997Sbostic 	dbp->get = hash_get;
17950997Sbostic 	dbp->put = hash_put;
18050997Sbostic 	dbp->seq = hash_seq;
18150997Sbostic 	dbp->sync = hash_sync;
18250997Sbostic 	dbp->type = DB_HASH;
18346366Sbostic 
18446366Sbostic #ifdef DEBUG
18550997Sbostic 	(void)fprintf(stderr,
18651061Sbostic "%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%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
18750997Sbostic 	    "init_htab:",
18850997Sbostic 	    "TABLE POINTER   ", hashp,
18950997Sbostic 	    "BUCKET SIZE     ", hashp->BSIZE,
19050997Sbostic 	    "BUCKET SHIFT    ", hashp->BSHIFT,
19150997Sbostic 	    "DIRECTORY SIZE  ", hashp->DSIZE,
19250997Sbostic 	    "SEGMENT SIZE    ", hashp->SGSIZE,
19350997Sbostic 	    "SEGMENT SHIFT   ", hashp->SSHIFT,
19450997Sbostic 	    "FILL FACTOR     ", hashp->FFACTOR,
19550997Sbostic 	    "MAX BUCKET      ", hashp->MAX_BUCKET,
19651061Sbostic 	    "OVFL POINT	     ", hashp->OVFL_POINT,
19751061Sbostic 	    "LAST FREED      ", hashp->LAST_FREED,
19850997Sbostic 	    "HIGH MASK       ", hashp->HIGH_MASK,
19950997Sbostic 	    "LOW  MASK       ", hashp->LOW_MASK,
20050997Sbostic 	    "NSEGS           ", hashp->nsegs,
20150997Sbostic 	    "NKEYS           ", hashp->NKEYS);
20246366Sbostic #endif
20346366Sbostic #ifdef HASH_STATISTICS
20446366Sbostic 	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
20546366Sbostic #endif
20650997Sbostic 	return (dbp);
20746366Sbostic 
20846366Sbostic error1:
20951192Sbostic 	if (hashp != NULL)
21051192Sbostic 		(void)close(hashp->fp);
21146366Sbostic 
21246366Sbostic error0:
21350997Sbostic 	free(hashp);
21450997Sbostic 	errno = save_errno;
21550997Sbostic 	return (NULL);
21646366Sbostic }
21746366Sbostic 
21846366Sbostic static int
21950997Sbostic hash_close(dbp)
22050997Sbostic 	DB *dbp;
22146366Sbostic {
22257586Sbostic 	HTAB *hashp;
22350997Sbostic 	int retval;
22446457Sbostic 
22550997Sbostic 	if (!dbp)
22650997Sbostic 		return (ERROR);
22757586Sbostic 
22846366Sbostic 	hashp = (HTAB *)dbp->internal;
22957586Sbostic 	retval = hdestroy(hashp);
23050997Sbostic 	free(dbp);
23150997Sbostic 	return (retval);
23246366Sbostic }
23346366Sbostic 
23460247Sbostic static int
23560247Sbostic hash_fd(dbp)
23660247Sbostic 	const DB *dbp;
23760247Sbostic {
23860247Sbostic 	HTAB *hashp;
23960247Sbostic 
24060247Sbostic 	if (!dbp)
24160247Sbostic 		return (ERROR);
24260247Sbostic 
24360247Sbostic 	hashp = (HTAB *)dbp->internal;
24460247Sbostic 	if (hashp->fp == -1) {
24560247Sbostic 		errno = ENOENT;
24660247Sbostic 		return (-1);
24760247Sbostic 	}
24860247Sbostic 	return (hashp->fp);
24960247Sbostic }
25060247Sbostic 
25146366Sbostic /************************** LOCAL CREATION ROUTINES **********************/
25250997Sbostic static HTAB *
25360247Sbostic init_hash(hashp, file, info)
25457586Sbostic 	HTAB *hashp;
25560247Sbostic 	const char *file;
25650997Sbostic 	HASHINFO *info;
25746366Sbostic {
25860247Sbostic 	struct stat statbuf;
25950997Sbostic 	int nelem;
26046366Sbostic 
26146366Sbostic 	nelem = 1;
26251061Sbostic 	hashp->NKEYS = 0;
26350997Sbostic 	hashp->LORDER = BYTE_ORDER;
26450997Sbostic 	hashp->BSIZE = DEF_BUCKET_SIZE;
26550997Sbostic 	hashp->BSHIFT = DEF_BUCKET_SHIFT;
26650997Sbostic 	hashp->SGSIZE = DEF_SEGSIZE;
26750997Sbostic 	hashp->SSHIFT = DEF_SEGSIZE_SHIFT;
26850997Sbostic 	hashp->DSIZE = DEF_DIRSIZE;
26950997Sbostic 	hashp->FFACTOR = DEF_FFACTOR;
27057586Sbostic 	hashp->hash = __default_hash;
27158016Sbostic 	memset(hashp->SPARES, 0, sizeof(hashp->SPARES));
27258016Sbostic 	memset(hashp->BITMAPS, 0, sizeof (hashp->BITMAPS));
27346366Sbostic 
27460247Sbostic 	/* Fix bucket size to be optimal for file system */
27560247Sbostic 	if (file != NULL) {
27660247Sbostic 		if (stat(file, &statbuf))
27760247Sbostic 			return (NULL);
27860247Sbostic 		hashp->BSIZE = statbuf.st_blksize;
27960247Sbostic 		hashp->BSHIFT = __log2(hashp->BSIZE);
28060247Sbostic 	}
28160247Sbostic 
28250997Sbostic 	if (info) {
28350997Sbostic 		if (info->bsize) {
28450997Sbostic 			/* Round pagesize up to power of 2 */
28550997Sbostic 			hashp->BSHIFT = __log2(info->bsize);
28650997Sbostic 			hashp->BSIZE = 1 << hashp->BSHIFT;
28750997Sbostic 			if (hashp->BSIZE > MAX_BSIZE) {
28850997Sbostic 				errno = EINVAL;
28950997Sbostic 				return (NULL);
29050997Sbostic 			}
29146366Sbostic 		}
29250997Sbostic 		if (info->ffactor)
29350997Sbostic 			hashp->FFACTOR = info->ffactor;
29450997Sbostic 		if (info->hash)
29550997Sbostic 			hashp->hash = info->hash;
29650997Sbostic 		if (info->nelem)
29750997Sbostic 			nelem = info->nelem;
29850997Sbostic 		if (info->lorder) {
29950997Sbostic 			if (info->lorder != BIG_ENDIAN &&
30050997Sbostic 			    info->lorder != LITTLE_ENDIAN) {
30150997Sbostic 				errno = EINVAL;
30250997Sbostic 				return (NULL);
30350997Sbostic 			}
30450997Sbostic 			hashp->LORDER = info->lorder;
30546366Sbostic 		}
30646366Sbostic 	}
30746366Sbostic 	/* init_htab should destroy the table and set errno if it fails */
30857586Sbostic 	if (init_htab(hashp, nelem))
30950997Sbostic 		return (NULL);
31050997Sbostic 	else
31150997Sbostic 		return (hashp);
31246366Sbostic }
31346366Sbostic /*
31450997Sbostic  * This calls alloc_segs which may run out of memory.  Alloc_segs will destroy
31550997Sbostic  * the table and set errno, so we just pass the error information along.
31650997Sbostic  *
31750997Sbostic  * Returns 0 on No Error
31850997Sbostic  */
31946366Sbostic static int
32057586Sbostic init_htab(hashp, nelem)
32157586Sbostic 	HTAB *hashp;
32250997Sbostic 	int nelem;
32346366Sbostic {
32450997Sbostic 	register int nbuckets, nsegs;
32550997Sbostic 	int l2;
32646366Sbostic 
32750997Sbostic 	/*
32850997Sbostic 	 * Divide number of elements by the fill factor and determine a
32950997Sbostic 	 * desired number of buckets.  Allocate space for the next greater
33050997Sbostic 	 * power of two number of buckets.
33150997Sbostic 	 */
33246366Sbostic 	nelem = (nelem - 1) / hashp->FFACTOR + 1;
33346366Sbostic 
33452001Sbostic 	l2 = __log2(MAX(nelem, 2));
33546366Sbostic 	nbuckets = 1 << l2;
33646366Sbostic 
33746366Sbostic 	hashp->SPARES[l2] = l2 + 1;
33850997Sbostic 	hashp->SPARES[l2 + 1] = l2 + 1;
33951061Sbostic 	hashp->OVFL_POINT = l2;
34051061Sbostic 	hashp->LAST_FREED = 2;
34151061Sbostic 
34250997Sbostic 	/* First bitmap page is at: splitpoint l2 page offset 1 */
34357586Sbostic 	if (__init_bitmap(hashp, OADDR_OF(l2, 1), l2 + 1, 0))
34451057Sbostic 		return (-1);
34546366Sbostic 
34646366Sbostic 	hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
34746366Sbostic 	hashp->HIGH_MASK = (nbuckets << 1) - 1;
34850997Sbostic 	hashp->HDRPAGES = ((MAX(sizeof(HASHHDR), MINHDRSIZE) - 1) >>
34950997Sbostic 	    hashp->BSHIFT) + 1;
35046366Sbostic 
35146366Sbostic 	nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
35246366Sbostic 	nsegs = 1 << __log2(nsegs);
35346366Sbostic 
35450997Sbostic 	if (nsegs > hashp->DSIZE)
35550997Sbostic 		hashp->DSIZE = nsegs;
35657586Sbostic 	return (alloc_segs(hashp, nsegs));
35746366Sbostic }
35846366Sbostic 
35946366Sbostic /********************** DESTROY/CLOSE ROUTINES ************************/
36046366Sbostic 
36146366Sbostic /*
36250997Sbostic  * Flushes any changes to the file if necessary and destroys the hashp
36350997Sbostic  * structure, freeing all allocated space.
36450997Sbostic  */
36546366Sbostic static int
36657586Sbostic hdestroy(hashp)
36757586Sbostic 	HTAB *hashp;
36846366Sbostic {
36950997Sbostic 	int i, save_errno;
37046366Sbostic 
37146366Sbostic 	save_errno = 0;
37246366Sbostic 
37346366Sbostic #ifdef HASH_STATISTICS
37457586Sbostic 	(void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
37557586Sbostic 	    hash_accesses, hash_collisions);
37657586Sbostic 	(void)fprintf(stderr, "hdestroy: expansions %ld\n",
37757586Sbostic 	    hash_expansions);
37857586Sbostic 	(void)fprintf(stderr, "hdestroy: overflows %ld\n",
37957586Sbostic 	    hash_overflows);
38057586Sbostic 	(void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n",
38157586Sbostic 	    hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
38246366Sbostic 
38357586Sbostic 	for (i = 0; i < NCACHED; i++)
38457586Sbostic 		(void)fprintf(stderr,
38557586Sbostic 		    "spares[%d] = %d\n", i, hashp->SPARES[i]);
38646366Sbostic #endif
38757586Sbostic 	/*
38857586Sbostic 	 * Call on buffer manager to free buffers, and if required,
38957586Sbostic 	 * write them to disk.
39057586Sbostic 	 */
39157586Sbostic 	if (__buf_free(hashp, 1, hashp->save_file))
39257586Sbostic 		save_errno = errno;
39357586Sbostic 	if (hashp->dir) {
39457586Sbostic 		free(*hashp->dir);	/* Free initial segments */
39557586Sbostic 		/* Free extra segments */
39657586Sbostic 		while (hashp->exsegs--)
39757586Sbostic 			free(hashp->dir[--hashp->nsegs]);
39857586Sbostic 		free(hashp->dir);
39957586Sbostic 	}
40057586Sbostic 	if (flush_meta(hashp) && !save_errno)
40157586Sbostic 		save_errno = errno;
40257586Sbostic 	/* Free Bigmaps */
40357586Sbostic 	for (i = 0; i < hashp->nmaps; i++)
40457586Sbostic 		if (hashp->mapp[i])
40557586Sbostic 			free(hashp->mapp[i]);
40646503Sbostic 
40757586Sbostic 	if (hashp->fp != -1)
40857586Sbostic 		(void)close(hashp->fp);
40957586Sbostic 
41050997Sbostic 	if (save_errno) {
41150997Sbostic 		errno = save_errno;
41250997Sbostic 		return (ERROR);
41346366Sbostic 	}
41450997Sbostic 	return (SUCCESS);
41546366Sbostic }
41650997Sbostic /*
41750997Sbostic  * Write modified pages to disk
41850997Sbostic  *
41950997Sbostic  * Returns:
42050997Sbostic  *	 0 == OK
42150997Sbostic  *	-1 ERROR
42250997Sbostic  */
42346366Sbostic static int
42460060Sbostic hash_sync(dbp, flags)
42550997Sbostic 	const DB *dbp;
42660060Sbostic 	u_int flags;
42746366Sbostic {
42857586Sbostic 	HTAB *hashp;
42957586Sbostic 
43060060Sbostic 	if (flags != 0) {
43160060Sbostic 		errno = EINVAL;
43260060Sbostic 		return (ERROR);
43360060Sbostic 	}
43460060Sbostic 
43550997Sbostic 	if (!dbp)
43650997Sbostic 		return (ERROR);
43757586Sbostic 
43846366Sbostic 	hashp = (HTAB *)dbp->internal;
43950997Sbostic 	if (!hashp->save_file)
44050997Sbostic 		return (0);
44157586Sbostic 	if (__buf_free(hashp, 0, 1) || flush_meta(hashp))
44250997Sbostic 		return (ERROR);
44346366Sbostic 	hashp->new_file = 0;
44450997Sbostic 	return (0);
44546366Sbostic }
44646366Sbostic 
44746366Sbostic /*
44850997Sbostic  * Returns:
44950997Sbostic  *	 0 == OK
45050997Sbostic  *	-1 indicates that errno should be set
45150997Sbostic  */
45246366Sbostic static int
45357586Sbostic flush_meta(hashp)
45457586Sbostic 	HTAB *hashp;
45546366Sbostic {
45651814Smarc 	HASHHDR *whdrp;
45751814Smarc #if BYTE_ORDER == LITTLE_ENDIAN
45851814Smarc 	HASHHDR whdr;
45951814Smarc #endif
46050997Sbostic 	int fp, i, wsize;
46146366Sbostic 
46250997Sbostic 	if (!hashp->save_file)
46350997Sbostic 		return (0);
46446366Sbostic 	hashp->MAGIC = HASHMAGIC;
46551061Sbostic 	hashp->VERSION = HASHVERSION;
46650997Sbostic 	hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY));
46746366Sbostic 
46846366Sbostic 	fp = hashp->fp;
46946366Sbostic 	whdrp = &hashp->hdr;
47046366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
47146366Sbostic 	whdrp = &whdr;
47250997Sbostic 	swap_header_copy(&hashp->hdr, whdrp);
47346366Sbostic #endif
47456669Sbostic 	if ((lseek(fp, (off_t)0, SEEK_SET) == -1) ||
47550997Sbostic 	    ((wsize = write(fp, whdrp, sizeof(HASHHDR))) == -1))
47650997Sbostic 		return (-1);
47750997Sbostic 	else
47850997Sbostic 		if (wsize != sizeof(HASHHDR)) {
47950997Sbostic 			errno = EFTYPE;
48050997Sbostic 			hashp->errno = errno;
48150997Sbostic 			return (-1);
48246366Sbostic 		}
48350997Sbostic 	for (i = 0; i < NCACHED; i++)
48450997Sbostic 		if (hashp->mapp[i])
48557586Sbostic 			if (__put_page(hashp, (char *)hashp->mapp[i],
48650997Sbostic 				hashp->BITMAPS[i], 0, 1))
48750997Sbostic 				return (-1);
48850997Sbostic 	return (0);
48946366Sbostic }
49050997Sbostic 
49146366Sbostic /*******************************SEARCH ROUTINES *****************************/
49246366Sbostic /*
49350997Sbostic  * All the access routines return
49450997Sbostic  *
49550997Sbostic  * Returns:
49650997Sbostic  *	 0 on SUCCESS
49750997Sbostic  *	 1 to indicate an external ERROR (i.e. key not found, etc)
49850997Sbostic  *	-1 to indicate an internal ERROR (i.e. out of memory, etc)
49950997Sbostic  */
50046366Sbostic static int
50150997Sbostic hash_get(dbp, key, data, flag)
50250997Sbostic 	const DB *dbp;
50351057Sbostic 	const DBT *key;
50451057Sbostic 	DBT *data;
50550997Sbostic 	u_int flag;
50646366Sbostic {
50757586Sbostic 	HTAB *hashp;
50857586Sbostic 
50957586Sbostic 	hashp = (HTAB *)dbp->internal;
51050997Sbostic 	if (flag) {
51150997Sbostic 		hashp->errno = errno = EINVAL;
51250997Sbostic 		return (ERROR);
51350997Sbostic 	}
51457586Sbostic 	return (hash_access(hashp, HASH_GET, (DBT *)key, data));
51546366Sbostic }
51646366Sbostic 
51746366Sbostic static int
51850997Sbostic hash_put(dbp, key, data, flag)
51950997Sbostic 	const DB *dbp;
52056893Sbostic 	DBT *key;
52156893Sbostic 	const DBT *data;
52250997Sbostic 	u_int flag;
52346366Sbostic {
52457586Sbostic 	HTAB *hashp;
52557586Sbostic 
52657586Sbostic 	hashp = (HTAB *)dbp->internal;
52750997Sbostic 	if (flag && flag != R_NOOVERWRITE) {
52850997Sbostic 		hashp->errno = errno = EINVAL;
52950997Sbostic 		return (ERROR);
53050997Sbostic 	}
53150997Sbostic 	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
53250997Sbostic 		hashp->errno = errno = EPERM;
53350997Sbostic 		return (ERROR);
53450997Sbostic 	}
53557586Sbostic 	return (hash_access(hashp, flag == R_NOOVERWRITE ?
53650997Sbostic 	    HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));
53746366Sbostic }
53846366Sbostic 
53946366Sbostic static int
54050997Sbostic hash_delete(dbp, key, flag)
54150997Sbostic 	const DB *dbp;
54250997Sbostic 	const DBT *key;
54350997Sbostic 	u_int flag;		/* Ignored */
54446366Sbostic {
54557586Sbostic 	HTAB *hashp;
54657586Sbostic 
54757586Sbostic 	hashp = (HTAB *)dbp->internal;
54850997Sbostic 	if (flag && flag != R_CURSOR) {
54950997Sbostic 		hashp->errno = errno = EINVAL;
55050997Sbostic 		return (ERROR);
55150997Sbostic 	}
55250997Sbostic 	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
55350997Sbostic 		hashp->errno = errno = EPERM;
55450997Sbostic 		return (ERROR);
55550997Sbostic 	}
55657586Sbostic 	return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
55746366Sbostic }
55846366Sbostic 
55946366Sbostic /*
56050997Sbostic  * Assume that hashp has been set in wrapper routine.
56150997Sbostic  */
56246366Sbostic static int
56357586Sbostic hash_access(hashp, action, key, val)
56457586Sbostic 	HTAB *hashp;
56550997Sbostic 	ACTION action;
56650997Sbostic 	DBT *key, *val;
56746366Sbostic {
56850997Sbostic 	register BUFHEAD *rbufp;
56950997Sbostic 	BUFHEAD *bufp, *save_bufp;
57050997Sbostic 	register u_short *bp;
57150997Sbostic 	register int n, ndx, off, size;
57250997Sbostic 	register char *kp;
57350997Sbostic 	u_short pageno;
57446366Sbostic 
57546366Sbostic #ifdef HASH_STATISTICS
57646366Sbostic 	hash_accesses++;
57746366Sbostic #endif
57846366Sbostic 
57950997Sbostic 	off = hashp->BSIZE;
58046366Sbostic 	size = key->size;
58146950Sbostic 	kp = (char *)key->data;
58257586Sbostic 	rbufp = __get_buf(hashp, __call_hash(hashp, kp, size), NULL, 0);
58350997Sbostic 	if (!rbufp)
58450997Sbostic 		return (ERROR);
58546457Sbostic 	save_bufp = rbufp;
58646366Sbostic 
58746457Sbostic 	/* Pin the bucket chain */
58846457Sbostic 	rbufp->flags |= BUF_PIN;
58950997Sbostic 	for (bp = (u_short *)rbufp->page, n = *bp++, ndx = 1; ndx < n;)
59050997Sbostic 		if (bp[1] >= REAL_KEY) {
59150997Sbostic 			/* Real key/data pair */
59250997Sbostic 			if (size == off - *bp &&
59358016Sbostic 			    memcmp(kp, rbufp->page + *bp, size) == 0)
59450997Sbostic 				goto found;
59550997Sbostic 			off = bp[1];
59646366Sbostic #ifdef HASH_STATISTICS
59750997Sbostic 			hash_collisions++;
59846366Sbostic #endif
59950997Sbostic 			bp += 2;
60050997Sbostic 			ndx += 2;
60150997Sbostic 		} else if (bp[1] == OVFLPAGE) {
60257586Sbostic 			rbufp = __get_buf(hashp, *bp, rbufp, 0);
60350997Sbostic 			if (!rbufp) {
60450997Sbostic 				save_bufp->flags &= ~BUF_PIN;
60550997Sbostic 				return (ERROR);
60650997Sbostic 			}
60750997Sbostic 			/* FOR LOOP INIT */
60850997Sbostic 			bp = (u_short *)rbufp->page;
60950997Sbostic 			n = *bp++;
61050997Sbostic 			ndx = 1;
61150997Sbostic 			off = hashp->BSIZE;
61250997Sbostic 		} else if (bp[1] < REAL_KEY) {
61357586Sbostic 			if ((ndx =
61457586Sbostic 			    __find_bigpair(hashp, rbufp, ndx, kp, size)) > 0)
61550997Sbostic 				goto found;
61650997Sbostic 			if (ndx == -2) {
61750997Sbostic 				bufp = rbufp;
61857586Sbostic 				if (!(pageno =
61957586Sbostic 				    __find_last_page(hashp, &bufp))) {
62050997Sbostic 					ndx = 0;
62150997Sbostic 					rbufp = bufp;
62250997Sbostic 					break;	/* FOR */
62350997Sbostic 				}
62457586Sbostic 				rbufp = __get_buf(hashp, pageno, bufp, 0);
62550997Sbostic 				if (!rbufp) {
62650997Sbostic 					save_bufp->flags &= ~BUF_PIN;
62750997Sbostic 					return (ERROR);
62850997Sbostic 				}
62950997Sbostic 				/* FOR LOOP INIT */
63050997Sbostic 				bp = (u_short *)rbufp->page;
63150997Sbostic 				n = *bp++;
63250997Sbostic 				ndx = 1;
63350997Sbostic 				off = hashp->BSIZE;
63450997Sbostic 			} else {
63550997Sbostic 				save_bufp->flags &= ~BUF_PIN;
63650997Sbostic 				return (ERROR);
63750997Sbostic 			}
63846457Sbostic 		}
63946366Sbostic 
64046366Sbostic 	/* Not found */
64150997Sbostic 	switch (action) {
64250997Sbostic 	case HASH_PUT:
64350997Sbostic 	case HASH_PUTNEW:
64457586Sbostic 		if (__addel(hashp, rbufp, key, val)) {
64550997Sbostic 			save_bufp->flags &= ~BUF_PIN;
64650997Sbostic 			return (ERROR);
64746366Sbostic 		} else {
64850997Sbostic 			save_bufp->flags &= ~BUF_PIN;
64950997Sbostic 			return (SUCCESS);
65046366Sbostic 		}
65150997Sbostic 	case HASH_GET:
65250997Sbostic 	case HASH_DELETE:
65350997Sbostic 	default:
65446457Sbostic 		save_bufp->flags &= ~BUF_PIN;
65550997Sbostic 		return (ABNORMAL);
65646366Sbostic 	}
65746366Sbostic 
65846366Sbostic found:
65946366Sbostic 	switch (action) {
66050997Sbostic 	case HASH_PUTNEW:
66146457Sbostic 		save_bufp->flags &= ~BUF_PIN;
66250997Sbostic 		return (ABNORMAL);
66350997Sbostic 	case HASH_GET:
66446366Sbostic 		bp = (u_short *)rbufp->page;
66551072Sbostic 		if (bp[ndx + 1] < REAL_KEY) {
66657586Sbostic 			if (__big_return(hashp, rbufp, ndx, val, 0))
66751057Sbostic 				return (ERROR);
66851072Sbostic 		} else {
66950997Sbostic 			val->data = (u_char *)rbufp->page + (int)bp[ndx + 1];
67050997Sbostic 			val->size = bp[ndx] - bp[ndx + 1];
67146366Sbostic 		}
67246366Sbostic 		break;
67350997Sbostic 	case HASH_PUT:
67457586Sbostic 		if ((__delpair(hashp, rbufp, ndx)) ||
67557586Sbostic 		    (__addel(hashp, rbufp, key, val))) {
67650997Sbostic 			save_bufp->flags &= ~BUF_PIN;
67750997Sbostic 			return (ERROR);
67846457Sbostic 		}
67946366Sbostic 		break;
68050997Sbostic 	case HASH_DELETE:
68157586Sbostic 		if (__delpair(hashp, rbufp, ndx))
68250997Sbostic 			return (ERROR);
68346366Sbostic 		break;
68457586Sbostic 	default:
68557586Sbostic 		abort();
68646366Sbostic 	}
68746457Sbostic 	save_bufp->flags &= ~BUF_PIN;
68846366Sbostic 	return (SUCCESS);
68946366Sbostic }
69046366Sbostic 
69146366Sbostic static int
69246366Sbostic hash_seq(dbp, key, data, flag)
69350997Sbostic 	const DB *dbp;
69450997Sbostic 	DBT *key, *data;
69550997Sbostic 	u_int flag;
69646366Sbostic {
69750997Sbostic 	register u_int bucket;
69850997Sbostic 	register BUFHEAD *bufp;
69957586Sbostic 	HTAB *hashp;
70050997Sbostic 	u_short *bp, ndx;
70146366Sbostic 
70257586Sbostic 	hashp = (HTAB *)dbp->internal;
70350997Sbostic 	if (flag && flag != R_FIRST && flag != R_NEXT) {
70450997Sbostic 		hashp->errno = errno = EINVAL;
70550997Sbostic 		return (ERROR);
70646366Sbostic 	}
70746366Sbostic #ifdef HASH_STATISTICS
70846366Sbostic 	hash_accesses++;
70946366Sbostic #endif
71050997Sbostic 	if ((hashp->cbucket < 0) || (flag == R_FIRST)) {
71150997Sbostic 		hashp->cbucket = 0;
71250997Sbostic 		hashp->cndx = 1;
71350997Sbostic 		hashp->cpage = NULL;
71446366Sbostic 	}
71546366Sbostic 
71655874Sbostic 	for (bp = NULL; !bp || !bp[0]; ) {
71755452Sbostic 		if (!(bufp = hashp->cpage)) {
71855452Sbostic 			for (bucket = hashp->cbucket;
71955452Sbostic 			    bucket <= hashp->MAX_BUCKET;
72055452Sbostic 			    bucket++, hashp->cndx = 1) {
72157586Sbostic 				bufp = __get_buf(hashp, bucket, NULL, 0);
72255452Sbostic 				if (!bufp)
72355452Sbostic 					return (ERROR);
72455452Sbostic 				hashp->cpage = bufp;
72555452Sbostic 				bp = (u_short *)bufp->page;
72655452Sbostic 				if (bp[0])
72755452Sbostic 					break;
72855452Sbostic 			}
72955452Sbostic 			hashp->cbucket = bucket;
73055452Sbostic 			if (hashp->cbucket > hashp->MAX_BUCKET) {
73155452Sbostic 				hashp->cbucket = -1;
73255452Sbostic 				return (ABNORMAL);
73355452Sbostic 			}
73455452Sbostic 		} else
73555452Sbostic 			bp = (u_short *)hashp->cpage->page;
73655452Sbostic 
73755452Sbostic #ifdef DEBUG
73855452Sbostic 		assert(bp);
73955452Sbostic 		assert(bufp);
74055452Sbostic #endif
74155452Sbostic 		while (bp[hashp->cndx + 1] == OVFLPAGE) {
74255452Sbostic 			bufp = hashp->cpage =
74357586Sbostic 			    __get_buf(hashp, bp[hashp->cndx], bufp, 0);
74450997Sbostic 			if (!bufp)
74550997Sbostic 				return (ERROR);
74655452Sbostic 			bp = (u_short *)(bufp->page);
74755452Sbostic 			hashp->cndx = 1;
74850997Sbostic 		}
74955874Sbostic 		if (!bp[0]) {
75055452Sbostic 			hashp->cpage = NULL;
75155874Sbostic 			++hashp->cbucket;
75255874Sbostic 		}
75346366Sbostic 	}
75446366Sbostic 	ndx = hashp->cndx;
75550997Sbostic 	if (bp[ndx + 1] < REAL_KEY) {
75657586Sbostic 		if (__big_keydata(hashp, bufp, key, data, 1))
75750997Sbostic 			return (ERROR);
75846366Sbostic 	} else {
75950997Sbostic 		key->data = (u_char *)hashp->cpage->page + bp[ndx];
76050997Sbostic 		key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
76150997Sbostic 		data->data = (u_char *)hashp->cpage->page + bp[ndx + 1];
76250997Sbostic 		data->size = bp[ndx] - bp[ndx + 1];
76350997Sbostic 		ndx += 2;
76450997Sbostic 		if (ndx > bp[0]) {
76550997Sbostic 			hashp->cpage = NULL;
76650997Sbostic 			hashp->cbucket++;
76750997Sbostic 			hashp->cndx = 1;
76850997Sbostic 		} else
76950997Sbostic 			hashp->cndx = ndx;
77046366Sbostic 	}
77146366Sbostic 	return (SUCCESS);
77246366Sbostic }
77346366Sbostic 
77446366Sbostic /********************************* UTILITIES ************************/
77550997Sbostic 
77646366Sbostic /*
77750997Sbostic  * Returns:
77850997Sbostic  *	 0 ==> OK
77950997Sbostic  *	-1 ==> Error
78050997Sbostic  */
78146366Sbostic extern int
78257586Sbostic __expand_table(hashp)
78357586Sbostic 	HTAB *hashp;
78446366Sbostic {
78550997Sbostic 	u_int old_bucket, new_bucket;
78650997Sbostic 	int dirsize, new_segnum, spare_ndx;
78750997Sbostic 
78846366Sbostic #ifdef HASH_STATISTICS
78946366Sbostic 	hash_expansions++;
79046366Sbostic #endif
79146366Sbostic 	new_bucket = ++hashp->MAX_BUCKET;
79246366Sbostic 	old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
79346366Sbostic 
79446366Sbostic 	new_segnum = new_bucket >> hashp->SSHIFT;
79546366Sbostic 
79646366Sbostic 	/* Check if we need a new segment */
79750997Sbostic 	if (new_segnum >= hashp->nsegs) {
79850997Sbostic 		/* Check if we need to expand directory */
79950997Sbostic 		if (new_segnum >= hashp->DSIZE) {
80050997Sbostic 			/* Reallocate directory */
80150997Sbostic 			dirsize = hashp->DSIZE * sizeof(SEGMENT *);
80250997Sbostic 			if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1))
80350997Sbostic 				return (-1);
80450997Sbostic 			hashp->DSIZE = dirsize << 1;
80546366Sbostic 		}
80650997Sbostic 		if (!(hashp->dir[new_segnum] =
80750997Sbostic 			calloc(hashp->SGSIZE, sizeof(SEGMENT))))
80850997Sbostic 			return (-1);
80950997Sbostic 		hashp->exsegs++;
81050997Sbostic 		hashp->nsegs++;
81146366Sbostic 	}
81246366Sbostic 	/*
81350997Sbostic 	 * If the split point is increasing (MAX_BUCKET's log base 2
81450997Sbostic 	 * * increases), we need to copy the current contents of the spare
81550997Sbostic 	 * split bucket to the next bucket.
81650997Sbostic 	 */
81752001Sbostic 	spare_ndx = __log2(hashp->MAX_BUCKET + 1);
81852001Sbostic 	if (spare_ndx > hashp->OVFL_POINT) {
81951061Sbostic 		hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT];
82051061Sbostic 		hashp->OVFL_POINT = spare_ndx;
82151061Sbostic 	}
82251061Sbostic 
82350997Sbostic 	if (new_bucket > hashp->HIGH_MASK) {
82450997Sbostic 		/* Starting a new doubling */
82550997Sbostic 		hashp->LOW_MASK = hashp->HIGH_MASK;
82650997Sbostic 		hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
82746366Sbostic 	}
82850997Sbostic 	/* Relocate records to the new bucket */
82957586Sbostic 	return (__split_page(hashp, old_bucket, new_bucket));
83050997Sbostic }
83146366Sbostic 
83246366Sbostic /*
83350997Sbostic  * If realloc guarantees that the pointer is not destroyed if the realloc
83450997Sbostic  * fails, then this routine can go away.
83550997Sbostic  */
83650997Sbostic static void *
83750997Sbostic hash_realloc(p_ptr, oldsize, newsize)
83850997Sbostic 	SEGMENT **p_ptr;
83950997Sbostic 	int oldsize, newsize;
84046366Sbostic {
84150997Sbostic 	register void *p;
84246366Sbostic 
84350997Sbostic 	if (p = malloc(newsize)) {
84458016Sbostic 		memmove(p, *p_ptr, oldsize);
84563747Sbostic 		memset((char *)p + oldsize, 0, newsize - oldsize);
84646366Sbostic 		free(*p_ptr);
84746366Sbostic 		*p_ptr = p;
84846366Sbostic 	}
84946366Sbostic 	return (p);
85046366Sbostic }
85146366Sbostic 
85247251Sbostic extern u_int
85357586Sbostic __call_hash(hashp, k, len)
85457586Sbostic 	HTAB *hashp;
85550997Sbostic 	char *k;
85650997Sbostic 	int len;
85746366Sbostic {
85850997Sbostic 	int n, bucket;
85950997Sbostic 
86046366Sbostic 	n = hashp->hash(k, len);
86146366Sbostic 	bucket = n & hashp->HIGH_MASK;
86250997Sbostic 	if (bucket > hashp->MAX_BUCKET)
86350997Sbostic 		bucket = bucket & hashp->LOW_MASK;
86450997Sbostic 	return (bucket);
86546366Sbostic }
86646366Sbostic 
86746366Sbostic /*
86850997Sbostic  * Allocate segment table.  On error, destroy the table and set errno.
86950997Sbostic  *
87050997Sbostic  * Returns 0 on success
87150997Sbostic  */
87246366Sbostic static int
87357586Sbostic alloc_segs(hashp, nsegs)
87457586Sbostic 	HTAB *hashp;
87550997Sbostic 	int nsegs;
87646366Sbostic {
87750997Sbostic 	register int i;
87850997Sbostic 	register SEGMENT store;
87946366Sbostic 
88050997Sbostic 	int save_errno;
88146366Sbostic 
88250997Sbostic 	if (!(hashp->dir = calloc(hashp->DSIZE, sizeof(SEGMENT *)))) {
88350997Sbostic 		save_errno = errno;
88457586Sbostic 		(void)hdestroy(hashp);
88550997Sbostic 		errno = save_errno;
88650997Sbostic 		return (-1);
88750997Sbostic 	}
88850997Sbostic 	/* Allocate segments */
88950997Sbostic 	store = calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT));
89050997Sbostic 	if (!store) {
89150997Sbostic 		save_errno = errno;
89257586Sbostic 		(void)hdestroy(hashp);
89350997Sbostic 		errno = save_errno;
89450997Sbostic 		return (-1);
89550997Sbostic 	}
89650997Sbostic 	for (i = 0; i < nsegs; i++, hashp->nsegs++)
89750997Sbostic 		hashp->dir[i] = &store[i << hashp->SSHIFT];
89850997Sbostic 	return (0);
89946366Sbostic }
90046366Sbostic 
90150997Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
90246366Sbostic /*
90350997Sbostic  * Hashp->hdr needs to be byteswapped.
90450997Sbostic  */
90546366Sbostic static void
90650997Sbostic swap_header_copy(srcp, destp)
90750997Sbostic 	HASHHDR *srcp, *destp;
90846366Sbostic {
90950997Sbostic 	int i;
91046366Sbostic 
91150997Sbostic 	BLSWAP_COPY(srcp->magic, destp->magic);
91250997Sbostic 	BLSWAP_COPY(srcp->version, destp->version);
91350997Sbostic 	BLSWAP_COPY(srcp->lorder, destp->lorder);
91450997Sbostic 	BLSWAP_COPY(srcp->bsize, destp->bsize);
91550997Sbostic 	BLSWAP_COPY(srcp->bshift, destp->bshift);
91650997Sbostic 	BLSWAP_COPY(srcp->dsize, destp->dsize);
91750997Sbostic 	BLSWAP_COPY(srcp->ssize, destp->ssize);
91850997Sbostic 	BLSWAP_COPY(srcp->sshift, destp->sshift);
91951061Sbostic 	BLSWAP_COPY(srcp->ovfl_point, destp->ovfl_point);
92051061Sbostic 	BLSWAP_COPY(srcp->last_freed, destp->last_freed);
92150997Sbostic 	BLSWAP_COPY(srcp->max_bucket, destp->max_bucket);
92250997Sbostic 	BLSWAP_COPY(srcp->high_mask, destp->high_mask);
92350997Sbostic 	BLSWAP_COPY(srcp->low_mask, destp->low_mask);
92450997Sbostic 	BLSWAP_COPY(srcp->ffactor, destp->ffactor);
92550997Sbostic 	BLSWAP_COPY(srcp->nkeys, destp->nkeys);
92650997Sbostic 	BLSWAP_COPY(srcp->hdrpages, destp->hdrpages);
92750997Sbostic 	BLSWAP_COPY(srcp->h_charkey, destp->h_charkey);
92850997Sbostic 	for (i = 0; i < NCACHED; i++) {
92950997Sbostic 		BLSWAP_COPY(srcp->spares[i], destp->spares[i]);
93050997Sbostic 		BSSWAP_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
93150997Sbostic 	}
93246366Sbostic }
93346366Sbostic 
93446366Sbostic static void
93557586Sbostic swap_header(hashp)
93657586Sbostic 	HTAB *hashp;
93746366Sbostic {
93850997Sbostic 	HASHHDR *hdrp;
93950997Sbostic 	int i;
94046366Sbostic 
94150997Sbostic 	hdrp = &hashp->hdr;
94246366Sbostic 
94350997Sbostic 	BLSWAP(hdrp->magic);
94450997Sbostic 	BLSWAP(hdrp->version);
94550997Sbostic 	BLSWAP(hdrp->lorder);
94650997Sbostic 	BLSWAP(hdrp->bsize);
94750997Sbostic 	BLSWAP(hdrp->bshift);
94850997Sbostic 	BLSWAP(hdrp->dsize);
94950997Sbostic 	BLSWAP(hdrp->ssize);
95050997Sbostic 	BLSWAP(hdrp->sshift);
95151061Sbostic 	BLSWAP(hdrp->ovfl_point);
95251061Sbostic 	BLSWAP(hdrp->last_freed);
95350997Sbostic 	BLSWAP(hdrp->max_bucket);
95450997Sbostic 	BLSWAP(hdrp->high_mask);
95550997Sbostic 	BLSWAP(hdrp->low_mask);
95650997Sbostic 	BLSWAP(hdrp->ffactor);
95750997Sbostic 	BLSWAP(hdrp->nkeys);
95850997Sbostic 	BLSWAP(hdrp->hdrpages);
95950997Sbostic 	BLSWAP(hdrp->h_charkey);
96050997Sbostic 	for (i = 0; i < NCACHED; i++) {
96150997Sbostic 		BLSWAP(hdrp->spares[i]);
96250997Sbostic 		BSSWAP(hdrp->bitmaps[i]);
96350997Sbostic 	}
96446366Sbostic }
96550997Sbostic #endif
966