Sync usage with man page.
[netbsd-mini2440.git] / lib / libc / db / hash / page.c
blobe577d658b55d1a8d9f2f820bdf52235564f17212
1 /*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Margo Seltzer.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char sccsid[] = "@(#)page.c 5.13 (Berkeley) 6/17/91";
39 #endif /* LIBC_SCCS and not lint */
41 /******************************************************************************
42 PACKAGE: hashing
44 DESCRIPTION:
45 Page manipulation for hashing package.
47 ROUTINES:
48 External
49 __get_page
50 __add_ovflpage
51 Internal
52 overflow_page
53 open_temp
54 ******************************************************************************/
56 #include <sys/param.h>
57 #include <fcntl.h>
58 #include <signal.h>
59 #include <assert.h>
60 #include <errno.h>
61 #include <db.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <unistd.h>
66 #include "hash.h"
67 #include "page.h"
69 /* Externals */
70 /* buf.c */
71 extern BUFHEAD *__get_buf();
72 extern void __reclaim_buf();
74 /* big.c */
75 extern int __big_split();
76 extern int __big_insert();
77 extern int __big_delete();
78 extern int __find_bigpair();
80 /* dynahash.c */
81 extern u_int __call_hash();
82 extern int __expand_table();
84 /* my externals */
85 extern int __get_page();
86 extern BUFHEAD *__add_ovflpage();
87 extern int __split_page();
88 extern int __addel();
90 /* my internals */
91 static u_short overflow_page();
92 static int open_temp();
93 static int ugly_split();
94 static void squeeze_key();
95 static void putpair();
96 static u_long *fetch_bitmap();
98 #ifdef HASH_STATISTICS
99 extern long hash_accesses, hash_collisions, hash_expansions, hash_overflows;
100 #endif
101 #define PAGE_INIT(P) \
103 ((u_short *)P)[0] = 0; \
104 ((u_short *)P)[1] = hashp->BSIZE - 3 * sizeof(u_short); \
105 ((u_short *)P)[2] = hashp->BSIZE; \
109 This is called AFTER we have verified that there is room on the
110 page for the pair (PAIRFITS has returned true) so we go right
111 ahead and start moving stuff on.
113 static void
114 putpair(p, key, val)
115 char *p;
116 DBT *key;
117 DBT *val;
119 register u_short n;
120 register u_short off;
121 register u_short *bp = (u_short *) p;
123 /* enter the key first */
124 n = bp[0];
126 off = OFFSET(bp) - key->size;
127 bcopy( key->data, p+off, key->size );
128 bp[++n] = off;
130 /* now the data */
131 off -= val->size;
132 bcopy(val->data, p + off, val->size);
133 bp[++n] = off;
135 /* adjust page info */
136 bp[0] = n;
137 bp[n+1] = off - ((n+3)*sizeof(u_short));
138 bp[n+2] = off;
139 return;
142 0 OK
143 -1 error
145 extern int
146 __delpair(bufp, ndx)
147 BUFHEAD *bufp;
148 register int ndx;
150 register u_short *bp = (u_short *) bufp->page;
151 register int n = bp[0];
152 register u_short newoff;
153 u_short pairlen;
155 if ( bp[ndx+1] < REAL_KEY ) return ( __big_delete ( bufp, ndx ) );
156 if ( ndx != 1 ) newoff = bp[ndx-1];
157 else newoff = hashp->BSIZE;
158 pairlen = newoff - bp[ndx+1];
160 if ( ndx != (n-1) ) {
161 /* Hard Case -- need to shuffle keys */
162 register int i;
163 register char *src = bufp->page + (int)OFFSET(bp);
164 register char *dst = src + (int)pairlen;
165 bcopy ( src, dst, bp[ndx+1] - OFFSET(bp) );
167 /* Now adjust the pointers */
168 for ( i = ndx+2; i <= n; i += 2 ) {
169 if ( bp[i+1] == OVFLPAGE ) {
170 bp[i-2] = bp[i];
171 bp[i-1] = bp[i+1];
172 } else {
173 bp[i-2] = bp[i] + pairlen;
174 bp[i-1] = bp[i+1] + pairlen;
179 /* Finally adjust the page data */
180 bp[n] = OFFSET(bp) + pairlen;
181 bp[n-1] = bp[n+1] + pairlen + 2 * sizeof(u_short);
182 bp[0] = n-2;
183 hashp->NKEYS--;
185 bufp->flags |= BUF_MOD;
186 return (0);
189 -1 ==> Error
190 0 ==> OK
192 extern int
193 __split_page(obucket, nbucket)
194 u_int obucket;
195 u_int nbucket;
197 DBT key;
198 DBT val;
200 register BUFHEAD *new_bufp;
201 register BUFHEAD *old_bufp;
202 register u_short *ino;
203 register char *np;
204 int n;
205 int ndx;
206 int retval;
207 char *op;
209 u_short copyto = (u_short)hashp->BSIZE;
210 u_short diff;
211 u_short off = (u_short)hashp->BSIZE;
212 u_short moved;
214 old_bufp = __get_buf ( obucket, NULL, 0 );
215 new_bufp = __get_buf ( nbucket, NULL, 0 );
217 old_bufp->flags |= (BUF_MOD|BUF_PIN);
218 new_bufp->flags |= (BUF_MOD|BUF_PIN);
220 ino = (u_short *)(op = old_bufp->page);
221 np = new_bufp->page;
223 moved = 0;
225 for (n = 1, ndx = 1; n < ino[0]; n+=2) {
226 if ( ino[n+1] < REAL_KEY ) {
227 retval = ugly_split( obucket, old_bufp, new_bufp,
228 copyto, moved );
229 old_bufp->flags &= ~BUF_PIN;
230 new_bufp->flags &= ~BUF_PIN;
231 return(retval);
234 key.data = (u_char *)op + ino[n];
235 key.size = off - ino[n];
237 if ( __call_hash ( key.data, key.size ) == obucket ) {
238 /* Don't switch page */
239 diff = copyto - off;
240 if ( diff ) {
241 copyto = ino[n+1] + diff;
242 bcopy ( op + ino[n+1], op + copyto, off-ino[n+1]);
243 ino[ndx] = copyto + ino[n] - ino[n+1];
244 ino[ndx+1] = copyto;
245 } else copyto = ino[n+1];
246 ndx += 2;
247 } else {
248 /* Switch page */
249 val.data = (u_char *)op + ino[n+1];
250 val.size = ino[n] - ino[n+1];
251 putpair( np, &key, &val);
252 moved +=2;
255 off = ino[n+1];
258 /* Now clean up the page */
259 ino[0] -= moved;
260 FREESPACE(ino) = copyto - sizeof(u_short) * (ino[0]+3);
261 OFFSET(ino) = copyto;
263 #ifdef DEBUG3
264 fprintf(stderr, "split %d/%d\n",
265 ((u_short *) np)[0] / 2,
266 ((u_short *) op)[0] / 2);
267 #endif
268 /* unpin both pages */
269 old_bufp->flags &= ~BUF_PIN;
270 new_bufp->flags &= ~BUF_PIN;
271 return(0);
274 0 ==> success
275 -1 ==> failure
277 Called when we encounter an overflow or big key/data page during
278 split handling.
279 This is special cased since we have to begin checking whether
280 the key/data pairs fit on their respective pages and because
281 we may need overflow pages for both the old and new pages
283 The first page might be a page with regular key/data pairs
284 in which case we have a regular overflow condition and just
285 need to go on to the next page or it might be a big key/data
286 pair in which case we need to fix the big key/data pair.
288 static int
289 ugly_split( obucket, old_bufp, new_bufp, copyto, moved )
290 u_int obucket; /* Same as __split_page */
291 BUFHEAD *old_bufp;
292 BUFHEAD *new_bufp;
293 u_short copyto; /* First byte on page which contains key/data values */
294 int moved; /* number of pairs moved to new page */
296 register BUFHEAD *bufp = old_bufp; /* Buffer header for ino */
297 register u_short *ino = (u_short *)old_bufp->page;
298 /* Page keys come off of */
299 register u_short *np = (u_short *)new_bufp->page; /* New page */
300 register u_short *op = (u_short *)old_bufp->page;
301 /* Page keys go on to if they
302 aren't moving */
304 char *cino; /* Character value of ino */
305 BUFHEAD *last_bfp = NULL; /* Last buffer header OVFL which
306 needs to be freed */
307 u_short ov_addr, last_addr = 0;
308 u_short n;
309 u_short off;
311 DBT key, val;
312 SPLIT_RETURN ret;
314 n = ino[0]-1;
315 while ( n < ino[0] ) {
316 if ( ino[2] < REAL_KEY && ino[2] != OVFLPAGE ) {
317 if (__big_split (old_bufp, new_bufp, bufp, ov_addr, obucket, &ret)) {
318 return(-1);
320 old_bufp = ret.oldp;
321 if ( !old_bufp ) return(-1);
322 op = (u_short *)old_bufp->page;
323 new_bufp = ret.newp;
324 if ( !new_bufp ) return(-1);
325 np = (u_short *)new_bufp->page;
326 bufp = ret.nextp;
327 if ( !bufp ) return(0);
328 cino = (char *)bufp->page;
329 ino = (u_short *)cino;
330 last_bfp = ret.nextp;
331 } else if ( ino[n+1] == OVFLPAGE ) {
332 ov_addr = ino[n];
334 Fix up the old page -- the extra 2 are the fields which
335 contained the overflow information
337 ino[0] -= (moved + 2);
338 FREESPACE(ino) = copyto - sizeof(u_short) * (ino[0]+3);
339 OFFSET(ino) = copyto;
341 bufp = __get_buf ( ov_addr, bufp, 0 );
342 if ( !bufp ) return(-1);
344 ino = (u_short *)bufp->page;
345 n = 1;
346 copyto = hashp->BSIZE;
347 moved = 0;
349 if ( last_bfp ) {
350 __free_ovflpage( last_bfp);
352 last_bfp = bufp;
356 /* Move regular sized pairs of there are any */
357 off = hashp->BSIZE;
358 for ( n = 1; (n < ino[0]) && (ino[n+1] >= REAL_KEY); n += 2 ) {
359 cino = (char *)ino;
360 key.data = (u_char *)cino + ino[n];
361 key.size = off - ino[n];
362 val.data = (u_char *)cino + ino[n+1];
363 val.size = ino[n] - ino[n+1];
364 off = ino[n+1];
366 if ( __call_hash ( key.data, key.size ) == obucket ) {
367 /* Keep on old page */
368 if (PAIRFITS(op,(&key),(&val))) putpair((char *)op, &key, &val);
369 else {
370 old_bufp = __add_ovflpage ( old_bufp );
371 if ( !old_bufp ) return(-1);
372 op = (u_short *)old_bufp->page;
373 putpair ((char *)op, &key, &val);
375 old_bufp->flags |= BUF_MOD;
376 } else {
377 /* Move to new page */
378 if (PAIRFITS(np,(&key),(&val))) putpair((char *)np, &key, &val);
379 else {
380 new_bufp = __add_ovflpage ( new_bufp );
381 if ( !new_bufp )return(-1);
382 np = (u_short *)new_bufp->page;
383 putpair ((char *)np, &key, &val);
385 new_bufp->flags |= BUF_MOD;
389 if ( last_bfp ) {
390 __free_ovflpage(last_bfp);
393 return (0);
396 Add the given pair to the page
397 1 ==> failure
398 0 ==> OK
400 extern int
401 __addel(bufp, key, val)
402 BUFHEAD *bufp;
403 DBT *key;
404 DBT *val;
406 register u_short *bp = (u_short *)bufp->page;
407 register u_short *sop;
408 int do_expand;
410 do_expand = 0;
411 while ( bp[0] && (bp[bp[0]] < REAL_KEY) ) {
412 /* Exception case */
413 if ( bp[2] < REAL_KEY ) {
414 /* This is a big-keydata pair */
415 bufp = __add_ovflpage(bufp);
416 if ( !bufp ) {
417 return(-1);
419 bp = (u_short *)bufp->page;
420 } else {
421 /* Try to squeeze key on this page */
422 if ( FREESPACE(bp) > PAIRSIZE(key,val) ) {
423 squeeze_key ( bp, key, val );
424 return(0);
425 } else {
426 bufp = __get_buf ( bp[bp[0]-1], bufp, 0 );
427 if (!bufp) {
428 return(-1);
430 bp = (u_short *)bufp->page;
435 if ( PAIRFITS(bp,key,val) ) putpair (bufp->page, key, val);
436 else {
437 do_expand = 1;
438 bufp = __add_ovflpage ( bufp );
439 if (!bufp)return(-1);
440 sop = (u_short *) bufp->page;
442 if ( PAIRFITS(sop, key, val) ) putpair ( (char *)sop, key, val );
443 else if ( __big_insert ( bufp, key, val ) ) {
444 return(-1);
447 bufp->flags |= BUF_MOD;
449 If the average number of keys per bucket exceeds the fill factor,
450 expand the table
452 hashp->NKEYS++;
453 if (do_expand ||
454 (hashp->NKEYS / (hashp->MAX_BUCKET+1) > hashp->FFACTOR) ) {
455 return(__expand_table());
457 return(0);
461 returns a pointer, NULL on error
463 extern BUFHEAD *
464 __add_ovflpage ( bufp )
465 BUFHEAD *bufp;
467 register u_short *sp = (u_short *)bufp->page;
469 u_short ovfl_num;
470 u_short ndx, newoff;
471 char *op;
472 DBT okey, oval;
473 #ifdef DEBUG1
474 int tmp1, tmp2;
475 #endif
477 bufp->flags |= BUF_MOD;
478 ovfl_num = overflow_page ();
479 #ifdef DEBUG1
480 tmp1 = bufp->addr;
481 tmp2 = bufp->ovfl?bufp->ovfl->addr:0;
482 #endif
483 if (!ovfl_num || !(bufp->ovfl = __get_buf ( ovfl_num, bufp, 1 ))) {
484 return(NULL);
486 bufp->ovfl->flags |= BUF_MOD;
487 #ifdef DEBUG1
488 fprintf ( stderr, "ADDOVFLPAGE: %d->ovfl was %d is now %d\n", tmp1, tmp2,
489 bufp->ovfl->addr );
490 #endif
491 ndx = sp[0];
493 Since a pair is allocated on a page only if there's room
494 to add an overflow page, we know that the OVFL information
495 will fit on the page
497 sp[ndx+4] = OFFSET(sp);
498 sp[ndx+3] = FREESPACE(sp) - OVFLSIZE;
499 sp[ndx+1] = ovfl_num;
500 sp[ndx+2] = OVFLPAGE;
501 sp[0] = ndx+2;
502 #ifdef HASH_STATISTICS
503 hash_overflows++;
504 #endif
505 return(bufp->ovfl);
509 0 indicates SUCCESS
510 -1 indicates FAILURE
512 extern int
513 __get_page ( p, bucket, is_bucket, is_disk, is_bitmap )
514 char *p;
515 u_int bucket;
516 int is_bucket;
517 int is_disk;
518 int is_bitmap;
520 register int size;
521 register int fd;
522 register int page;
523 u_short *bp;
524 int rsize;
526 fd = hashp->fp;
527 size = hashp->BSIZE;
529 if ( (fd == -1) || !is_disk ) {
530 PAGE_INIT(p);
531 return(0);
534 if ( is_bucket) page = BUCKET_TO_PAGE (bucket);
535 else page = OADDR_TO_PAGE (bucket);
536 if ((lseek ( fd, page << hashp->BSHIFT, SEEK_SET ) == -1) ||
537 ((rsize = read ( fd, p, size )) == -1 )) {
538 return(-1);
540 bp = (u_short *)p;
541 if ( !rsize ) {
542 bp[0] = 0; /* We hit the EOF, so initialize a new page */
543 } else if ( rsize != size ) {
544 errno = EFTYPE;
545 return(-1);
547 if (!bp[0]) {
548 PAGE_INIT(p);
549 } else if ( hashp->LORDER != BYTE_ORDER ) {
550 register int i;
551 register int max;
553 if ( is_bitmap ) {
554 max = hashp->BSIZE >> 2; /* divide by 4 */
555 for ( i=0; i < max; i++ ) {
556 BLSWAP(((long *)p)[i]);
558 } else {
559 BSSWAP(bp[0]);
560 max = bp[0] + 2;
561 for ( i=1; i <= max; i++ ) {
562 BSSWAP(bp[i]);
566 return (0);
570 Write page p to disk
571 -1==>failure
572 0==> OK
574 extern int
575 __put_page ( p, bucket, is_bucket, is_bitmap )
576 char *p;
577 u_int bucket;
578 int is_bucket;
579 int is_bitmap;
581 register int size;
582 register int fd;
583 register int page;
584 int wsize;
586 size = hashp->BSIZE;
587 if ( (hashp->fp == -1) && open_temp() ) return (1);
588 fd = hashp->fp;
590 if ( hashp->LORDER != BYTE_ORDER ) {
591 register int i;
592 register int max;
594 if ( is_bitmap ) {
595 max = hashp->BSIZE >> 2; /* divide by 4 */
596 for ( i=0; i < max; i++ ) {
597 BLSWAP(((long *)p)[i]);
599 } else {
600 max = ((u_short *)p)[0] + 2;
601 for ( i=0; i <= max; i++ ) {
602 BSSWAP(((u_short *)p)[i]);
606 if (is_bucket ) page = BUCKET_TO_PAGE (bucket);
607 else page = OADDR_TO_PAGE ( bucket );
608 if ((lseek ( fd, page << hashp->BSHIFT, SEEK_SET ) == -1) ||
609 ((wsize = write ( fd, p, size )) == -1 )) {
610 /* Errno is set */
611 return(-1);
613 if ( wsize != size ) {
614 errno = EFTYPE;
615 return(-1);
617 return(0);
619 #define BYTE_MASK ((1 << INT_BYTE_SHIFT) -1)
621 Initialize a new bitmap page. Bitmap pages are left in memory
622 once they are read in.
624 extern u_long *
625 __init_bitmap(pnum, nbits, ndx)
626 u_short pnum;
627 int nbits;
628 int ndx;
630 u_long *ip;
631 int clearints;
632 int clearbytes;
634 if ( !(ip = (u_long *)malloc (hashp->BSIZE)) ) return (NULL);
635 hashp->nmaps++;
636 clearints = ((nbits - 1) >> INT_BYTE_SHIFT) + 1;
637 clearbytes = clearints << INT_TO_BYTE;
638 memset ((char *)ip, 0, clearbytes );
639 memset ( ((char *) ip) + clearbytes, 0xFF,
640 hashp->BSIZE-clearbytes );
641 ip[clearints-1] = ALL_SET << (nbits & BYTE_MASK);
642 SETBIT(ip, 0);
643 hashp->BITMAPS[ndx] = pnum;
644 hashp->mapp[ndx] = ip;
645 return(ip);
647 static int
648 first_free ( map )
649 u_long map;
651 register u_long mask;
652 register u_long i;
654 mask = 0x1;
655 for ( i=0; i < BITS_PER_MAP; i++ ) {
656 if ( !(mask & map) ) return(i);
657 mask = mask << 1;
659 return ( i );
662 static u_short
663 overflow_page ( )
665 register int max_free;
666 register int splitnum;
667 register u_long *freep;
668 register int offset;
669 u_short addr;
670 int in_use_bits;
671 int free_page, free_bit;
672 int i, j, bit;
673 #ifdef DEBUG2
674 int tmp1, tmp2;
675 #endif
677 splitnum = __log2(hashp->MAX_BUCKET);
678 max_free = hashp->SPARES[splitnum];
680 free_page = (max_free-1) >> (hashp->BSHIFT + BYTE_SHIFT);
681 free_bit = (max_free-1) & ((hashp->BSIZE << BYTE_SHIFT) - 1);
683 /* Look through all the free maps to find the first free block */
684 for ( i = 0; i <= free_page; i++ ) {
685 if (!(freep = (u_long *)hashp->mapp[i]) &&
686 !(freep = fetch_bitmap(i)) ) {
687 return ( NULL );
689 if ( i == free_page ) in_use_bits = free_bit;
690 else in_use_bits = (hashp->BSIZE << BYTE_SHIFT) -1;
692 for (j = 0, bit = 0; bit <= in_use_bits; j++, bit += BITS_PER_MAP ) {
693 if ( freep[j] != ALL_SET ) goto found;
696 /* No Free Page Found */
697 hashp->SPARES[splitnum]++;
698 offset = hashp->SPARES[splitnum] -
699 (splitnum ? hashp->SPARES[splitnum-1] : 0);
701 /* Check if we need to allocate a new bitmap page */
702 if ( free_bit == (hashp->BSIZE << BYTE_SHIFT) - 1 ) {
703 free_page++;
704 #define OVMSG "hash: out of overflow pages; increase page size\n"
705 if ( free_page >= NCACHED ) {
706 (void) write (STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
707 return(NULL);
710 This is tricky. The 1 indicates that you want the
711 new page allocated with 1 clear bit. Actually, you
712 are going to allocate 2 pages from this map. The first
713 is going to be the map page, the second is the overflow
714 page we were looking for. The init_bitmap routine
715 automatically, sets the first bit of itself to indicate
716 that the bitmap itself is in use. We would explicitly
717 set the second bit, but don't have to if we tell init_bitmap
718 not to leave it clear in the first place.
720 __init_bitmap ( OADDR_OF(splitnum, offset), 1, free_page );
721 hashp->SPARES[splitnum]++;
722 #ifdef DEBUG2
723 free_bit = 2;
724 #endif
725 offset++;
726 } else {
728 Free_bit addresses the last used bit. Bump it to
729 address the first available bit.
731 free_bit++;
732 SETBIT ( freep, free_bit );
735 /* Calculate address of the new overflow page */
736 if ( offset > SPLITMASK ) {
737 (void) write (STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
738 return(NULL);
740 addr = OADDR_OF(splitnum, offset);
741 #ifdef DEBUG2
742 fprintf ( stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
743 addr, free_bit, free_page );
744 #endif
745 return(addr);
747 found:
748 bit = bit + first_free(freep[j]);
749 SETBIT(freep,bit);
750 #ifdef DEBUG2
751 tmp1 = bit;
752 tmp2 = i;
753 #endif
755 Bits are addressed starting with 0, but overflow pages are
756 addressed beginning at 1. Bit is a bit addressnumber, so we
757 need to increment it to convert it to a page number.
759 bit = 1 + bit + (i * (hashp->BSIZE << BYTE_SHIFT));
761 /* Calculate the split number for this page */
762 for ( i = 0; (i < splitnum) && (bit > hashp->SPARES[i]); i++ );
763 offset =(i ? bit - hashp->SPARES[i-1] : bit );
764 if ( offset >= SPLITMASK ) return(NULL);/* Out of overflow pages */
765 addr = OADDR_OF(i, offset);
766 #ifdef DEBUG2
767 fprintf ( stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
768 addr, tmp1, tmp2 );
769 #endif
771 /* Allocate and return the overflow page */
772 return (addr);
776 Mark this overflow page as free.
778 __free_ovflpage ( obufp )
779 BUFHEAD *obufp;
781 register u_short addr = obufp->addr;
782 int free_page, free_bit;
783 int bit_address;
784 u_short ndx;
785 u_long *freep;
786 int j;
788 #ifdef DEBUG1
789 fprintf ( stderr, "Freeing %d\n", addr );
790 #endif
791 ndx = (((u_short)addr) >> SPLITSHIFT);
792 bit_address = (ndx ? hashp->SPARES[ndx-1] : 0) + (addr & SPLITMASK) - 1;
793 free_page = (bit_address >> (hashp->BSHIFT + BYTE_SHIFT));
794 free_bit = bit_address & ((hashp->BSIZE << BYTE_SHIFT) - 1);
796 if ( !(freep = hashp->mapp[free_page]) &&
797 !(freep = fetch_bitmap( free_page )) ) {
799 This had better never happen. It means we tried to
800 read a bitmap that has already had overflow pages allocated
801 off it, and we failed to read it from the file
803 assert(0);
805 CLRBIT(freep, free_bit);
806 #ifdef DEBUG2
807 fprintf ( stderr, "FREE_OVFLPAGE: ADDR: %d BIT: %d PAGE %d\n",
808 obufp->addr, free_bit, free_page );
809 #endif
810 __reclaim_buf ( obufp );
811 return;
815 0 success
816 -1 failure
818 static int
819 open_temp()
821 sigset_t set, oset;
822 static char namestr[] = "_hashXXXXXX";
824 /* Block signals; make sure file goes away at process exit. */
825 sigemptyset(&set);
826 sigaddset(&set, SIGHUP);
827 sigaddset(&set, SIGINT);
828 sigaddset(&set, SIGQUIT);
829 sigaddset(&set, SIGTERM);
830 (void)sigprocmask(SIG_BLOCK, &set, &oset);
831 if ((hashp->fp = mkstemp ( namestr )) != -1) {
832 (void)unlink(namestr);
833 (void)fcntl(hashp->fp, F_SETFD, 1);
835 (void)sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL);
836 return(hashp->fp != -1 ? 0 : -1);
840 We have to know that the key will fit, but the
841 last entry on the page is an overflow pair, so we
842 need to shift things.
844 static void
845 squeeze_key ( sp, key, val )
846 u_short *sp;
847 DBT *key;
848 DBT *val;
850 register char *p = (char *)sp;
851 u_short free_space, off;
852 u_short pageno, n;
854 n = sp[0];
855 free_space = FREESPACE(sp);
856 off = OFFSET(sp);
858 pageno = sp[n-1];
859 off -= key->size;
860 sp[n-1] = off;
861 bcopy ( key->data, p + off, key->size );
862 off -= val->size;
863 sp[n] = off;
864 bcopy ( val->data, p + off, val->size );
865 sp[0] = n+2;
866 sp[n+1] = pageno;
867 sp[n+2] = OVFLPAGE;
868 FREESPACE(sp) = free_space - PAIRSIZE(key,val);
869 OFFSET(sp) = off;
872 static u_long *
873 fetch_bitmap ( ndx )
874 int ndx;
876 if ( ndx >= hashp->nmaps ||
877 !(hashp->mapp[ndx] = (u_long *)malloc ( hashp->BSIZE )) ||
878 __get_page ((char *)hashp->mapp[ndx], hashp->BITMAPS[ndx], 0, 1, 1)) {
880 return(NULL);
882 return ( hashp->mapp[ndx] );
884 #ifdef DEBUG4
885 print_chain ( addr )
886 short addr;
888 BUFHEAD *bufp;
889 short *bp;
890 short oaddr;
892 fprintf ( stderr, "%d ", addr );
893 bufp = __get_buf ( (int)addr, NULL, 0 );
894 bp = (short *)bufp->page;
895 while ( bp[0] &&
896 ((bp[bp[0]] == OVFLPAGE) ||
897 ((bp[0] > 2) && bp[2] < REAL_KEY))) {
898 oaddr = bp[bp[0]-1];
899 fprintf ( stderr, "%d ", (int)oaddr );
900 bufp = __get_buf ( (int)oaddr, bufp, 0 );
901 bp = (short *)bufp->page;
903 fprintf ( stderr, "\n" );
905 #endif