xref: /csrg-svn/lib/libc/db/hash/hash.c (revision 66215)
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*66215Sbostic static char sccsid[] = "@(#)hash.c	8.7 (Berkeley) 02/21/94";
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 
85*66215Sbostic 	if (!(hashp = (HTAB *)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);
13064708Sbostic #define	OLDHASHVERSION	1
13164708Sbostic 		if (hashp->VERSION != HASHVERSION &&
13264708Sbostic 		    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;
168*66215Sbostic 	if (!(dbp = (DB *)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
hash_close(dbp)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
hash_fd(dbp)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 *
init_hash(hashp,file,info)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
init_htab(hashp,nelem)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
hdestroy(hashp)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 
41065725Sbostic 	free(hashp);
41165725Sbostic 
41250997Sbostic 	if (save_errno) {
41350997Sbostic 		errno = save_errno;
41450997Sbostic 		return (ERROR);
41546366Sbostic 	}
41650997Sbostic 	return (SUCCESS);
41746366Sbostic }
41850997Sbostic /*
41950997Sbostic  * Write modified pages to disk
42050997Sbostic  *
42150997Sbostic  * Returns:
42250997Sbostic  *	 0 == OK
42350997Sbostic  *	-1 ERROR
42450997Sbostic  */
42546366Sbostic static int
hash_sync(dbp,flags)42660060Sbostic hash_sync(dbp, flags)
42750997Sbostic 	const DB *dbp;
42860060Sbostic 	u_int flags;
42946366Sbostic {
43057586Sbostic 	HTAB *hashp;
43157586Sbostic 
43260060Sbostic 	if (flags != 0) {
43360060Sbostic 		errno = EINVAL;
43460060Sbostic 		return (ERROR);
43560060Sbostic 	}
43660060Sbostic 
43750997Sbostic 	if (!dbp)
43850997Sbostic 		return (ERROR);
43957586Sbostic 
44046366Sbostic 	hashp = (HTAB *)dbp->internal;
44150997Sbostic 	if (!hashp->save_file)
44250997Sbostic 		return (0);
44357586Sbostic 	if (__buf_free(hashp, 0, 1) || flush_meta(hashp))
44450997Sbostic 		return (ERROR);
44546366Sbostic 	hashp->new_file = 0;
44650997Sbostic 	return (0);
44746366Sbostic }
44846366Sbostic 
44946366Sbostic /*
45050997Sbostic  * Returns:
45150997Sbostic  *	 0 == OK
45250997Sbostic  *	-1 indicates that errno should be set
45350997Sbostic  */
45446366Sbostic static int
flush_meta(hashp)45557586Sbostic flush_meta(hashp)
45657586Sbostic 	HTAB *hashp;
45746366Sbostic {
45851814Smarc 	HASHHDR *whdrp;
45951814Smarc #if BYTE_ORDER == LITTLE_ENDIAN
46051814Smarc 	HASHHDR whdr;
46151814Smarc #endif
46250997Sbostic 	int fp, i, wsize;
46346366Sbostic 
46450997Sbostic 	if (!hashp->save_file)
46550997Sbostic 		return (0);
46646366Sbostic 	hashp->MAGIC = HASHMAGIC;
46751061Sbostic 	hashp->VERSION = HASHVERSION;
46850997Sbostic 	hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY));
46946366Sbostic 
47046366Sbostic 	fp = hashp->fp;
47146366Sbostic 	whdrp = &hashp->hdr;
47246366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
47346366Sbostic 	whdrp = &whdr;
47450997Sbostic 	swap_header_copy(&hashp->hdr, whdrp);
47546366Sbostic #endif
47656669Sbostic 	if ((lseek(fp, (off_t)0, SEEK_SET) == -1) ||
47750997Sbostic 	    ((wsize = write(fp, whdrp, sizeof(HASHHDR))) == -1))
47850997Sbostic 		return (-1);
47950997Sbostic 	else
48050997Sbostic 		if (wsize != sizeof(HASHHDR)) {
48150997Sbostic 			errno = EFTYPE;
48250997Sbostic 			hashp->errno = errno;
48350997Sbostic 			return (-1);
48446366Sbostic 		}
48550997Sbostic 	for (i = 0; i < NCACHED; i++)
48650997Sbostic 		if (hashp->mapp[i])
48757586Sbostic 			if (__put_page(hashp, (char *)hashp->mapp[i],
48850997Sbostic 				hashp->BITMAPS[i], 0, 1))
48950997Sbostic 				return (-1);
49050997Sbostic 	return (0);
49146366Sbostic }
49250997Sbostic 
49346366Sbostic /*******************************SEARCH ROUTINES *****************************/
49446366Sbostic /*
49550997Sbostic  * All the access routines return
49650997Sbostic  *
49750997Sbostic  * Returns:
49850997Sbostic  *	 0 on SUCCESS
49950997Sbostic  *	 1 to indicate an external ERROR (i.e. key not found, etc)
50050997Sbostic  *	-1 to indicate an internal ERROR (i.e. out of memory, etc)
50150997Sbostic  */
50246366Sbostic static int
hash_get(dbp,key,data,flag)50350997Sbostic hash_get(dbp, key, data, flag)
50450997Sbostic 	const DB *dbp;
50551057Sbostic 	const DBT *key;
50651057Sbostic 	DBT *data;
50750997Sbostic 	u_int flag;
50846366Sbostic {
50957586Sbostic 	HTAB *hashp;
51057586Sbostic 
51157586Sbostic 	hashp = (HTAB *)dbp->internal;
51250997Sbostic 	if (flag) {
51350997Sbostic 		hashp->errno = errno = EINVAL;
51450997Sbostic 		return (ERROR);
51550997Sbostic 	}
51657586Sbostic 	return (hash_access(hashp, HASH_GET, (DBT *)key, data));
51746366Sbostic }
51846366Sbostic 
51946366Sbostic static int
hash_put(dbp,key,data,flag)52050997Sbostic hash_put(dbp, key, data, flag)
52150997Sbostic 	const DB *dbp;
52256893Sbostic 	DBT *key;
52356893Sbostic 	const DBT *data;
52450997Sbostic 	u_int flag;
52546366Sbostic {
52657586Sbostic 	HTAB *hashp;
52757586Sbostic 
52857586Sbostic 	hashp = (HTAB *)dbp->internal;
52950997Sbostic 	if (flag && flag != R_NOOVERWRITE) {
53050997Sbostic 		hashp->errno = errno = EINVAL;
53150997Sbostic 		return (ERROR);
53250997Sbostic 	}
53350997Sbostic 	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
53450997Sbostic 		hashp->errno = errno = EPERM;
53550997Sbostic 		return (ERROR);
53650997Sbostic 	}
53757586Sbostic 	return (hash_access(hashp, flag == R_NOOVERWRITE ?
53850997Sbostic 	    HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));
53946366Sbostic }
54046366Sbostic 
54146366Sbostic static int
hash_delete(dbp,key,flag)54250997Sbostic hash_delete(dbp, key, flag)
54350997Sbostic 	const DB *dbp;
54450997Sbostic 	const DBT *key;
54550997Sbostic 	u_int flag;		/* Ignored */
54646366Sbostic {
54757586Sbostic 	HTAB *hashp;
54857586Sbostic 
54957586Sbostic 	hashp = (HTAB *)dbp->internal;
55050997Sbostic 	if (flag && flag != R_CURSOR) {
55150997Sbostic 		hashp->errno = errno = EINVAL;
55250997Sbostic 		return (ERROR);
55350997Sbostic 	}
55450997Sbostic 	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
55550997Sbostic 		hashp->errno = errno = EPERM;
55650997Sbostic 		return (ERROR);
55750997Sbostic 	}
55857586Sbostic 	return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
55946366Sbostic }
56046366Sbostic 
56146366Sbostic /*
56250997Sbostic  * Assume that hashp has been set in wrapper routine.
56350997Sbostic  */
56446366Sbostic static int
hash_access(hashp,action,key,val)56557586Sbostic hash_access(hashp, action, key, val)
56657586Sbostic 	HTAB *hashp;
56750997Sbostic 	ACTION action;
56850997Sbostic 	DBT *key, *val;
56946366Sbostic {
57050997Sbostic 	register BUFHEAD *rbufp;
57150997Sbostic 	BUFHEAD *bufp, *save_bufp;
57250997Sbostic 	register u_short *bp;
57350997Sbostic 	register int n, ndx, off, size;
57450997Sbostic 	register char *kp;
57550997Sbostic 	u_short pageno;
57646366Sbostic 
57746366Sbostic #ifdef HASH_STATISTICS
57846366Sbostic 	hash_accesses++;
57946366Sbostic #endif
58046366Sbostic 
58150997Sbostic 	off = hashp->BSIZE;
58246366Sbostic 	size = key->size;
58346950Sbostic 	kp = (char *)key->data;
58457586Sbostic 	rbufp = __get_buf(hashp, __call_hash(hashp, kp, size), NULL, 0);
58550997Sbostic 	if (!rbufp)
58650997Sbostic 		return (ERROR);
58746457Sbostic 	save_bufp = rbufp;
58846366Sbostic 
58946457Sbostic 	/* Pin the bucket chain */
59046457Sbostic 	rbufp->flags |= BUF_PIN;
59150997Sbostic 	for (bp = (u_short *)rbufp->page, n = *bp++, ndx = 1; ndx < n;)
59250997Sbostic 		if (bp[1] >= REAL_KEY) {
59350997Sbostic 			/* Real key/data pair */
59450997Sbostic 			if (size == off - *bp &&
59558016Sbostic 			    memcmp(kp, rbufp->page + *bp, size) == 0)
59650997Sbostic 				goto found;
59750997Sbostic 			off = bp[1];
59846366Sbostic #ifdef HASH_STATISTICS
59950997Sbostic 			hash_collisions++;
60046366Sbostic #endif
60150997Sbostic 			bp += 2;
60250997Sbostic 			ndx += 2;
60350997Sbostic 		} else if (bp[1] == OVFLPAGE) {
60457586Sbostic 			rbufp = __get_buf(hashp, *bp, rbufp, 0);
60550997Sbostic 			if (!rbufp) {
60650997Sbostic 				save_bufp->flags &= ~BUF_PIN;
60750997Sbostic 				return (ERROR);
60850997Sbostic 			}
60950997Sbostic 			/* FOR LOOP INIT */
61050997Sbostic 			bp = (u_short *)rbufp->page;
61150997Sbostic 			n = *bp++;
61250997Sbostic 			ndx = 1;
61350997Sbostic 			off = hashp->BSIZE;
61450997Sbostic 		} else if (bp[1] < REAL_KEY) {
61557586Sbostic 			if ((ndx =
61657586Sbostic 			    __find_bigpair(hashp, rbufp, ndx, kp, size)) > 0)
61750997Sbostic 				goto found;
61850997Sbostic 			if (ndx == -2) {
61950997Sbostic 				bufp = rbufp;
62057586Sbostic 				if (!(pageno =
62157586Sbostic 				    __find_last_page(hashp, &bufp))) {
62250997Sbostic 					ndx = 0;
62350997Sbostic 					rbufp = bufp;
62450997Sbostic 					break;	/* FOR */
62550997Sbostic 				}
62657586Sbostic 				rbufp = __get_buf(hashp, pageno, bufp, 0);
62750997Sbostic 				if (!rbufp) {
62850997Sbostic 					save_bufp->flags &= ~BUF_PIN;
62950997Sbostic 					return (ERROR);
63050997Sbostic 				}
63150997Sbostic 				/* FOR LOOP INIT */
63250997Sbostic 				bp = (u_short *)rbufp->page;
63350997Sbostic 				n = *bp++;
63450997Sbostic 				ndx = 1;
63550997Sbostic 				off = hashp->BSIZE;
63650997Sbostic 			} else {
63750997Sbostic 				save_bufp->flags &= ~BUF_PIN;
63850997Sbostic 				return (ERROR);
63950997Sbostic 			}
64046457Sbostic 		}
64146366Sbostic 
64246366Sbostic 	/* Not found */
64350997Sbostic 	switch (action) {
64450997Sbostic 	case HASH_PUT:
64550997Sbostic 	case HASH_PUTNEW:
64657586Sbostic 		if (__addel(hashp, rbufp, key, val)) {
64750997Sbostic 			save_bufp->flags &= ~BUF_PIN;
64850997Sbostic 			return (ERROR);
64946366Sbostic 		} else {
65050997Sbostic 			save_bufp->flags &= ~BUF_PIN;
65150997Sbostic 			return (SUCCESS);
65246366Sbostic 		}
65350997Sbostic 	case HASH_GET:
65450997Sbostic 	case HASH_DELETE:
65550997Sbostic 	default:
65646457Sbostic 		save_bufp->flags &= ~BUF_PIN;
65750997Sbostic 		return (ABNORMAL);
65846366Sbostic 	}
65946366Sbostic 
66046366Sbostic found:
66146366Sbostic 	switch (action) {
66250997Sbostic 	case HASH_PUTNEW:
66346457Sbostic 		save_bufp->flags &= ~BUF_PIN;
66450997Sbostic 		return (ABNORMAL);
66550997Sbostic 	case HASH_GET:
66646366Sbostic 		bp = (u_short *)rbufp->page;
66751072Sbostic 		if (bp[ndx + 1] < REAL_KEY) {
66857586Sbostic 			if (__big_return(hashp, rbufp, ndx, val, 0))
66951057Sbostic 				return (ERROR);
67051072Sbostic 		} else {
67150997Sbostic 			val->data = (u_char *)rbufp->page + (int)bp[ndx + 1];
67250997Sbostic 			val->size = bp[ndx] - bp[ndx + 1];
67346366Sbostic 		}
67446366Sbostic 		break;
67550997Sbostic 	case HASH_PUT:
67657586Sbostic 		if ((__delpair(hashp, rbufp, ndx)) ||
67757586Sbostic 		    (__addel(hashp, rbufp, key, val))) {
67850997Sbostic 			save_bufp->flags &= ~BUF_PIN;
67950997Sbostic 			return (ERROR);
68046457Sbostic 		}
68146366Sbostic 		break;
68250997Sbostic 	case HASH_DELETE:
68357586Sbostic 		if (__delpair(hashp, rbufp, ndx))
68450997Sbostic 			return (ERROR);
68546366Sbostic 		break;
68657586Sbostic 	default:
68757586Sbostic 		abort();
68846366Sbostic 	}
68946457Sbostic 	save_bufp->flags &= ~BUF_PIN;
69046366Sbostic 	return (SUCCESS);
69146366Sbostic }
69246366Sbostic 
69346366Sbostic static int
hash_seq(dbp,key,data,flag)69446366Sbostic hash_seq(dbp, key, data, flag)
69550997Sbostic 	const DB *dbp;
69650997Sbostic 	DBT *key, *data;
69750997Sbostic 	u_int flag;
69846366Sbostic {
69950997Sbostic 	register u_int bucket;
70050997Sbostic 	register BUFHEAD *bufp;
70157586Sbostic 	HTAB *hashp;
70250997Sbostic 	u_short *bp, ndx;
70346366Sbostic 
70457586Sbostic 	hashp = (HTAB *)dbp->internal;
70550997Sbostic 	if (flag && flag != R_FIRST && flag != R_NEXT) {
70650997Sbostic 		hashp->errno = errno = EINVAL;
70750997Sbostic 		return (ERROR);
70846366Sbostic 	}
70946366Sbostic #ifdef HASH_STATISTICS
71046366Sbostic 	hash_accesses++;
71146366Sbostic #endif
71250997Sbostic 	if ((hashp->cbucket < 0) || (flag == R_FIRST)) {
71350997Sbostic 		hashp->cbucket = 0;
71450997Sbostic 		hashp->cndx = 1;
71550997Sbostic 		hashp->cpage = NULL;
71646366Sbostic 	}
71746366Sbostic 
71855874Sbostic 	for (bp = NULL; !bp || !bp[0]; ) {
71955452Sbostic 		if (!(bufp = hashp->cpage)) {
72055452Sbostic 			for (bucket = hashp->cbucket;
72155452Sbostic 			    bucket <= hashp->MAX_BUCKET;
72255452Sbostic 			    bucket++, hashp->cndx = 1) {
72357586Sbostic 				bufp = __get_buf(hashp, bucket, NULL, 0);
72455452Sbostic 				if (!bufp)
72555452Sbostic 					return (ERROR);
72655452Sbostic 				hashp->cpage = bufp;
72755452Sbostic 				bp = (u_short *)bufp->page;
72855452Sbostic 				if (bp[0])
72955452Sbostic 					break;
73055452Sbostic 			}
73155452Sbostic 			hashp->cbucket = bucket;
73255452Sbostic 			if (hashp->cbucket > hashp->MAX_BUCKET) {
73355452Sbostic 				hashp->cbucket = -1;
73455452Sbostic 				return (ABNORMAL);
73555452Sbostic 			}
73655452Sbostic 		} else
73755452Sbostic 			bp = (u_short *)hashp->cpage->page;
73855452Sbostic 
73955452Sbostic #ifdef DEBUG
74055452Sbostic 		assert(bp);
74155452Sbostic 		assert(bufp);
74255452Sbostic #endif
74355452Sbostic 		while (bp[hashp->cndx + 1] == OVFLPAGE) {
74455452Sbostic 			bufp = hashp->cpage =
74557586Sbostic 			    __get_buf(hashp, bp[hashp->cndx], bufp, 0);
74650997Sbostic 			if (!bufp)
74750997Sbostic 				return (ERROR);
74855452Sbostic 			bp = (u_short *)(bufp->page);
74955452Sbostic 			hashp->cndx = 1;
75050997Sbostic 		}
75155874Sbostic 		if (!bp[0]) {
75255452Sbostic 			hashp->cpage = NULL;
75355874Sbostic 			++hashp->cbucket;
75455874Sbostic 		}
75546366Sbostic 	}
75646366Sbostic 	ndx = hashp->cndx;
75750997Sbostic 	if (bp[ndx + 1] < REAL_KEY) {
75857586Sbostic 		if (__big_keydata(hashp, bufp, key, data, 1))
75950997Sbostic 			return (ERROR);
76046366Sbostic 	} else {
76150997Sbostic 		key->data = (u_char *)hashp->cpage->page + bp[ndx];
76250997Sbostic 		key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
76350997Sbostic 		data->data = (u_char *)hashp->cpage->page + bp[ndx + 1];
76450997Sbostic 		data->size = bp[ndx] - bp[ndx + 1];
76550997Sbostic 		ndx += 2;
76650997Sbostic 		if (ndx > bp[0]) {
76750997Sbostic 			hashp->cpage = NULL;
76850997Sbostic 			hashp->cbucket++;
76950997Sbostic 			hashp->cndx = 1;
77050997Sbostic 		} else
77150997Sbostic 			hashp->cndx = ndx;
77246366Sbostic 	}
77346366Sbostic 	return (SUCCESS);
77446366Sbostic }
77546366Sbostic 
77646366Sbostic /********************************* UTILITIES ************************/
77750997Sbostic 
77846366Sbostic /*
77950997Sbostic  * Returns:
78050997Sbostic  *	 0 ==> OK
78150997Sbostic  *	-1 ==> Error
78250997Sbostic  */
78346366Sbostic extern int
78457586Sbostic __expand_table(hashp)
78557586Sbostic 	HTAB *hashp;
78646366Sbostic {
78750997Sbostic 	u_int old_bucket, new_bucket;
78850997Sbostic 	int dirsize, new_segnum, spare_ndx;
78950997Sbostic 
79046366Sbostic #ifdef HASH_STATISTICS
79146366Sbostic 	hash_expansions++;
79246366Sbostic #endif
79346366Sbostic 	new_bucket = ++hashp->MAX_BUCKET;
79446366Sbostic 	old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
79546366Sbostic 
79646366Sbostic 	new_segnum = new_bucket >> hashp->SSHIFT;
79746366Sbostic 
79846366Sbostic 	/* Check if we need a new segment */
79950997Sbostic 	if (new_segnum >= hashp->nsegs) {
80050997Sbostic 		/* Check if we need to expand directory */
80150997Sbostic 		if (new_segnum >= hashp->DSIZE) {
80250997Sbostic 			/* Reallocate directory */
80350997Sbostic 			dirsize = hashp->DSIZE * sizeof(SEGMENT *);
80450997Sbostic 			if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1))
80550997Sbostic 				return (-1);
80650997Sbostic 			hashp->DSIZE = dirsize << 1;
80746366Sbostic 		}
808*66215Sbostic 		if ((hashp->dir[new_segnum] =
809*66215Sbostic 		    (SEGMENT)calloc(hashp->SGSIZE, sizeof(SEGMENT))) == NULL)
81050997Sbostic 			return (-1);
81150997Sbostic 		hashp->exsegs++;
81250997Sbostic 		hashp->nsegs++;
81346366Sbostic 	}
81446366Sbostic 	/*
81550997Sbostic 	 * If the split point is increasing (MAX_BUCKET's log base 2
81650997Sbostic 	 * * increases), we need to copy the current contents of the spare
81750997Sbostic 	 * split bucket to the next bucket.
81850997Sbostic 	 */
81952001Sbostic 	spare_ndx = __log2(hashp->MAX_BUCKET + 1);
82052001Sbostic 	if (spare_ndx > hashp->OVFL_POINT) {
82151061Sbostic 		hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT];
82251061Sbostic 		hashp->OVFL_POINT = spare_ndx;
82351061Sbostic 	}
82451061Sbostic 
82550997Sbostic 	if (new_bucket > hashp->HIGH_MASK) {
82650997Sbostic 		/* Starting a new doubling */
82750997Sbostic 		hashp->LOW_MASK = hashp->HIGH_MASK;
82850997Sbostic 		hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
82946366Sbostic 	}
83050997Sbostic 	/* Relocate records to the new bucket */
83157586Sbostic 	return (__split_page(hashp, old_bucket, new_bucket));
83250997Sbostic }
83346366Sbostic 
83446366Sbostic /*
83550997Sbostic  * If realloc guarantees that the pointer is not destroyed if the realloc
83650997Sbostic  * fails, then this routine can go away.
83750997Sbostic  */
83850997Sbostic static void *
hash_realloc(p_ptr,oldsize,newsize)83950997Sbostic hash_realloc(p_ptr, oldsize, newsize)
84050997Sbostic 	SEGMENT **p_ptr;
84150997Sbostic 	int oldsize, newsize;
84246366Sbostic {
84350997Sbostic 	register void *p;
84446366Sbostic 
84550997Sbostic 	if (p = malloc(newsize)) {
84658016Sbostic 		memmove(p, *p_ptr, oldsize);
84763747Sbostic 		memset((char *)p + oldsize, 0, newsize - oldsize);
84846366Sbostic 		free(*p_ptr);
84946366Sbostic 		*p_ptr = p;
85046366Sbostic 	}
85146366Sbostic 	return (p);
85246366Sbostic }
85346366Sbostic 
85447251Sbostic extern u_int
85557586Sbostic __call_hash(hashp, k, len)
85657586Sbostic 	HTAB *hashp;
85750997Sbostic 	char *k;
85850997Sbostic 	int len;
85946366Sbostic {
86050997Sbostic 	int n, bucket;
86150997Sbostic 
86246366Sbostic 	n = hashp->hash(k, len);
86346366Sbostic 	bucket = n & hashp->HIGH_MASK;
86450997Sbostic 	if (bucket > hashp->MAX_BUCKET)
86550997Sbostic 		bucket = bucket & hashp->LOW_MASK;
86650997Sbostic 	return (bucket);
86746366Sbostic }
86846366Sbostic 
86946366Sbostic /*
87050997Sbostic  * Allocate segment table.  On error, destroy the table and set errno.
87150997Sbostic  *
87250997Sbostic  * Returns 0 on success
87350997Sbostic  */
87446366Sbostic static int
alloc_segs(hashp,nsegs)87557586Sbostic alloc_segs(hashp, nsegs)
87657586Sbostic 	HTAB *hashp;
87750997Sbostic 	int nsegs;
87846366Sbostic {
87950997Sbostic 	register int i;
88050997Sbostic 	register SEGMENT store;
88146366Sbostic 
88250997Sbostic 	int save_errno;
88346366Sbostic 
884*66215Sbostic 	if ((hashp->dir =
885*66215Sbostic 	    (SEGMENT *)calloc(hashp->DSIZE, sizeof(SEGMENT *))) == NULL) {
88650997Sbostic 		save_errno = errno;
88757586Sbostic 		(void)hdestroy(hashp);
88850997Sbostic 		errno = save_errno;
88950997Sbostic 		return (-1);
89050997Sbostic 	}
89150997Sbostic 	/* Allocate segments */
892*66215Sbostic 	if ((store =
893*66215Sbostic 	    (SEGMENT)calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT))) == NULL) {
89450997Sbostic 		save_errno = errno;
89557586Sbostic 		(void)hdestroy(hashp);
89650997Sbostic 		errno = save_errno;
89750997Sbostic 		return (-1);
89850997Sbostic 	}
89950997Sbostic 	for (i = 0; i < nsegs; i++, hashp->nsegs++)
90050997Sbostic 		hashp->dir[i] = &store[i << hashp->SSHIFT];
90150997Sbostic 	return (0);
90246366Sbostic }
90346366Sbostic 
90450997Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
90546366Sbostic /*
90650997Sbostic  * Hashp->hdr needs to be byteswapped.
90750997Sbostic  */
90846366Sbostic static void
swap_header_copy(srcp,destp)90950997Sbostic swap_header_copy(srcp, destp)
91050997Sbostic 	HASHHDR *srcp, *destp;
91146366Sbostic {
91250997Sbostic 	int i;
91346366Sbostic 
91466193Sbostic 	P_32_COPY(srcp->magic, destp->magic);
91566193Sbostic 	P_32_COPY(srcp->version, destp->version);
91666193Sbostic 	P_32_COPY(srcp->lorder, destp->lorder);
91766193Sbostic 	P_32_COPY(srcp->bsize, destp->bsize);
91866193Sbostic 	P_32_COPY(srcp->bshift, destp->bshift);
91966193Sbostic 	P_32_COPY(srcp->dsize, destp->dsize);
92066193Sbostic 	P_32_COPY(srcp->ssize, destp->ssize);
92166193Sbostic 	P_32_COPY(srcp->sshift, destp->sshift);
92266193Sbostic 	P_32_COPY(srcp->ovfl_point, destp->ovfl_point);
92366193Sbostic 	P_32_COPY(srcp->last_freed, destp->last_freed);
92466193Sbostic 	P_32_COPY(srcp->max_bucket, destp->max_bucket);
92566193Sbostic 	P_32_COPY(srcp->high_mask, destp->high_mask);
92666193Sbostic 	P_32_COPY(srcp->low_mask, destp->low_mask);
92766193Sbostic 	P_32_COPY(srcp->ffactor, destp->ffactor);
92866193Sbostic 	P_32_COPY(srcp->nkeys, destp->nkeys);
92966193Sbostic 	P_32_COPY(srcp->hdrpages, destp->hdrpages);
93066193Sbostic 	P_32_COPY(srcp->h_charkey, destp->h_charkey);
93150997Sbostic 	for (i = 0; i < NCACHED; i++) {
93266193Sbostic 		P_32_COPY(srcp->spares[i], destp->spares[i]);
93366193Sbostic 		P_16_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
93450997Sbostic 	}
93546366Sbostic }
93646366Sbostic 
93746366Sbostic static void
swap_header(hashp)93857586Sbostic swap_header(hashp)
93957586Sbostic 	HTAB *hashp;
94046366Sbostic {
94150997Sbostic 	HASHHDR *hdrp;
94250997Sbostic 	int i;
94346366Sbostic 
94450997Sbostic 	hdrp = &hashp->hdr;
94546366Sbostic 
94666193Sbostic 	M_32_SWAP(hdrp->magic);
94766193Sbostic 	M_32_SWAP(hdrp->version);
94866193Sbostic 	M_32_SWAP(hdrp->lorder);
94966193Sbostic 	M_32_SWAP(hdrp->bsize);
95066193Sbostic 	M_32_SWAP(hdrp->bshift);
95166193Sbostic 	M_32_SWAP(hdrp->dsize);
95266193Sbostic 	M_32_SWAP(hdrp->ssize);
95366193Sbostic 	M_32_SWAP(hdrp->sshift);
95466193Sbostic 	M_32_SWAP(hdrp->ovfl_point);
95566193Sbostic 	M_32_SWAP(hdrp->last_freed);
95666193Sbostic 	M_32_SWAP(hdrp->max_bucket);
95766193Sbostic 	M_32_SWAP(hdrp->high_mask);
95866193Sbostic 	M_32_SWAP(hdrp->low_mask);
95966193Sbostic 	M_32_SWAP(hdrp->ffactor);
96066193Sbostic 	M_32_SWAP(hdrp->nkeys);
96166193Sbostic 	M_32_SWAP(hdrp->hdrpages);
96266193Sbostic 	M_32_SWAP(hdrp->h_charkey);
96350997Sbostic 	for (i = 0; i < NCACHED; i++) {
96466193Sbostic 		M_32_SWAP(hdrp->spares[i]);
96566193Sbostic 		M_16_SWAP(hdrp->bitmaps[i]);
96650997Sbostic 	}
96746366Sbostic }
96850997Sbostic #endif
969