2 * Copyright (c) 1990 The Regents of the University of California.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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 /******************************************************************************
45 Page manipulation for hashing package.
54 ******************************************************************************/
56 #include <sys/param.h>
71 extern BUFHEAD
*__get_buf();
72 extern void __reclaim_buf();
75 extern int __big_split();
76 extern int __big_insert();
77 extern int __big_delete();
78 extern int __find_bigpair();
81 extern u_int
__call_hash();
82 extern int __expand_table();
85 extern int __get_page();
86 extern BUFHEAD
*__add_ovflpage();
87 extern int __split_page();
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
;
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.
120 register u_short off
;
121 register u_short
*bp
= (u_short
*) p
;
123 /* enter the key first */
126 off
= OFFSET(bp
) - key
->size
;
127 bcopy( key
->data
, p
+off
, key
->size
);
132 bcopy(val
->data
, p
+ off
, val
->size
);
135 /* adjust page info */
137 bp
[n
+1] = off
- ((n
+3)*sizeof(u_short
));
150 register u_short
*bp
= (u_short
*) bufp
->page
;
151 register int n
= bp
[0];
152 register u_short newoff
;
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 */
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
) {
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
);
185 bufp
->flags
|= BUF_MOD
;
193 __split_page(obucket
, nbucket
)
200 register BUFHEAD
*new_bufp
;
201 register BUFHEAD
*old_bufp
;
202 register u_short
*ino
;
209 u_short copyto
= (u_short
)hashp
->BSIZE
;
211 u_short off
= (u_short
)hashp
->BSIZE
;
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
);
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
,
229 old_bufp
->flags
&= ~BUF_PIN
;
230 new_bufp
->flags
&= ~BUF_PIN
;
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 */
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];
245 } else copyto
= ino
[n
+1];
249 val
.data
= (u_char
*)op
+ ino
[n
+1];
250 val
.size
= ino
[n
] - ino
[n
+1];
251 putpair( np
, &key
, &val
);
258 /* Now clean up the page */
260 FREESPACE(ino
) = copyto
- sizeof(u_short
) * (ino
[0]+3);
261 OFFSET(ino
) = copyto
;
264 fprintf(stderr
, "split %d/%d\n",
265 ((u_short
*) np
)[0] / 2,
266 ((u_short
*) op
)[0] / 2);
268 /* unpin both pages */
269 old_bufp
->flags
&= ~BUF_PIN
;
270 new_bufp
->flags
&= ~BUF_PIN
;
277 Called when we encounter an overflow or big key/data page during
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.
289 ugly_split( obucket
, old_bufp
, new_bufp
, copyto
, moved
)
290 u_int obucket
; /* Same as __split_page */
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
304 char *cino
; /* Character value of ino */
305 BUFHEAD
*last_bfp
= NULL
; /* Last buffer header OVFL which
307 u_short ov_addr
, last_addr
= 0;
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
)) {
321 if ( !old_bufp
) return(-1);
322 op
= (u_short
*)old_bufp
->page
;
324 if ( !new_bufp
) return(-1);
325 np
= (u_short
*)new_bufp
->page
;
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
) {
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
;
346 copyto
= hashp
->BSIZE
;
350 __free_ovflpage( last_bfp
);
356 /* Move regular sized pairs of there are any */
358 for ( n
= 1; (n
< ino
[0]) && (ino
[n
+1] >= REAL_KEY
); n
+= 2 ) {
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];
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
);
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
;
377 /* Move to new page */
378 if (PAIRFITS(np
,(&key
),(&val
))) putpair((char *)np
, &key
, &val
);
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
;
390 __free_ovflpage(last_bfp
);
396 Add the given pair to the page
401 __addel(bufp
, key
, val
)
406 register u_short
*bp
= (u_short
*)bufp
->page
;
407 register u_short
*sop
;
411 while ( bp
[0] && (bp
[bp
[0]] < REAL_KEY
) ) {
413 if ( bp
[2] < REAL_KEY
) {
414 /* This is a big-keydata pair */
415 bufp
= __add_ovflpage(bufp
);
419 bp
= (u_short
*)bufp
->page
;
421 /* Try to squeeze key on this page */
422 if ( FREESPACE(bp
) > PAIRSIZE(key
,val
) ) {
423 squeeze_key ( bp
, key
, val
);
426 bufp
= __get_buf ( bp
[bp
[0]-1], bufp
, 0 );
430 bp
= (u_short
*)bufp
->page
;
435 if ( PAIRFITS(bp
,key
,val
) ) putpair (bufp
->page
, key
, val
);
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
) ) {
447 bufp
->flags
|= BUF_MOD
;
449 If the average number of keys per bucket exceeds the fill factor,
454 (hashp
->NKEYS
/ (hashp
->MAX_BUCKET
+1) > hashp
->FFACTOR
) ) {
455 return(__expand_table());
461 returns a pointer, NULL on error
464 __add_ovflpage ( bufp
)
467 register u_short
*sp
= (u_short
*)bufp
->page
;
477 bufp
->flags
|= BUF_MOD
;
478 ovfl_num
= overflow_page ();
481 tmp2
= bufp
->ovfl
?bufp
->ovfl
->addr
:0;
483 if (!ovfl_num
|| !(bufp
->ovfl
= __get_buf ( ovfl_num
, bufp
, 1 ))) {
486 bufp
->ovfl
->flags
|= BUF_MOD
;
488 fprintf ( stderr
, "ADDOVFLPAGE: %d->ovfl was %d is now %d\n", tmp1
, tmp2
,
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
497 sp
[ndx
+4] = OFFSET(sp
);
498 sp
[ndx
+3] = FREESPACE(sp
) - OVFLSIZE
;
499 sp
[ndx
+1] = ovfl_num
;
500 sp
[ndx
+2] = OVFLPAGE
;
502 #ifdef HASH_STATISTICS
513 __get_page ( p
, bucket
, is_bucket
, is_disk
, is_bitmap
)
529 if ( (fd
== -1) || !is_disk
) {
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 )) {
542 bp
[0] = 0; /* We hit the EOF, so initialize a new page */
543 } else if ( rsize
!= size
) {
549 } else if ( hashp
->LORDER
!= BYTE_ORDER
) {
554 max
= hashp
->BSIZE
>> 2; /* divide by 4 */
555 for ( i
=0; i
< max
; i
++ ) {
556 BLSWAP(((long *)p
)[i
]);
561 for ( i
=1; i
<= max
; i
++ ) {
575 __put_page ( p
, bucket
, is_bucket
, is_bitmap
)
587 if ( (hashp
->fp
== -1) && open_temp() ) return (1);
590 if ( hashp
->LORDER
!= BYTE_ORDER
) {
595 max
= hashp
->BSIZE
>> 2; /* divide by 4 */
596 for ( i
=0; i
< max
; i
++ ) {
597 BLSWAP(((long *)p
)[i
]);
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 )) {
613 if ( wsize
!= size
) {
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.
625 __init_bitmap(pnum
, nbits
, ndx
)
634 if ( !(ip
= (u_long
*)malloc (hashp
->BSIZE
)) ) return (NULL
);
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
);
643 hashp
->BITMAPS
[ndx
] = pnum
;
644 hashp
->mapp
[ndx
] = ip
;
651 register u_long mask
;
655 for ( i
=0; i
< BITS_PER_MAP
; i
++ ) {
656 if ( !(mask
& map
) ) return(i
);
665 register int max_free
;
666 register int splitnum
;
667 register u_long
*freep
;
671 int free_page
, free_bit
;
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
)) ) {
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 ) {
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);
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
]++;
728 Free_bit addresses the last used bit. Bump it to
729 address the first available 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);
740 addr
= OADDR_OF(splitnum
, offset
);
742 fprintf ( stderr
, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
743 addr
, free_bit
, free_page
);
748 bit
= bit
+ first_free(freep
[j
]);
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
);
767 fprintf ( stderr
, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
771 /* Allocate and return the overflow page */
776 Mark this overflow page as free.
778 __free_ovflpage ( obufp
)
781 register u_short addr
= obufp
->addr
;
782 int free_page
, free_bit
;
789 fprintf ( stderr
, "Freeing %d\n", addr
);
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
805 CLRBIT(freep
, free_bit
);
807 fprintf ( stderr
, "FREE_OVFLPAGE: ADDR: %d BIT: %d PAGE %d\n",
808 obufp
->addr
, free_bit
, free_page
);
810 __reclaim_buf ( obufp
);
822 static char namestr
[] = "_hashXXXXXX";
824 /* Block signals; make sure file goes away at process exit. */
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.
845 squeeze_key ( sp
, key
, val
)
850 register char *p
= (char *)sp
;
851 u_short free_space
, off
;
855 free_space
= FREESPACE(sp
);
861 bcopy ( key
->data
, p
+ off
, key
->size
);
864 bcopy ( val
->data
, p
+ off
, val
->size
);
868 FREESPACE(sp
) = free_space
- PAIRSIZE(key
,val
);
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)) {
882 return ( hashp
->mapp
[ndx
] );
892 fprintf ( stderr
, "%d ", addr
);
893 bufp
= __get_buf ( (int)addr
, NULL
, 0 );
894 bp
= (short *)bufp
->page
;
896 ((bp
[bp
[0]] == OVFLPAGE
) ||
897 ((bp
[0] > 2) && bp
[2] < REAL_KEY
))) {
899 fprintf ( stderr
, "%d ", (int)oaddr
);
900 bufp
= __get_buf ( (int)oaddr
, bufp
, 0 );
901 bp
= (short *)bufp
->page
;
903 fprintf ( stderr
, "\n" );