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