xref: /csrg-svn/lib/libc/db/hash/hash.c (revision 64466)
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*64466Sbostic static char sccsid[] = "@(#)hash.c	8.3 (Berkeley) 09/07/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 *
70*64466Sbostic __hash_open(file, flags, mode, info, dflags)
7150997Sbostic 	const char *file;
72*64466Sbostic 	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;
88*64466Sbostic 
8950997Sbostic 	/*
90*64466Sbostic 	 * Even if user wants write only, we need to be able to read
91*64466Sbostic 	 * the actual file, so we need to open it read/write. But, the
92*64466Sbostic 	 * field in the hashp structure needs to be accurate so that
9350997Sbostic 	 * we can check accesses.
9450997Sbostic 	 */
95*64466Sbostic 	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);
13051061Sbostic 		if (hashp->VERSION != HASHVERSION)
13150997Sbostic 			RETURN_ERROR(EFTYPE, error1);
13250997Sbostic 		if (hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY)
13350997Sbostic 			RETURN_ERROR(EFTYPE, error1);
13451057Sbostic 		/*
13551057Sbostic 		 * Figure out how many segments we need.  Max_Bucket is the
13651057Sbostic 		 * maximum bucket number, so the number of buckets is
13751057Sbostic 		 * max_bucket + 1.
13851057Sbostic 		 */
13951057Sbostic 		nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) /
14050997Sbostic 			 hashp->SGSIZE;
14150997Sbostic 		hashp->nsegs = 0;
14257586Sbostic 		if (alloc_segs(hashp, nsegs))
14350997Sbostic 			/*
14450997Sbostic 			 * If alloc_segs fails, table will have been destroyed
14550997Sbostic 			 * and errno will have been set.
14650997Sbostic 			 */
14750997Sbostic 			return (NULL);
14850997Sbostic 		/* Read in bitmaps */
14951061Sbostic 		bpages = (hashp->SPARES[hashp->OVFL_POINT] +
15050997Sbostic 		    (hashp->BSIZE << BYTE_SHIFT) - 1) >>
15150997Sbostic 		    (hashp->BSHIFT + BYTE_SHIFT);
15246366Sbostic 
15350997Sbostic 		hashp->nmaps = bpages;
15451057Sbostic 		(void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_long *));
15546366Sbostic 	}
15646366Sbostic 
15750997Sbostic 	/* Initialize Buffer Manager */
15850997Sbostic 	if (info && info->cachesize)
15957586Sbostic 		__buf_init(hashp, info->cachesize);
16050997Sbostic 	else
16157586Sbostic 		__buf_init(hashp, DEF_BUFSIZE);
16250997Sbostic 
16350997Sbostic 	hashp->new_file = new_table;
16456422Smargo 	hashp->save_file = file && (hashp->flags & O_RDWR);
16550997Sbostic 	hashp->cbucket = -1;
16650997Sbostic 	if (!(dbp = malloc(sizeof(DB)))) {
16750997Sbostic 		save_errno = errno;
16857586Sbostic 		hdestroy(hashp);
16950997Sbostic 		errno = save_errno;
17050997Sbostic 		return (NULL);
17146366Sbostic 	}
17257586Sbostic 	dbp->internal = hashp;
17350997Sbostic 	dbp->close = hash_close;
17450997Sbostic 	dbp->del = hash_delete;
17560247Sbostic 	dbp->fd = hash_fd;
17650997Sbostic 	dbp->get = hash_get;
17750997Sbostic 	dbp->put = hash_put;
17850997Sbostic 	dbp->seq = hash_seq;
17950997Sbostic 	dbp->sync = hash_sync;
18050997Sbostic 	dbp->type = DB_HASH;
18146366Sbostic 
18246366Sbostic #ifdef DEBUG
18350997Sbostic 	(void)fprintf(stderr,
18451061Sbostic "%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",
18550997Sbostic 	    "init_htab:",
18650997Sbostic 	    "TABLE POINTER   ", hashp,
18750997Sbostic 	    "BUCKET SIZE     ", hashp->BSIZE,
18850997Sbostic 	    "BUCKET SHIFT    ", hashp->BSHIFT,
18950997Sbostic 	    "DIRECTORY SIZE  ", hashp->DSIZE,
19050997Sbostic 	    "SEGMENT SIZE    ", hashp->SGSIZE,
19150997Sbostic 	    "SEGMENT SHIFT   ", hashp->SSHIFT,
19250997Sbostic 	    "FILL FACTOR     ", hashp->FFACTOR,
19350997Sbostic 	    "MAX BUCKET      ", hashp->MAX_BUCKET,
19451061Sbostic 	    "OVFL POINT	     ", hashp->OVFL_POINT,
19551061Sbostic 	    "LAST FREED      ", hashp->LAST_FREED,
19650997Sbostic 	    "HIGH MASK       ", hashp->HIGH_MASK,
19750997Sbostic 	    "LOW  MASK       ", hashp->LOW_MASK,
19850997Sbostic 	    "NSEGS           ", hashp->nsegs,
19950997Sbostic 	    "NKEYS           ", hashp->NKEYS);
20046366Sbostic #endif
20146366Sbostic #ifdef HASH_STATISTICS
20246366Sbostic 	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
20346366Sbostic #endif
20450997Sbostic 	return (dbp);
20546366Sbostic 
20646366Sbostic error1:
20751192Sbostic 	if (hashp != NULL)
20851192Sbostic 		(void)close(hashp->fp);
20946366Sbostic 
21046366Sbostic error0:
21150997Sbostic 	free(hashp);
21250997Sbostic 	errno = save_errno;
21350997Sbostic 	return (NULL);
21446366Sbostic }
21546366Sbostic 
21646366Sbostic static int
21750997Sbostic hash_close(dbp)
21850997Sbostic 	DB *dbp;
21946366Sbostic {
22057586Sbostic 	HTAB *hashp;
22150997Sbostic 	int retval;
22246457Sbostic 
22350997Sbostic 	if (!dbp)
22450997Sbostic 		return (ERROR);
22557586Sbostic 
22646366Sbostic 	hashp = (HTAB *)dbp->internal;
22757586Sbostic 	retval = hdestroy(hashp);
22850997Sbostic 	free(dbp);
22950997Sbostic 	return (retval);
23046366Sbostic }
23146366Sbostic 
23260247Sbostic static int
23360247Sbostic hash_fd(dbp)
23460247Sbostic 	const DB *dbp;
23560247Sbostic {
23660247Sbostic 	HTAB *hashp;
23760247Sbostic 
23860247Sbostic 	if (!dbp)
23960247Sbostic 		return (ERROR);
24060247Sbostic 
24160247Sbostic 	hashp = (HTAB *)dbp->internal;
24260247Sbostic 	if (hashp->fp == -1) {
24360247Sbostic 		errno = ENOENT;
24460247Sbostic 		return (-1);
24560247Sbostic 	}
24660247Sbostic 	return (hashp->fp);
24760247Sbostic }
24860247Sbostic 
24946366Sbostic /************************** LOCAL CREATION ROUTINES **********************/
25050997Sbostic static HTAB *
25160247Sbostic init_hash(hashp, file, info)
25257586Sbostic 	HTAB *hashp;
25360247Sbostic 	const char *file;
25450997Sbostic 	HASHINFO *info;
25546366Sbostic {
25660247Sbostic 	struct stat statbuf;
25750997Sbostic 	int nelem;
25846366Sbostic 
25946366Sbostic 	nelem = 1;
26051061Sbostic 	hashp->NKEYS = 0;
26150997Sbostic 	hashp->LORDER = BYTE_ORDER;
26250997Sbostic 	hashp->BSIZE = DEF_BUCKET_SIZE;
26350997Sbostic 	hashp->BSHIFT = DEF_BUCKET_SHIFT;
26450997Sbostic 	hashp->SGSIZE = DEF_SEGSIZE;
26550997Sbostic 	hashp->SSHIFT = DEF_SEGSIZE_SHIFT;
26650997Sbostic 	hashp->DSIZE = DEF_DIRSIZE;
26750997Sbostic 	hashp->FFACTOR = DEF_FFACTOR;
26857586Sbostic 	hashp->hash = __default_hash;
26958016Sbostic 	memset(hashp->SPARES, 0, sizeof(hashp->SPARES));
27058016Sbostic 	memset(hashp->BITMAPS, 0, sizeof (hashp->BITMAPS));
27146366Sbostic 
27260247Sbostic 	/* Fix bucket size to be optimal for file system */
27360247Sbostic 	if (file != NULL) {
27460247Sbostic 		if (stat(file, &statbuf))
27560247Sbostic 			return (NULL);
27660247Sbostic 		hashp->BSIZE = statbuf.st_blksize;
27760247Sbostic 		hashp->BSHIFT = __log2(hashp->BSIZE);
27860247Sbostic 	}
27960247Sbostic 
28050997Sbostic 	if (info) {
28150997Sbostic 		if (info->bsize) {
28250997Sbostic 			/* Round pagesize up to power of 2 */
28350997Sbostic 			hashp->BSHIFT = __log2(info->bsize);
28450997Sbostic 			hashp->BSIZE = 1 << hashp->BSHIFT;
28550997Sbostic 			if (hashp->BSIZE > MAX_BSIZE) {
28650997Sbostic 				errno = EINVAL;
28750997Sbostic 				return (NULL);
28850997Sbostic 			}
28946366Sbostic 		}
29050997Sbostic 		if (info->ffactor)
29150997Sbostic 			hashp->FFACTOR = info->ffactor;
29250997Sbostic 		if (info->hash)
29350997Sbostic 			hashp->hash = info->hash;
29450997Sbostic 		if (info->nelem)
29550997Sbostic 			nelem = info->nelem;
29650997Sbostic 		if (info->lorder) {
29750997Sbostic 			if (info->lorder != BIG_ENDIAN &&
29850997Sbostic 			    info->lorder != LITTLE_ENDIAN) {
29950997Sbostic 				errno = EINVAL;
30050997Sbostic 				return (NULL);
30150997Sbostic 			}
30250997Sbostic 			hashp->LORDER = info->lorder;
30346366Sbostic 		}
30446366Sbostic 	}
30546366Sbostic 	/* init_htab should destroy the table and set errno if it fails */
30657586Sbostic 	if (init_htab(hashp, nelem))
30750997Sbostic 		return (NULL);
30850997Sbostic 	else
30950997Sbostic 		return (hashp);
31046366Sbostic }
31146366Sbostic /*
31250997Sbostic  * This calls alloc_segs which may run out of memory.  Alloc_segs will destroy
31350997Sbostic  * the table and set errno, so we just pass the error information along.
31450997Sbostic  *
31550997Sbostic  * Returns 0 on No Error
31650997Sbostic  */
31746366Sbostic static int
31857586Sbostic init_htab(hashp, nelem)
31957586Sbostic 	HTAB *hashp;
32050997Sbostic 	int nelem;
32146366Sbostic {
32250997Sbostic 	register int nbuckets, nsegs;
32350997Sbostic 	int l2;
32446366Sbostic 
32550997Sbostic 	/*
32650997Sbostic 	 * Divide number of elements by the fill factor and determine a
32750997Sbostic 	 * desired number of buckets.  Allocate space for the next greater
32850997Sbostic 	 * power of two number of buckets.
32950997Sbostic 	 */
33046366Sbostic 	nelem = (nelem - 1) / hashp->FFACTOR + 1;
33146366Sbostic 
33252001Sbostic 	l2 = __log2(MAX(nelem, 2));
33346366Sbostic 	nbuckets = 1 << l2;
33446366Sbostic 
33546366Sbostic 	hashp->SPARES[l2] = l2 + 1;
33650997Sbostic 	hashp->SPARES[l2 + 1] = l2 + 1;
33751061Sbostic 	hashp->OVFL_POINT = l2;
33851061Sbostic 	hashp->LAST_FREED = 2;
33951061Sbostic 
34050997Sbostic 	/* First bitmap page is at: splitpoint l2 page offset 1 */
34157586Sbostic 	if (__init_bitmap(hashp, OADDR_OF(l2, 1), l2 + 1, 0))
34251057Sbostic 		return (-1);
34346366Sbostic 
34446366Sbostic 	hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
34546366Sbostic 	hashp->HIGH_MASK = (nbuckets << 1) - 1;
34650997Sbostic 	hashp->HDRPAGES = ((MAX(sizeof(HASHHDR), MINHDRSIZE) - 1) >>
34750997Sbostic 	    hashp->BSHIFT) + 1;
34846366Sbostic 
34946366Sbostic 	nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
35046366Sbostic 	nsegs = 1 << __log2(nsegs);
35146366Sbostic 
35250997Sbostic 	if (nsegs > hashp->DSIZE)
35350997Sbostic 		hashp->DSIZE = nsegs;
35457586Sbostic 	return (alloc_segs(hashp, nsegs));
35546366Sbostic }
35646366Sbostic 
35746366Sbostic /********************** DESTROY/CLOSE ROUTINES ************************/
35846366Sbostic 
35946366Sbostic /*
36050997Sbostic  * Flushes any changes to the file if necessary and destroys the hashp
36150997Sbostic  * structure, freeing all allocated space.
36250997Sbostic  */
36346366Sbostic static int
36457586Sbostic hdestroy(hashp)
36557586Sbostic 	HTAB *hashp;
36646366Sbostic {
36750997Sbostic 	int i, save_errno;
36846366Sbostic 
36946366Sbostic 	save_errno = 0;
37046366Sbostic 
37146366Sbostic #ifdef HASH_STATISTICS
37257586Sbostic 	(void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
37357586Sbostic 	    hash_accesses, hash_collisions);
37457586Sbostic 	(void)fprintf(stderr, "hdestroy: expansions %ld\n",
37557586Sbostic 	    hash_expansions);
37657586Sbostic 	(void)fprintf(stderr, "hdestroy: overflows %ld\n",
37757586Sbostic 	    hash_overflows);
37857586Sbostic 	(void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n",
37957586Sbostic 	    hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
38046366Sbostic 
38157586Sbostic 	for (i = 0; i < NCACHED; i++)
38257586Sbostic 		(void)fprintf(stderr,
38357586Sbostic 		    "spares[%d] = %d\n", i, hashp->SPARES[i]);
38446366Sbostic #endif
38557586Sbostic 	/*
38657586Sbostic 	 * Call on buffer manager to free buffers, and if required,
38757586Sbostic 	 * write them to disk.
38857586Sbostic 	 */
38957586Sbostic 	if (__buf_free(hashp, 1, hashp->save_file))
39057586Sbostic 		save_errno = errno;
39157586Sbostic 	if (hashp->dir) {
39257586Sbostic 		free(*hashp->dir);	/* Free initial segments */
39357586Sbostic 		/* Free extra segments */
39457586Sbostic 		while (hashp->exsegs--)
39557586Sbostic 			free(hashp->dir[--hashp->nsegs]);
39657586Sbostic 		free(hashp->dir);
39757586Sbostic 	}
39857586Sbostic 	if (flush_meta(hashp) && !save_errno)
39957586Sbostic 		save_errno = errno;
40057586Sbostic 	/* Free Bigmaps */
40157586Sbostic 	for (i = 0; i < hashp->nmaps; i++)
40257586Sbostic 		if (hashp->mapp[i])
40357586Sbostic 			free(hashp->mapp[i]);
40446503Sbostic 
40557586Sbostic 	if (hashp->fp != -1)
40657586Sbostic 		(void)close(hashp->fp);
40757586Sbostic 
40850997Sbostic 	if (save_errno) {
40950997Sbostic 		errno = save_errno;
41050997Sbostic 		return (ERROR);
41146366Sbostic 	}
41250997Sbostic 	return (SUCCESS);
41346366Sbostic }
41450997Sbostic /*
41550997Sbostic  * Write modified pages to disk
41650997Sbostic  *
41750997Sbostic  * Returns:
41850997Sbostic  *	 0 == OK
41950997Sbostic  *	-1 ERROR
42050997Sbostic  */
42146366Sbostic static int
42260060Sbostic hash_sync(dbp, flags)
42350997Sbostic 	const DB *dbp;
42460060Sbostic 	u_int flags;
42546366Sbostic {
42657586Sbostic 	HTAB *hashp;
42757586Sbostic 
42860060Sbostic 	if (flags != 0) {
42960060Sbostic 		errno = EINVAL;
43060060Sbostic 		return (ERROR);
43160060Sbostic 	}
43260060Sbostic 
43350997Sbostic 	if (!dbp)
43450997Sbostic 		return (ERROR);
43557586Sbostic 
43646366Sbostic 	hashp = (HTAB *)dbp->internal;
43750997Sbostic 	if (!hashp->save_file)
43850997Sbostic 		return (0);
43957586Sbostic 	if (__buf_free(hashp, 0, 1) || flush_meta(hashp))
44050997Sbostic 		return (ERROR);
44146366Sbostic 	hashp->new_file = 0;
44250997Sbostic 	return (0);
44346366Sbostic }
44446366Sbostic 
44546366Sbostic /*
44650997Sbostic  * Returns:
44750997Sbostic  *	 0 == OK
44850997Sbostic  *	-1 indicates that errno should be set
44950997Sbostic  */
45046366Sbostic static int
45157586Sbostic flush_meta(hashp)
45257586Sbostic 	HTAB *hashp;
45346366Sbostic {
45451814Smarc 	HASHHDR *whdrp;
45551814Smarc #if BYTE_ORDER == LITTLE_ENDIAN
45651814Smarc 	HASHHDR whdr;
45751814Smarc #endif
45850997Sbostic 	int fp, i, wsize;
45946366Sbostic 
46050997Sbostic 	if (!hashp->save_file)
46150997Sbostic 		return (0);
46246366Sbostic 	hashp->MAGIC = HASHMAGIC;
46351061Sbostic 	hashp->VERSION = HASHVERSION;
46450997Sbostic 	hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY));
46546366Sbostic 
46646366Sbostic 	fp = hashp->fp;
46746366Sbostic 	whdrp = &hashp->hdr;
46846366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
46946366Sbostic 	whdrp = &whdr;
47050997Sbostic 	swap_header_copy(&hashp->hdr, whdrp);
47146366Sbostic #endif
47256669Sbostic 	if ((lseek(fp, (off_t)0, SEEK_SET) == -1) ||
47350997Sbostic 	    ((wsize = write(fp, whdrp, sizeof(HASHHDR))) == -1))
47450997Sbostic 		return (-1);
47550997Sbostic 	else
47650997Sbostic 		if (wsize != sizeof(HASHHDR)) {
47750997Sbostic 			errno = EFTYPE;
47850997Sbostic 			hashp->errno = errno;
47950997Sbostic 			return (-1);
48046366Sbostic 		}
48150997Sbostic 	for (i = 0; i < NCACHED; i++)
48250997Sbostic 		if (hashp->mapp[i])
48357586Sbostic 			if (__put_page(hashp, (char *)hashp->mapp[i],
48450997Sbostic 				hashp->BITMAPS[i], 0, 1))
48550997Sbostic 				return (-1);
48650997Sbostic 	return (0);
48746366Sbostic }
48850997Sbostic 
48946366Sbostic /*******************************SEARCH ROUTINES *****************************/
49046366Sbostic /*
49150997Sbostic  * All the access routines return
49250997Sbostic  *
49350997Sbostic  * Returns:
49450997Sbostic  *	 0 on SUCCESS
49550997Sbostic  *	 1 to indicate an external ERROR (i.e. key not found, etc)
49650997Sbostic  *	-1 to indicate an internal ERROR (i.e. out of memory, etc)
49750997Sbostic  */
49846366Sbostic static int
49950997Sbostic hash_get(dbp, key, data, flag)
50050997Sbostic 	const DB *dbp;
50151057Sbostic 	const DBT *key;
50251057Sbostic 	DBT *data;
50350997Sbostic 	u_int flag;
50446366Sbostic {
50557586Sbostic 	HTAB *hashp;
50657586Sbostic 
50757586Sbostic 	hashp = (HTAB *)dbp->internal;
50850997Sbostic 	if (flag) {
50950997Sbostic 		hashp->errno = errno = EINVAL;
51050997Sbostic 		return (ERROR);
51150997Sbostic 	}
51257586Sbostic 	return (hash_access(hashp, HASH_GET, (DBT *)key, data));
51346366Sbostic }
51446366Sbostic 
51546366Sbostic static int
51650997Sbostic hash_put(dbp, key, data, flag)
51750997Sbostic 	const DB *dbp;
51856893Sbostic 	DBT *key;
51956893Sbostic 	const DBT *data;
52050997Sbostic 	u_int flag;
52146366Sbostic {
52257586Sbostic 	HTAB *hashp;
52357586Sbostic 
52457586Sbostic 	hashp = (HTAB *)dbp->internal;
52550997Sbostic 	if (flag && flag != R_NOOVERWRITE) {
52650997Sbostic 		hashp->errno = errno = EINVAL;
52750997Sbostic 		return (ERROR);
52850997Sbostic 	}
52950997Sbostic 	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
53050997Sbostic 		hashp->errno = errno = EPERM;
53150997Sbostic 		return (ERROR);
53250997Sbostic 	}
53357586Sbostic 	return (hash_access(hashp, flag == R_NOOVERWRITE ?
53450997Sbostic 	    HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));
53546366Sbostic }
53646366Sbostic 
53746366Sbostic static int
53850997Sbostic hash_delete(dbp, key, flag)
53950997Sbostic 	const DB *dbp;
54050997Sbostic 	const DBT *key;
54150997Sbostic 	u_int flag;		/* Ignored */
54246366Sbostic {
54357586Sbostic 	HTAB *hashp;
54457586Sbostic 
54557586Sbostic 	hashp = (HTAB *)dbp->internal;
54650997Sbostic 	if (flag && flag != R_CURSOR) {
54750997Sbostic 		hashp->errno = errno = EINVAL;
54850997Sbostic 		return (ERROR);
54950997Sbostic 	}
55050997Sbostic 	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
55150997Sbostic 		hashp->errno = errno = EPERM;
55250997Sbostic 		return (ERROR);
55350997Sbostic 	}
55457586Sbostic 	return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
55546366Sbostic }
55646366Sbostic 
55746366Sbostic /*
55850997Sbostic  * Assume that hashp has been set in wrapper routine.
55950997Sbostic  */
56046366Sbostic static int
56157586Sbostic hash_access(hashp, action, key, val)
56257586Sbostic 	HTAB *hashp;
56350997Sbostic 	ACTION action;
56450997Sbostic 	DBT *key, *val;
56546366Sbostic {
56650997Sbostic 	register BUFHEAD *rbufp;
56750997Sbostic 	BUFHEAD *bufp, *save_bufp;
56850997Sbostic 	register u_short *bp;
56950997Sbostic 	register int n, ndx, off, size;
57050997Sbostic 	register char *kp;
57150997Sbostic 	u_short pageno;
57246366Sbostic 
57346366Sbostic #ifdef HASH_STATISTICS
57446366Sbostic 	hash_accesses++;
57546366Sbostic #endif
57646366Sbostic 
57750997Sbostic 	off = hashp->BSIZE;
57846366Sbostic 	size = key->size;
57946950Sbostic 	kp = (char *)key->data;
58057586Sbostic 	rbufp = __get_buf(hashp, __call_hash(hashp, kp, size), NULL, 0);
58150997Sbostic 	if (!rbufp)
58250997Sbostic 		return (ERROR);
58346457Sbostic 	save_bufp = rbufp;
58446366Sbostic 
58546457Sbostic 	/* Pin the bucket chain */
58646457Sbostic 	rbufp->flags |= BUF_PIN;
58750997Sbostic 	for (bp = (u_short *)rbufp->page, n = *bp++, ndx = 1; ndx < n;)
58850997Sbostic 		if (bp[1] >= REAL_KEY) {
58950997Sbostic 			/* Real key/data pair */
59050997Sbostic 			if (size == off - *bp &&
59158016Sbostic 			    memcmp(kp, rbufp->page + *bp, size) == 0)
59250997Sbostic 				goto found;
59350997Sbostic 			off = bp[1];
59446366Sbostic #ifdef HASH_STATISTICS
59550997Sbostic 			hash_collisions++;
59646366Sbostic #endif
59750997Sbostic 			bp += 2;
59850997Sbostic 			ndx += 2;
59950997Sbostic 		} else if (bp[1] == OVFLPAGE) {
60057586Sbostic 			rbufp = __get_buf(hashp, *bp, rbufp, 0);
60150997Sbostic 			if (!rbufp) {
60250997Sbostic 				save_bufp->flags &= ~BUF_PIN;
60350997Sbostic 				return (ERROR);
60450997Sbostic 			}
60550997Sbostic 			/* FOR LOOP INIT */
60650997Sbostic 			bp = (u_short *)rbufp->page;
60750997Sbostic 			n = *bp++;
60850997Sbostic 			ndx = 1;
60950997Sbostic 			off = hashp->BSIZE;
61050997Sbostic 		} else if (bp[1] < REAL_KEY) {
61157586Sbostic 			if ((ndx =
61257586Sbostic 			    __find_bigpair(hashp, rbufp, ndx, kp, size)) > 0)
61350997Sbostic 				goto found;
61450997Sbostic 			if (ndx == -2) {
61550997Sbostic 				bufp = rbufp;
61657586Sbostic 				if (!(pageno =
61757586Sbostic 				    __find_last_page(hashp, &bufp))) {
61850997Sbostic 					ndx = 0;
61950997Sbostic 					rbufp = bufp;
62050997Sbostic 					break;	/* FOR */
62150997Sbostic 				}
62257586Sbostic 				rbufp = __get_buf(hashp, pageno, bufp, 0);
62350997Sbostic 				if (!rbufp) {
62450997Sbostic 					save_bufp->flags &= ~BUF_PIN;
62550997Sbostic 					return (ERROR);
62650997Sbostic 				}
62750997Sbostic 				/* FOR LOOP INIT */
62850997Sbostic 				bp = (u_short *)rbufp->page;
62950997Sbostic 				n = *bp++;
63050997Sbostic 				ndx = 1;
63150997Sbostic 				off = hashp->BSIZE;
63250997Sbostic 			} else {
63350997Sbostic 				save_bufp->flags &= ~BUF_PIN;
63450997Sbostic 				return (ERROR);
63550997Sbostic 			}
63646457Sbostic 		}
63746366Sbostic 
63846366Sbostic 	/* Not found */
63950997Sbostic 	switch (action) {
64050997Sbostic 	case HASH_PUT:
64150997Sbostic 	case HASH_PUTNEW:
64257586Sbostic 		if (__addel(hashp, rbufp, key, val)) {
64350997Sbostic 			save_bufp->flags &= ~BUF_PIN;
64450997Sbostic 			return (ERROR);
64546366Sbostic 		} else {
64650997Sbostic 			save_bufp->flags &= ~BUF_PIN;
64750997Sbostic 			return (SUCCESS);
64846366Sbostic 		}
64950997Sbostic 	case HASH_GET:
65050997Sbostic 	case HASH_DELETE:
65150997Sbostic 	default:
65246457Sbostic 		save_bufp->flags &= ~BUF_PIN;
65350997Sbostic 		return (ABNORMAL);
65446366Sbostic 	}
65546366Sbostic 
65646366Sbostic found:
65746366Sbostic 	switch (action) {
65850997Sbostic 	case HASH_PUTNEW:
65946457Sbostic 		save_bufp->flags &= ~BUF_PIN;
66050997Sbostic 		return (ABNORMAL);
66150997Sbostic 	case HASH_GET:
66246366Sbostic 		bp = (u_short *)rbufp->page;
66351072Sbostic 		if (bp[ndx + 1] < REAL_KEY) {
66457586Sbostic 			if (__big_return(hashp, rbufp, ndx, val, 0))
66551057Sbostic 				return (ERROR);
66651072Sbostic 		} else {
66750997Sbostic 			val->data = (u_char *)rbufp->page + (int)bp[ndx + 1];
66850997Sbostic 			val->size = bp[ndx] - bp[ndx + 1];
66946366Sbostic 		}
67046366Sbostic 		break;
67150997Sbostic 	case HASH_PUT:
67257586Sbostic 		if ((__delpair(hashp, rbufp, ndx)) ||
67357586Sbostic 		    (__addel(hashp, rbufp, key, val))) {
67450997Sbostic 			save_bufp->flags &= ~BUF_PIN;
67550997Sbostic 			return (ERROR);
67646457Sbostic 		}
67746366Sbostic 		break;
67850997Sbostic 	case HASH_DELETE:
67957586Sbostic 		if (__delpair(hashp, rbufp, ndx))
68050997Sbostic 			return (ERROR);
68146366Sbostic 		break;
68257586Sbostic 	default:
68357586Sbostic 		abort();
68446366Sbostic 	}
68546457Sbostic 	save_bufp->flags &= ~BUF_PIN;
68646366Sbostic 	return (SUCCESS);
68746366Sbostic }
68846366Sbostic 
68946366Sbostic static int
69046366Sbostic hash_seq(dbp, key, data, flag)
69150997Sbostic 	const DB *dbp;
69250997Sbostic 	DBT *key, *data;
69350997Sbostic 	u_int flag;
69446366Sbostic {
69550997Sbostic 	register u_int bucket;
69650997Sbostic 	register BUFHEAD *bufp;
69757586Sbostic 	HTAB *hashp;
69850997Sbostic 	u_short *bp, ndx;
69946366Sbostic 
70057586Sbostic 	hashp = (HTAB *)dbp->internal;
70150997Sbostic 	if (flag && flag != R_FIRST && flag != R_NEXT) {
70250997Sbostic 		hashp->errno = errno = EINVAL;
70350997Sbostic 		return (ERROR);
70446366Sbostic 	}
70546366Sbostic #ifdef HASH_STATISTICS
70646366Sbostic 	hash_accesses++;
70746366Sbostic #endif
70850997Sbostic 	if ((hashp->cbucket < 0) || (flag == R_FIRST)) {
70950997Sbostic 		hashp->cbucket = 0;
71050997Sbostic 		hashp->cndx = 1;
71150997Sbostic 		hashp->cpage = NULL;
71246366Sbostic 	}
71346366Sbostic 
71455874Sbostic 	for (bp = NULL; !bp || !bp[0]; ) {
71555452Sbostic 		if (!(bufp = hashp->cpage)) {
71655452Sbostic 			for (bucket = hashp->cbucket;
71755452Sbostic 			    bucket <= hashp->MAX_BUCKET;
71855452Sbostic 			    bucket++, hashp->cndx = 1) {
71957586Sbostic 				bufp = __get_buf(hashp, bucket, NULL, 0);
72055452Sbostic 				if (!bufp)
72155452Sbostic 					return (ERROR);
72255452Sbostic 				hashp->cpage = bufp;
72355452Sbostic 				bp = (u_short *)bufp->page;
72455452Sbostic 				if (bp[0])
72555452Sbostic 					break;
72655452Sbostic 			}
72755452Sbostic 			hashp->cbucket = bucket;
72855452Sbostic 			if (hashp->cbucket > hashp->MAX_BUCKET) {
72955452Sbostic 				hashp->cbucket = -1;
73055452Sbostic 				return (ABNORMAL);
73155452Sbostic 			}
73255452Sbostic 		} else
73355452Sbostic 			bp = (u_short *)hashp->cpage->page;
73455452Sbostic 
73555452Sbostic #ifdef DEBUG
73655452Sbostic 		assert(bp);
73755452Sbostic 		assert(bufp);
73855452Sbostic #endif
73955452Sbostic 		while (bp[hashp->cndx + 1] == OVFLPAGE) {
74055452Sbostic 			bufp = hashp->cpage =
74157586Sbostic 			    __get_buf(hashp, bp[hashp->cndx], bufp, 0);
74250997Sbostic 			if (!bufp)
74350997Sbostic 				return (ERROR);
74455452Sbostic 			bp = (u_short *)(bufp->page);
74555452Sbostic 			hashp->cndx = 1;
74650997Sbostic 		}
74755874Sbostic 		if (!bp[0]) {
74855452Sbostic 			hashp->cpage = NULL;
74955874Sbostic 			++hashp->cbucket;
75055874Sbostic 		}
75146366Sbostic 	}
75246366Sbostic 	ndx = hashp->cndx;
75350997Sbostic 	if (bp[ndx + 1] < REAL_KEY) {
75457586Sbostic 		if (__big_keydata(hashp, bufp, key, data, 1))
75550997Sbostic 			return (ERROR);
75646366Sbostic 	} else {
75750997Sbostic 		key->data = (u_char *)hashp->cpage->page + bp[ndx];
75850997Sbostic 		key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
75950997Sbostic 		data->data = (u_char *)hashp->cpage->page + bp[ndx + 1];
76050997Sbostic 		data->size = bp[ndx] - bp[ndx + 1];
76150997Sbostic 		ndx += 2;
76250997Sbostic 		if (ndx > bp[0]) {
76350997Sbostic 			hashp->cpage = NULL;
76450997Sbostic 			hashp->cbucket++;
76550997Sbostic 			hashp->cndx = 1;
76650997Sbostic 		} else
76750997Sbostic 			hashp->cndx = ndx;
76846366Sbostic 	}
76946366Sbostic 	return (SUCCESS);
77046366Sbostic }
77146366Sbostic 
77246366Sbostic /********************************* UTILITIES ************************/
77350997Sbostic 
77446366Sbostic /*
77550997Sbostic  * Returns:
77650997Sbostic  *	 0 ==> OK
77750997Sbostic  *	-1 ==> Error
77850997Sbostic  */
77946366Sbostic extern int
78057586Sbostic __expand_table(hashp)
78157586Sbostic 	HTAB *hashp;
78246366Sbostic {
78350997Sbostic 	u_int old_bucket, new_bucket;
78450997Sbostic 	int dirsize, new_segnum, spare_ndx;
78550997Sbostic 
78646366Sbostic #ifdef HASH_STATISTICS
78746366Sbostic 	hash_expansions++;
78846366Sbostic #endif
78946366Sbostic 	new_bucket = ++hashp->MAX_BUCKET;
79046366Sbostic 	old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
79146366Sbostic 
79246366Sbostic 	new_segnum = new_bucket >> hashp->SSHIFT;
79346366Sbostic 
79446366Sbostic 	/* Check if we need a new segment */
79550997Sbostic 	if (new_segnum >= hashp->nsegs) {
79650997Sbostic 		/* Check if we need to expand directory */
79750997Sbostic 		if (new_segnum >= hashp->DSIZE) {
79850997Sbostic 			/* Reallocate directory */
79950997Sbostic 			dirsize = hashp->DSIZE * sizeof(SEGMENT *);
80050997Sbostic 			if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1))
80150997Sbostic 				return (-1);
80250997Sbostic 			hashp->DSIZE = dirsize << 1;
80346366Sbostic 		}
80450997Sbostic 		if (!(hashp->dir[new_segnum] =
80550997Sbostic 			calloc(hashp->SGSIZE, sizeof(SEGMENT))))
80650997Sbostic 			return (-1);
80750997Sbostic 		hashp->exsegs++;
80850997Sbostic 		hashp->nsegs++;
80946366Sbostic 	}
81046366Sbostic 	/*
81150997Sbostic 	 * If the split point is increasing (MAX_BUCKET's log base 2
81250997Sbostic 	 * * increases), we need to copy the current contents of the spare
81350997Sbostic 	 * split bucket to the next bucket.
81450997Sbostic 	 */
81552001Sbostic 	spare_ndx = __log2(hashp->MAX_BUCKET + 1);
81652001Sbostic 	if (spare_ndx > hashp->OVFL_POINT) {
81751061Sbostic 		hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT];
81851061Sbostic 		hashp->OVFL_POINT = spare_ndx;
81951061Sbostic 	}
82051061Sbostic 
82150997Sbostic 	if (new_bucket > hashp->HIGH_MASK) {
82250997Sbostic 		/* Starting a new doubling */
82350997Sbostic 		hashp->LOW_MASK = hashp->HIGH_MASK;
82450997Sbostic 		hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
82546366Sbostic 	}
82650997Sbostic 	/* Relocate records to the new bucket */
82757586Sbostic 	return (__split_page(hashp, old_bucket, new_bucket));
82850997Sbostic }
82946366Sbostic 
83046366Sbostic /*
83150997Sbostic  * If realloc guarantees that the pointer is not destroyed if the realloc
83250997Sbostic  * fails, then this routine can go away.
83350997Sbostic  */
83450997Sbostic static void *
83550997Sbostic hash_realloc(p_ptr, oldsize, newsize)
83650997Sbostic 	SEGMENT **p_ptr;
83750997Sbostic 	int oldsize, newsize;
83846366Sbostic {
83950997Sbostic 	register void *p;
84046366Sbostic 
84150997Sbostic 	if (p = malloc(newsize)) {
84258016Sbostic 		memmove(p, *p_ptr, oldsize);
84363747Sbostic 		memset((char *)p + oldsize, 0, newsize - oldsize);
84446366Sbostic 		free(*p_ptr);
84546366Sbostic 		*p_ptr = p;
84646366Sbostic 	}
84746366Sbostic 	return (p);
84846366Sbostic }
84946366Sbostic 
85047251Sbostic extern u_int
85157586Sbostic __call_hash(hashp, k, len)
85257586Sbostic 	HTAB *hashp;
85350997Sbostic 	char *k;
85450997Sbostic 	int len;
85546366Sbostic {
85650997Sbostic 	int n, bucket;
85750997Sbostic 
85846366Sbostic 	n = hashp->hash(k, len);
85946366Sbostic 	bucket = n & hashp->HIGH_MASK;
86050997Sbostic 	if (bucket > hashp->MAX_BUCKET)
86150997Sbostic 		bucket = bucket & hashp->LOW_MASK;
86250997Sbostic 	return (bucket);
86346366Sbostic }
86446366Sbostic 
86546366Sbostic /*
86650997Sbostic  * Allocate segment table.  On error, destroy the table and set errno.
86750997Sbostic  *
86850997Sbostic  * Returns 0 on success
86950997Sbostic  */
87046366Sbostic static int
87157586Sbostic alloc_segs(hashp, nsegs)
87257586Sbostic 	HTAB *hashp;
87350997Sbostic 	int nsegs;
87446366Sbostic {
87550997Sbostic 	register int i;
87650997Sbostic 	register SEGMENT store;
87746366Sbostic 
87850997Sbostic 	int save_errno;
87946366Sbostic 
88050997Sbostic 	if (!(hashp->dir = calloc(hashp->DSIZE, sizeof(SEGMENT *)))) {
88150997Sbostic 		save_errno = errno;
88257586Sbostic 		(void)hdestroy(hashp);
88350997Sbostic 		errno = save_errno;
88450997Sbostic 		return (-1);
88550997Sbostic 	}
88650997Sbostic 	/* Allocate segments */
88750997Sbostic 	store = calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT));
88850997Sbostic 	if (!store) {
88950997Sbostic 		save_errno = errno;
89057586Sbostic 		(void)hdestroy(hashp);
89150997Sbostic 		errno = save_errno;
89250997Sbostic 		return (-1);
89350997Sbostic 	}
89450997Sbostic 	for (i = 0; i < nsegs; i++, hashp->nsegs++)
89550997Sbostic 		hashp->dir[i] = &store[i << hashp->SSHIFT];
89650997Sbostic 	return (0);
89746366Sbostic }
89846366Sbostic 
89950997Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
90046366Sbostic /*
90150997Sbostic  * Hashp->hdr needs to be byteswapped.
90250997Sbostic  */
90346366Sbostic static void
90450997Sbostic swap_header_copy(srcp, destp)
90550997Sbostic 	HASHHDR *srcp, *destp;
90646366Sbostic {
90750997Sbostic 	int i;
90846366Sbostic 
90950997Sbostic 	BLSWAP_COPY(srcp->magic, destp->magic);
91050997Sbostic 	BLSWAP_COPY(srcp->version, destp->version);
91150997Sbostic 	BLSWAP_COPY(srcp->lorder, destp->lorder);
91250997Sbostic 	BLSWAP_COPY(srcp->bsize, destp->bsize);
91350997Sbostic 	BLSWAP_COPY(srcp->bshift, destp->bshift);
91450997Sbostic 	BLSWAP_COPY(srcp->dsize, destp->dsize);
91550997Sbostic 	BLSWAP_COPY(srcp->ssize, destp->ssize);
91650997Sbostic 	BLSWAP_COPY(srcp->sshift, destp->sshift);
91751061Sbostic 	BLSWAP_COPY(srcp->ovfl_point, destp->ovfl_point);
91851061Sbostic 	BLSWAP_COPY(srcp->last_freed, destp->last_freed);
91950997Sbostic 	BLSWAP_COPY(srcp->max_bucket, destp->max_bucket);
92050997Sbostic 	BLSWAP_COPY(srcp->high_mask, destp->high_mask);
92150997Sbostic 	BLSWAP_COPY(srcp->low_mask, destp->low_mask);
92250997Sbostic 	BLSWAP_COPY(srcp->ffactor, destp->ffactor);
92350997Sbostic 	BLSWAP_COPY(srcp->nkeys, destp->nkeys);
92450997Sbostic 	BLSWAP_COPY(srcp->hdrpages, destp->hdrpages);
92550997Sbostic 	BLSWAP_COPY(srcp->h_charkey, destp->h_charkey);
92650997Sbostic 	for (i = 0; i < NCACHED; i++) {
92750997Sbostic 		BLSWAP_COPY(srcp->spares[i], destp->spares[i]);
92850997Sbostic 		BSSWAP_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
92950997Sbostic 	}
93046366Sbostic }
93146366Sbostic 
93246366Sbostic static void
93357586Sbostic swap_header(hashp)
93457586Sbostic 	HTAB *hashp;
93546366Sbostic {
93650997Sbostic 	HASHHDR *hdrp;
93750997Sbostic 	int i;
93846366Sbostic 
93950997Sbostic 	hdrp = &hashp->hdr;
94046366Sbostic 
94150997Sbostic 	BLSWAP(hdrp->magic);
94250997Sbostic 	BLSWAP(hdrp->version);
94350997Sbostic 	BLSWAP(hdrp->lorder);
94450997Sbostic 	BLSWAP(hdrp->bsize);
94550997Sbostic 	BLSWAP(hdrp->bshift);
94650997Sbostic 	BLSWAP(hdrp->dsize);
94750997Sbostic 	BLSWAP(hdrp->ssize);
94850997Sbostic 	BLSWAP(hdrp->sshift);
94951061Sbostic 	BLSWAP(hdrp->ovfl_point);
95051061Sbostic 	BLSWAP(hdrp->last_freed);
95150997Sbostic 	BLSWAP(hdrp->max_bucket);
95250997Sbostic 	BLSWAP(hdrp->high_mask);
95350997Sbostic 	BLSWAP(hdrp->low_mask);
95450997Sbostic 	BLSWAP(hdrp->ffactor);
95550997Sbostic 	BLSWAP(hdrp->nkeys);
95650997Sbostic 	BLSWAP(hdrp->hdrpages);
95750997Sbostic 	BLSWAP(hdrp->h_charkey);
95850997Sbostic 	for (i = 0; i < NCACHED; i++) {
95950997Sbostic 		BLSWAP(hdrp->spares[i]);
96050997Sbostic 		BSSWAP(hdrp->bitmaps[i]);
96150997Sbostic 	}
96246366Sbostic }
96350997Sbostic #endif
964