xref: /csrg-svn/lib/libc/db/hash/hash_page.c (revision 46460)
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_page.c	5.3 (Berkeley) 02/19/91";
13 #endif /* LIBC_SCCS and not lint */
14 
15 /******************************************************************************
16 PACKAGE:  hashing
17 
18 DESCRIPTION:
19 	Page manipulation for hashing package.
20 
21 ROUTINES:
22     External
23 	__get_page
24 	__add_ovflpage
25     Internal
26 	overflow_page
27 	open_temp
28 ******************************************************************************/
29 
30 #include <sys/param.h>
31 #include <sys/file.h>
32 #include <signal.h>
33 #include <assert.h>
34 #include <errno.h>
35 #include <db.h>
36 #include <stdio.h>
37 #include "hash.h"
38 #include "page.h"
39 
40 /* Externals */
41 /* buf.c */
42 extern BUFHEAD	*__get_buf();
43 extern void __reclaim_buf();
44 
45 /* big.c */
46 extern int __big_split();
47 extern int __big_insert();
48 extern int __big_delete();
49 extern int __find_bigpair();
50 
51 /* dynahash.c */
52 extern	int	__call_hash();
53 extern	int	__expand_table();
54 
55 /* my externals */
56 extern int __get_page();
57 extern BUFHEAD *__add_ovflpage();
58 extern int __split_page();
59 extern int __addel();
60 
61 /* my internals */
62 static u_short overflow_page();
63 static int open_temp();
64 static void squeeze_key();
65 static void putpair();
66 
67 #ifdef HASH_STATISTICS
68 extern long hash_accesses, hash_collisions, hash_expansions, hash_overflows;
69 #endif
70 #define	PAGE_INIT(P)					\
71 {							\
72     ((u_short *)P)[0] = 0;				\
73     ((u_short *)P)[1] = hashp->BSIZE - 3 * sizeof(u_short);	\
74     ((u_short *)P)[2] = hashp->BSIZE;			\
75 }
76 
77 /*
78 	This is called AFTER we have verified that there is room on the
79 	page for the pair (PAIRFITS has returned true) so we go right
80 	ahead and start moving stuff on.
81 */
82 static void
83 putpair(p, key, val)
84 char *p;
85 DBT *key;
86 DBT *val;
87 {
88 	register u_short n;
89 	register u_short off;
90 	register u_short *bp = (u_short *) p;
91 
92 /* enter the key first */
93 	n = bp[0];
94 
95 	off = OFFSET(bp) - key->size;
96 	bcopy( key->data, p+off, key->size );
97 	bp[++n] = off;
98 
99 /* now the data */
100 	off -= val->size;
101 	bcopy(val->data,  p + off, val->size);
102 	bp[++n] = off;
103 
104 /* adjust page info */
105 	bp[0] = n;
106 	bp[n+1] = off - ((n+3)*sizeof(u_short));
107 	bp[n+2] = off;
108 	return;
109 }
110 /*
111     0 OK
112     -1 error
113 */
114 extern int
115 __delpair(bufp, ndx)
116 BUFHEAD *bufp;
117 register int ndx;
118 {
119 	register u_short *bp = (u_short *) bufp->page;
120 	register int n = bp[0];
121 	register u_short newoff;
122 	u_short pairlen;
123 
124 	if ( bp[ndx+1] < REAL_KEY ) return ( __big_delete ( bufp, ndx ) );
125 	if ( ndx != 1 ) newoff = bp[ndx-1];
126 	else newoff = hashp->BSIZE;
127 	pairlen = newoff - bp[ndx+1];
128 
129 	if ( ndx != (n-1) ) {
130 		/* Hard Case -- need to shuffle keys */
131 		register int i;
132 		register char *src = bufp->page + (int)OFFSET(bp);
133 		register char *dst = src + (int)pairlen;
134 		bcopy ( src, dst, bp[ndx+1] - OFFSET(bp) );
135 
136 		/* Now adjust the pointers */
137 		for ( i = ndx+2; i <= n; i += 2 ) {
138 		    if ( bp[i+1]  == OVFLPAGE ) {
139 			bp[i-2] = bp[i];
140 			bp[i-1] = bp[i+1];
141 		    } else {
142 			bp[i-2] = bp[i] + pairlen;
143 			bp[i-1] = bp[i+1] + pairlen;
144 		    }
145 		}
146 	}
147 
148 	/* Finally adjust the page data */
149 	bp[n] = OFFSET(bp) + pairlen;
150 	bp[n-1] = bp[n+1] + pairlen + 2 * sizeof(u_short);
151 	bp[0] = n-2;
152 	hashp->NKEYS--;
153 
154 	bufp->flags |= BUF_MOD;
155 	return (0);
156 }
157 /*
158     -1 ==> Error
159     0 ==> OK
160 */
161 extern int
162 __split_page(obucket, nbucket)
163 int obucket;
164 int nbucket;
165 {
166 	DBT key;
167 	DBT val;
168 
169 	register BUFHEAD *new_bufp;
170 	register BUFHEAD *old_bufp;
171 	register u_short *ino;
172 	register char	*np;
173 	int n;
174 	int ndx;
175 	int retval;
176 	char	*op;
177 
178 	u_short copyto = (u_short)hashp->BSIZE;
179 	u_short diff;
180 	u_short off = (u_short)hashp->BSIZE;
181 	u_short moved;
182 
183 	old_bufp = __get_buf ( obucket, NULL, 0 );
184 	new_bufp = __get_buf ( nbucket, NULL, 0 );
185 
186 	old_bufp->flags |= (BUF_MOD|BUF_PIN);
187 	new_bufp->flags |= (BUF_MOD|BUF_PIN);
188 
189 	ino = (u_short *)(op = old_bufp->page);
190 	np = new_bufp->page;
191 
192 	moved = 0;
193 
194 	for (n = 1, ndx = 1; n < ino[0]; n+=2) {
195 		if ( ino[n+1] < REAL_KEY ) {
196 		    retval = ugly_split( obucket, old_bufp, new_bufp,
197 					 copyto, moved );
198 		    old_bufp->flags &= ~BUF_PIN;
199 		    new_bufp->flags &= ~BUF_PIN;
200 		    return(retval);
201 
202 		}
203 		key.data = op + ino[n];
204 		key.size = off - ino[n];
205 
206 		if ( __call_hash ( key.data, key.size ) == obucket ) {
207 		    /* Don't switch page */
208 		    diff = copyto - off;
209 		    if ( diff ) {
210 			copyto = ino[n+1] + diff;
211 			bcopy ( op + ino[n+1], op + copyto,  off-ino[n+1]);
212 			ino[ndx] = copyto + ino[n] - ino[n+1];
213 			ino[ndx+1] = copyto;
214 		    } else copyto = ino[n+1];
215 		    ndx += 2;
216 		} else {
217 		    /* Switch page */
218 		    val.data = op + ino[n+1];
219 		    val.size = ino[n] - ino[n+1];
220 		    putpair( np, &key, &val);
221 		    moved +=2;
222 		}
223 
224 		off = ino[n+1];
225 	}
226 
227 	/* Now clean up the page */
228 	ino[0] -= moved;
229 	FREESPACE(ino) = copyto - sizeof(u_short) * (ino[0]+3);
230 	OFFSET(ino) = copyto;
231 
232 #ifdef DEBUG3
233 	fprintf(stderr, "split %d/%d\n",
234 	       ((u_short *) np)[0] / 2,
235 	       ((u_short *) op)[0] / 2);
236 #endif
237 	/* unpin both pages */
238 	old_bufp->flags &= ~BUF_PIN;
239 	new_bufp->flags &= ~BUF_PIN;
240 	return(0);
241 }
242 /*
243     0 ==> success
244     -1 ==> failure
245 
246     Called when we encounter an overflow or big key/data page during
247     split handling.
248     This is special cased since we have to begin checking whether
249     the key/data pairs fit on their respective pages and because
250     we may need overflow pages for both the old and new pages
251 
252     The first page might be a page with regular key/data pairs
253     in which case we have a regular overflow condition and just
254     need to go on to the next page or it might be a big key/data
255     pair in which case we need to fix the big key/data pair.
256 */
257 static int
258 ugly_split( obucket, old_bufp, new_bufp, copyto, moved )
259 int	obucket;	/* Same as __split_page */
260 BUFHEAD	*old_bufp;
261 BUFHEAD	*new_bufp;
262 u_short	copyto;		/* First byte on page which contains key/data values */
263 int	moved;		/* number of pairs moved to new page */
264 {
265     register BUFHEAD *bufp = old_bufp;		/* Buffer header for ino */
266     register u_short	*ino = (u_short *)old_bufp->page;
267 						/* Page keys come off of */
268     register u_short	*np = (u_short *)new_bufp->page;	/* New page */
269     register u_short	*op = (u_short *)old_bufp->page;
270 						/* Page keys go on to if they
271 						   aren't moving */
272 
273     char	*cino;				/* Character value of ino */
274     BUFHEAD	*last_bfp = NULL;		/* Last buffer header OVFL which
275 						   needs to be freed */
276     u_short	ov_addr, last_addr = 0;
277     u_short	n;
278     u_short	off;
279 
280     DBT	key, val;
281     SPLIT_RETURN	ret;
282 
283     n = ino[0]-1;
284     while ( n < ino[0] ) {
285 	if ( ino[n+1] == OVFLPAGE ) {
286 	    ov_addr = ino[n];
287 	    /*
288 		Fix up the old page -- the extra 2 are the fields which
289 		contained the overflow information
290 	    */
291 	    ino[0] -= (moved + 2);
292 	    FREESPACE(ino) = copyto - sizeof(u_short) * (ino[0]+3);
293 	    OFFSET(ino) = copyto;
294 
295 	    bufp = __get_buf ( ov_addr, bufp, 0 );
296 	    if ( !bufp ) return(-1);
297 
298 	    ino = (u_short *)bufp->page;
299 	    n = 1;
300 	    copyto = hashp->BSIZE;
301 	    moved = 0;
302 
303 	    if ( last_bfp ) {
304 		__free_ovflpage( last_bfp);
305 	    }
306 	    last_bfp = bufp;
307 	}
308 
309 	if ( (ino[2] < REAL_KEY) && (ino[2] != OVFLPAGE) ) {
310 	    if (__big_split (old_bufp,
311 		new_bufp, bufp, ov_addr, obucket, &ret)) {
312 		    return(-1);
313 	    }
314 	    old_bufp = ret.oldp;
315 	    if ( !old_bufp ) return(-1);
316 	    op = (u_short *)old_bufp->page;
317 	    new_bufp = ret.newp;
318 	    if ( !new_bufp ) return(-1);
319 	    np = (u_short *)new_bufp->page;
320 	    bufp = ret.nextp;
321 	    if ( !bufp ) return(0);
322 	    cino = (char *)bufp->page;
323 	    ino = (u_short *)cino;
324 	    last_bfp = ret.nextp;
325 	}
326 
327 
328 	/* Move regular sized pairs of there are any */
329 	off = hashp->BSIZE;
330 	for ( n = 1; (n < ino[0]) && (ino[n+1] >= REAL_KEY); n += 2 ) {
331 	    cino = (char *)ino;
332 	    key.data = cino + ino[n];
333 	    key.size = off - ino[n];
334 	    val.data = cino + ino[n+1];
335 	    val.size = ino[n] - ino[n+1];
336 	    off = ino[n+1];
337 
338 	    if ( __call_hash ( key.data, key.size ) == obucket ) {
339 		/* Keep on old page */
340 		if (PAIRFITS(op,(&key),(&val))) putpair((char *)op, &key, &val);
341 		else {
342 		    old_bufp = __add_ovflpage ( old_bufp );
343 		    if ( !old_bufp ) return(-1);
344 		    op = (u_short *)old_bufp->page;
345 		    putpair ((char *)op, &key, &val);
346 		}
347 		old_bufp->flags |= BUF_MOD;
348 	    } else {
349 		/* Move to new page */
350 		if (PAIRFITS(np,(&key),(&val))) putpair((char *)np, &key, &val);
351 		else {
352 		    new_bufp = __add_ovflpage ( new_bufp );
353 		    if ( !new_bufp )return(-1);
354 		    np = (u_short *)new_bufp->page;
355 		    putpair ((char *)np, &key, &val);
356 		}
357 		new_bufp->flags |= BUF_MOD;
358 	    }
359 	}
360     }
361     if ( last_bfp ) {
362 	__free_ovflpage(last_bfp);
363     }
364 
365     return (0);
366 }
367 /*
368     Add the given pair to the page
369     1 ==> failure
370     0 ==> OK
371 */
372 extern int
373 __addel(bufp, key, val)
374 BUFHEAD	*bufp;
375 DBT	*key;
376 DBT	*val;
377 {
378     register u_short *bp = (u_short *)bufp->page;
379     register u_short *sop;
380     int	do_expand;
381 
382     do_expand = 0;
383     while ( bp[0] &&  (bp[bp[0]] < REAL_KEY) ) {
384 	/* Exception case */
385 	if ( bp[2] < REAL_KEY ) {
386 	    /* This is a big-keydata pair */
387 	    bufp = __add_ovflpage(bufp);
388 	    if ( !bufp ) {
389 		return(-1);
390 	    }
391 	    bp = (u_short *)bufp->page;
392 	} else {
393 	    /* Try to squeeze key on this page */
394 	    if ( FREESPACE(bp) > PAIRSIZE(key,val) ) {
395 		squeeze_key ( bp, key, val );
396 		return(0);
397 	    } else {
398 		bufp = __get_buf ( bp[bp[0]-1], bufp, 0 );
399 		if (!bufp) {
400 		    return(-1);
401 		}
402 		bp = (u_short *)bufp->page;
403 	    }
404 	}
405     }
406 
407     if ( PAIRFITS(bp,key,val) ) putpair (bufp->page, key, val);
408     else {
409 	do_expand = 1;
410 	bufp = __add_ovflpage ( bufp );
411 	if (!bufp)return(-1);
412 	sop = (u_short *) bufp->page;
413 
414 	if ( PAIRFITS(sop, key, val) ) putpair ( (char *)sop, key, val );
415 	else if ( __big_insert ( bufp, key, val ) ) {
416 	    return(-1);
417 	}
418     }
419     bufp->flags |= BUF_MOD;
420     /*
421 	If the average number of keys per bucket exceeds the fill factor,
422 	expand the table
423     */
424     hashp->NKEYS++;
425     if (do_expand ||
426 	(hashp->NKEYS / (hashp->MAX_BUCKET+1) > hashp->FFACTOR) ) {
427 	 return(__expand_table());
428     }
429     return(0);
430 }
431 
432 /*
433     returns a pointer, NULL on error
434 */
435 extern BUFHEAD *
436 __add_ovflpage ( bufp )
437 BUFHEAD	*bufp;
438 {
439     register	u_short	*sp = (u_short *)bufp->page;
440 
441     u_short	ovfl_num;
442     u_short	ndx, newoff;
443     char	*op;
444     DBT	okey, oval;
445 #ifdef DEBUG1
446     int	tmp1, tmp2;
447 #endif
448 
449     bufp->flags |= BUF_MOD;
450     ovfl_num = overflow_page ();
451 #ifdef DEBUG1
452     tmp1 = bufp->addr;
453     tmp2 = bufp->ovfl?bufp->ovfl->addr:0;
454 #endif
455     if (!ovfl_num || !(bufp->ovfl = __get_buf ( ovfl_num, bufp, 1 ))) {
456 	return(NULL);
457     }
458     bufp->ovfl->flags |= BUF_MOD;
459 #ifdef DEBUG1
460     fprintf ( stderr, "ADDOVFLPAGE: %d->ovfl was %d is now %d\n", tmp1, tmp2,
461 		bufp->ovfl->addr );
462 #endif
463     ndx = sp[0];
464     /*
465 	Since a pair is allocated on a page only if there's room
466 	to add an overflow page, we know that the OVFL information
467 	will fit on the page
468     */
469     sp[ndx+4] = OFFSET(sp);
470     sp[ndx+3] = FREESPACE(sp) - OVFLSIZE;
471     sp[ndx+1] = ovfl_num;
472     sp[ndx+2] = OVFLPAGE;
473     sp[0] = ndx+2;
474 #ifdef HASH_STATISTICS
475 	    hash_overflows++;
476 #endif
477     return(bufp->ovfl);
478 }
479 
480 /*
481     0 indicates SUCCESS
482     -1 indicates FAILURE
483 */
484 extern	int
485 __get_page ( p, bucket, is_bucket, is_disk, is_bitmap )
486 char	*p;
487 int	bucket;
488 int	is_bucket;
489 int	is_disk;
490 int	is_bitmap;
491 {
492     register int size;
493     register int fd;
494     register int page;
495     u_short	*bp;
496     int		rsize;
497 
498     fd = hashp->fp;
499     size = hashp->BSIZE;
500 
501     if ( (fd == -1) || (hashp->new_file && !is_disk) ) {
502 	PAGE_INIT(p);
503 	return(0);
504     }
505 
506     if ( is_bucket) page = BUCKET_TO_PAGE (bucket);
507     else page = OADDR_TO_PAGE (bucket);
508     if ((lseek ( fd, page << hashp->BSHIFT, L_SET ) == -1) ||
509 	((rsize = read ( fd, p, size )) == -1 )) {
510 	return(-1);
511     }
512     bp = (u_short *)p;
513     if ( !rsize ) {
514 	bp[0] = 0;		/* We hit the EOF, so initialize a new page */
515     } else if ( rsize != size ) {
516 	errno = EFTYPE;
517 	return(-1);
518     }
519     if (!bp[0]) {
520 	PAGE_INIT(p);
521     } else if ( hashp->LORDER != BYTE_ORDER ) {
522 	register int i;
523 	register int max;
524 
525 	if ( is_bitmap ) {
526 	    max = hashp->BSIZE >> 2;	/* divide by 4 */
527 	    for ( i=0; i < max; i++ ) {
528 		BLSWAP(((long *)p)[i]);
529 	    }
530 	} else {
531 	    BSSWAP(bp[0]);
532 	    max = bp[0] + 2;
533 	    for ( i=1; i <= max; i++ ) {
534 		BSSWAP(bp[i]);
535 	    }
536 	}
537     }
538     return (0);
539 }
540 
541 /*
542     Write page p to disk
543     -1==>failure
544     0==> OK
545 */
546 extern int
547 __put_page ( p, bucket, is_bucket, is_bitmap )
548 char	*p;
549 int	bucket;
550 int	is_bucket;
551 int	is_bitmap;
552 {
553     register int size;
554     register int fd;
555     register int page;
556     int	wsize;
557 
558     size = hashp->BSIZE;
559     if ( (hashp->fp == -1) && open_temp() ) return (1);
560     fd = hashp->fp;
561 
562     if ( hashp->LORDER != BYTE_ORDER ) {
563 	register int i;
564 	register int max;
565 
566 	if ( is_bitmap ) {
567 	    max = hashp->BSIZE >> 2;	/* divide by 4 */
568 	    for ( i=0; i < max; i++ ) {
569 		BLSWAP(((long *)p)[i]);
570 	    }
571 	} else {
572 	    max = ((u_short *)p)[0] + 2;
573 	    for ( i=0; i <= max; i++ ) {
574 		BSSWAP(((u_short *)p)[i]);
575 	    }
576 	}
577     }
578     if (is_bucket ) page = BUCKET_TO_PAGE (bucket);
579     else page = OADDR_TO_PAGE ( bucket );
580     if ((lseek ( fd, page << hashp->BSHIFT, L_SET ) == -1) ||
581 	((wsize = write ( fd, p, size )) == -1 )) {
582 	/* Errno is set */
583 	return(-1);
584     }
585     if ( wsize != size ) {
586 	errno = EFTYPE;
587 	return(-1);
588     }
589     return(0);
590 }
591 #define BYTE_MASK	((1 << INT_BYTE_SHIFT) -1)
592 /*
593     Initialize a new bitmap page.  Bitmap pages are left in memory
594     once they are read in.
595 */
596 extern u_long *
597 __init_bitmap(pnum, nbits, ndx)
598 u_short	pnum;
599 int	nbits;
600 int	ndx;
601 {
602     u_long	*ip;
603     int		clearints;
604     int		clearbytes;
605 
606     if ( !(ip = (u_long *)malloc (hashp->BSIZE)) ) return (NULL);
607     clearints = ((nbits - 1) >> INT_BYTE_SHIFT) + 1;
608     clearbytes = clearints << INT_TO_BYTE;
609     memset ((char *)ip, 0, clearbytes );
610     memset ( ((char *) ip) + clearbytes, 0xFF,
611 		hashp->BSIZE-clearbytes );
612     ip[clearints-1] = ALL_SET << (nbits & BYTE_MASK);
613     SETBIT(ip, 0);
614     hashp->BITMAPS[ndx] = pnum;
615     hashp->mapp[ndx] = ip;
616     return(ip);
617 }
618 static int
619 first_free ( map )
620 u_long map;
621 {
622     register u_long      mask;
623     register u_long      i;
624 
625     mask = 0x1;
626     for ( i=0; i < BITS_PER_MAP; i++ ) {
627 	if ( !(mask & map) ) return(i);
628 	mask = mask << 1;
629     }
630     return ( i );
631 }
632 
633 static u_short
634 overflow_page ( )
635 {
636     register	int max_free;
637     register	int splitnum;
638     register	u_long *freep;
639     register	int offset;
640     u_short	addr;
641     int		in_use_bits;
642     int		free_page, free_bit;
643     int		i, j, bit;
644 #ifdef DEBUG2
645     int	tmp1, tmp2;
646 #endif
647 
648     splitnum = __log2(hashp->MAX_BUCKET);
649     max_free = hashp->SPARES[splitnum];
650 
651     free_page = (max_free-1) >> (hashp->BSHIFT + BYTE_SHIFT);
652     free_bit  = (max_free-1) & ((hashp->BSIZE << BYTE_SHIFT) - 1);
653 
654     /* Look through all the free maps to find the first free block */
655     for ( i = 0; i <= free_page; i++ ) {
656 	if (!(freep = (u_long *)hashp->mapp[i]) ) return(NULL);
657 	if ( i == free_page ) in_use_bits = free_bit;
658 	else in_use_bits = (hashp->BSIZE << BYTE_SHIFT) -1;
659 
660 	for (j = 0, bit = 0; bit <= in_use_bits; j++, bit += BITS_PER_MAP ) {
661 	     if ( freep[j] != ALL_SET ) goto found;
662 	}
663     }
664     /* No Free Page Found */
665     hashp->SPARES[splitnum]++;
666     offset = hashp->SPARES[splitnum] -
667 	     (splitnum ? hashp->SPARES[splitnum-1] : 0);
668 
669     /* Check if we need to allocate a new bitmap page */
670     if ( free_bit == (hashp->BSIZE << BYTE_SHIFT) - 1 ) {
671 	free_page++;
672 	if ( free_page >= NCACHED ) {
673 	    fprintf ( stderr,
674 		"HASH: Out of overflow pages.  Increase page size\n" );
675 	    return(NULL);
676 	}
677 	/*
678 	    This is tricky.  The 1 indicates that you want the
679 	    new page allocated with 1 clear bit.  Actually, you
680 	    are going to allocate 2 pages from this map.  The first
681 	    is going to be the map page, the second is the overflow
682 	    page we were looking for.  The init_bitmap routine
683 	    automatically, sets the first bit of itself to indicate
684 	    that the bitmap itself is in use.  We would explicitly
685 	    set the second bit, but don't have to if we tell init_bitmap
686 	    not to leave it clear in the first place.
687 	*/
688 	__init_bitmap ( OADDR_OF(splitnum, offset), 1, free_page );
689 	hashp->SPARES[splitnum]++;
690 #ifdef DEBUG2
691 	free_bit = 2;
692 #endif
693 	offset++;
694     } else {
695 	/*
696 		Free_bit addresses the last used bit.  Bump it to
697 		address the first available bit.
698 	*/
699 	free_bit++;
700 	SETBIT ( freep, free_bit );
701     }
702 
703     /* Calculate address of the new overflow page */
704     if ( offset > SPLITMASK ) {
705 	fprintf ( stderr,
706 	    "HASH: Out of overflow pages.  Increase page size\n" );
707 	return(NULL);
708     }
709     addr = OADDR_OF(splitnum, offset);
710 #ifdef DEBUG2
711     fprintf ( stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
712 		addr, free_bit, free_page );
713 #endif
714     return(addr);
715 
716 found:
717     bit = bit + first_free(freep[j]);
718     SETBIT(freep,bit);
719 #ifdef DEBUG2
720     tmp1 = bit;
721     tmp2 = i;
722 #endif
723     /*
724 	Bits are addressed starting with 0, but overflow pages are
725 	addressed beginning at 1. Bit is a bit addressnumber, so we
726 	need to increment it to convert it to a page number.
727     */
728     bit = 1 + bit + (i * (hashp->BSIZE << BYTE_SHIFT));
729 
730     /* Calculate the split number for this page */
731     for ( i = 0; (i < splitnum) && (bit > hashp->SPARES[i]); i++ );
732     offset =(i ? bit - hashp->SPARES[i-1] : bit );
733     if ( offset >= SPLITMASK ) return(NULL);/* Out of overflow pages */
734     addr = OADDR_OF(i, offset);
735 #ifdef DEBUG2
736     fprintf ( stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
737 		addr, tmp1, tmp2 );
738 #endif
739 
740     /* Allocate and return the overflow page */
741     return (addr);
742 }
743 
744 /*
745     Mark this overflow page as free.
746 */
747 __free_ovflpage ( obufp )
748 BUFHEAD	*obufp;
749 {
750     register u_short addr = obufp->addr;
751     int	free_page, free_bit;
752     int bit_address;
753     u_short ndx;
754     u_long *freep;
755     int j;
756 
757 #ifdef DEBUG1
758     fprintf ( stderr, "Freeing %d\n", addr );
759 #endif
760     ndx = (((u_short)addr) >> SPLITSHIFT);
761     bit_address = (ndx ? hashp->SPARES[ndx-1] : 0) + (addr & SPLITMASK) - 1;
762     free_page = (bit_address >> (hashp->BSHIFT + BYTE_SHIFT));
763     free_bit  = bit_address & ((hashp->BSIZE << BYTE_SHIFT) - 1);
764 
765     freep = hashp->mapp[free_page];
766     assert(freep);
767     CLRBIT(freep, free_bit);
768 #ifdef DEBUG2
769     fprintf ( stderr, "FREE_OVFLPAGE: ADDR: %d BIT: %d PAGE %d\n",
770 		obufp->addr, free_bit, free_page );
771 #endif
772     __reclaim_buf ( obufp );
773     return;
774 }
775 
776 /*
777 0 success
778 -1 failure
779 */
780 static int
781 open_temp()
782 {
783     sigset_t	set, oset;
784     char	*namestr = "_hashXXXXXX";
785 
786     /* Block signals; make sure file goes away at process exit. */
787     sigemptyset(&set);
788     sigaddset(&set, SIGHUP);
789     sigaddset(&set, SIGINT);
790     sigaddset(&set, SIGQUIT);
791     sigaddset(&set, SIGTERM);
792     (void)sigprocmask(SIG_BLOCK, &set, &oset);
793     if ((hashp->fp = mkstemp ( namestr )) != -1) {
794 	(void)unlink(namestr);
795 	(void)fcntl(hashp->fp, F_SETFD, 1);
796     }
797     (void)sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL);
798     return(hashp->fp != -1 ? 0 : -1);
799 }
800 
801 /*
802     We have to know that the key will fit, but the
803     last entry on the page is an overflow pair, so we
804     need to shift things.
805 */
806 static void
807 squeeze_key ( sp, key, val )
808 u_short	*sp;
809 DBT	*key;
810 DBT	*val;
811 {
812     register	char	*p = (char *)sp;
813     u_short	free_space, off;
814     u_short	pageno, n;
815 
816     n = sp[0];
817     free_space = FREESPACE(sp);
818     off = OFFSET(sp);
819 
820     pageno = sp[n-1];
821     off -= key->size;
822     sp[n-1] = off;
823     bcopy ( key->data, p + off, key->size );
824     off -= val->size;
825     sp[n] = off;
826     bcopy ( val->data, p + off, val->size );
827     sp[0] = n+2;
828     sp[n+1] = pageno;
829     sp[n+2] = OVFLPAGE;
830     FREESPACE(sp) = free_space - PAIRSIZE(key,val);
831     OFFSET(sp) = off;
832 }
833 
834 #ifdef DEBUG4
835 print_chain ( addr )
836 short	addr;
837 {
838 	BUFHEAD	*bufp;
839 	short	*bp;
840 	short	oaddr;
841 
842 	fprintf ( stderr, "%d ", addr );
843 	bufp = __get_buf ( (int)addr, NULL, 0 );
844 	bp = (short *)bufp->page;
845 	while ( bp[0] &&
846 		((bp[bp[0]] == OVFLPAGE) ||
847 		 ((bp[0] > 2) && bp[2] < REAL_KEY))) {
848 		oaddr = bp[bp[0]-1];
849 		fprintf ( stderr, "%d ", (int)oaddr );
850 		bufp = __get_buf ( (int)oaddr, bufp, 0 );
851 		bp = (short *)bufp->page;
852 	}
853 	fprintf ( stderr, "\n" );
854 }
855 #endif
856