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