146372Sbostic /*- 246372Sbostic * Copyright (c) 1990 The Regents of the University of California. 346372Sbostic * All rights reserved. 446372Sbostic * 546372Sbostic * This code is derived from software contributed to Berkeley by 646372Sbostic * Margo Seltzer. 746372Sbostic * 846372Sbostic * %sccs.include.redist.c% 946372Sbostic */ 1046372Sbostic 1146372Sbostic #if defined(LIBC_SCCS) && !defined(lint) 12*50997Sbostic static char sccsid[] = "@(#)hash_page.c 5.14 (Berkeley) 09/04/91"; 1346372Sbostic #endif /* LIBC_SCCS and not lint */ 1446372Sbostic 15*50997Sbostic /* 16*50997Sbostic * PACKAGE: hashing 17*50997Sbostic * 18*50997Sbostic * DESCRIPTION: 19*50997Sbostic * Page manipulation for hashing package. 20*50997Sbostic * 21*50997Sbostic * ROUTINES: 22*50997Sbostic * 23*50997Sbostic * External 24*50997Sbostic * __get_page 25*50997Sbostic * __add_ovflpage 26*50997Sbostic * Internal 27*50997Sbostic * overflow_page 28*50997Sbostic * open_temp 29*50997Sbostic */ 3046372Sbostic 3146372Sbostic #include <sys/param.h> 3246562Sbostic #include <fcntl.h> 3346416Sbostic #include <signal.h> 3446372Sbostic #include <errno.h> 3546372Sbostic #include <db.h> 3646372Sbostic #include <stdio.h> 3746562Sbostic #include <stdlib.h> 3846562Sbostic #include <string.h> 3946500Sbostic #include <unistd.h> 40*50997Sbostic #ifdef DEBUG 41*50997Sbostic #include <assert.h> 42*50997Sbostic #endif 4346372Sbostic #include "hash.h" 4446372Sbostic #include "page.h" 45*50997Sbostic #include "extern.h" 4646372Sbostic 47*50997Sbostic static void putpair __P((char *, const DBT *, const DBT *)); 48*50997Sbostic static int ugly_split __P((u_int, BUFHEAD *, BUFHEAD *, int, int)); 49*50997Sbostic static int first_free __P((u_long)); 50*50997Sbostic static u_short overflow_page __P((void)); 51*50997Sbostic static int open_temp __P((void)); 52*50997Sbostic static void squeeze_key __P((u_short *, const DBT *, const DBT *)); 53*50997Sbostic static u_long *fetch_bitmap __P((int)); 5446372Sbostic 55*50997Sbostic #define PAGE_INIT(P) { \ 56*50997Sbostic ((u_short *)(P))[0] = 0; \ 57*50997Sbostic ((u_short *)(P))[1] = hashp->BSIZE - 3 * sizeof(u_short); \ 58*50997Sbostic ((u_short *)(P))[2] = hashp->BSIZE; \ 5946372Sbostic } 6046372Sbostic 6146372Sbostic /* 62*50997Sbostic * This is called AFTER we have verified that there is room on the page for 63*50997Sbostic * the pair (PAIRFITS has returned true) so we go right ahead and start moving 64*50997Sbostic * stuff on. 65*50997Sbostic */ 6646372Sbostic static void 6746372Sbostic putpair(p, key, val) 68*50997Sbostic char *p; 69*50997Sbostic const DBT *key, *val; 7046372Sbostic { 71*50997Sbostic register u_short *bp, n, off; 7246372Sbostic 73*50997Sbostic bp = (u_short *)p; 74*50997Sbostic 75*50997Sbostic /* Enter the key first. */ 7646372Sbostic n = bp[0]; 7746372Sbostic 7846372Sbostic off = OFFSET(bp) - key->size; 79*50997Sbostic bcopy(key->data, p + off, key->size); 8046372Sbostic bp[++n] = off; 8146372Sbostic 82*50997Sbostic /* Now the data. */ 8346372Sbostic off -= val->size; 84*50997Sbostic bcopy(val->data, p + off, val->size); 8546372Sbostic bp[++n] = off; 8646372Sbostic 87*50997Sbostic /* Adjust page info. */ 8846372Sbostic bp[0] = n; 89*50997Sbostic bp[n + 1] = off - ((n + 3) * sizeof(u_short)); 90*50997Sbostic bp[n + 2] = off; 9146372Sbostic } 92*50997Sbostic 9346372Sbostic /* 94*50997Sbostic * Returns: 95*50997Sbostic * 0 OK 96*50997Sbostic * -1 error 97*50997Sbostic */ 9846372Sbostic extern int 9946372Sbostic __delpair(bufp, ndx) 100*50997Sbostic BUFHEAD *bufp; 101*50997Sbostic register int ndx; 10246372Sbostic { 103*50997Sbostic register u_short *bp, newoff; 104*50997Sbostic register int n; 10546372Sbostic u_short pairlen; 10646372Sbostic 107*50997Sbostic bp = (u_short *)bufp->page; 108*50997Sbostic n = bp[0]; 10946372Sbostic 110*50997Sbostic if (bp[ndx + 1] < REAL_KEY) 111*50997Sbostic return (__big_delete(bufp, ndx)); 112*50997Sbostic if (ndx != 1) 113*50997Sbostic newoff = bp[ndx - 1]; 114*50997Sbostic else 115*50997Sbostic newoff = hashp->BSIZE; 116*50997Sbostic pairlen = newoff - bp[ndx + 1]; 117*50997Sbostic 118*50997Sbostic if (ndx != (n - 1)) { 11946372Sbostic /* Hard Case -- need to shuffle keys */ 12046372Sbostic register int i; 12146372Sbostic register char *src = bufp->page + (int)OFFSET(bp); 12246372Sbostic register char *dst = src + (int)pairlen; 123*50997Sbostic bcopy(src, dst, bp[ndx + 1] - OFFSET(bp)); 12446372Sbostic 12546372Sbostic /* Now adjust the pointers */ 126*50997Sbostic for (i = ndx + 2; i <= n; i += 2) { 127*50997Sbostic if (bp[i + 1] == OVFLPAGE) { 128*50997Sbostic bp[i - 2] = bp[i]; 129*50997Sbostic bp[i - 1] = bp[i + 1]; 130*50997Sbostic } else { 131*50997Sbostic bp[i - 2] = bp[i] + pairlen; 132*50997Sbostic bp[i - 1] = bp[i + 1] + pairlen; 133*50997Sbostic } 13446372Sbostic } 13546372Sbostic } 13646372Sbostic /* Finally adjust the page data */ 13746372Sbostic bp[n] = OFFSET(bp) + pairlen; 138*50997Sbostic bp[n - 1] = bp[n + 1] + pairlen + 2 * sizeof(u_short); 139*50997Sbostic bp[0] = n - 2; 14046372Sbostic hashp->NKEYS--; 14146372Sbostic 14246372Sbostic bufp->flags |= BUF_MOD; 14346372Sbostic return (0); 14446372Sbostic } 14546372Sbostic /* 146*50997Sbostic * Returns: 147*50997Sbostic * 0 ==> OK 148*50997Sbostic * -1 ==> Error 149*50997Sbostic */ 15046372Sbostic extern int 15146372Sbostic __split_page(obucket, nbucket) 152*50997Sbostic u_int obucket, nbucket; 15346372Sbostic { 154*50997Sbostic register BUFHEAD *new_bufp, *old_bufp; 15546372Sbostic register u_short *ino; 156*50997Sbostic register char *np; 157*50997Sbostic DBT key, val; 158*50997Sbostic int n, ndx, retval; 159*50997Sbostic u_short copyto, diff, off, moved; 160*50997Sbostic char *op; 16146372Sbostic 162*50997Sbostic copyto = (u_short)hashp->BSIZE; 163*50997Sbostic off = (u_short)hashp->BSIZE; 164*50997Sbostic old_bufp = __get_buf(obucket, NULL, 0); 165*50997Sbostic new_bufp = __get_buf(nbucket, NULL, 0); 16646372Sbostic 167*50997Sbostic old_bufp->flags |= (BUF_MOD | BUF_PIN); 168*50997Sbostic new_bufp->flags |= (BUF_MOD | BUF_PIN); 16946372Sbostic 17046372Sbostic ino = (u_short *)(op = old_bufp->page); 17146372Sbostic np = new_bufp->page; 17246372Sbostic 17346372Sbostic moved = 0; 17446372Sbostic 175*50997Sbostic for (n = 1, ndx = 1; n < ino[0]; n += 2) { 176*50997Sbostic if (ino[n + 1] < REAL_KEY) { 177*50997Sbostic retval = ugly_split(obucket, old_bufp, new_bufp, 178*50997Sbostic copyto, moved); 179*50997Sbostic old_bufp->flags &= ~BUF_PIN; 180*50997Sbostic new_bufp->flags &= ~BUF_PIN; 181*50997Sbostic return (retval); 182*50997Sbostic 18346372Sbostic } 184*50997Sbostic key.data = (u_char *)op + ino[n]; 18546372Sbostic key.size = off - ino[n]; 18646372Sbostic 187*50997Sbostic if (__call_hash(key.data, key.size) == obucket) { 188*50997Sbostic /* Don't switch page */ 189*50997Sbostic diff = copyto - off; 190*50997Sbostic if (diff) { 191*50997Sbostic copyto = ino[n + 1] + diff; 192*50997Sbostic bcopy(op + ino[n + 1], op + copyto, 193*50997Sbostic off - ino[n + 1]); 194*50997Sbostic ino[ndx] = copyto + ino[n] - ino[n + 1]; 195*50997Sbostic ino[ndx + 1] = copyto; 196*50997Sbostic } else 197*50997Sbostic copyto = ino[n + 1]; 198*50997Sbostic ndx += 2; 19946372Sbostic } else { 200*50997Sbostic /* Switch page */ 201*50997Sbostic val.data = (u_char *)op + ino[n + 1]; 202*50997Sbostic val.size = ino[n] - ino[n + 1]; 203*50997Sbostic putpair(np, &key, &val); 204*50997Sbostic moved += 2; 20546372Sbostic } 20646372Sbostic 207*50997Sbostic off = ino[n + 1]; 20846372Sbostic } 20946372Sbostic 21046372Sbostic /* Now clean up the page */ 21146372Sbostic ino[0] -= moved; 212*50997Sbostic FREESPACE(ino) = copyto - sizeof(u_short) * (ino[0] + 3); 21346372Sbostic OFFSET(ino) = copyto; 21446372Sbostic 21546372Sbostic #ifdef DEBUG3 216*50997Sbostic (void)fprintf(stderr, "split %d/%d\n", 217*50997Sbostic ((u_short *)np)[0] / 2, 218*50997Sbostic ((u_short *)op)[0] / 2); 21946372Sbostic #endif 22046460Sbostic /* unpin both pages */ 22146460Sbostic old_bufp->flags &= ~BUF_PIN; 22246460Sbostic new_bufp->flags &= ~BUF_PIN; 223*50997Sbostic return (0); 22446372Sbostic } 225*50997Sbostic 22646372Sbostic /* 227*50997Sbostic * Called when we encounter an overflow or big key/data page during split 228*50997Sbostic * handling. This is special cased since we have to begin checking whether 229*50997Sbostic * the key/data pairs fit on their respective pages and because we may need 230*50997Sbostic * overflow pages for both the old and new pages. 231*50997Sbostic * 232*50997Sbostic * The first page might be a page with regular key/data pairs in which case 233*50997Sbostic * we have a regular overflow condition and just need to go on to the next 234*50997Sbostic * page or it might be a big key/data pair in which case we need to fix the 235*50997Sbostic * big key/data pair. 236*50997Sbostic * 237*50997Sbostic * Returns: 238*50997Sbostic * 0 ==> success 239*50997Sbostic * -1 ==> failure 240*50997Sbostic */ 24146372Sbostic static int 242*50997Sbostic ugly_split(obucket, old_bufp, new_bufp, copyto, moved) 243*50997Sbostic u_int obucket; /* Same as __split_page. */ 244*50997Sbostic BUFHEAD *old_bufp, *new_bufp; 245*50997Sbostic int copyto; /* First byte on page which contains key/data values. */ 246*50997Sbostic int moved; /* Number of pairs moved to new page. */ 24746372Sbostic { 248*50997Sbostic register BUFHEAD *bufp; /* Buffer header for ino */ 249*50997Sbostic register u_short *ino; /* Page keys come off of */ 250*50997Sbostic register u_short *np; /* New page */ 251*50997Sbostic register u_short *op; /* Page keys go on to if they aren't moving */ 25246372Sbostic 253*50997Sbostic BUFHEAD *last_bfp; /* Last buf header OVFL needing to be freed */ 254*50997Sbostic DBT key, val; 255*50997Sbostic SPLIT_RETURN ret; 256*50997Sbostic u_short last_addr, n, off, ov_addr, scopyto; 257*50997Sbostic char *cino; /* Character value of ino */ 25846372Sbostic 259*50997Sbostic bufp = old_bufp; 260*50997Sbostic ino = (u_short *)old_bufp->page; 261*50997Sbostic np = (u_short *)new_bufp->page; 262*50997Sbostic op = (u_short *)old_bufp->page; 263*50997Sbostic last_bfp = NULL; 264*50997Sbostic last_addr = 0; 265*50997Sbostic scopyto = (u_short)copyto; /* ANSI */ 26646372Sbostic 267*50997Sbostic n = ino[0] - 1; 268*50997Sbostic while (n < ino[0]) { 269*50997Sbostic if (ino[2] < REAL_KEY && ino[2] != OVFLPAGE) { 270*50997Sbostic if (__big_split(old_bufp, 271*50997Sbostic new_bufp, bufp, ov_addr, obucket, &ret)) 272*50997Sbostic return (-1); 273*50997Sbostic old_bufp = ret.oldp; 274*50997Sbostic if (!old_bufp) 275*50997Sbostic return (-1); 276*50997Sbostic op = (u_short *)old_bufp->page; 277*50997Sbostic new_bufp = ret.newp; 278*50997Sbostic if (!new_bufp) 279*50997Sbostic return (-1); 280*50997Sbostic np = (u_short *)new_bufp->page; 281*50997Sbostic bufp = ret.nextp; 282*50997Sbostic if (!bufp) 283*50997Sbostic return (0); 284*50997Sbostic cino = (char *)bufp->page; 285*50997Sbostic ino = (u_short *)cino; 286*50997Sbostic last_bfp = ret.nextp; 287*50997Sbostic } else if (ino[n + 1] == OVFLPAGE) { 288*50997Sbostic ov_addr = ino[n]; 289*50997Sbostic /* 290*50997Sbostic * Fix up the old page -- the extra 2 are the fields 291*50997Sbostic * which contained the overflow information. 292*50997Sbostic */ 293*50997Sbostic ino[0] -= (moved + 2); 294*50997Sbostic FREESPACE(ino) = 295*50997Sbostic scopyto - sizeof(u_short) * (ino[0] + 3); 296*50997Sbostic OFFSET(ino) = scopyto; 29746372Sbostic 298*50997Sbostic bufp = __get_buf(ov_addr, bufp, 0); 299*50997Sbostic if (!bufp) 300*50997Sbostic return (-1); 30146372Sbostic 302*50997Sbostic ino = (u_short *)bufp->page; 303*50997Sbostic n = 1; 304*50997Sbostic scopyto = hashp->BSIZE; 305*50997Sbostic moved = 0; 30646372Sbostic 307*50997Sbostic if (last_bfp) 308*50997Sbostic __free_ovflpage(last_bfp); 309*50997Sbostic last_bfp = bufp; 310*50997Sbostic } 311*50997Sbostic /* Move regular sized pairs of there are any */ 312*50997Sbostic off = hashp->BSIZE; 313*50997Sbostic for (n = 1; (n < ino[0]) && (ino[n + 1] >= REAL_KEY); n += 2) { 314*50997Sbostic cino = (char *)ino; 315*50997Sbostic key.data = (u_char *)cino + ino[n]; 316*50997Sbostic key.size = off - ino[n]; 317*50997Sbostic val.data = (u_char *)cino + ino[n + 1]; 318*50997Sbostic val.size = ino[n] - ino[n + 1]; 319*50997Sbostic off = ino[n + 1]; 32046372Sbostic 321*50997Sbostic if (__call_hash(key.data, key.size) == obucket) { 322*50997Sbostic /* Keep on old page */ 323*50997Sbostic if (PAIRFITS(op, (&key), (&val))) 324*50997Sbostic putpair((char *)op, &key, &val); 325*50997Sbostic else { 326*50997Sbostic old_bufp = __add_ovflpage(old_bufp); 327*50997Sbostic if (!old_bufp) 328*50997Sbostic return (-1); 329*50997Sbostic op = (u_short *)old_bufp->page; 330*50997Sbostic putpair((char *)op, &key, &val); 331*50997Sbostic } 332*50997Sbostic old_bufp->flags |= BUF_MOD; 333*50997Sbostic } else { 334*50997Sbostic /* Move to new page */ 335*50997Sbostic if (PAIRFITS(np, (&key), (&val))) 336*50997Sbostic putpair((char *)np, &key, &val); 337*50997Sbostic else { 338*50997Sbostic new_bufp = __add_ovflpage(new_bufp); 339*50997Sbostic if (!new_bufp) 340*50997Sbostic return (-1); 341*50997Sbostic np = (u_short *)new_bufp->page; 342*50997Sbostic putpair((char *)np, &key, &val); 343*50997Sbostic } 344*50997Sbostic new_bufp->flags |= BUF_MOD; 345*50997Sbostic } 34646372Sbostic } 34746372Sbostic } 348*50997Sbostic if (last_bfp) 349*50997Sbostic __free_ovflpage(last_bfp); 350*50997Sbostic return (0); 351*50997Sbostic } 35246372Sbostic 35346372Sbostic /* 354*50997Sbostic * Add the given pair to the page 355*50997Sbostic * 356*50997Sbostic * Returns: 357*50997Sbostic * 0 ==> OK 358*50997Sbostic * 1 ==> failure 359*50997Sbostic */ 36046372Sbostic extern int 36146372Sbostic __addel(bufp, key, val) 362*50997Sbostic BUFHEAD *bufp; 363*50997Sbostic const DBT *key, *val; 36446372Sbostic { 365*50997Sbostic register u_short *bp, *sop; 366*50997Sbostic int do_expand; 36746372Sbostic 368*50997Sbostic bp = (u_short *)bufp->page; 369*50997Sbostic do_expand = 0; 370*50997Sbostic while (bp[0] && (bp[bp[0]] < REAL_KEY)) 371*50997Sbostic /* Exception case */ 372*50997Sbostic if (bp[2] < REAL_KEY) { 373*50997Sbostic /* This is a big-keydata pair */ 374*50997Sbostic bufp = __add_ovflpage(bufp); 375*50997Sbostic if (!bufp) 376*50997Sbostic return (-1); 377*50997Sbostic bp = (u_short *)bufp->page; 378*50997Sbostic } else 379*50997Sbostic /* Try to squeeze key on this page */ 380*50997Sbostic if (FREESPACE(bp) > PAIRSIZE(key, val)) { 381*50997Sbostic squeeze_key(bp, key, val); 382*50997Sbostic return (0); 383*50997Sbostic } else { 384*50997Sbostic bufp = __get_buf(bp[bp[0] - 1], bufp, 0); 385*50997Sbostic if (!bufp) 386*50997Sbostic return (-1); 387*50997Sbostic bp = (u_short *)bufp->page; 388*50997Sbostic } 38946372Sbostic 390*50997Sbostic if (PAIRFITS(bp, key, val)) 391*50997Sbostic putpair(bufp->page, key, val); 392*50997Sbostic else { 393*50997Sbostic do_expand = 1; 394*50997Sbostic bufp = __add_ovflpage(bufp); 395*50997Sbostic if (!bufp) 396*50997Sbostic return (-1); 397*50997Sbostic sop = (u_short *)bufp->page; 39846372Sbostic 399*50997Sbostic if (PAIRFITS(sop, key, val)) 400*50997Sbostic putpair((char *)sop, key, val); 401*50997Sbostic else 402*50997Sbostic if (__big_insert(bufp, key, val)) 403*50997Sbostic return (-1); 40446372Sbostic } 405*50997Sbostic bufp->flags |= BUF_MOD; 406*50997Sbostic /* 407*50997Sbostic * If the average number of keys per bucket exceeds the fill factor, 408*50997Sbostic * expand the table. 409*50997Sbostic */ 410*50997Sbostic hashp->NKEYS++; 411*50997Sbostic if (do_expand || 412*50997Sbostic (hashp->NKEYS / (hashp->MAX_BUCKET + 1) > hashp->FFACTOR)) 413*50997Sbostic return (__expand_table()); 414*50997Sbostic return (0); 41546372Sbostic } 41646372Sbostic 41746372Sbostic /* 418*50997Sbostic * 419*50997Sbostic * Returns: 420*50997Sbostic * pointer on success 421*50997Sbostic * NULL on error 422*50997Sbostic */ 42346372Sbostic extern BUFHEAD * 424*50997Sbostic __add_ovflpage(bufp) 425*50997Sbostic BUFHEAD *bufp; 42646372Sbostic { 427*50997Sbostic register u_short *sp; 428*50997Sbostic u_short ndx, ovfl_num; 42946372Sbostic #ifdef DEBUG1 430*50997Sbostic int tmp1, tmp2; 43146372Sbostic #endif 432*50997Sbostic sp = (u_short *)bufp->page; 433*50997Sbostic bufp->flags |= BUF_MOD; 434*50997Sbostic ovfl_num = overflow_page(); 43546372Sbostic #ifdef DEBUG1 436*50997Sbostic tmp1 = bufp->addr; 437*50997Sbostic tmp2 = bufp->ovfl ? bufp->ovfl->addr : 0; 43846372Sbostic #endif 439*50997Sbostic if (!ovfl_num || !(bufp->ovfl = __get_buf(ovfl_num, bufp, 1))) 440*50997Sbostic return (NULL); 441*50997Sbostic bufp->ovfl->flags |= BUF_MOD; 44246372Sbostic #ifdef DEBUG1 443*50997Sbostic (void)fprintf(stderr, "ADDOVFLPAGE: %d->ovfl was %d is now %d\n", 444*50997Sbostic tmp1, tmp2, bufp->ovfl->addr); 44546372Sbostic #endif 446*50997Sbostic ndx = sp[0]; 447*50997Sbostic /* 448*50997Sbostic * Since a pair is allocated on a page only if there's room to add 449*50997Sbostic * an overflow page, we know that the OVFL information will fit on 450*50997Sbostic * the page. 451*50997Sbostic */ 452*50997Sbostic sp[ndx + 4] = OFFSET(sp); 453*50997Sbostic sp[ndx + 3] = FREESPACE(sp) - OVFLSIZE; 454*50997Sbostic sp[ndx + 1] = ovfl_num; 455*50997Sbostic sp[ndx + 2] = OVFLPAGE; 456*50997Sbostic sp[0] = ndx + 2; 45746372Sbostic #ifdef HASH_STATISTICS 458*50997Sbostic hash_overflows++; 45946372Sbostic #endif 460*50997Sbostic return (bufp->ovfl); 46146372Sbostic } 46246372Sbostic 46346372Sbostic /* 464*50997Sbostic * Returns: 465*50997Sbostic * 0 indicates SUCCESS 466*50997Sbostic * -1 indicates FAILURE 467*50997Sbostic */ 468*50997Sbostic extern int 469*50997Sbostic __get_page(p, bucket, is_bucket, is_disk, is_bitmap) 470*50997Sbostic char *p; 471*50997Sbostic u_int bucket; 472*50997Sbostic int is_bucket, is_disk, is_bitmap; 47346372Sbostic { 474*50997Sbostic register int fd, page, size; 475*50997Sbostic int rsize; 476*50997Sbostic u_short *bp; 47746372Sbostic 478*50997Sbostic fd = hashp->fp; 479*50997Sbostic size = hashp->BSIZE; 48046372Sbostic 481*50997Sbostic if ((fd == -1) || !is_disk) { 482*50997Sbostic PAGE_INIT(p); 483*50997Sbostic return (0); 484*50997Sbostic } 485*50997Sbostic if (is_bucket) 486*50997Sbostic page = BUCKET_TO_PAGE(bucket); 487*50997Sbostic else 488*50997Sbostic page = OADDR_TO_PAGE(bucket); 489*50997Sbostic if ((lseek(fd, page << hashp->BSHIFT, SEEK_SET) == -1) || 490*50997Sbostic ((rsize = read(fd, p, size)) == -1)) 491*50997Sbostic return (-1); 492*50997Sbostic bp = (u_short *)p; 493*50997Sbostic if (!rsize) 494*50997Sbostic bp[0] = 0; /* We hit the EOF, so initialize a new page */ 495*50997Sbostic else 496*50997Sbostic if (rsize != size) { 497*50997Sbostic errno = EFTYPE; 498*50997Sbostic return (-1); 499*50997Sbostic } 500*50997Sbostic if (!bp[0]) { 501*50997Sbostic PAGE_INIT(p); 502*50997Sbostic } else 503*50997Sbostic if (hashp->LORDER != BYTE_ORDER) { 504*50997Sbostic register int i, max; 50546372Sbostic 506*50997Sbostic if (is_bitmap) { 507*50997Sbostic max = hashp->BSIZE >> 2; /* divide by 4 */ 508*50997Sbostic for (i = 0; i < max; i++) 509*50997Sbostic BLSWAP(((long *)p)[i]); 510*50997Sbostic } else { 511*50997Sbostic BSSWAP(bp[0]); 512*50997Sbostic max = bp[0] + 2; 513*50997Sbostic for (i = 1; i <= max; i++) 514*50997Sbostic BSSWAP(bp[i]); 515*50997Sbostic } 516*50997Sbostic } 517*50997Sbostic return (0); 51846372Sbostic } 51946372Sbostic 520*50997Sbostic /* 521*50997Sbostic * Write page p to disk 522*50997Sbostic * 523*50997Sbostic * Returns: 524*50997Sbostic * 0 ==> OK 525*50997Sbostic * -1 ==>failure 526*50997Sbostic */ 52746372Sbostic extern int 528*50997Sbostic __put_page(p, bucket, is_bucket, is_bitmap) 529*50997Sbostic char *p; 530*50997Sbostic u_int bucket; 531*50997Sbostic int is_bucket, is_bitmap; 53246372Sbostic { 533*50997Sbostic register int fd, page, size; 534*50997Sbostic int wsize; 53546372Sbostic 536*50997Sbostic size = hashp->BSIZE; 537*50997Sbostic if ((hashp->fp == -1) && open_temp()) 538*50997Sbostic return (1); 539*50997Sbostic fd = hashp->fp; 54046372Sbostic 541*50997Sbostic if (hashp->LORDER != BYTE_ORDER) { 542*50997Sbostic register int i; 543*50997Sbostic register int max; 54446372Sbostic 545*50997Sbostic if (is_bitmap) { 546*50997Sbostic max = hashp->BSIZE >> 2; /* divide by 4 */ 547*50997Sbostic for (i = 0; i < max; i++) 548*50997Sbostic BLSWAP(((long *)p)[i]); 549*50997Sbostic } else { 550*50997Sbostic max = ((u_short *)p)[0] + 2; 551*50997Sbostic for (i = 0; i <= max; i++) 552*50997Sbostic BSSWAP(((u_short *)p)[i]); 553*50997Sbostic } 55446372Sbostic } 555*50997Sbostic if (is_bucket) 556*50997Sbostic page = BUCKET_TO_PAGE(bucket); 557*50997Sbostic else 558*50997Sbostic page = OADDR_TO_PAGE(bucket); 559*50997Sbostic if ((lseek(fd, page << hashp->BSHIFT, SEEK_SET) == -1) || 560*50997Sbostic ((wsize = write(fd, p, size)) == -1)) 561*50997Sbostic /* Errno is set */ 562*50997Sbostic return (-1); 563*50997Sbostic if (wsize != size) { 564*50997Sbostic errno = EFTYPE; 565*50997Sbostic return (-1); 566*50997Sbostic } 567*50997Sbostic return (0); 56846372Sbostic } 569*50997Sbostic 57046372Sbostic #define BYTE_MASK ((1 << INT_BYTE_SHIFT) -1) 57146372Sbostic /* 572*50997Sbostic * Initialize a new bitmap page. Bitmap pages are left in memory 573*50997Sbostic * once they are read in. 574*50997Sbostic */ 57546372Sbostic extern u_long * 57646372Sbostic __init_bitmap(pnum, nbits, ndx) 577*50997Sbostic int pnum, nbits, ndx; 57846372Sbostic { 579*50997Sbostic u_long *ip; 580*50997Sbostic int clearbytes, clearints; 58146372Sbostic 582*50997Sbostic if (!(ip = malloc(hashp->BSIZE))) 583*50997Sbostic return (NULL); 584*50997Sbostic hashp->nmaps++; 585*50997Sbostic clearints = ((nbits - 1) >> INT_BYTE_SHIFT) + 1; 586*50997Sbostic clearbytes = clearints << INT_TO_BYTE; 587*50997Sbostic memset((char *)ip, 0, clearbytes); 588*50997Sbostic memset(((char *)ip) + clearbytes, 0xFF, 589*50997Sbostic hashp->BSIZE - clearbytes); 590*50997Sbostic ip[clearints - 1] = ALL_SET << (nbits & BYTE_MASK); 591*50997Sbostic SETBIT(ip, 0); 592*50997Sbostic hashp->BITMAPS[ndx] = (u_short)pnum; 593*50997Sbostic hashp->mapp[ndx] = ip; 594*50997Sbostic return (ip); 59546372Sbostic } 596*50997Sbostic 59746372Sbostic static int 598*50997Sbostic first_free(map) 599*50997Sbostic u_long map; 60046372Sbostic { 601*50997Sbostic register u_long i, mask; 60246372Sbostic 603*50997Sbostic mask = 0x1; 604*50997Sbostic for (i = 0; i < BITS_PER_MAP; i++) { 605*50997Sbostic if (!(mask & map)) 606*50997Sbostic return (i); 607*50997Sbostic mask = mask << 1; 608*50997Sbostic } 609*50997Sbostic return (i); 61046372Sbostic } 61146372Sbostic 612*50997Sbostic static u_short 613*50997Sbostic overflow_page() 61446372Sbostic { 615*50997Sbostic register u_long *freep; 616*50997Sbostic register int max_free, offset, splitnum; 617*50997Sbostic u_short addr; 618*50997Sbostic int bit, free_bit, free_page, i, in_use_bits, j; 61946372Sbostic #ifdef DEBUG2 620*50997Sbostic int tmp1, tmp2; 62146372Sbostic #endif 622*50997Sbostic splitnum = __log2(hashp->MAX_BUCKET); 623*50997Sbostic max_free = hashp->SPARES[splitnum]; 62446372Sbostic 625*50997Sbostic free_page = (max_free - 1) >> (hashp->BSHIFT + BYTE_SHIFT); 626*50997Sbostic free_bit = (max_free - 1) & ((hashp->BSIZE << BYTE_SHIFT) - 1); 62746372Sbostic 628*50997Sbostic /* Look through all the free maps to find the first free block */ 629*50997Sbostic for (i = 0; i <= free_page; i++) { 630*50997Sbostic if (!(freep = (u_long *)hashp->mapp[i]) && 631*50997Sbostic !(freep = fetch_bitmap(i))) 632*50997Sbostic return (NULL); 633*50997Sbostic if (i == free_page) 634*50997Sbostic in_use_bits = free_bit; 635*50997Sbostic else 636*50997Sbostic in_use_bits = (hashp->BSIZE << BYTE_SHIFT) - 1; 63746372Sbostic 638*50997Sbostic for (j = 0, bit = 0; bit <= in_use_bits; 639*50997Sbostic j++, bit += BITS_PER_MAP) 640*50997Sbostic if (freep[j] != ALL_SET) 641*50997Sbostic goto found; 64247250Sbostic } 64346372Sbostic 644*50997Sbostic /* No Free Page Found */ 645*50997Sbostic hashp->SPARES[splitnum]++; 646*50997Sbostic offset = hashp->SPARES[splitnum] - 647*50997Sbostic (splitnum ? hashp->SPARES[splitnum - 1] : 0); 64846372Sbostic 649*50997Sbostic /* Check if we need to allocate a new bitmap page */ 650*50997Sbostic if (free_bit == (hashp->BSIZE << BYTE_SHIFT) - 1) { 651*50997Sbostic free_page++; 65250058Sbostic #define OVMSG "hash: out of overflow pages; increase page size\n" 653*50997Sbostic if (free_page >= NCACHED) { 654*50997Sbostic (void)write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1); 655*50997Sbostic return (NULL); 656*50997Sbostic } 657*50997Sbostic /* 658*50997Sbostic * This is tricky. The 1 indicates that you want the new page 659*50997Sbostic * allocated with 1 clear bit. Actually, you are going to 660*50997Sbostic * allocate 2 pages from this map. The first is going to be 661*50997Sbostic * the map page, the second is the overflow page we were 662*50997Sbostic * looking for. The init_bitmap routine automatically, sets 663*50997Sbostic * the first bit of itself to indicate that the bitmap itself 664*50997Sbostic * is in use. We would explicitly set the second bit, but 665*50997Sbostic * don't have to if we tell init_bitmap not to leave it clear 666*50997Sbostic * in the first place. 667*50997Sbostic */ 668*50997Sbostic __init_bitmap(OADDR_OF(splitnum, offset), 1, free_page); 669*50997Sbostic hashp->SPARES[splitnum]++; 67046372Sbostic #ifdef DEBUG2 671*50997Sbostic free_bit = 2; 67246372Sbostic #endif 673*50997Sbostic offset++; 674*50997Sbostic } else { 675*50997Sbostic /* 676*50997Sbostic * Free_bit addresses the last used bit. Bump it to address 677*50997Sbostic * the first available bit. 678*50997Sbostic */ 679*50997Sbostic free_bit++; 680*50997Sbostic SETBIT(freep, free_bit); 681*50997Sbostic } 68246372Sbostic 683*50997Sbostic /* Calculate address of the new overflow page */ 684*50997Sbostic if (offset > SPLITMASK) { 685*50997Sbostic (void)write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1); 686*50997Sbostic return (NULL); 687*50997Sbostic } 688*50997Sbostic addr = OADDR_OF(splitnum, offset); 68946372Sbostic #ifdef DEBUG2 690*50997Sbostic (void)fprintf(stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n", 691*50997Sbostic addr, free_bit, free_page); 69246372Sbostic #endif 693*50997Sbostic return (addr); 69446372Sbostic 69546372Sbostic found: 696*50997Sbostic bit = bit + first_free(freep[j]); 697*50997Sbostic SETBIT(freep, bit); 69846372Sbostic #ifdef DEBUG2 699*50997Sbostic tmp1 = bit; 700*50997Sbostic tmp2 = i; 70146372Sbostic #endif 702*50997Sbostic /* 703*50997Sbostic * Bits are addressed starting with 0, but overflow pages are addressed 704*50997Sbostic * beginning at 1. Bit is a bit addressnumber, so we need to increment 705*50997Sbostic * it to convert it to a page number. 706*50997Sbostic */ 707*50997Sbostic bit = 1 + bit + (i * (hashp->BSIZE << BYTE_SHIFT)); 70846372Sbostic 709*50997Sbostic /* Calculate the split number for this page */ 710*50997Sbostic for (i = 0; (i < splitnum) && (bit > hashp->SPARES[i]); i++); 711*50997Sbostic offset = (i ? bit - hashp->SPARES[i - 1] : bit); 712*50997Sbostic if (offset >= SPLITMASK) 713*50997Sbostic return (NULL); /* Out of overflow pages */ 714*50997Sbostic addr = OADDR_OF(i, offset); 71546372Sbostic #ifdef DEBUG2 716*50997Sbostic (void)fprintf(stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n", 717*50997Sbostic addr, tmp1, tmp2); 71846372Sbostic #endif 71946372Sbostic 720*50997Sbostic /* Allocate and return the overflow page */ 721*50997Sbostic return (addr); 72246372Sbostic } 72346372Sbostic 72446372Sbostic /* 725*50997Sbostic * Mark this overflow page as free. 726*50997Sbostic */ 727*50997Sbostic extern void 728*50997Sbostic __free_ovflpage(obufp) 729*50997Sbostic BUFHEAD *obufp; 73046372Sbostic { 731*50997Sbostic register u_short addr; 732*50997Sbostic u_long *freep; 733*50997Sbostic int bit_address, free_page, free_bit; 734*50997Sbostic u_short ndx; 73546372Sbostic 736*50997Sbostic addr = obufp->addr; 73746372Sbostic #ifdef DEBUG1 738*50997Sbostic (void)fprintf(stderr, "Freeing %d\n", addr); 73946372Sbostic #endif 740*50997Sbostic ndx = (((u_short)addr) >> SPLITSHIFT); 741*50997Sbostic bit_address = 742*50997Sbostic (ndx ? hashp->SPARES[ndx - 1] : 0) + (addr & SPLITMASK) - 1; 743*50997Sbostic free_page = (bit_address >> (hashp->BSHIFT + BYTE_SHIFT)); 744*50997Sbostic free_bit = bit_address & ((hashp->BSIZE << BYTE_SHIFT) - 1); 74546372Sbostic 746*50997Sbostic if (!(freep = hashp->mapp[free_page])) 747*50997Sbostic freep = fetch_bitmap(free_page); 748*50997Sbostic #ifdef DEBUG 749*50997Sbostic /* 750*50997Sbostic * This had better never happen. It means we tried to read a bitmap 751*50997Sbostic * that has already had overflow pages allocated off it, and we 752*50997Sbostic * failed to read it from the file. 753*50997Sbostic */ 754*50997Sbostic if (!freep) 755*50997Sbostic assert(0); 756*50997Sbostic #endif 757*50997Sbostic CLRBIT(freep, free_bit); 75846372Sbostic #ifdef DEBUG2 759*50997Sbostic (void)fprintf(stderr, "FREE_OVFLPAGE: ADDR: %d BIT: %d PAGE %d\n", 760*50997Sbostic obufp->addr, free_bit, free_page); 76146372Sbostic #endif 762*50997Sbostic __reclaim_buf(obufp); 76346372Sbostic } 76446372Sbostic 76546372Sbostic /* 766*50997Sbostic * Returns: 767*50997Sbostic * 0 success 768*50997Sbostic * -1 failure 769*50997Sbostic */ 77046372Sbostic static int 77146372Sbostic open_temp() 77246372Sbostic { 773*50997Sbostic sigset_t set, oset; 774*50997Sbostic static char namestr[] = "_hashXXXXXX"; 77546372Sbostic 776*50997Sbostic /* Block signals; make sure file goes away at process exit. */ 777*50997Sbostic sigfillset(&set); 778*50997Sbostic (void)sigprocmask(SIG_BLOCK, &set, &oset); 779*50997Sbostic if ((hashp->fp = mkstemp(namestr)) != -1) { 780*50997Sbostic (void)unlink(namestr); 781*50997Sbostic (void)fcntl(hashp->fp, F_SETFD, 1); 782*50997Sbostic } 783*50997Sbostic (void)sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL); 784*50997Sbostic return (hashp->fp != -1 ? 0 : -1); 78546372Sbostic } 78646372Sbostic 787*50997Sbostic /* 788*50997Sbostic * We have to know that the key will fit, but the last entry on the page is 789*50997Sbostic * an overflow pair, so we need to shift things. 790*50997Sbostic */ 79146372Sbostic static void 792*50997Sbostic squeeze_key(sp, key, val) 793*50997Sbostic u_short *sp; 794*50997Sbostic const DBT *key, *val; 79546372Sbostic { 796*50997Sbostic register char *p; 797*50997Sbostic u_short free_space, n, off, pageno; 79846372Sbostic 799*50997Sbostic p = (char *)sp; 800*50997Sbostic n = sp[0]; 801*50997Sbostic free_space = FREESPACE(sp); 802*50997Sbostic off = OFFSET(sp); 80346372Sbostic 804*50997Sbostic pageno = sp[n - 1]; 805*50997Sbostic off -= key->size; 806*50997Sbostic sp[n - 1] = off; 807*50997Sbostic bcopy(key->data, p + off, key->size); 808*50997Sbostic off -= val->size; 809*50997Sbostic sp[n] = off; 810*50997Sbostic bcopy(val->data, p + off, val->size); 811*50997Sbostic sp[0] = n + 2; 812*50997Sbostic sp[n + 1] = pageno; 813*50997Sbostic sp[n + 2] = OVFLPAGE; 814*50997Sbostic FREESPACE(sp) = free_space - PAIRSIZE(key, val); 815*50997Sbostic OFFSET(sp) = off; 81646372Sbostic } 81746372Sbostic 81847250Sbostic static u_long * 819*50997Sbostic fetch_bitmap(ndx) 820*50997Sbostic int ndx; 82147250Sbostic { 822*50997Sbostic if (ndx >= hashp->nmaps || 823*50997Sbostic !(hashp->mapp[ndx] = malloc(hashp->BSIZE)) || 824*50997Sbostic __get_page((char *)hashp->mapp[ndx], 825*50997Sbostic hashp->BITMAPS[ndx], 0, 1, 1)) 826*50997Sbostic return (NULL); 827*50997Sbostic return (hashp->mapp[ndx]); 828*50997Sbostic } 82947250Sbostic 83046372Sbostic #ifdef DEBUG4 831*50997Sbostic int 832*50997Sbostic print_chain(addr) 833*50997Sbostic int addr; 83446372Sbostic { 835*50997Sbostic BUFHEAD *bufp; 836*50997Sbostic short *bp, oaddr; 83746372Sbostic 838*50997Sbostic (void)fprintf(stderr, "%d ", addr); 839*50997Sbostic bufp = __get_buf(addr, NULL, 0); 84046372Sbostic bp = (short *)bufp->page; 841*50997Sbostic while (bp[0] && ((bp[bp[0]] == OVFLPAGE) || 842*50997Sbostic ((bp[0] > 2) && bp[2] < REAL_KEY))) { 843*50997Sbostic oaddr = bp[bp[0] - 1]; 844*50997Sbostic (void)fprintf(stderr, "%d ", (int)oaddr); 845*50997Sbostic bufp = __get_buf((int)oaddr, bufp, 0); 84646372Sbostic bp = (short *)bufp->page; 84746372Sbostic } 848*50997Sbostic (void)fprintf(stderr, "\n"); 84946372Sbostic } 85046372Sbostic #endif 851