xref: /csrg-svn/lib/libc/db/hash/hash.c (revision 46366)
1*46366Sbostic /*-
2*46366Sbostic  * Copyright (c) 1990 The Regents of the University of California.
3*46366Sbostic  * All rights reserved.
4*46366Sbostic  *
5*46366Sbostic  * This code is derived from software contributed to Berkeley by
6*46366Sbostic  * Margo Seltzer.
7*46366Sbostic  *
8*46366Sbostic  * %sccs.include.redist.c%
9*46366Sbostic  */
10*46366Sbostic 
11*46366Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*46366Sbostic static char sccsid[] = "@(#)hash.c	5.1 (Berkeley) 02/12/91";
13*46366Sbostic #endif /* LIBC_SCCS and not lint */
14*46366Sbostic 
15*46366Sbostic #include <sys/param.h>
16*46366Sbostic #include <sys/file.h>
17*46366Sbostic #include <sys/stat.h>
18*46366Sbostic #include <errno.h>
19*46366Sbostic #include <assert.h>
20*46366Sbostic #include <db.h>
21*46366Sbostic #include "hash.h"
22*46366Sbostic #include <string.h>
23*46366Sbostic 
24*46366Sbostic /* For systems that do not have O_ACCMODE */
25*46366Sbostic #ifndef O_ACCMODE
26*46366Sbostic #define O_ACCMODE       (O_RDONLY|O_WRONLY|O_RDWR)
27*46366Sbostic #endif
28*46366Sbostic 
29*46366Sbostic /* Fast arithmetic, relying on powers of 2, */
30*46366Sbostic 
31*46366Sbostic #define MOD(x,y)		((x) & ((y)-1))
32*46366Sbostic #define RETURN_ERROR(ERR,LOC)	{ save_errno = ERR; goto LOC; }
33*46366Sbostic 
34*46366Sbostic /* Return values */
35*46366Sbostic 
36*46366Sbostic #define	SUCCESS	0
37*46366Sbostic #define	ERROR	-1
38*46366Sbostic #define	ABNORMAL 1
39*46366Sbostic 
40*46366Sbostic /* external routines */
41*46366Sbostic extern char *calloc();
42*46366Sbostic 
43*46366Sbostic /* page.c */
44*46366Sbostic extern int __get_page();
45*46366Sbostic extern int __split_page();
46*46366Sbostic extern int __addel();
47*46366Sbostic extern int __delpair();
48*46366Sbostic extern u_long *__init_bitmap();
49*46366Sbostic 
50*46366Sbostic /* big.c */
51*46366Sbostic extern void __big_return();
52*46366Sbostic extern int __big_keydata();
53*46366Sbostic extern u_short __find_last_page();
54*46366Sbostic 
55*46366Sbostic /* buf.c */
56*46366Sbostic extern BUFHEAD	*__get_buf();
57*46366Sbostic extern void __buf_init();
58*46366Sbostic extern int __buf_free();
59*46366Sbostic 
60*46366Sbostic /* hash function */
61*46366Sbostic extern int (*default_hash)();
62*46366Sbostic 
63*46366Sbostic /* My externals */
64*46366Sbostic extern int __expand_table();
65*46366Sbostic extern int __call_hash();
66*46366Sbostic 
67*46366Sbostic /* Internal routines */
68*46366Sbostic static HTAB *init_hash();
69*46366Sbostic static int hash_access();
70*46366Sbostic static int flush_meta();
71*46366Sbostic static int alloc_segs();
72*46366Sbostic static int init_htab();
73*46366Sbostic static char *hash_realloc();
74*46366Sbostic static int hdestroy();
75*46366Sbostic static int hash_put();
76*46366Sbostic static int hash_delete();
77*46366Sbostic static int hash_get();
78*46366Sbostic static int hash_sync();
79*46366Sbostic static int hash_close();
80*46366Sbostic static int hash_seq();
81*46366Sbostic static void swap_header_copy();
82*46366Sbostic static void swap_header();
83*46366Sbostic 
84*46366Sbostic /* Local data */
85*46366Sbostic 
86*46366Sbostic HTAB *hashp = NULL;
87*46366Sbostic 
88*46366Sbostic #ifdef HASH_STATISTICS
89*46366Sbostic long hash_accesses, hash_collisions, hash_expansions, hash_overflows;
90*46366Sbostic #endif
91*46366Sbostic 
92*46366Sbostic /************************** INTERFACE ROUTINES **********************/
93*46366Sbostic /* OPEN/CLOSE */
94*46366Sbostic 
95*46366Sbostic extern	DB *
96*46366Sbostic hash_open ( file, flags, mode, info )
97*46366Sbostic char	*file;
98*46366Sbostic int	flags;
99*46366Sbostic int	mode;
100*46366Sbostic HASHINFO	*info;		/* Special directives for create */
101*46366Sbostic {
102*46366Sbostic     int		buckets;
103*46366Sbostic     int		bpages;
104*46366Sbostic     int		hdrsize;
105*46366Sbostic     int		i;
106*46366Sbostic     int		new_table = 0;
107*46366Sbostic     int		nkey;
108*46366Sbostic     int		nsegs;
109*46366Sbostic     int		save_errno;
110*46366Sbostic     struct	stat statbuf;
111*46366Sbostic     DB		*dbp;
112*46366Sbostic 
113*46366Sbostic 
114*46366Sbostic     if ( !(hashp = (HTAB *) calloc( 1, sizeof(HTAB) ))) {
115*46366Sbostic 	/* calloc should set errno */
116*46366Sbostic 	return(0);
117*46366Sbostic     }
118*46366Sbostic     /*
119*46366Sbostic 	Select flags relevant to us.
120*46366Sbostic 	Even if user wants write only, we need to be able to read
121*46366Sbostic 	the actual file, so we need to open it read/write.  But, the
122*46366Sbostic 	field in the hashp structure needs to be accurate so that
123*46366Sbostic 	we can check accesses.
124*46366Sbostic     */
125*46366Sbostic     flags = flags & (O_CREAT | O_EXCL | O_RDONLY | O_RDWR | O_TRUNC | O_WRONLY);
126*46366Sbostic     hashp->flags = flags;
127*46366Sbostic     if ( flags & O_WRONLY )  flags = (flags & ~O_WRONLY) | O_RDWR;
128*46366Sbostic 
129*46366Sbostic     if ( !file ||
130*46366Sbostic 	 (flags & O_TRUNC) ||
131*46366Sbostic 	 (stat ( file, &statbuf ) && (errno == ENOENT)) ) {
132*46366Sbostic 	 new_table = 1;
133*46366Sbostic     }
134*46366Sbostic 
135*46366Sbostic     if ( file && ((hashp->fp = open ( file, flags, mode )) == -1)) {
136*46366Sbostic 	RETURN_ERROR (errno, error0);
137*46366Sbostic     }
138*46366Sbostic 
139*46366Sbostic     if ( new_table ) {
140*46366Sbostic 	if ( !(hashp = init_hash( info )) ) {
141*46366Sbostic 	    RETURN_ERROR(errno,error1);
142*46366Sbostic 	}
143*46366Sbostic     } else {
144*46366Sbostic 	/* Table already exists */
145*46366Sbostic 	if ( info && info->hash ) hashp->hash = info->hash;
146*46366Sbostic 	else hashp->hash = default_hash;
147*46366Sbostic 
148*46366Sbostic 	hdrsize = read ( hashp->fp, &hashp->hdr, sizeof(HASHHDR) );
149*46366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
150*46366Sbostic 	swap_header ( );
151*46366Sbostic #endif
152*46366Sbostic 	if ( hdrsize == -1 ) {
153*46366Sbostic 	    RETURN_ERROR(errno, error1);
154*46366Sbostic 	}
155*46366Sbostic 	if ( hdrsize != sizeof(HASHHDR) ) {
156*46366Sbostic 	    RETURN_ERROR(EFTYPE, error1);
157*46366Sbostic 	}
158*46366Sbostic 
159*46366Sbostic 	/* Verify file type, versions and hash function */
160*46366Sbostic 	if ( hashp->MAGIC != HASHMAGIC )
161*46366Sbostic 	    RETURN_ERROR ( EFTYPE, error1 );
162*46366Sbostic 	if ( hashp->VERSION != VERSION_NO )
163*46366Sbostic 	    RETURN_ERROR ( EFTYPE, error1 );
164*46366Sbostic 	if (hashp->hash ( CHARKEY, sizeof(CHARKEY) ) != hashp->H_CHARKEY ) {
165*46366Sbostic 	    RETURN_ERROR ( EFTYPE, error1 );
166*46366Sbostic 	}
167*46366Sbostic 
168*46366Sbostic 	/*
169*46366Sbostic 	    Figure out how many segments we need.
170*46366Sbostic 	*/
171*46366Sbostic 	nsegs = (hashp->MAX_BUCKET + hashp->SGSIZE -1)/ hashp->SGSIZE;
172*46366Sbostic 	hashp->nsegs = 0;
173*46366Sbostic 	if (alloc_segs( nsegs )) {
174*46366Sbostic 	    /*
175*46366Sbostic 		If alloc_segs fails, table will have been destroyed
176*46366Sbostic 		and errno will have been set.
177*46366Sbostic 	    */
178*46366Sbostic 	    return( (DB *) NULL );
179*46366Sbostic 	}
180*46366Sbostic 
181*46366Sbostic 	/* Read in bitmaps */
182*46366Sbostic 	bpages = (hashp->SPARES[__log2(hashp->MAX_BUCKET)] +
183*46366Sbostic 		  (hashp->BSIZE << BYTE_SHIFT) - 1) >>
184*46366Sbostic 		  (hashp->BSHIFT + BYTE_SHIFT);
185*46366Sbostic 
186*46366Sbostic 	hashp->mapp[0] = (u_long *)malloc(bpages<<hashp->BSHIFT);
187*46366Sbostic 	if ( !hashp->mapp[0] ) {
188*46366Sbostic 	    RETURN_ERROR(errno, error2);
189*46366Sbostic 	}
190*46366Sbostic 	for ( i = 0; i < bpages; i++ ) {
191*46366Sbostic 	    hashp->mapp[i] = &hashp->mapp[0][i<<hashp->BSHIFT];
192*46366Sbostic 	    if (__get_page ((char *)hashp->mapp[i],
193*46366Sbostic 		hashp->BITMAPS[i], 0, 1, 1)) {
194*46366Sbostic 		    RETURN_ERROR(errno, error2);
195*46366Sbostic 	    }
196*46366Sbostic 	}
197*46366Sbostic 
198*46366Sbostic     }
199*46366Sbostic 
200*46366Sbostic     /* Initialize Buffer Manager */
201*46366Sbostic     if ( info && info->ncached ) {
202*46366Sbostic 	__buf_init (info->ncached);
203*46366Sbostic     } else {
204*46366Sbostic 	__buf_init (DEF_BUFSIZE);
205*46366Sbostic     }
206*46366Sbostic 
207*46366Sbostic     hashp->new_file = new_table;
208*46366Sbostic     hashp->save_file = (file != NULL);
209*46366Sbostic     hashp->cbucket = -1;
210*46366Sbostic     if ( !(dbp = (DB *)malloc ( sizeof (DB) )) ) {
211*46366Sbostic 	save_errno = errno;
212*46366Sbostic 	hdestroy();
213*46366Sbostic 	errno = save_errno;
214*46366Sbostic 	return ( NULL );
215*46366Sbostic     }
216*46366Sbostic     dbp->internal = (char *)hashp;
217*46366Sbostic     dbp->close = hash_close;
218*46366Sbostic     dbp->delete = hash_delete;
219*46366Sbostic     dbp->get = hash_get;
220*46366Sbostic     dbp->put = hash_put;
221*46366Sbostic     dbp->seq = hash_seq;
222*46366Sbostic     dbp->sync = hash_sync;
223*46366Sbostic 
224*46366Sbostic #ifdef DEBUG
225*46366Sbostic 	(void)fprintf(stderr, "%s\n%s%x\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
226*46366Sbostic 		"init_htab:",
227*46366Sbostic 		"TABLE POINTER   ", hashp,
228*46366Sbostic 		"BUCKET SIZE     ", hashp->BSIZE,
229*46366Sbostic 		"BUCKET SHIFT    ", hashp->BSHIFT,
230*46366Sbostic 		"DIRECTORY SIZE  ", hashp->DSIZE,
231*46366Sbostic 		"SEGMENT SIZE    ", hashp->SGSIZE,
232*46366Sbostic 		"SEGMENT SHIFT   ", hashp->SSHIFT,
233*46366Sbostic 		"FILL FACTOR     ", hashp->FFACTOR,
234*46366Sbostic 		"MAX BUCKET      ", hashp->MAX_BUCKET,
235*46366Sbostic 		"HIGH MASK       ", hashp->HIGH_MASK,
236*46366Sbostic 		"LOW  MASK       ", hashp->LOW_MASK,
237*46366Sbostic 		"NSEGS           ", hashp->nsegs,
238*46366Sbostic 		"NKEYS           ", hashp->NKEYS );
239*46366Sbostic #endif
240*46366Sbostic #ifdef HASH_STATISTICS
241*46366Sbostic 	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
242*46366Sbostic #endif
243*46366Sbostic     return (dbp);
244*46366Sbostic 
245*46366Sbostic error2:
246*46366Sbostic     (void)hdestroy();
247*46366Sbostic     errno = save_errno;
248*46366Sbostic     hashp->errno = errno;
249*46366Sbostic     return ( (DB *)NULL );
250*46366Sbostic 
251*46366Sbostic error1:
252*46366Sbostic     (void) close ( hashp->fp );
253*46366Sbostic 
254*46366Sbostic error0:
255*46366Sbostic     free ( hashp );
256*46366Sbostic     errno = save_errno;
257*46366Sbostic     hashp->errno = errno;
258*46366Sbostic     return ( (DB *) NULL );
259*46366Sbostic }
260*46366Sbostic 
261*46366Sbostic static int
262*46366Sbostic hash_close (dbp)
263*46366Sbostic DB	*dbp;
264*46366Sbostic {
265*46366Sbostic 	if ( !dbp ) {
266*46366Sbostic 	    return(ERROR);
267*46366Sbostic 	}
268*46366Sbostic 	hashp = (HTAB *)dbp->internal;
269*46366Sbostic 	return (hdestroy());
270*46366Sbostic }
271*46366Sbostic 
272*46366Sbostic 
273*46366Sbostic /************************** LOCAL CREATION ROUTINES **********************/
274*46366Sbostic static HTAB *
275*46366Sbostic init_hash( info )
276*46366Sbostic HASHINFO *info;
277*46366Sbostic {
278*46366Sbostic 	int	nelem;
279*46366Sbostic 
280*46366Sbostic 	nelem = 1;
281*46366Sbostic 
282*46366Sbostic 	hashp->LORDER	= BYTE_ORDER;
283*46366Sbostic 	hashp->BSIZE    = DEF_BUCKET_SIZE;
284*46366Sbostic 	hashp->BSHIFT   = DEF_BUCKET_SHIFT;
285*46366Sbostic 	hashp->SGSIZE   = DEF_SEGSIZE;
286*46366Sbostic 	hashp->SSHIFT   = DEF_SEGSIZE_SHIFT;
287*46366Sbostic 	hashp->DSIZE    = DEF_DIRSIZE;
288*46366Sbostic 	hashp->FFACTOR  = DEF_FFACTOR;
289*46366Sbostic 	hashp->hash     = default_hash;
290*46366Sbostic 	bzero (hashp->SPARES, sizeof (hashp->SPARES));
291*46366Sbostic 
292*46366Sbostic 	if ( info ) {
293*46366Sbostic 	    if ( info->bsize )   {
294*46366Sbostic 		/* Round pagesize up to power of 2 */
295*46366Sbostic 		hashp->BSHIFT  = __log2(info->bsize);
296*46366Sbostic 		hashp->BSIZE   = 1 << hashp->BSHIFT;
297*46366Sbostic 		if ( hashp->BSIZE > MAX_BSIZE ) {
298*46366Sbostic 		    errno = EINVAL;
299*46366Sbostic 		    return(0);
300*46366Sbostic 		}
301*46366Sbostic 	    }
302*46366Sbostic 	    if ( info->ffactor )  hashp->FFACTOR = info->ffactor;
303*46366Sbostic 	    if ( info->hash ) hashp->hash    = info->hash;
304*46366Sbostic 	    if ( info->nelem ) nelem = info->nelem;
305*46366Sbostic 	    if ( info->lorder ) {
306*46366Sbostic 		if ( info->lorder != BIG_ENDIAN &&
307*46366Sbostic 		     info->lorder != LITTLE_ENDIAN) {
308*46366Sbostic 		    errno = EINVAL;
309*46366Sbostic 		    return(0);
310*46366Sbostic 		}
311*46366Sbostic 		hashp->LORDER = info->lorder;
312*46366Sbostic 	    }
313*46366Sbostic 	}
314*46366Sbostic 
315*46366Sbostic 	/* init_htab should destroy the table and set errno if it fails */
316*46366Sbostic 	if ( init_htab ( nelem ) ) {
317*46366Sbostic 	    return(0);
318*46366Sbostic 	} else {
319*46366Sbostic 	    return(hashp);
320*46366Sbostic 	}
321*46366Sbostic }
322*46366Sbostic 
323*46366Sbostic /*
324*46366Sbostic     This calls alloc_segs which may run out of memory.
325*46366Sbostic     Alloc_segs will destroy the table and set errno,
326*46366Sbostic     so we just pass the error information along.
327*46366Sbostic 
328*46366Sbostic     Returns 0 on No Error
329*46366Sbostic 
330*46366Sbostic */
331*46366Sbostic static int
332*46366Sbostic init_htab ( nelem )
333*46366Sbostic int	nelem;
334*46366Sbostic {
335*46366Sbostic 	register SEGMENT	*segp;
336*46366Sbostic 	register int nbuckets;
337*46366Sbostic 	register int nsegs;
338*46366Sbostic 	int	l2;
339*46366Sbostic 
340*46366Sbostic  /*
341*46366Sbostic   * Divide number of elements by the fill factor and determine a desired
342*46366Sbostic   * number of buckets.  Allocate space for the next greater power of
343*46366Sbostic   * two number of buckets
344*46366Sbostic   */
345*46366Sbostic 	nelem = (nelem - 1) / hashp->FFACTOR + 1;
346*46366Sbostic 
347*46366Sbostic 	l2 = __log2(nelem);
348*46366Sbostic 	nbuckets = 1 << l2;
349*46366Sbostic 	nbuckets = MAX ( nbuckets, 2 );
350*46366Sbostic 
351*46366Sbostic 	hashp->SPARES[l2] = l2 + 1;
352*46366Sbostic 	hashp->SPARES[l2+1] = l2 + 1;
353*46366Sbostic 	/*
354*46366Sbostic 	    First bitmap page is at:
355*46366Sbostic 		splitpoint l2
356*46366Sbostic 		page offset 1
357*46366Sbostic 	*/
358*46366Sbostic 	__init_bitmap ( OADDR_OF(l2,1), l2+1, 0 );
359*46366Sbostic 
360*46366Sbostic 	hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
361*46366Sbostic 	hashp->HIGH_MASK = (nbuckets << 1) - 1;
362*46366Sbostic 	hashp->HDRPAGES = ((MAX(sizeof(HASHHDR),MINHDRSIZE) - 1) >>
363*46366Sbostic 			  hashp->BSHIFT) + 1;
364*46366Sbostic 
365*46366Sbostic 	nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
366*46366Sbostic 	nsegs = 1 << __log2(nsegs);
367*46366Sbostic 
368*46366Sbostic 	if ( nsegs > hashp->DSIZE ) {
369*46366Sbostic 	    hashp->DSIZE  = nsegs;
370*46366Sbostic 	}
371*46366Sbostic 
372*46366Sbostic 	return (alloc_segs ( nsegs ) );
373*46366Sbostic }
374*46366Sbostic 
375*46366Sbostic /********************** DESTROY/CLOSE ROUTINES ************************/
376*46366Sbostic 
377*46366Sbostic /*
378*46366Sbostic     Flushes any changes to the file if necessary and
379*46366Sbostic     destroys the hashp structure, freeing all allocated
380*46366Sbostic     space.
381*46366Sbostic */
382*46366Sbostic static int
383*46366Sbostic hdestroy()
384*46366Sbostic {
385*46366Sbostic 	int	save_errno;
386*46366Sbostic 	int	i;
387*46366Sbostic 
388*46366Sbostic 	save_errno = 0;
389*46366Sbostic 
390*46366Sbostic 	if (hashp != NULL) {
391*46366Sbostic #ifdef HASH_STATISTICS
392*46366Sbostic 	 (void)	fprintf(stderr,	"hdestroy: accesses %ld collisions %ld\n",
393*46366Sbostic 			hash_accesses, hash_collisions);
394*46366Sbostic 	 (void)	fprintf(stderr, "hdestroy: expansions %ld\n",
395*46366Sbostic 			hash_expansions);
396*46366Sbostic 	 (void)	fprintf(stderr, "hdestroy: overflows %ld\n",
397*46366Sbostic 			hash_overflows);
398*46366Sbostic 	 (void)	fprintf(stderr,	"keys %ld maxp %d segmentcount %d\n",
399*46366Sbostic 			hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
400*46366Sbostic 
401*46366Sbostic 	for ( i = 0; i < NCACHED; i++ ) {
402*46366Sbostic 	    (void) fprintf ( stderr, "spares[%d] = %d\n", i, hashp->SPARES[i] );
403*46366Sbostic 	}
404*46366Sbostic #endif
405*46366Sbostic 
406*46366Sbostic 		/*
407*46366Sbostic 		    Call on buffer manager to free buffers, and if
408*46366Sbostic 		    required, write them to disk
409*46366Sbostic 		*/
410*46366Sbostic 		if (__buf_free(1, hashp->save_file)) {
411*46366Sbostic 		    save_errno = errno;
412*46366Sbostic 		}
413*46366Sbostic 		if ( hashp->dir ) {
414*46366Sbostic 		    (void)free(*hashp->dir);	/* Free initial segments */
415*46366Sbostic 		    /* Free extra segments */
416*46366Sbostic 		    while ( hashp->exsegs-- ) {
417*46366Sbostic 			(void)free ( hashp->dir[--hashp->nsegs] );
418*46366Sbostic 		    }
419*46366Sbostic 		    (void)free(hashp->dir);
420*46366Sbostic 		}
421*46366Sbostic 		if (flush_meta() && !save_errno) {
422*46366Sbostic 		    save_errno = errno;
423*46366Sbostic 		}
424*46366Sbostic 		if ( hashp->save_file ) (void)close (hashp->fp);
425*46366Sbostic 		(void)free(hashp);
426*46366Sbostic 		hashp = NULL;
427*46366Sbostic 	}
428*46366Sbostic 	if ( save_errno ) {
429*46366Sbostic 	    errno = save_errno;
430*46366Sbostic 	    return(ERROR);
431*46366Sbostic 	} else {
432*46366Sbostic 	    return(SUCCESS);
433*46366Sbostic 	}
434*46366Sbostic }
435*46366Sbostic 
436*46366Sbostic /*
437*46366Sbostic     Write modified pages to disk
438*46366Sbostic     0 == OK
439*46366Sbostic     -1 ERROR
440*46366Sbostic */
441*46366Sbostic static int
442*46366Sbostic hash_sync(dbp)
443*46366Sbostic DB	*dbp;
444*46366Sbostic {
445*46366Sbostic 	if ( !dbp ) {
446*46366Sbostic 	    return (ERROR);
447*46366Sbostic 	}
448*46366Sbostic 
449*46366Sbostic 	hashp = (HTAB *)dbp->internal;
450*46366Sbostic 
451*46366Sbostic 	if (!hashp->save_file) return(0);
452*46366Sbostic 	if ( __buf_free ( 0, 1 )  || flush_meta()) {
453*46366Sbostic 	    return(ERROR);
454*46366Sbostic 	}
455*46366Sbostic 	hashp->new_file = 0;
456*46366Sbostic 	return(0);
457*46366Sbostic }
458*46366Sbostic 
459*46366Sbostic /*
460*46366Sbostic 0 == OK
461*46366Sbostic -1 indicates that errno should be set
462*46366Sbostic */
463*46366Sbostic static int
464*46366Sbostic flush_meta()
465*46366Sbostic {
466*46366Sbostic     	int	fp;
467*46366Sbostic 	int	hdrsize;
468*46366Sbostic 	int	i;
469*46366Sbostic 	int	wsize;
470*46366Sbostic 	HASHHDR	*whdrp;
471*46366Sbostic 	HASHHDR	whdr;
472*46366Sbostic 
473*46366Sbostic 	if (!hashp->save_file) return(0);
474*46366Sbostic 	hashp->MAGIC = HASHMAGIC;
475*46366Sbostic 	hashp->VERSION = VERSION_NO;
476*46366Sbostic 	hashp->H_CHARKEY = hashp->hash ( CHARKEY, sizeof(CHARKEY));
477*46366Sbostic 
478*46366Sbostic 	fp = hashp->fp;
479*46366Sbostic 	whdrp = &hashp->hdr;
480*46366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
481*46366Sbostic 	whdrp = &whdr;
482*46366Sbostic 	swap_header_copy( &hashp->hdr, whdrp );
483*46366Sbostic #endif
484*46366Sbostic 	if ( (lseek (fp, 0, L_SET) == -1 ) ||
485*46366Sbostic 	     ((wsize = write ( fp, whdrp, sizeof(HASHHDR))) == -1)) {
486*46366Sbostic 	    return(-1);
487*46366Sbostic 	} else if ( wsize != sizeof(HASHHDR) ) {
488*46366Sbostic 	    errno = EFTYPE;
489*46366Sbostic 	    hashp->errno = errno;
490*46366Sbostic 	    return(-1);
491*46366Sbostic 	}
492*46366Sbostic 	for ( i = 0; i < NCACHED; i++ ) {
493*46366Sbostic 	    if ( hashp->mapp[i] ) {
494*46366Sbostic 		if (!__put_page((char *)hashp->mapp[i],
495*46366Sbostic 		    hashp->BITMAPS[i], 0, 1)){
496*46366Sbostic 		    return(-1);
497*46366Sbostic 		}
498*46366Sbostic 	    }
499*46366Sbostic 	}
500*46366Sbostic 	return(0);
501*46366Sbostic }
502*46366Sbostic /*******************************SEARCH ROUTINES *****************************/
503*46366Sbostic /*
504*46366Sbostic     All the access routines return
505*46366Sbostic 	0 on SUCCESS
506*46366Sbostic 	1 to indicate an external ERROR (i.e. key not found, etc)
507*46366Sbostic 	-1 to indicate an internal ERROR (i.e. out of memory, etc)
508*46366Sbostic */
509*46366Sbostic static int
510*46366Sbostic hash_get ( dbp, key, data )
511*46366Sbostic DB	*dbp;
512*46366Sbostic DBT *key, *data;
513*46366Sbostic {
514*46366Sbostic     if ( !dbp ) {
515*46366Sbostic 	return (ERROR);
516*46366Sbostic     }
517*46366Sbostic     hashp = (HTAB *)dbp->internal;
518*46366Sbostic     if ( hashp->flags & O_WRONLY ) {
519*46366Sbostic 	errno = EBADF;
520*46366Sbostic 	hashp->errno = errno;
521*46366Sbostic 	return ( ERROR );
522*46366Sbostic     }
523*46366Sbostic     return ( hash_access ( HASH_GET, key, data ) );
524*46366Sbostic }
525*46366Sbostic 
526*46366Sbostic static int
527*46366Sbostic hash_put ( dbp, key, data, flag )
528*46366Sbostic DB	*dbp;
529*46366Sbostic DBT 	*key, *data;
530*46366Sbostic int	flag;
531*46366Sbostic {
532*46366Sbostic     if ( !dbp ) {
533*46366Sbostic 	return (ERROR);
534*46366Sbostic     }
535*46366Sbostic     hashp = (HTAB *)dbp->internal;
536*46366Sbostic     if ( (hashp->flags & O_ACCMODE) == O_RDONLY ) {
537*46366Sbostic 	errno = EBADF;
538*46366Sbostic 	hashp->errno = errno;
539*46366Sbostic 	return ( ERROR );
540*46366Sbostic     }
541*46366Sbostic     if ( flag == R_NOOVERWRITE ) {
542*46366Sbostic 	return ( hash_access ( HASH_PUTNEW, key, data ) );
543*46366Sbostic     } else {
544*46366Sbostic 	return ( hash_access ( HASH_PUT, key, data ) );
545*46366Sbostic     }
546*46366Sbostic }
547*46366Sbostic 
548*46366Sbostic static int
549*46366Sbostic hash_delete ( dbp, key, flags )
550*46366Sbostic DB	*dbp;
551*46366Sbostic DBT 	*key;
552*46366Sbostic int	flags;		/* Ignored */
553*46366Sbostic {
554*46366Sbostic     if ( !dbp ) {
555*46366Sbostic 	return (ERROR);
556*46366Sbostic     }
557*46366Sbostic     hashp = (HTAB *)dbp->internal;
558*46366Sbostic     if ( (hashp->flags & O_ACCMODE) == O_RDONLY ) {
559*46366Sbostic 	errno = EBADF;
560*46366Sbostic 	hashp->errno = errno;
561*46366Sbostic 	return ( ERROR );
562*46366Sbostic     }
563*46366Sbostic     return ( hash_access ( HASH_DELETE, key, NULL ) );
564*46366Sbostic }
565*46366Sbostic 
566*46366Sbostic /*
567*46366Sbostic     Assume that hashp has been set in wrapper routine
568*46366Sbostic */
569*46366Sbostic static int
570*46366Sbostic hash_access(action, key, val)
571*46366Sbostic ACTION action;
572*46366Sbostic DBT *key, *val;
573*46366Sbostic {
574*46366Sbostic 	register	BUFHEAD	*rbufp;
575*46366Sbostic 	register	u_short	*bp;
576*46366Sbostic 	register	int	ndx;
577*46366Sbostic 	register 	int n;
578*46366Sbostic 	register 	int off = hashp->BSIZE;
579*46366Sbostic 	register	int		size;
580*46366Sbostic 	register	char	*kp;
581*46366Sbostic 	BUFHEAD	*bufp;
582*46366Sbostic 	u_short	pageno;
583*46366Sbostic 
584*46366Sbostic #ifdef HASH_STATISTICS
585*46366Sbostic 	hash_accesses++;
586*46366Sbostic #endif
587*46366Sbostic 
588*46366Sbostic 	size = key->size;
589*46366Sbostic 	kp = key->data;
590*46366Sbostic 	rbufp = __get_buf ( __call_hash(key->data, size), NULL, 0 );
591*46366Sbostic 	if ( !rbufp ) return(ERROR);
592*46366Sbostic 
593*46366Sbostic 	for ( bp = (u_short *)rbufp->page, n = *bp++, ndx = 1; ndx < n;  ) {
594*46366Sbostic 	    if ( bp[1] >= REAL_KEY ) {
595*46366Sbostic 		/* Real key/data pair */
596*46366Sbostic 		if (size == off - *bp &&
597*46366Sbostic 		    bcmp(kp, rbufp->page + *bp, size) == 0) {
598*46366Sbostic 		    goto found;
599*46366Sbostic 		}
600*46366Sbostic 		off = bp[1];
601*46366Sbostic #ifdef HASH_STATISTICS
602*46366Sbostic 		hash_collisions++;
603*46366Sbostic #endif
604*46366Sbostic 	        bp += 2;
605*46366Sbostic 	        ndx += 2;
606*46366Sbostic 	    } else if ( bp[1] == OVFLPAGE ) {
607*46366Sbostic 		rbufp = __get_buf ( *bp, rbufp, 0 );
608*46366Sbostic 		if ( !rbufp ) return (ERROR);
609*46366Sbostic 		/* FOR LOOP INIT */
610*46366Sbostic 		bp = (u_short *)rbufp->page;
611*46366Sbostic 		n = *bp++;
612*46366Sbostic 		ndx = 1;
613*46366Sbostic 		off = hashp->BSIZE;
614*46366Sbostic 	    } else if ( bp[1] < REAL_KEY ) {
615*46366Sbostic 		if ( (ndx = __find_bigpair(rbufp, ndx, kp, size )) > 0 ) {
616*46366Sbostic 		    goto found;
617*46366Sbostic 		} else if ( ndx == -2 ) {
618*46366Sbostic 		    bufp = rbufp;
619*46366Sbostic 		    if ( !(pageno = __find_last_page ( &bufp )) ) {
620*46366Sbostic 			ndx = 0;
621*46366Sbostic 			rbufp = bufp;
622*46366Sbostic 			break;	/* FOR */
623*46366Sbostic 		    }
624*46366Sbostic 		    rbufp = __get_buf ( pageno, bufp, 0 );
625*46366Sbostic 		    if ( !rbufp ) return (ERROR);
626*46366Sbostic 		    /* FOR LOOP INIT */
627*46366Sbostic 		    bp = (u_short *)rbufp->page;
628*46366Sbostic 		    n = *bp++;
629*46366Sbostic 		    ndx = 1;
630*46366Sbostic 		    off = hashp->BSIZE;
631*46366Sbostic 		} else  {
632*46366Sbostic 		    return(ERROR);
633*46366Sbostic 		}
634*46366Sbostic 	    }
635*46366Sbostic 	}
636*46366Sbostic 
637*46366Sbostic 	/* Not found */
638*46366Sbostic 	switch ( action ) {
639*46366Sbostic 	    case HASH_PUT:
640*46366Sbostic 	    case HASH_PUTNEW:
641*46366Sbostic 		if (__addel(rbufp, key, val)) {
642*46366Sbostic 		    return(ERROR);
643*46366Sbostic 		} else {
644*46366Sbostic 		    return(SUCCESS);
645*46366Sbostic 		}
646*46366Sbostic 	    case HASH_GET:
647*46366Sbostic 		return ( ABNORMAL );
648*46366Sbostic 	    case HASH_DELETE:
649*46366Sbostic 		return ( ABNORMAL );
650*46366Sbostic 	    default:
651*46366Sbostic 		return(ABNORMAL);
652*46366Sbostic 	}
653*46366Sbostic 
654*46366Sbostic found:
655*46366Sbostic 	switch (action) {
656*46366Sbostic 	    case HASH_PUTNEW:
657*46366Sbostic 		return(ABNORMAL);
658*46366Sbostic 	    case HASH_GET:
659*46366Sbostic 		bp = (u_short *)rbufp->page;
660*46366Sbostic 		if (bp[ndx+1] < REAL_KEY) __big_return(rbufp, ndx, val, 0);
661*46366Sbostic 		else {
662*46366Sbostic 		    val->data = rbufp->page + (int) bp[ndx + 1];
663*46366Sbostic 		    val->size = bp[ndx] - bp[ndx + 1];
664*46366Sbostic 		}
665*46366Sbostic 		break;
666*46366Sbostic 	    case HASH_PUT:
667*46366Sbostic 		if (__delpair (rbufp, ndx))return(ERROR);
668*46366Sbostic 		if (__addel (rbufp, key, val)) return(ERROR);
669*46366Sbostic 		break;
670*46366Sbostic 	    case HASH_DELETE:
671*46366Sbostic 		if (__delpair (rbufp, ndx))return(ERROR);
672*46366Sbostic 		break;
673*46366Sbostic 	}
674*46366Sbostic 	return (SUCCESS);
675*46366Sbostic }
676*46366Sbostic 
677*46366Sbostic static int
678*46366Sbostic hash_seq(dbp, key, data, flag)
679*46366Sbostic DB	*dbp;
680*46366Sbostic DBT 	*key, *data;
681*46366Sbostic int flag;
682*46366Sbostic {
683*46366Sbostic 	register	int bucket;
684*46366Sbostic 	register	BUFHEAD	*bufp;
685*46366Sbostic 	u_short	*bp;
686*46366Sbostic 	u_short	ndx;
687*46366Sbostic 	u_short	pageno;
688*46366Sbostic 
689*46366Sbostic 	if ( !dbp ) {
690*46366Sbostic 	    return (ERROR);
691*46366Sbostic 	}
692*46366Sbostic 
693*46366Sbostic 	hashp = (HTAB *)dbp->internal;
694*46366Sbostic 	if ( hashp->flags & O_WRONLY ) {
695*46366Sbostic 	    errno = EBADF;
696*46366Sbostic 	    hashp->errno = errno;
697*46366Sbostic 	    return ( ERROR );
698*46366Sbostic 	}
699*46366Sbostic #ifdef HASH_STATISTICS
700*46366Sbostic 	hash_accesses++;
701*46366Sbostic #endif
702*46366Sbostic 
703*46366Sbostic 	if ( (hashp->cbucket < 0) || (flag == R_FIRST) ) {
704*46366Sbostic 	    hashp->cbucket = 0;
705*46366Sbostic 	    hashp->cndx = 1;
706*46366Sbostic 	    hashp->cpage = NULL;
707*46366Sbostic 	}
708*46366Sbostic 
709*46366Sbostic 	if ( !(bufp = hashp->cpage) ) {
710*46366Sbostic 	    for (bucket = hashp->cbucket;
711*46366Sbostic 		 bucket <= hashp->MAX_BUCKET;
712*46366Sbostic 		 bucket++, hashp->cndx = 1 ) {
713*46366Sbostic 
714*46366Sbostic 		bufp = __get_buf ( bucket, NULL, 0 );
715*46366Sbostic 		if (!bufp) return(ERROR);
716*46366Sbostic 		hashp->cpage = bufp;
717*46366Sbostic 		bp = (u_short *)bufp->page;
718*46366Sbostic 		if (bp[0]) break;
719*46366Sbostic 	    }
720*46366Sbostic 	    hashp->cbucket = bucket;
721*46366Sbostic 	    if ( hashp->cbucket > hashp->MAX_BUCKET ) {
722*46366Sbostic 		hashp->cbucket = -1;
723*46366Sbostic 		return ( ABNORMAL );
724*46366Sbostic 	    }
725*46366Sbostic 	} else {
726*46366Sbostic 	    bp  = (u_short *)hashp->cpage->page;
727*46366Sbostic 	}
728*46366Sbostic 
729*46366Sbostic #ifdef DEBUG
730*46366Sbostic 	assert (bp);
731*46366Sbostic 	assert (bufp);
732*46366Sbostic #endif
733*46366Sbostic 	while ( bp[hashp->cndx+1] == OVFLPAGE ) {
734*46366Sbostic 	    bufp = hashp->cpage = __get_buf ( bp[hashp->cndx], bufp, 0 );
735*46366Sbostic 	    if (!bufp) return(ERROR);
736*46366Sbostic 	    bp = (u_short *)(bufp->page);
737*46366Sbostic 	    hashp->cndx = 1;
738*46366Sbostic 	}
739*46366Sbostic 	ndx = hashp->cndx;
740*46366Sbostic 	if (bp[ndx+1] < REAL_KEY) {
741*46366Sbostic 	    if (__big_keydata(bufp, ndx, key, data, 1)) {
742*46366Sbostic 		return(ERROR);
743*46366Sbostic 	    }
744*46366Sbostic 	} else {
745*46366Sbostic 	    key->data = hashp->cpage->page + bp[ndx];
746*46366Sbostic 	    key->size = (ndx > 1 ? bp[ndx-1] : hashp->BSIZE) - bp[ndx];
747*46366Sbostic 	    data->data = hashp->cpage->page + bp[ndx + 1];
748*46366Sbostic 	    data->size = bp[ndx] - bp[ndx + 1];
749*46366Sbostic 	    ndx += 2;
750*46366Sbostic 	    if ( ndx > bp[0] ) {
751*46366Sbostic 		hashp->cpage = NULL;
752*46366Sbostic 		hashp->cbucket++;
753*46366Sbostic 		hashp->cndx=1;
754*46366Sbostic 	    } else hashp->cndx = ndx;
755*46366Sbostic 	}
756*46366Sbostic 	return (SUCCESS);
757*46366Sbostic }
758*46366Sbostic 
759*46366Sbostic /********************************* UTILITIES ************************/
760*46366Sbostic /*
761*46366Sbostic     0 ==> OK
762*46366Sbostic     -1 ==> Error
763*46366Sbostic */
764*46366Sbostic extern int
765*46366Sbostic __expand_table()
766*46366Sbostic {
767*46366Sbostic 	int	old_bucket, new_bucket;
768*46366Sbostic 	int	new_segnum;
769*46366Sbostic 	int	dirsize;
770*46366Sbostic 	int	spare_ndx;
771*46366Sbostic 	register	char **old, **new;
772*46366Sbostic #ifdef HASH_STATISTICS
773*46366Sbostic 	hash_expansions++;
774*46366Sbostic #endif
775*46366Sbostic 
776*46366Sbostic 	new_bucket = ++hashp->MAX_BUCKET;
777*46366Sbostic 	old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
778*46366Sbostic 
779*46366Sbostic 	new_segnum = new_bucket >> hashp->SSHIFT;
780*46366Sbostic 
781*46366Sbostic 	/* Check if we need a new segment */
782*46366Sbostic 	if ( new_segnum >= hashp->nsegs ) {
783*46366Sbostic 
784*46366Sbostic 	    /* Check if we need to expand directory */
785*46366Sbostic 	    if ( new_segnum >= hashp->DSIZE ) {
786*46366Sbostic 
787*46366Sbostic 		/* Reallocate directory */
788*46366Sbostic 		dirsize = hashp->DSIZE * sizeof ( SEGMENT * );
789*46366Sbostic 		if (!hash_realloc ( &hashp->dir, dirsize, (dirsize << 1 ) )) {
790*46366Sbostic 		    return(-1);
791*46366Sbostic 		}
792*46366Sbostic 		hashp->DSIZE = dirsize << 1;
793*46366Sbostic 	    }
794*46366Sbostic 	    if (!(hashp->dir[new_segnum] =
795*46366Sbostic 		    (SEGMENT)calloc ( hashp->SGSIZE, sizeof(SEGMENT)))) {
796*46366Sbostic 		    return(-1);
797*46366Sbostic 	    }
798*46366Sbostic 	    hashp->exsegs++;
799*46366Sbostic 	    hashp->nsegs++;
800*46366Sbostic 	}
801*46366Sbostic 
802*46366Sbostic 	/*
803*46366Sbostic 	    If the split point is increasing (MAX_BUCKET's log
804*46366Sbostic 	    base 2 increases), we need to copy the current contents
805*46366Sbostic 	    of the spare split bucket to the next bucket
806*46366Sbostic 	*/
807*46366Sbostic 	spare_ndx = __log2(hashp->MAX_BUCKET);
808*46366Sbostic 	if ( spare_ndx != (__log2(hashp->MAX_BUCKET - 1))) {
809*46366Sbostic 	    hashp->SPARES[spare_ndx] = hashp->SPARES[spare_ndx-1];
810*46366Sbostic 	}
811*46366Sbostic 
812*46366Sbostic 	if ( new_bucket > hashp->HIGH_MASK ) {
813*46366Sbostic 	    /* Starting a new doubling */
814*46366Sbostic 	    hashp->LOW_MASK = hashp->HIGH_MASK;
815*46366Sbostic 	    hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
816*46366Sbostic 	}
817*46366Sbostic 
818*46366Sbostic 	/*
819*46366Sbostic 	 * Relocate records to the new bucket
820*46366Sbostic 	 */
821*46366Sbostic 	return(__split_page ( old_bucket, new_bucket ));
822*46366Sbostic }
823*46366Sbostic /*
824*46366Sbostic     If realloc guarantees that the pointer is not destroyed
825*46366Sbostic     if the realloc fails, then this routine can go away
826*46366Sbostic */
827*46366Sbostic static char *
828*46366Sbostic hash_realloc ( p_ptr, oldsize, newsize )
829*46366Sbostic char	**p_ptr;
830*46366Sbostic int	oldsize;
831*46366Sbostic int	newsize;
832*46366Sbostic {
833*46366Sbostic 	register char	*p;
834*46366Sbostic 
835*46366Sbostic 	if (p = (char *)malloc ( newsize ) ) {
836*46366Sbostic 		bcopy ( *p_ptr, p, oldsize );
837*46366Sbostic 		bzero ( *p_ptr + oldsize, newsize-oldsize );
838*46366Sbostic 		free(*p_ptr);
839*46366Sbostic 		*p_ptr = p;
840*46366Sbostic 	}
841*46366Sbostic 	return (p);
842*46366Sbostic }
843*46366Sbostic 
844*46366Sbostic extern int
845*46366Sbostic __call_hash ( k, len )
846*46366Sbostic char	*k;
847*46366Sbostic int	len;
848*46366Sbostic {
849*46366Sbostic 	int	n, bucket;
850*46366Sbostic 	n = hashp->hash(k, len);
851*46366Sbostic 
852*46366Sbostic 	bucket = n & hashp->HIGH_MASK;
853*46366Sbostic 	if ( bucket > hashp->MAX_BUCKET ) {
854*46366Sbostic 	    bucket = bucket & hashp->LOW_MASK;
855*46366Sbostic 	}
856*46366Sbostic 
857*46366Sbostic 	return(bucket);
858*46366Sbostic }
859*46366Sbostic 
860*46366Sbostic /*
861*46366Sbostic     Allocate segment table.  On error, destroy the table
862*46366Sbostic     and set errno.
863*46366Sbostic 
864*46366Sbostic     Returns 0 on success
865*46366Sbostic */
866*46366Sbostic static int
867*46366Sbostic alloc_segs ( nsegs )
868*46366Sbostic int	nsegs;
869*46366Sbostic {
870*46366Sbostic     register int	i;
871*46366Sbostic     register SEGMENT	store;
872*46366Sbostic 
873*46366Sbostic     int	save_errno;
874*46366Sbostic 
875*46366Sbostic     if (!(hashp->dir = (SEGMENT *)calloc(hashp->DSIZE, sizeof(SEGMENT *)))) {
876*46366Sbostic 	save_errno = errno;
877*46366Sbostic 	(void)hdestroy();
878*46366Sbostic 	errno = save_errno;
879*46366Sbostic 	return(-1);
880*46366Sbostic     }
881*46366Sbostic 
882*46366Sbostic     /* Allocate segments */
883*46366Sbostic     store = (SEGMENT)calloc ( nsegs << hashp->SSHIFT, sizeof (SEGMENT) );
884*46366Sbostic     if ( !store ) {
885*46366Sbostic 	save_errno = errno;
886*46366Sbostic 	(void)hdestroy();
887*46366Sbostic 	errno = save_errno;
888*46366Sbostic 	return(-1);
889*46366Sbostic     }
890*46366Sbostic 
891*46366Sbostic     for ( i=0; i < nsegs; i++, hashp->nsegs++ ) {
892*46366Sbostic 	hashp->dir[i] = &store[i<<hashp->SSHIFT];
893*46366Sbostic     }
894*46366Sbostic     return(0);
895*46366Sbostic }
896*46366Sbostic 
897*46366Sbostic /*
898*46366Sbostic     Hashp->hdr needs to be byteswapped.
899*46366Sbostic */
900*46366Sbostic static void
901*46366Sbostic swap_header_copy ( srcp, destp )
902*46366Sbostic HASHHDR	*srcp;
903*46366Sbostic HASHHDR	*destp;
904*46366Sbostic {
905*46366Sbostic     int i;
906*46366Sbostic 
907*46366Sbostic     BLSWAP_COPY(srcp->magic, destp->magic);
908*46366Sbostic     BLSWAP_COPY(srcp->version, destp->version);
909*46366Sbostic     BLSWAP_COPY(srcp->lorder, destp->lorder);
910*46366Sbostic     BLSWAP_COPY(srcp->bsize, destp->bsize);
911*46366Sbostic     BLSWAP_COPY(srcp->bshift, destp->bshift);
912*46366Sbostic     BLSWAP_COPY(srcp->dsize, destp->dsize);
913*46366Sbostic     BLSWAP_COPY(srcp->ssize, destp->ssize);
914*46366Sbostic     BLSWAP_COPY(srcp->sshift, destp->sshift);
915*46366Sbostic     BLSWAP_COPY(srcp->max_bucket, destp->max_bucket);
916*46366Sbostic     BLSWAP_COPY(srcp->high_mask, destp->high_mask);
917*46366Sbostic     BLSWAP_COPY(srcp->low_mask, destp->low_mask);
918*46366Sbostic     BLSWAP_COPY(srcp->ffactor, destp->ffactor);
919*46366Sbostic     BLSWAP_COPY(srcp->nkeys, destp->nkeys);
920*46366Sbostic     BLSWAP_COPY(srcp->hdrpages, destp->hdrpages);
921*46366Sbostic     BLSWAP_COPY(srcp->h_charkey, destp->h_charkey);
922*46366Sbostic     for ( i=0; i < NCACHED; i++ ) {
923*46366Sbostic 	BLSWAP_COPY ( srcp->spares[i] , destp->spares[i]);
924*46366Sbostic 	BSSWAP_COPY ( srcp->bitmaps[i] , destp->bitmaps[i]);
925*46366Sbostic     }
926*46366Sbostic     return;
927*46366Sbostic }
928*46366Sbostic 
929*46366Sbostic static void
930*46366Sbostic swap_header ( )
931*46366Sbostic {
932*46366Sbostic     HASHHDR	*hdrp;
933*46366Sbostic     int	i;
934*46366Sbostic 
935*46366Sbostic     hdrp = &hashp->hdr;
936*46366Sbostic 
937*46366Sbostic     BLSWAP(hdrp->magic);
938*46366Sbostic     BLSWAP(hdrp->version);
939*46366Sbostic     BLSWAP(hdrp->lorder);
940*46366Sbostic     BLSWAP(hdrp->bsize);
941*46366Sbostic     BLSWAP(hdrp->bshift);
942*46366Sbostic     BLSWAP(hdrp->dsize);
943*46366Sbostic     BLSWAP(hdrp->ssize);
944*46366Sbostic     BLSWAP(hdrp->sshift);
945*46366Sbostic     BLSWAP(hdrp->max_bucket);
946*46366Sbostic     BLSWAP(hdrp->high_mask);
947*46366Sbostic     BLSWAP(hdrp->low_mask);
948*46366Sbostic     BLSWAP(hdrp->ffactor);
949*46366Sbostic     BLSWAP(hdrp->nkeys);
950*46366Sbostic     BLSWAP(hdrp->hdrpages);
951*46366Sbostic     BLSWAP(hdrp->h_charkey);
952*46366Sbostic     for ( i=0; i < NCACHED; i++ ) {
953*46366Sbostic 	BLSWAP ( hdrp->spares[i] );
954*46366Sbostic 	BSSWAP ( hdrp->bitmaps[i] );
955*46366Sbostic     }
956*46366Sbostic     return;
957*46366Sbostic }
958