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