xref: /csrg-svn/lib/libc/db/hash/hash.c (revision 62489)
146366Sbostic /*-
2*62489Sbostic  * Copyright (c) 1990, 1993
3*62489Sbostic  *	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*62489Sbostic static char sccsid[] = "@(#)hash.c	8.1 (Berkeley) 06/06/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 *
7051072Sbostic __hash_open(file, flags, mode, info)
7150997Sbostic 	const char *file;
7250997Sbostic 	int flags, mode;
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;
8850997Sbostic 	/*
8950997Sbostic 	 * Select flags relevant to us. Even if user wants write only, we need
9050997Sbostic 	 * to be able to read the actual file, so we need to open it read/write.
9150997Sbostic 	 * But, the field in the hashp structure needs to be accurate so that
9250997Sbostic 	 * we can check accesses.
9350997Sbostic 	 */
9456893Sbostic 	hashp->flags = flags = flags & __USE_OPEN_FLAGS;
9546366Sbostic 
9650997Sbostic 	new_table = 0;
9750997Sbostic 	if (!file || (flags & O_TRUNC) ||
9850997Sbostic 	    (stat(file, &statbuf) && (errno == ENOENT))) {
9950997Sbostic 		if (errno == ENOENT)
10050997Sbostic 			errno = 0; /* Just in case someone looks at errno */
10150997Sbostic 		new_table = 1;
10246485Sbostic 	}
10350997Sbostic 	if (file) {
10450997Sbostic 		if ((hashp->fp = open(file, flags, mode)) == -1)
10550997Sbostic 			RETURN_ERROR(errno, error0);
10650997Sbostic 		(void)fcntl(hashp->fp, F_SETFD, 1);
10746366Sbostic 	}
10850997Sbostic 	if (new_table) {
10960247Sbostic 		if (!(hashp = init_hash(hashp, file, (HASHINFO *)info)))
11050997Sbostic 			RETURN_ERROR(errno, error1);
11150997Sbostic 	} else {
11250997Sbostic 		/* Table already exists */
11350997Sbostic 		if (info && info->hash)
11450997Sbostic 			hashp->hash = info->hash;
11550997Sbostic 		else
11657586Sbostic 			hashp->hash = __default_hash;
11746366Sbostic 
11850997Sbostic 		hdrsize = read(hashp->fp, &hashp->hdr, sizeof(HASHHDR));
11946366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
12057586Sbostic 		swap_header(hashp);
12146366Sbostic #endif
12250997Sbostic 		if (hdrsize == -1)
12350997Sbostic 			RETURN_ERROR(errno, error1);
12450997Sbostic 		if (hdrsize != sizeof(HASHHDR))
12550997Sbostic 			RETURN_ERROR(EFTYPE, error1);
12650997Sbostic 		/* Verify file type, versions and hash function */
12750997Sbostic 		if (hashp->MAGIC != HASHMAGIC)
12850997Sbostic 			RETURN_ERROR(EFTYPE, error1);
12951061Sbostic 		if (hashp->VERSION != HASHVERSION)
13050997Sbostic 			RETURN_ERROR(EFTYPE, error1);
13150997Sbostic 		if (hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY)
13250997Sbostic 			RETURN_ERROR(EFTYPE, error1);
13351057Sbostic 		/*
13451057Sbostic 		 * Figure out how many segments we need.  Max_Bucket is the
13551057Sbostic 		 * maximum bucket number, so the number of buckets is
13651057Sbostic 		 * max_bucket + 1.
13751057Sbostic 		 */
13851057Sbostic 		nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) /
13950997Sbostic 			 hashp->SGSIZE;
14050997Sbostic 		hashp->nsegs = 0;
14157586Sbostic 		if (alloc_segs(hashp, nsegs))
14250997Sbostic 			/*
14350997Sbostic 			 * If alloc_segs fails, table will have been destroyed
14450997Sbostic 			 * and errno will have been set.
14550997Sbostic 			 */
14650997Sbostic 			return (NULL);
14750997Sbostic 		/* Read in bitmaps */
14851061Sbostic 		bpages = (hashp->SPARES[hashp->OVFL_POINT] +
14950997Sbostic 		    (hashp->BSIZE << BYTE_SHIFT) - 1) >>
15050997Sbostic 		    (hashp->BSHIFT + BYTE_SHIFT);
15146366Sbostic 
15250997Sbostic 		hashp->nmaps = bpages;
15351057Sbostic 		(void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_long *));
15446366Sbostic 	}
15546366Sbostic 
15650997Sbostic 	/* Initialize Buffer Manager */
15750997Sbostic 	if (info && info->cachesize)
15857586Sbostic 		__buf_init(hashp, info->cachesize);
15950997Sbostic 	else
16057586Sbostic 		__buf_init(hashp, DEF_BUFSIZE);
16150997Sbostic 
16250997Sbostic 	hashp->new_file = new_table;
16356422Smargo 	hashp->save_file = file && (hashp->flags & O_RDWR);
16450997Sbostic 	hashp->cbucket = -1;
16550997Sbostic 	if (!(dbp = malloc(sizeof(DB)))) {
16650997Sbostic 		save_errno = errno;
16757586Sbostic 		hdestroy(hashp);
16850997Sbostic 		errno = save_errno;
16950997Sbostic 		return (NULL);
17046366Sbostic 	}
17157586Sbostic 	dbp->internal = hashp;
17250997Sbostic 	dbp->close = hash_close;
17350997Sbostic 	dbp->del = hash_delete;
17460247Sbostic 	dbp->fd = hash_fd;
17550997Sbostic 	dbp->get = hash_get;
17650997Sbostic 	dbp->put = hash_put;
17750997Sbostic 	dbp->seq = hash_seq;
17850997Sbostic 	dbp->sync = hash_sync;
17950997Sbostic 	dbp->type = DB_HASH;
18046366Sbostic 
18146366Sbostic #ifdef DEBUG
18250997Sbostic 	(void)fprintf(stderr,
18351061Sbostic "%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",
18450997Sbostic 	    "init_htab:",
18550997Sbostic 	    "TABLE POINTER   ", hashp,
18650997Sbostic 	    "BUCKET SIZE     ", hashp->BSIZE,
18750997Sbostic 	    "BUCKET SHIFT    ", hashp->BSHIFT,
18850997Sbostic 	    "DIRECTORY SIZE  ", hashp->DSIZE,
18950997Sbostic 	    "SEGMENT SIZE    ", hashp->SGSIZE,
19050997Sbostic 	    "SEGMENT SHIFT   ", hashp->SSHIFT,
19150997Sbostic 	    "FILL FACTOR     ", hashp->FFACTOR,
19250997Sbostic 	    "MAX BUCKET      ", hashp->MAX_BUCKET,
19351061Sbostic 	    "OVFL POINT	     ", hashp->OVFL_POINT,
19451061Sbostic 	    "LAST FREED      ", hashp->LAST_FREED,
19550997Sbostic 	    "HIGH MASK       ", hashp->HIGH_MASK,
19650997Sbostic 	    "LOW  MASK       ", hashp->LOW_MASK,
19750997Sbostic 	    "NSEGS           ", hashp->nsegs,
19850997Sbostic 	    "NKEYS           ", hashp->NKEYS);
19946366Sbostic #endif
20046366Sbostic #ifdef HASH_STATISTICS
20146366Sbostic 	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
20246366Sbostic #endif
20350997Sbostic 	return (dbp);
20446366Sbostic 
20546366Sbostic error1:
20651192Sbostic 	if (hashp != NULL)
20751192Sbostic 		(void)close(hashp->fp);
20846366Sbostic 
20946366Sbostic error0:
21050997Sbostic 	free(hashp);
21150997Sbostic 	errno = save_errno;
21250997Sbostic 	return (NULL);
21346366Sbostic }
21446366Sbostic 
21546366Sbostic static int
21650997Sbostic hash_close(dbp)
21750997Sbostic 	DB *dbp;
21846366Sbostic {
21957586Sbostic 	HTAB *hashp;
22050997Sbostic 	int retval;
22146457Sbostic 
22250997Sbostic 	if (!dbp)
22350997Sbostic 		return (ERROR);
22457586Sbostic 
22546366Sbostic 	hashp = (HTAB *)dbp->internal;
22657586Sbostic 	retval = hdestroy(hashp);
22750997Sbostic 	free(dbp);
22850997Sbostic 	return (retval);
22946366Sbostic }
23046366Sbostic 
23160247Sbostic static int
23260247Sbostic hash_fd(dbp)
23360247Sbostic 	const DB *dbp;
23460247Sbostic {
23560247Sbostic 	HTAB *hashp;
23660247Sbostic 
23760247Sbostic 	if (!dbp)
23860247Sbostic 		return (ERROR);
23960247Sbostic 
24060247Sbostic 	hashp = (HTAB *)dbp->internal;
24160247Sbostic 	if (hashp->fp == -1) {
24260247Sbostic 		errno = ENOENT;
24360247Sbostic 		return (-1);
24460247Sbostic 	}
24560247Sbostic 	return (hashp->fp);
24660247Sbostic }
24760247Sbostic 
24846366Sbostic /************************** LOCAL CREATION ROUTINES **********************/
24950997Sbostic static HTAB *
25060247Sbostic init_hash(hashp, file, info)
25157586Sbostic 	HTAB *hashp;
25260247Sbostic 	const char *file;
25350997Sbostic 	HASHINFO *info;
25446366Sbostic {
25560247Sbostic 	struct stat statbuf;
25650997Sbostic 	int nelem;
25746366Sbostic 
25846366Sbostic 	nelem = 1;
25951061Sbostic 	hashp->NKEYS = 0;
26050997Sbostic 	hashp->LORDER = BYTE_ORDER;
26150997Sbostic 	hashp->BSIZE = DEF_BUCKET_SIZE;
26250997Sbostic 	hashp->BSHIFT = DEF_BUCKET_SHIFT;
26350997Sbostic 	hashp->SGSIZE = DEF_SEGSIZE;
26450997Sbostic 	hashp->SSHIFT = DEF_SEGSIZE_SHIFT;
26550997Sbostic 	hashp->DSIZE = DEF_DIRSIZE;
26650997Sbostic 	hashp->FFACTOR = DEF_FFACTOR;
26757586Sbostic 	hashp->hash = __default_hash;
26858016Sbostic 	memset(hashp->SPARES, 0, sizeof(hashp->SPARES));
26958016Sbostic 	memset(hashp->BITMAPS, 0, sizeof (hashp->BITMAPS));
27046366Sbostic 
27160247Sbostic 	/* Fix bucket size to be optimal for file system */
27260247Sbostic 	if (file != NULL) {
27360247Sbostic 		if (stat(file, &statbuf))
27460247Sbostic 			return (NULL);
27560247Sbostic 		hashp->BSIZE = statbuf.st_blksize;
27660247Sbostic 		hashp->BSHIFT = __log2(hashp->BSIZE);
27760247Sbostic 	}
27860247Sbostic 
27950997Sbostic 	if (info) {
28050997Sbostic 		if (info->bsize) {
28150997Sbostic 			/* Round pagesize up to power of 2 */
28250997Sbostic 			hashp->BSHIFT = __log2(info->bsize);
28350997Sbostic 			hashp->BSIZE = 1 << hashp->BSHIFT;
28450997Sbostic 			if (hashp->BSIZE > MAX_BSIZE) {
28550997Sbostic 				errno = EINVAL;
28650997Sbostic 				return (NULL);
28750997Sbostic 			}
28846366Sbostic 		}
28950997Sbostic 		if (info->ffactor)
29050997Sbostic 			hashp->FFACTOR = info->ffactor;
29150997Sbostic 		if (info->hash)
29250997Sbostic 			hashp->hash = info->hash;
29350997Sbostic 		if (info->nelem)
29450997Sbostic 			nelem = info->nelem;
29550997Sbostic 		if (info->lorder) {
29650997Sbostic 			if (info->lorder != BIG_ENDIAN &&
29750997Sbostic 			    info->lorder != LITTLE_ENDIAN) {
29850997Sbostic 				errno = EINVAL;
29950997Sbostic 				return (NULL);
30050997Sbostic 			}
30150997Sbostic 			hashp->LORDER = info->lorder;
30246366Sbostic 		}
30346366Sbostic 	}
30446366Sbostic 	/* init_htab should destroy the table and set errno if it fails */
30557586Sbostic 	if (init_htab(hashp, nelem))
30650997Sbostic 		return (NULL);
30750997Sbostic 	else
30850997Sbostic 		return (hashp);
30946366Sbostic }
31046366Sbostic /*
31150997Sbostic  * This calls alloc_segs which may run out of memory.  Alloc_segs will destroy
31250997Sbostic  * the table and set errno, so we just pass the error information along.
31350997Sbostic  *
31450997Sbostic  * Returns 0 on No Error
31550997Sbostic  */
31646366Sbostic static int
31757586Sbostic init_htab(hashp, nelem)
31857586Sbostic 	HTAB *hashp;
31950997Sbostic 	int nelem;
32046366Sbostic {
32150997Sbostic 	register int nbuckets, nsegs;
32250997Sbostic 	int l2;
32346366Sbostic 
32450997Sbostic 	/*
32550997Sbostic 	 * Divide number of elements by the fill factor and determine a
32650997Sbostic 	 * desired number of buckets.  Allocate space for the next greater
32750997Sbostic 	 * power of two number of buckets.
32850997Sbostic 	 */
32946366Sbostic 	nelem = (nelem - 1) / hashp->FFACTOR + 1;
33046366Sbostic 
33152001Sbostic 	l2 = __log2(MAX(nelem, 2));
33246366Sbostic 	nbuckets = 1 << l2;
33346366Sbostic 
33446366Sbostic 	hashp->SPARES[l2] = l2 + 1;
33550997Sbostic 	hashp->SPARES[l2 + 1] = l2 + 1;
33651061Sbostic 	hashp->OVFL_POINT = l2;
33751061Sbostic 	hashp->LAST_FREED = 2;
33851061Sbostic 
33950997Sbostic 	/* First bitmap page is at: splitpoint l2 page offset 1 */
34057586Sbostic 	if (__init_bitmap(hashp, OADDR_OF(l2, 1), l2 + 1, 0))
34151057Sbostic 		return (-1);
34246366Sbostic 
34346366Sbostic 	hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
34446366Sbostic 	hashp->HIGH_MASK = (nbuckets << 1) - 1;
34550997Sbostic 	hashp->HDRPAGES = ((MAX(sizeof(HASHHDR), MINHDRSIZE) - 1) >>
34650997Sbostic 	    hashp->BSHIFT) + 1;
34746366Sbostic 
34846366Sbostic 	nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
34946366Sbostic 	nsegs = 1 << __log2(nsegs);
35046366Sbostic 
35150997Sbostic 	if (nsegs > hashp->DSIZE)
35250997Sbostic 		hashp->DSIZE = nsegs;
35357586Sbostic 	return (alloc_segs(hashp, nsegs));
35446366Sbostic }
35546366Sbostic 
35646366Sbostic /********************** DESTROY/CLOSE ROUTINES ************************/
35746366Sbostic 
35846366Sbostic /*
35950997Sbostic  * Flushes any changes to the file if necessary and destroys the hashp
36050997Sbostic  * structure, freeing all allocated space.
36150997Sbostic  */
36246366Sbostic static int
36357586Sbostic hdestroy(hashp)
36457586Sbostic 	HTAB *hashp;
36546366Sbostic {
36650997Sbostic 	int i, save_errno;
36746366Sbostic 
36846366Sbostic 	save_errno = 0;
36946366Sbostic 
37046366Sbostic #ifdef HASH_STATISTICS
37157586Sbostic 	(void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
37257586Sbostic 	    hash_accesses, hash_collisions);
37357586Sbostic 	(void)fprintf(stderr, "hdestroy: expansions %ld\n",
37457586Sbostic 	    hash_expansions);
37557586Sbostic 	(void)fprintf(stderr, "hdestroy: overflows %ld\n",
37657586Sbostic 	    hash_overflows);
37757586Sbostic 	(void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n",
37857586Sbostic 	    hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
37946366Sbostic 
38057586Sbostic 	for (i = 0; i < NCACHED; i++)
38157586Sbostic 		(void)fprintf(stderr,
38257586Sbostic 		    "spares[%d] = %d\n", i, hashp->SPARES[i]);
38346366Sbostic #endif
38457586Sbostic 	/*
38557586Sbostic 	 * Call on buffer manager to free buffers, and if required,
38657586Sbostic 	 * write them to disk.
38757586Sbostic 	 */
38857586Sbostic 	if (__buf_free(hashp, 1, hashp->save_file))
38957586Sbostic 		save_errno = errno;
39057586Sbostic 	if (hashp->dir) {
39157586Sbostic 		free(*hashp->dir);	/* Free initial segments */
39257586Sbostic 		/* Free extra segments */
39357586Sbostic 		while (hashp->exsegs--)
39457586Sbostic 			free(hashp->dir[--hashp->nsegs]);
39557586Sbostic 		free(hashp->dir);
39657586Sbostic 	}
39757586Sbostic 	if (flush_meta(hashp) && !save_errno)
39857586Sbostic 		save_errno = errno;
39957586Sbostic 	/* Free Bigmaps */
40057586Sbostic 	for (i = 0; i < hashp->nmaps; i++)
40157586Sbostic 		if (hashp->mapp[i])
40257586Sbostic 			free(hashp->mapp[i]);
40346503Sbostic 
40457586Sbostic 	if (hashp->fp != -1)
40557586Sbostic 		(void)close(hashp->fp);
40657586Sbostic 
40750997Sbostic 	if (save_errno) {
40850997Sbostic 		errno = save_errno;
40950997Sbostic 		return (ERROR);
41046366Sbostic 	}
41150997Sbostic 	return (SUCCESS);
41246366Sbostic }
41350997Sbostic /*
41450997Sbostic  * Write modified pages to disk
41550997Sbostic  *
41650997Sbostic  * Returns:
41750997Sbostic  *	 0 == OK
41850997Sbostic  *	-1 ERROR
41950997Sbostic  */
42046366Sbostic static int
42160060Sbostic hash_sync(dbp, flags)
42250997Sbostic 	const DB *dbp;
42360060Sbostic 	u_int flags;
42446366Sbostic {
42557586Sbostic 	HTAB *hashp;
42657586Sbostic 
42760060Sbostic 	if (flags != 0) {
42860060Sbostic 		errno = EINVAL;
42960060Sbostic 		return (ERROR);
43060060Sbostic 	}
43160060Sbostic 
43250997Sbostic 	if (!dbp)
43350997Sbostic 		return (ERROR);
43457586Sbostic 
43546366Sbostic 	hashp = (HTAB *)dbp->internal;
43650997Sbostic 	if (!hashp->save_file)
43750997Sbostic 		return (0);
43857586Sbostic 	if (__buf_free(hashp, 0, 1) || flush_meta(hashp))
43950997Sbostic 		return (ERROR);
44046366Sbostic 	hashp->new_file = 0;
44150997Sbostic 	return (0);
44246366Sbostic }
44346366Sbostic 
44446366Sbostic /*
44550997Sbostic  * Returns:
44650997Sbostic  *	 0 == OK
44750997Sbostic  *	-1 indicates that errno should be set
44850997Sbostic  */
44946366Sbostic static int
45057586Sbostic flush_meta(hashp)
45157586Sbostic 	HTAB *hashp;
45246366Sbostic {
45351814Smarc 	HASHHDR *whdrp;
45451814Smarc #if BYTE_ORDER == LITTLE_ENDIAN
45551814Smarc 	HASHHDR whdr;
45651814Smarc #endif
45750997Sbostic 	int fp, i, wsize;
45846366Sbostic 
45950997Sbostic 	if (!hashp->save_file)
46050997Sbostic 		return (0);
46146366Sbostic 	hashp->MAGIC = HASHMAGIC;
46251061Sbostic 	hashp->VERSION = HASHVERSION;
46350997Sbostic 	hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY));
46446366Sbostic 
46546366Sbostic 	fp = hashp->fp;
46646366Sbostic 	whdrp = &hashp->hdr;
46746366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
46846366Sbostic 	whdrp = &whdr;
46950997Sbostic 	swap_header_copy(&hashp->hdr, whdrp);
47046366Sbostic #endif
47156669Sbostic 	if ((lseek(fp, (off_t)0, SEEK_SET) == -1) ||
47250997Sbostic 	    ((wsize = write(fp, whdrp, sizeof(HASHHDR))) == -1))
47350997Sbostic 		return (-1);
47450997Sbostic 	else
47550997Sbostic 		if (wsize != sizeof(HASHHDR)) {
47650997Sbostic 			errno = EFTYPE;
47750997Sbostic 			hashp->errno = errno;
47850997Sbostic 			return (-1);
47946366Sbostic 		}
48050997Sbostic 	for (i = 0; i < NCACHED; i++)
48150997Sbostic 		if (hashp->mapp[i])
48257586Sbostic 			if (__put_page(hashp, (char *)hashp->mapp[i],
48350997Sbostic 				hashp->BITMAPS[i], 0, 1))
48450997Sbostic 				return (-1);
48550997Sbostic 	return (0);
48646366Sbostic }
48750997Sbostic 
48846366Sbostic /*******************************SEARCH ROUTINES *****************************/
48946366Sbostic /*
49050997Sbostic  * All the access routines return
49150997Sbostic  *
49250997Sbostic  * Returns:
49350997Sbostic  *	 0 on SUCCESS
49450997Sbostic  *	 1 to indicate an external ERROR (i.e. key not found, etc)
49550997Sbostic  *	-1 to indicate an internal ERROR (i.e. out of memory, etc)
49650997Sbostic  */
49746366Sbostic static int
49850997Sbostic hash_get(dbp, key, data, flag)
49950997Sbostic 	const DB *dbp;
50051057Sbostic 	const DBT *key;
50151057Sbostic 	DBT *data;
50250997Sbostic 	u_int flag;
50346366Sbostic {
50457586Sbostic 	HTAB *hashp;
50557586Sbostic 
50657586Sbostic 	hashp = (HTAB *)dbp->internal;
50750997Sbostic 	if (flag) {
50850997Sbostic 		hashp->errno = errno = EINVAL;
50950997Sbostic 		return (ERROR);
51050997Sbostic 	}
51157586Sbostic 	return (hash_access(hashp, HASH_GET, (DBT *)key, data));
51246366Sbostic }
51346366Sbostic 
51446366Sbostic static int
51550997Sbostic hash_put(dbp, key, data, flag)
51650997Sbostic 	const DB *dbp;
51756893Sbostic 	DBT *key;
51856893Sbostic 	const DBT *data;
51950997Sbostic 	u_int flag;
52046366Sbostic {
52157586Sbostic 	HTAB *hashp;
52257586Sbostic 
52357586Sbostic 	hashp = (HTAB *)dbp->internal;
52450997Sbostic 	if (flag && flag != R_NOOVERWRITE) {
52550997Sbostic 		hashp->errno = errno = EINVAL;
52650997Sbostic 		return (ERROR);
52750997Sbostic 	}
52850997Sbostic 	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
52950997Sbostic 		hashp->errno = errno = EPERM;
53050997Sbostic 		return (ERROR);
53150997Sbostic 	}
53257586Sbostic 	return (hash_access(hashp, flag == R_NOOVERWRITE ?
53350997Sbostic 	    HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));
53446366Sbostic }
53546366Sbostic 
53646366Sbostic static int
53750997Sbostic hash_delete(dbp, key, flag)
53850997Sbostic 	const DB *dbp;
53950997Sbostic 	const DBT *key;
54050997Sbostic 	u_int flag;		/* Ignored */
54146366Sbostic {
54257586Sbostic 	HTAB *hashp;
54357586Sbostic 
54457586Sbostic 	hashp = (HTAB *)dbp->internal;
54550997Sbostic 	if (flag && flag != R_CURSOR) {
54650997Sbostic 		hashp->errno = errno = EINVAL;
54750997Sbostic 		return (ERROR);
54850997Sbostic 	}
54950997Sbostic 	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
55050997Sbostic 		hashp->errno = errno = EPERM;
55150997Sbostic 		return (ERROR);
55250997Sbostic 	}
55357586Sbostic 	return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
55446366Sbostic }
55546366Sbostic 
55646366Sbostic /*
55750997Sbostic  * Assume that hashp has been set in wrapper routine.
55850997Sbostic  */
55946366Sbostic static int
56057586Sbostic hash_access(hashp, action, key, val)
56157586Sbostic 	HTAB *hashp;
56250997Sbostic 	ACTION action;
56350997Sbostic 	DBT *key, *val;
56446366Sbostic {
56550997Sbostic 	register BUFHEAD *rbufp;
56650997Sbostic 	BUFHEAD *bufp, *save_bufp;
56750997Sbostic 	register u_short *bp;
56850997Sbostic 	register int n, ndx, off, size;
56950997Sbostic 	register char *kp;
57050997Sbostic 	u_short pageno;
57146366Sbostic 
57246366Sbostic #ifdef HASH_STATISTICS
57346366Sbostic 	hash_accesses++;
57446366Sbostic #endif
57546366Sbostic 
57650997Sbostic 	off = hashp->BSIZE;
57746366Sbostic 	size = key->size;
57846950Sbostic 	kp = (char *)key->data;
57957586Sbostic 	rbufp = __get_buf(hashp, __call_hash(hashp, kp, size), NULL, 0);
58050997Sbostic 	if (!rbufp)
58150997Sbostic 		return (ERROR);
58246457Sbostic 	save_bufp = rbufp;
58346366Sbostic 
58446457Sbostic 	/* Pin the bucket chain */
58546457Sbostic 	rbufp->flags |= BUF_PIN;
58650997Sbostic 	for (bp = (u_short *)rbufp->page, n = *bp++, ndx = 1; ndx < n;)
58750997Sbostic 		if (bp[1] >= REAL_KEY) {
58850997Sbostic 			/* Real key/data pair */
58950997Sbostic 			if (size == off - *bp &&
59058016Sbostic 			    memcmp(kp, rbufp->page + *bp, size) == 0)
59150997Sbostic 				goto found;
59250997Sbostic 			off = bp[1];
59346366Sbostic #ifdef HASH_STATISTICS
59450997Sbostic 			hash_collisions++;
59546366Sbostic #endif
59650997Sbostic 			bp += 2;
59750997Sbostic 			ndx += 2;
59850997Sbostic 		} else if (bp[1] == OVFLPAGE) {
59957586Sbostic 			rbufp = __get_buf(hashp, *bp, rbufp, 0);
60050997Sbostic 			if (!rbufp) {
60150997Sbostic 				save_bufp->flags &= ~BUF_PIN;
60250997Sbostic 				return (ERROR);
60350997Sbostic 			}
60450997Sbostic 			/* FOR LOOP INIT */
60550997Sbostic 			bp = (u_short *)rbufp->page;
60650997Sbostic 			n = *bp++;
60750997Sbostic 			ndx = 1;
60850997Sbostic 			off = hashp->BSIZE;
60950997Sbostic 		} else if (bp[1] < REAL_KEY) {
61057586Sbostic 			if ((ndx =
61157586Sbostic 			    __find_bigpair(hashp, rbufp, ndx, kp, size)) > 0)
61250997Sbostic 				goto found;
61350997Sbostic 			if (ndx == -2) {
61450997Sbostic 				bufp = rbufp;
61557586Sbostic 				if (!(pageno =
61657586Sbostic 				    __find_last_page(hashp, &bufp))) {
61750997Sbostic 					ndx = 0;
61850997Sbostic 					rbufp = bufp;
61950997Sbostic 					break;	/* FOR */
62050997Sbostic 				}
62157586Sbostic 				rbufp = __get_buf(hashp, pageno, bufp, 0);
62250997Sbostic 				if (!rbufp) {
62350997Sbostic 					save_bufp->flags &= ~BUF_PIN;
62450997Sbostic 					return (ERROR);
62550997Sbostic 				}
62650997Sbostic 				/* FOR LOOP INIT */
62750997Sbostic 				bp = (u_short *)rbufp->page;
62850997Sbostic 				n = *bp++;
62950997Sbostic 				ndx = 1;
63050997Sbostic 				off = hashp->BSIZE;
63150997Sbostic 			} else {
63250997Sbostic 				save_bufp->flags &= ~BUF_PIN;
63350997Sbostic 				return (ERROR);
63450997Sbostic 			}
63546457Sbostic 		}
63646366Sbostic 
63746366Sbostic 	/* Not found */
63850997Sbostic 	switch (action) {
63950997Sbostic 	case HASH_PUT:
64050997Sbostic 	case HASH_PUTNEW:
64157586Sbostic 		if (__addel(hashp, rbufp, key, val)) {
64250997Sbostic 			save_bufp->flags &= ~BUF_PIN;
64350997Sbostic 			return (ERROR);
64446366Sbostic 		} else {
64550997Sbostic 			save_bufp->flags &= ~BUF_PIN;
64650997Sbostic 			return (SUCCESS);
64746366Sbostic 		}
64850997Sbostic 	case HASH_GET:
64950997Sbostic 	case HASH_DELETE:
65050997Sbostic 	default:
65146457Sbostic 		save_bufp->flags &= ~BUF_PIN;
65250997Sbostic 		return (ABNORMAL);
65346366Sbostic 	}
65446366Sbostic 
65546366Sbostic found:
65646366Sbostic 	switch (action) {
65750997Sbostic 	case HASH_PUTNEW:
65846457Sbostic 		save_bufp->flags &= ~BUF_PIN;
65950997Sbostic 		return (ABNORMAL);
66050997Sbostic 	case HASH_GET:
66146366Sbostic 		bp = (u_short *)rbufp->page;
66251072Sbostic 		if (bp[ndx + 1] < REAL_KEY) {
66357586Sbostic 			if (__big_return(hashp, rbufp, ndx, val, 0))
66451057Sbostic 				return (ERROR);
66551072Sbostic 		} else {
66650997Sbostic 			val->data = (u_char *)rbufp->page + (int)bp[ndx + 1];
66750997Sbostic 			val->size = bp[ndx] - bp[ndx + 1];
66846366Sbostic 		}
66946366Sbostic 		break;
67050997Sbostic 	case HASH_PUT:
67157586Sbostic 		if ((__delpair(hashp, rbufp, ndx)) ||
67257586Sbostic 		    (__addel(hashp, rbufp, key, val))) {
67350997Sbostic 			save_bufp->flags &= ~BUF_PIN;
67450997Sbostic 			return (ERROR);
67546457Sbostic 		}
67646366Sbostic 		break;
67750997Sbostic 	case HASH_DELETE:
67857586Sbostic 		if (__delpair(hashp, rbufp, ndx))
67950997Sbostic 			return (ERROR);
68046366Sbostic 		break;
68157586Sbostic 	default:
68257586Sbostic 		abort();
68346366Sbostic 	}
68446457Sbostic 	save_bufp->flags &= ~BUF_PIN;
68546366Sbostic 	return (SUCCESS);
68646366Sbostic }
68746366Sbostic 
68846366Sbostic static int
68946366Sbostic hash_seq(dbp, key, data, flag)
69050997Sbostic 	const DB *dbp;
69150997Sbostic 	DBT *key, *data;
69250997Sbostic 	u_int flag;
69346366Sbostic {
69450997Sbostic 	register u_int bucket;
69550997Sbostic 	register BUFHEAD *bufp;
69657586Sbostic 	HTAB *hashp;
69750997Sbostic 	u_short *bp, ndx;
69846366Sbostic 
69957586Sbostic 	hashp = (HTAB *)dbp->internal;
70050997Sbostic 	if (flag && flag != R_FIRST && flag != R_NEXT) {
70150997Sbostic 		hashp->errno = errno = EINVAL;
70250997Sbostic 		return (ERROR);
70346366Sbostic 	}
70446366Sbostic #ifdef HASH_STATISTICS
70546366Sbostic 	hash_accesses++;
70646366Sbostic #endif
70750997Sbostic 	if ((hashp->cbucket < 0) || (flag == R_FIRST)) {
70850997Sbostic 		hashp->cbucket = 0;
70950997Sbostic 		hashp->cndx = 1;
71050997Sbostic 		hashp->cpage = NULL;
71146366Sbostic 	}
71246366Sbostic 
71355874Sbostic 	for (bp = NULL; !bp || !bp[0]; ) {
71455452Sbostic 		if (!(bufp = hashp->cpage)) {
71555452Sbostic 			for (bucket = hashp->cbucket;
71655452Sbostic 			    bucket <= hashp->MAX_BUCKET;
71755452Sbostic 			    bucket++, hashp->cndx = 1) {
71857586Sbostic 				bufp = __get_buf(hashp, bucket, NULL, 0);
71955452Sbostic 				if (!bufp)
72055452Sbostic 					return (ERROR);
72155452Sbostic 				hashp->cpage = bufp;
72255452Sbostic 				bp = (u_short *)bufp->page;
72355452Sbostic 				if (bp[0])
72455452Sbostic 					break;
72555452Sbostic 			}
72655452Sbostic 			hashp->cbucket = bucket;
72755452Sbostic 			if (hashp->cbucket > hashp->MAX_BUCKET) {
72855452Sbostic 				hashp->cbucket = -1;
72955452Sbostic 				return (ABNORMAL);
73055452Sbostic 			}
73155452Sbostic 		} else
73255452Sbostic 			bp = (u_short *)hashp->cpage->page;
73355452Sbostic 
73455452Sbostic #ifdef DEBUG
73555452Sbostic 		assert(bp);
73655452Sbostic 		assert(bufp);
73755452Sbostic #endif
73855452Sbostic 		while (bp[hashp->cndx + 1] == OVFLPAGE) {
73955452Sbostic 			bufp = hashp->cpage =
74057586Sbostic 			    __get_buf(hashp, bp[hashp->cndx], bufp, 0);
74150997Sbostic 			if (!bufp)
74250997Sbostic 				return (ERROR);
74355452Sbostic 			bp = (u_short *)(bufp->page);
74455452Sbostic 			hashp->cndx = 1;
74550997Sbostic 		}
74655874Sbostic 		if (!bp[0]) {
74755452Sbostic 			hashp->cpage = NULL;
74855874Sbostic 			++hashp->cbucket;
74955874Sbostic 		}
75046366Sbostic 	}
75146366Sbostic 	ndx = hashp->cndx;
75250997Sbostic 	if (bp[ndx + 1] < REAL_KEY) {
75357586Sbostic 		if (__big_keydata(hashp, bufp, key, data, 1))
75450997Sbostic 			return (ERROR);
75546366Sbostic 	} else {
75650997Sbostic 		key->data = (u_char *)hashp->cpage->page + bp[ndx];
75750997Sbostic 		key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
75850997Sbostic 		data->data = (u_char *)hashp->cpage->page + bp[ndx + 1];
75950997Sbostic 		data->size = bp[ndx] - bp[ndx + 1];
76050997Sbostic 		ndx += 2;
76150997Sbostic 		if (ndx > bp[0]) {
76250997Sbostic 			hashp->cpage = NULL;
76350997Sbostic 			hashp->cbucket++;
76450997Sbostic 			hashp->cndx = 1;
76550997Sbostic 		} else
76650997Sbostic 			hashp->cndx = ndx;
76746366Sbostic 	}
76846366Sbostic 	return (SUCCESS);
76946366Sbostic }
77046366Sbostic 
77146366Sbostic /********************************* UTILITIES ************************/
77250997Sbostic 
77346366Sbostic /*
77450997Sbostic  * Returns:
77550997Sbostic  *	 0 ==> OK
77650997Sbostic  *	-1 ==> Error
77750997Sbostic  */
77846366Sbostic extern int
77957586Sbostic __expand_table(hashp)
78057586Sbostic 	HTAB *hashp;
78146366Sbostic {
78250997Sbostic 	u_int old_bucket, new_bucket;
78350997Sbostic 	int dirsize, new_segnum, spare_ndx;
78450997Sbostic 
78546366Sbostic #ifdef HASH_STATISTICS
78646366Sbostic 	hash_expansions++;
78746366Sbostic #endif
78846366Sbostic 	new_bucket = ++hashp->MAX_BUCKET;
78946366Sbostic 	old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
79046366Sbostic 
79146366Sbostic 	new_segnum = new_bucket >> hashp->SSHIFT;
79246366Sbostic 
79346366Sbostic 	/* Check if we need a new segment */
79450997Sbostic 	if (new_segnum >= hashp->nsegs) {
79550997Sbostic 		/* Check if we need to expand directory */
79650997Sbostic 		if (new_segnum >= hashp->DSIZE) {
79750997Sbostic 			/* Reallocate directory */
79850997Sbostic 			dirsize = hashp->DSIZE * sizeof(SEGMENT *);
79950997Sbostic 			if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1))
80050997Sbostic 				return (-1);
80150997Sbostic 			hashp->DSIZE = dirsize << 1;
80246366Sbostic 		}
80350997Sbostic 		if (!(hashp->dir[new_segnum] =
80450997Sbostic 			calloc(hashp->SGSIZE, sizeof(SEGMENT))))
80550997Sbostic 			return (-1);
80650997Sbostic 		hashp->exsegs++;
80750997Sbostic 		hashp->nsegs++;
80846366Sbostic 	}
80946366Sbostic 	/*
81050997Sbostic 	 * If the split point is increasing (MAX_BUCKET's log base 2
81150997Sbostic 	 * * increases), we need to copy the current contents of the spare
81250997Sbostic 	 * split bucket to the next bucket.
81350997Sbostic 	 */
81452001Sbostic 	spare_ndx = __log2(hashp->MAX_BUCKET + 1);
81552001Sbostic 	if (spare_ndx > hashp->OVFL_POINT) {
81651061Sbostic 		hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT];
81751061Sbostic 		hashp->OVFL_POINT = spare_ndx;
81851061Sbostic 	}
81951061Sbostic 
82050997Sbostic 	if (new_bucket > hashp->HIGH_MASK) {
82150997Sbostic 		/* Starting a new doubling */
82250997Sbostic 		hashp->LOW_MASK = hashp->HIGH_MASK;
82350997Sbostic 		hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
82446366Sbostic 	}
82550997Sbostic 	/* Relocate records to the new bucket */
82657586Sbostic 	return (__split_page(hashp, old_bucket, new_bucket));
82750997Sbostic }
82846366Sbostic 
82946366Sbostic /*
83050997Sbostic  * If realloc guarantees that the pointer is not destroyed if the realloc
83150997Sbostic  * fails, then this routine can go away.
83250997Sbostic  */
83350997Sbostic static void *
83450997Sbostic hash_realloc(p_ptr, oldsize, newsize)
83550997Sbostic 	SEGMENT **p_ptr;
83650997Sbostic 	int oldsize, newsize;
83746366Sbostic {
83850997Sbostic 	register void *p;
83946366Sbostic 
84050997Sbostic 	if (p = malloc(newsize)) {
84158016Sbostic 		memmove(p, *p_ptr, oldsize);
84262487Sbostic 		memset(p + oldsize, 0, newsize - oldsize);
84346366Sbostic 		free(*p_ptr);
84446366Sbostic 		*p_ptr = p;
84546366Sbostic 	}
84646366Sbostic 	return (p);
84746366Sbostic }
84846366Sbostic 
84947251Sbostic extern u_int
85057586Sbostic __call_hash(hashp, k, len)
85157586Sbostic 	HTAB *hashp;
85250997Sbostic 	char *k;
85350997Sbostic 	int len;
85446366Sbostic {
85550997Sbostic 	int n, bucket;
85650997Sbostic 
85746366Sbostic 	n = hashp->hash(k, len);
85846366Sbostic 	bucket = n & hashp->HIGH_MASK;
85950997Sbostic 	if (bucket > hashp->MAX_BUCKET)
86050997Sbostic 		bucket = bucket & hashp->LOW_MASK;
86150997Sbostic 	return (bucket);
86246366Sbostic }
86346366Sbostic 
86446366Sbostic /*
86550997Sbostic  * Allocate segment table.  On error, destroy the table and set errno.
86650997Sbostic  *
86750997Sbostic  * Returns 0 on success
86850997Sbostic  */
86946366Sbostic static int
87057586Sbostic alloc_segs(hashp, nsegs)
87157586Sbostic 	HTAB *hashp;
87250997Sbostic 	int nsegs;
87346366Sbostic {
87450997Sbostic 	register int i;
87550997Sbostic 	register SEGMENT store;
87646366Sbostic 
87750997Sbostic 	int save_errno;
87846366Sbostic 
87950997Sbostic 	if (!(hashp->dir = calloc(hashp->DSIZE, sizeof(SEGMENT *)))) {
88050997Sbostic 		save_errno = errno;
88157586Sbostic 		(void)hdestroy(hashp);
88250997Sbostic 		errno = save_errno;
88350997Sbostic 		return (-1);
88450997Sbostic 	}
88550997Sbostic 	/* Allocate segments */
88650997Sbostic 	store = calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT));
88750997Sbostic 	if (!store) {
88850997Sbostic 		save_errno = errno;
88957586Sbostic 		(void)hdestroy(hashp);
89050997Sbostic 		errno = save_errno;
89150997Sbostic 		return (-1);
89250997Sbostic 	}
89350997Sbostic 	for (i = 0; i < nsegs; i++, hashp->nsegs++)
89450997Sbostic 		hashp->dir[i] = &store[i << hashp->SSHIFT];
89550997Sbostic 	return (0);
89646366Sbostic }
89746366Sbostic 
89850997Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
89946366Sbostic /*
90050997Sbostic  * Hashp->hdr needs to be byteswapped.
90150997Sbostic  */
90246366Sbostic static void
90350997Sbostic swap_header_copy(srcp, destp)
90450997Sbostic 	HASHHDR *srcp, *destp;
90546366Sbostic {
90650997Sbostic 	int i;
90746366Sbostic 
90850997Sbostic 	BLSWAP_COPY(srcp->magic, destp->magic);
90950997Sbostic 	BLSWAP_COPY(srcp->version, destp->version);
91050997Sbostic 	BLSWAP_COPY(srcp->lorder, destp->lorder);
91150997Sbostic 	BLSWAP_COPY(srcp->bsize, destp->bsize);
91250997Sbostic 	BLSWAP_COPY(srcp->bshift, destp->bshift);
91350997Sbostic 	BLSWAP_COPY(srcp->dsize, destp->dsize);
91450997Sbostic 	BLSWAP_COPY(srcp->ssize, destp->ssize);
91550997Sbostic 	BLSWAP_COPY(srcp->sshift, destp->sshift);
91651061Sbostic 	BLSWAP_COPY(srcp->ovfl_point, destp->ovfl_point);
91751061Sbostic 	BLSWAP_COPY(srcp->last_freed, destp->last_freed);
91850997Sbostic 	BLSWAP_COPY(srcp->max_bucket, destp->max_bucket);
91950997Sbostic 	BLSWAP_COPY(srcp->high_mask, destp->high_mask);
92050997Sbostic 	BLSWAP_COPY(srcp->low_mask, destp->low_mask);
92150997Sbostic 	BLSWAP_COPY(srcp->ffactor, destp->ffactor);
92250997Sbostic 	BLSWAP_COPY(srcp->nkeys, destp->nkeys);
92350997Sbostic 	BLSWAP_COPY(srcp->hdrpages, destp->hdrpages);
92450997Sbostic 	BLSWAP_COPY(srcp->h_charkey, destp->h_charkey);
92550997Sbostic 	for (i = 0; i < NCACHED; i++) {
92650997Sbostic 		BLSWAP_COPY(srcp->spares[i], destp->spares[i]);
92750997Sbostic 		BSSWAP_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
92850997Sbostic 	}
92946366Sbostic }
93046366Sbostic 
93146366Sbostic static void
93257586Sbostic swap_header(hashp)
93357586Sbostic 	HTAB *hashp;
93446366Sbostic {
93550997Sbostic 	HASHHDR *hdrp;
93650997Sbostic 	int i;
93746366Sbostic 
93850997Sbostic 	hdrp = &hashp->hdr;
93946366Sbostic 
94050997Sbostic 	BLSWAP(hdrp->magic);
94150997Sbostic 	BLSWAP(hdrp->version);
94250997Sbostic 	BLSWAP(hdrp->lorder);
94350997Sbostic 	BLSWAP(hdrp->bsize);
94450997Sbostic 	BLSWAP(hdrp->bshift);
94550997Sbostic 	BLSWAP(hdrp->dsize);
94650997Sbostic 	BLSWAP(hdrp->ssize);
94750997Sbostic 	BLSWAP(hdrp->sshift);
94851061Sbostic 	BLSWAP(hdrp->ovfl_point);
94951061Sbostic 	BLSWAP(hdrp->last_freed);
95050997Sbostic 	BLSWAP(hdrp->max_bucket);
95150997Sbostic 	BLSWAP(hdrp->high_mask);
95250997Sbostic 	BLSWAP(hdrp->low_mask);
95350997Sbostic 	BLSWAP(hdrp->ffactor);
95450997Sbostic 	BLSWAP(hdrp->nkeys);
95550997Sbostic 	BLSWAP(hdrp->hdrpages);
95650997Sbostic 	BLSWAP(hdrp->h_charkey);
95750997Sbostic 	for (i = 0; i < NCACHED; i++) {
95850997Sbostic 		BLSWAP(hdrp->spares[i]);
95950997Sbostic 		BSSWAP(hdrp->bitmaps[i]);
96050997Sbostic 	}
96146366Sbostic }
96250997Sbostic #endif
963