security/nss/lib/dbm/src/h_page.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*-
michael@0 2 * Copyright (c) 1990, 1993, 1994
michael@0 3 * The Regents of the University of California. All rights reserved.
michael@0 4 *
michael@0 5 * This code is derived from software contributed to Berkeley by
michael@0 6 * Margo Seltzer.
michael@0 7 *
michael@0 8 * Redistribution and use in source and binary forms, with or without
michael@0 9 * modification, are permitted provided that the following conditions
michael@0 10 * are met:
michael@0 11 * 1. Redistributions of source code must retain the above copyright
michael@0 12 * notice, this list of conditions and the following disclaimer.
michael@0 13 * 2. Redistributions in binary form must reproduce the above copyright
michael@0 14 * notice, this list of conditions and the following disclaimer in the
michael@0 15 * documentation and/or other materials provided with the distribution.
michael@0 16 * 3. ***REMOVED*** - see
michael@0 17 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
michael@0 18 * 4. Neither the name of the University nor the names of its contributors
michael@0 19 * may be used to endorse or promote products derived from this software
michael@0 20 * without specific prior written permission.
michael@0 21 *
michael@0 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
michael@0 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
michael@0 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
michael@0 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
michael@0 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
michael@0 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
michael@0 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
michael@0 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
michael@0 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
michael@0 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
michael@0 32 * SUCH DAMAGE.
michael@0 33 */
michael@0 34
michael@0 35 #if defined(unix)
michael@0 36 #define MY_LSEEK lseek
michael@0 37 #else
michael@0 38 #define MY_LSEEK new_lseek
michael@0 39 extern long new_lseek(int fd, long pos, int start);
michael@0 40 #endif
michael@0 41
michael@0 42 #if defined(LIBC_SCCS) && !defined(lint)
michael@0 43 static char sccsid[] = "@(#)hash_page.c 8.7 (Berkeley) 8/16/94";
michael@0 44 #endif /* LIBC_SCCS and not lint */
michael@0 45
michael@0 46 /*
michael@0 47 * PACKAGE: hashing
michael@0 48 *
michael@0 49 * DESCRIPTION:
michael@0 50 * Page manipulation for hashing package.
michael@0 51 *
michael@0 52 * ROUTINES:
michael@0 53 *
michael@0 54 * External
michael@0 55 * __get_page
michael@0 56 * __add_ovflpage
michael@0 57 * Internal
michael@0 58 * overflow_page
michael@0 59 * open_temp
michael@0 60 */
michael@0 61 #ifndef macintosh
michael@0 62 #include <sys/types.h>
michael@0 63 #endif
michael@0 64
michael@0 65 #if defined(macintosh)
michael@0 66 #include <unistd.h>
michael@0 67 #endif
michael@0 68
michael@0 69 #include <errno.h>
michael@0 70 #include <fcntl.h>
michael@0 71 #if defined(_WIN32) || defined(_WINDOWS)
michael@0 72 #include <io.h>
michael@0 73 #endif
michael@0 74 #include <signal.h>
michael@0 75 #include <stdio.h>
michael@0 76 #include <stdlib.h>
michael@0 77 #include <string.h>
michael@0 78
michael@0 79 #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh)
michael@0 80 #include <unistd.h>
michael@0 81 #endif
michael@0 82
michael@0 83 #include <assert.h>
michael@0 84
michael@0 85 #include "mcom_db.h"
michael@0 86 #include "hash.h"
michael@0 87 #include "page.h"
michael@0 88 /* #include "extern.h" */
michael@0 89
michael@0 90 extern int mkstempflags(char *path, int extraFlags);
michael@0 91
michael@0 92 static uint32 *fetch_bitmap __P((HTAB *, uint32));
michael@0 93 static uint32 first_free __P((uint32));
michael@0 94 static int open_temp __P((HTAB *));
michael@0 95 static uint16 overflow_page __P((HTAB *));
michael@0 96 static void squeeze_key __P((uint16 *, const DBT *, const DBT *));
michael@0 97 static int ugly_split
michael@0 98 __P((HTAB *, uint32, BUFHEAD *, BUFHEAD *, int, int));
michael@0 99
michael@0 100 #define PAGE_INIT(P) { \
michael@0 101 ((uint16 *)(P))[0] = 0; \
michael@0 102 ((uint16 *)(P))[1] = hashp->BSIZE - 3 * sizeof(uint16); \
michael@0 103 ((uint16 *)(P))[2] = hashp->BSIZE; \
michael@0 104 }
michael@0 105
michael@0 106 /* implement a new lseek using lseek that
michael@0 107 * writes zero's when extending a file
michael@0 108 * beyond the end.
michael@0 109 */
michael@0 110 long new_lseek(int fd, long offset, int origin)
michael@0 111 {
michael@0 112 long cur_pos=0;
michael@0 113 long end_pos=0;
michael@0 114 long seek_pos=0;
michael@0 115
michael@0 116 if(origin == SEEK_CUR)
michael@0 117 {
michael@0 118 if(offset < 1)
michael@0 119 return(lseek(fd, offset, SEEK_CUR));
michael@0 120
michael@0 121 cur_pos = lseek(fd, 0, SEEK_CUR);
michael@0 122
michael@0 123 if(cur_pos < 0)
michael@0 124 return(cur_pos);
michael@0 125 }
michael@0 126
michael@0 127 end_pos = lseek(fd, 0, SEEK_END);
michael@0 128 if(end_pos < 0)
michael@0 129 return(end_pos);
michael@0 130
michael@0 131 if(origin == SEEK_SET)
michael@0 132 seek_pos = offset;
michael@0 133 else if(origin == SEEK_CUR)
michael@0 134 seek_pos = cur_pos + offset;
michael@0 135 else if(origin == SEEK_END)
michael@0 136 seek_pos = end_pos + offset;
michael@0 137 else
michael@0 138 {
michael@0 139 assert(0);
michael@0 140 return(-1);
michael@0 141 }
michael@0 142
michael@0 143 /* the seek position desired is before the
michael@0 144 * end of the file. We don't need
michael@0 145 * to do anything special except the seek.
michael@0 146 */
michael@0 147 if(seek_pos <= end_pos)
michael@0 148 return(lseek(fd, seek_pos, SEEK_SET));
michael@0 149
michael@0 150 /* the seek position is beyond the end of the
michael@0 151 * file. Write zero's to the end.
michael@0 152 *
michael@0 153 * we are already at the end of the file so
michael@0 154 * we just need to "write()" zeros for the
michael@0 155 * difference between seek_pos-end_pos and
michael@0 156 * then seek to the position to finish
michael@0 157 * the call
michael@0 158 */
michael@0 159 {
michael@0 160 char buffer[1024];
michael@0 161 long len = seek_pos-end_pos;
michael@0 162 memset(&buffer, 0, 1024);
michael@0 163 while(len > 0)
michael@0 164 {
michael@0 165 write(fd, (char*)&buffer, (size_t)(1024 > len ? len : 1024));
michael@0 166 len -= 1024;
michael@0 167 }
michael@0 168 return(lseek(fd, seek_pos, SEEK_SET));
michael@0 169 }
michael@0 170
michael@0 171 }
michael@0 172
michael@0 173 /*
michael@0 174 * This is called AFTER we have verified that there is room on the page for
michael@0 175 * the pair (PAIRFITS has returned true) so we go right ahead and start moving
michael@0 176 * stuff on.
michael@0 177 */
michael@0 178 static void
michael@0 179 putpair(char *p, const DBT *key, DBT * val)
michael@0 180 {
michael@0 181 register uint16 *bp, n, off;
michael@0 182
michael@0 183 bp = (uint16 *)p;
michael@0 184
michael@0 185 /* Enter the key first. */
michael@0 186 n = bp[0];
michael@0 187
michael@0 188 off = OFFSET(bp) - key->size;
michael@0 189 memmove(p + off, key->data, key->size);
michael@0 190 bp[++n] = off;
michael@0 191
michael@0 192 /* Now the data. */
michael@0 193 off -= val->size;
michael@0 194 memmove(p + off, val->data, val->size);
michael@0 195 bp[++n] = off;
michael@0 196
michael@0 197 /* Adjust page info. */
michael@0 198 bp[0] = n;
michael@0 199 bp[n + 1] = off - ((n + 3) * sizeof(uint16));
michael@0 200 bp[n + 2] = off;
michael@0 201 }
michael@0 202
michael@0 203 /*
michael@0 204 * Returns:
michael@0 205 * 0 OK
michael@0 206 * -1 error
michael@0 207 */
michael@0 208 extern int
michael@0 209 __delpair(HTAB *hashp, BUFHEAD *bufp, int ndx)
michael@0 210 {
michael@0 211 register uint16 *bp, newoff;
michael@0 212 register int n;
michael@0 213 uint16 pairlen;
michael@0 214
michael@0 215 bp = (uint16 *)bufp->page;
michael@0 216 n = bp[0];
michael@0 217
michael@0 218 if (bp[ndx + 1] < REAL_KEY)
michael@0 219 return (__big_delete(hashp, bufp));
michael@0 220 if (ndx != 1)
michael@0 221 newoff = bp[ndx - 1];
michael@0 222 else
michael@0 223 newoff = hashp->BSIZE;
michael@0 224 pairlen = newoff - bp[ndx + 1];
michael@0 225
michael@0 226 if (ndx != (n - 1)) {
michael@0 227 /* Hard Case -- need to shuffle keys */
michael@0 228 register int i;
michael@0 229 register char *src = bufp->page + (int)OFFSET(bp);
michael@0 230 uint32 dst_offset = (uint32)OFFSET(bp) + (uint32)pairlen;
michael@0 231 register char *dst = bufp->page + dst_offset;
michael@0 232 uint32 length = bp[ndx + 1] - OFFSET(bp);
michael@0 233
michael@0 234 /*
michael@0 235 * +-----------+XXX+---------+XXX+---------+---------> +infinity
michael@0 236 * | | | |
michael@0 237 * 0 src_offset dst_offset BSIZE
michael@0 238 *
michael@0 239 * Dst_offset is > src_offset, so if src_offset were bad, dst_offset
michael@0 240 * would be too, therefore we check only dst_offset.
michael@0 241 *
michael@0 242 * If dst_offset is >= BSIZE, either OFFSET(bp), or pairlen, or both
michael@0 243 * is corrupted.
michael@0 244 *
michael@0 245 * Once we know dst_offset is < BSIZE, we can subtract it from BSIZE
michael@0 246 * to get an upper bound on length.
michael@0 247 */
michael@0 248 if(dst_offset > (uint32)hashp->BSIZE)
michael@0 249 return(DATABASE_CORRUPTED_ERROR);
michael@0 250
michael@0 251 if(length > (uint32)(hashp->BSIZE - dst_offset))
michael@0 252 return(DATABASE_CORRUPTED_ERROR);
michael@0 253
michael@0 254 memmove(dst, src, length);
michael@0 255
michael@0 256 /* Now adjust the pointers */
michael@0 257 for (i = ndx + 2; i <= n; i += 2) {
michael@0 258 if (bp[i + 1] == OVFLPAGE) {
michael@0 259 bp[i - 2] = bp[i];
michael@0 260 bp[i - 1] = bp[i + 1];
michael@0 261 } else {
michael@0 262 bp[i - 2] = bp[i] + pairlen;
michael@0 263 bp[i - 1] = bp[i + 1] + pairlen;
michael@0 264 }
michael@0 265 }
michael@0 266 }
michael@0 267 /* Finally adjust the page data */
michael@0 268 bp[n] = OFFSET(bp) + pairlen;
michael@0 269 bp[n - 1] = bp[n + 1] + pairlen + 2 * sizeof(uint16);
michael@0 270 bp[0] = n - 2;
michael@0 271 hashp->NKEYS--;
michael@0 272
michael@0 273 bufp->flags |= BUF_MOD;
michael@0 274 return (0);
michael@0 275 }
michael@0 276 /*
michael@0 277 * Returns:
michael@0 278 * 0 ==> OK
michael@0 279 * -1 ==> Error
michael@0 280 */
michael@0 281 extern int
michael@0 282 __split_page(HTAB *hashp, uint32 obucket, uint32 nbucket)
michael@0 283 {
michael@0 284 register BUFHEAD *new_bufp, *old_bufp;
michael@0 285 register uint16 *ino;
michael@0 286 register uint16 *tmp_uint16_array;
michael@0 287 register char *np;
michael@0 288 DBT key, val;
michael@0 289 uint16 n, ndx;
michael@0 290 int retval;
michael@0 291 uint16 copyto, diff, moved;
michael@0 292 size_t off;
michael@0 293 char *op;
michael@0 294
michael@0 295 copyto = (uint16)hashp->BSIZE;
michael@0 296 off = (uint16)hashp->BSIZE;
michael@0 297 old_bufp = __get_buf(hashp, obucket, NULL, 0);
michael@0 298 if (old_bufp == NULL)
michael@0 299 return (-1);
michael@0 300 new_bufp = __get_buf(hashp, nbucket, NULL, 0);
michael@0 301 if (new_bufp == NULL)
michael@0 302 return (-1);
michael@0 303
michael@0 304 old_bufp->flags |= (BUF_MOD | BUF_PIN);
michael@0 305 new_bufp->flags |= (BUF_MOD | BUF_PIN);
michael@0 306
michael@0 307 ino = (uint16 *)(op = old_bufp->page);
michael@0 308 np = new_bufp->page;
michael@0 309
michael@0 310 moved = 0;
michael@0 311
michael@0 312 for (n = 1, ndx = 1; n < ino[0]; n += 2) {
michael@0 313 if (ino[n + 1] < REAL_KEY) {
michael@0 314 retval = ugly_split(hashp, obucket, old_bufp, new_bufp,
michael@0 315 (int)copyto, (int)moved);
michael@0 316 old_bufp->flags &= ~BUF_PIN;
michael@0 317 new_bufp->flags &= ~BUF_PIN;
michael@0 318 return (retval);
michael@0 319
michael@0 320 }
michael@0 321 key.data = (uint8 *)op + ino[n];
michael@0 322
michael@0 323 /* check here for ino[n] being greater than
michael@0 324 * off. If it is then the database has
michael@0 325 * been corrupted.
michael@0 326 */
michael@0 327 if(ino[n] > off)
michael@0 328 return(DATABASE_CORRUPTED_ERROR);
michael@0 329
michael@0 330 key.size = off - ino[n];
michael@0 331
michael@0 332 #ifdef DEBUG
michael@0 333 /* make sure the size is positive */
michael@0 334 assert(((int)key.size) > -1);
michael@0 335 #endif
michael@0 336
michael@0 337 if (__call_hash(hashp, (char *)key.data, key.size) == obucket) {
michael@0 338 /* Don't switch page */
michael@0 339 diff = copyto - off;
michael@0 340 if (diff) {
michael@0 341 copyto = ino[n + 1] + diff;
michael@0 342 memmove(op + copyto, op + ino[n + 1],
michael@0 343 off - ino[n + 1]);
michael@0 344 ino[ndx] = copyto + ino[n] - ino[n + 1];
michael@0 345 ino[ndx + 1] = copyto;
michael@0 346 } else
michael@0 347 copyto = ino[n + 1];
michael@0 348 ndx += 2;
michael@0 349 } else {
michael@0 350 /* Switch page */
michael@0 351 val.data = (uint8 *)op + ino[n + 1];
michael@0 352 val.size = ino[n] - ino[n + 1];
michael@0 353
michael@0 354 /* if the pair doesn't fit something is horribly
michael@0 355 * wrong. LJM
michael@0 356 */
michael@0 357 tmp_uint16_array = (uint16*)np;
michael@0 358 if(!PAIRFITS(tmp_uint16_array, &key, &val))
michael@0 359 return(DATABASE_CORRUPTED_ERROR);
michael@0 360
michael@0 361 putpair(np, &key, &val);
michael@0 362 moved += 2;
michael@0 363 }
michael@0 364
michael@0 365 off = ino[n + 1];
michael@0 366 }
michael@0 367
michael@0 368 /* Now clean up the page */
michael@0 369 ino[0] -= moved;
michael@0 370 FREESPACE(ino) = copyto - sizeof(uint16) * (ino[0] + 3);
michael@0 371 OFFSET(ino) = copyto;
michael@0 372
michael@0 373 #ifdef DEBUG3
michael@0 374 (void)fprintf(stderr, "split %d/%d\n",
michael@0 375 ((uint16 *)np)[0] / 2,
michael@0 376 ((uint16 *)op)[0] / 2);
michael@0 377 #endif
michael@0 378 /* unpin both pages */
michael@0 379 old_bufp->flags &= ~BUF_PIN;
michael@0 380 new_bufp->flags &= ~BUF_PIN;
michael@0 381 return (0);
michael@0 382 }
michael@0 383
michael@0 384 /*
michael@0 385 * Called when we encounter an overflow or big key/data page during split
michael@0 386 * handling. This is special cased since we have to begin checking whether
michael@0 387 * the key/data pairs fit on their respective pages and because we may need
michael@0 388 * overflow pages for both the old and new pages.
michael@0 389 *
michael@0 390 * The first page might be a page with regular key/data pairs in which case
michael@0 391 * we have a regular overflow condition and just need to go on to the next
michael@0 392 * page or it might be a big key/data pair in which case we need to fix the
michael@0 393 * big key/data pair.
michael@0 394 *
michael@0 395 * Returns:
michael@0 396 * 0 ==> success
michael@0 397 * -1 ==> failure
michael@0 398 */
michael@0 399
michael@0 400 /* the maximum number of loops we will allow UGLY split to chew
michael@0 401 * on before we assume the database is corrupted and throw it
michael@0 402 * away.
michael@0 403 */
michael@0 404 #define MAX_UGLY_SPLIT_LOOPS 10000
michael@0 405
michael@0 406 static int
michael@0 407 ugly_split(HTAB *hashp, uint32 obucket, BUFHEAD *old_bufp,
michael@0 408 BUFHEAD *new_bufp,/* Same as __split_page. */ int copyto, int moved)
michael@0 409 /* int copyto; First byte on page which contains key/data values. */
michael@0 410 /* int moved; Number of pairs moved to new page. */
michael@0 411 {
michael@0 412 register BUFHEAD *bufp; /* Buffer header for ino */
michael@0 413 register uint16 *ino; /* Page keys come off of */
michael@0 414 register uint16 *np; /* New page */
michael@0 415 register uint16 *op; /* Page keys go on to if they aren't moving */
michael@0 416 uint32 loop_detection=0;
michael@0 417
michael@0 418 BUFHEAD *last_bfp; /* Last buf header OVFL needing to be freed */
michael@0 419 DBT key, val;
michael@0 420 SPLIT_RETURN ret;
michael@0 421 uint16 n, off, ov_addr, scopyto;
michael@0 422 char *cino; /* Character value of ino */
michael@0 423 int status;
michael@0 424
michael@0 425 bufp = old_bufp;
michael@0 426 ino = (uint16 *)old_bufp->page;
michael@0 427 np = (uint16 *)new_bufp->page;
michael@0 428 op = (uint16 *)old_bufp->page;
michael@0 429 last_bfp = NULL;
michael@0 430 scopyto = (uint16)copyto; /* ANSI */
michael@0 431
michael@0 432 n = ino[0] - 1;
michael@0 433 while (n < ino[0]) {
michael@0 434
michael@0 435
michael@0 436 /* this function goes nuts sometimes and never returns.
michael@0 437 * I havent found the problem yet but I need a solution
michael@0 438 * so if we loop too often we assume a database curruption error
michael@0 439 * :LJM
michael@0 440 */
michael@0 441 loop_detection++;
michael@0 442
michael@0 443 if(loop_detection > MAX_UGLY_SPLIT_LOOPS)
michael@0 444 return DATABASE_CORRUPTED_ERROR;
michael@0 445
michael@0 446 if (ino[2] < REAL_KEY && ino[2] != OVFLPAGE) {
michael@0 447 if ((status = __big_split(hashp, old_bufp,
michael@0 448 new_bufp, bufp, bufp->addr, obucket, &ret)))
michael@0 449 return (status);
michael@0 450 old_bufp = ret.oldp;
michael@0 451 if (!old_bufp)
michael@0 452 return (-1);
michael@0 453 op = (uint16 *)old_bufp->page;
michael@0 454 new_bufp = ret.newp;
michael@0 455 if (!new_bufp)
michael@0 456 return (-1);
michael@0 457 np = (uint16 *)new_bufp->page;
michael@0 458 bufp = ret.nextp;
michael@0 459 if (!bufp)
michael@0 460 return (0);
michael@0 461 cino = (char *)bufp->page;
michael@0 462 ino = (uint16 *)cino;
michael@0 463 last_bfp = ret.nextp;
michael@0 464 } else if (ino[n + 1] == OVFLPAGE) {
michael@0 465 ov_addr = ino[n];
michael@0 466 /*
michael@0 467 * Fix up the old page -- the extra 2 are the fields
michael@0 468 * which contained the overflow information.
michael@0 469 */
michael@0 470 ino[0] -= (moved + 2);
michael@0 471 FREESPACE(ino) =
michael@0 472 scopyto - sizeof(uint16) * (ino[0] + 3);
michael@0 473 OFFSET(ino) = scopyto;
michael@0 474
michael@0 475 bufp = __get_buf(hashp, ov_addr, bufp, 0);
michael@0 476 if (!bufp)
michael@0 477 return (-1);
michael@0 478
michael@0 479 ino = (uint16 *)bufp->page;
michael@0 480 n = 1;
michael@0 481 scopyto = hashp->BSIZE;
michael@0 482 moved = 0;
michael@0 483
michael@0 484 if (last_bfp)
michael@0 485 __free_ovflpage(hashp, last_bfp);
michael@0 486 last_bfp = bufp;
michael@0 487 }
michael@0 488 /* Move regular sized pairs of there are any */
michael@0 489 off = hashp->BSIZE;
michael@0 490 for (n = 1; (n < ino[0]) && (ino[n + 1] >= REAL_KEY); n += 2) {
michael@0 491 cino = (char *)ino;
michael@0 492 key.data = (uint8 *)cino + ino[n];
michael@0 493 key.size = off - ino[n];
michael@0 494 val.data = (uint8 *)cino + ino[n + 1];
michael@0 495 val.size = ino[n] - ino[n + 1];
michael@0 496 off = ino[n + 1];
michael@0 497
michael@0 498 if (__call_hash(hashp, (char*)key.data, key.size) == obucket) {
michael@0 499 /* Keep on old page */
michael@0 500 if (PAIRFITS(op, (&key), (&val)))
michael@0 501 putpair((char *)op, &key, &val);
michael@0 502 else {
michael@0 503 old_bufp =
michael@0 504 __add_ovflpage(hashp, old_bufp);
michael@0 505 if (!old_bufp)
michael@0 506 return (-1);
michael@0 507 op = (uint16 *)old_bufp->page;
michael@0 508 putpair((char *)op, &key, &val);
michael@0 509 }
michael@0 510 old_bufp->flags |= BUF_MOD;
michael@0 511 } else {
michael@0 512 /* Move to new page */
michael@0 513 if (PAIRFITS(np, (&key), (&val)))
michael@0 514 putpair((char *)np, &key, &val);
michael@0 515 else {
michael@0 516 new_bufp =
michael@0 517 __add_ovflpage(hashp, new_bufp);
michael@0 518 if (!new_bufp)
michael@0 519 return (-1);
michael@0 520 np = (uint16 *)new_bufp->page;
michael@0 521 putpair((char *)np, &key, &val);
michael@0 522 }
michael@0 523 new_bufp->flags |= BUF_MOD;
michael@0 524 }
michael@0 525 }
michael@0 526 }
michael@0 527 if (last_bfp)
michael@0 528 __free_ovflpage(hashp, last_bfp);
michael@0 529 return (0);
michael@0 530 }
michael@0 531
michael@0 532 /*
michael@0 533 * Add the given pair to the page
michael@0 534 *
michael@0 535 * Returns:
michael@0 536 * 0 ==> OK
michael@0 537 * 1 ==> failure
michael@0 538 */
michael@0 539 extern int
michael@0 540 __addel(HTAB *hashp, BUFHEAD *bufp, const DBT *key, const DBT * val)
michael@0 541 {
michael@0 542 register uint16 *bp, *sop;
michael@0 543 int do_expand;
michael@0 544
michael@0 545 bp = (uint16 *)bufp->page;
michael@0 546 do_expand = 0;
michael@0 547 while (bp[0] && (bp[2] < REAL_KEY || bp[bp[0]] < REAL_KEY))
michael@0 548 /* Exception case */
michael@0 549 if (bp[2] == FULL_KEY_DATA && bp[0] == 2)
michael@0 550 /* This is the last page of a big key/data pair
michael@0 551 and we need to add another page */
michael@0 552 break;
michael@0 553 else if (bp[2] < REAL_KEY && bp[bp[0]] != OVFLPAGE) {
michael@0 554 bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
michael@0 555 if (!bufp)
michael@0 556 {
michael@0 557 #ifdef DEBUG
michael@0 558 assert(0);
michael@0 559 #endif
michael@0 560 return (-1);
michael@0 561 }
michael@0 562 bp = (uint16 *)bufp->page;
michael@0 563 } else
michael@0 564 /* Try to squeeze key on this page */
michael@0 565 if (FREESPACE(bp) > PAIRSIZE(key, val)) {
michael@0 566 {
michael@0 567 squeeze_key(bp, key, val);
michael@0 568
michael@0 569 /* LJM: I added this because I think it was
michael@0 570 * left out on accident.
michael@0 571 * if this isn't incremented nkeys will not
michael@0 572 * be the actual number of keys in the db.
michael@0 573 */
michael@0 574 hashp->NKEYS++;
michael@0 575 return (0);
michael@0 576 }
michael@0 577 } else {
michael@0 578 bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
michael@0 579 if (!bufp)
michael@0 580 {
michael@0 581 #ifdef DEBUG
michael@0 582 assert(0);
michael@0 583 #endif
michael@0 584 return (-1);
michael@0 585 }
michael@0 586 bp = (uint16 *)bufp->page;
michael@0 587 }
michael@0 588
michael@0 589 if (PAIRFITS(bp, key, val))
michael@0 590 putpair(bufp->page, key, (DBT *)val);
michael@0 591 else {
michael@0 592 do_expand = 1;
michael@0 593 bufp = __add_ovflpage(hashp, bufp);
michael@0 594 if (!bufp)
michael@0 595 {
michael@0 596 #ifdef DEBUG
michael@0 597 assert(0);
michael@0 598 #endif
michael@0 599 return (-1);
michael@0 600 }
michael@0 601 sop = (uint16 *)bufp->page;
michael@0 602
michael@0 603 if (PAIRFITS(sop, key, val))
michael@0 604 putpair((char *)sop, key, (DBT *)val);
michael@0 605 else
michael@0 606 if (__big_insert(hashp, bufp, key, val))
michael@0 607 {
michael@0 608 #ifdef DEBUG
michael@0 609 assert(0);
michael@0 610 #endif
michael@0 611 return (-1);
michael@0 612 }
michael@0 613 }
michael@0 614 bufp->flags |= BUF_MOD;
michael@0 615 /*
michael@0 616 * If the average number of keys per bucket exceeds the fill factor,
michael@0 617 * expand the table.
michael@0 618 */
michael@0 619 hashp->NKEYS++;
michael@0 620 if (do_expand ||
michael@0 621 (hashp->NKEYS / (hashp->MAX_BUCKET + 1) > hashp->FFACTOR))
michael@0 622 return (__expand_table(hashp));
michael@0 623 return (0);
michael@0 624 }
michael@0 625
michael@0 626 /*
michael@0 627 *
michael@0 628 * Returns:
michael@0 629 * pointer on success
michael@0 630 * NULL on error
michael@0 631 */
michael@0 632 extern BUFHEAD *
michael@0 633 __add_ovflpage(HTAB *hashp, BUFHEAD *bufp)
michael@0 634 {
michael@0 635 register uint16 *sp;
michael@0 636 uint16 ndx, ovfl_num;
michael@0 637 #ifdef DEBUG1
michael@0 638 int tmp1, tmp2;
michael@0 639 #endif
michael@0 640 sp = (uint16 *)bufp->page;
michael@0 641
michael@0 642 /* Check if we are dynamically determining the fill factor */
michael@0 643 if (hashp->FFACTOR == DEF_FFACTOR) {
michael@0 644 hashp->FFACTOR = sp[0] >> 1;
michael@0 645 if (hashp->FFACTOR < MIN_FFACTOR)
michael@0 646 hashp->FFACTOR = MIN_FFACTOR;
michael@0 647 }
michael@0 648 bufp->flags |= BUF_MOD;
michael@0 649 ovfl_num = overflow_page(hashp);
michael@0 650 #ifdef DEBUG1
michael@0 651 tmp1 = bufp->addr;
michael@0 652 tmp2 = bufp->ovfl ? bufp->ovfl->addr : 0;
michael@0 653 #endif
michael@0 654 if (!ovfl_num || !(bufp->ovfl = __get_buf(hashp, ovfl_num, bufp, 1)))
michael@0 655 return (NULL);
michael@0 656 bufp->ovfl->flags |= BUF_MOD;
michael@0 657 #ifdef DEBUG1
michael@0 658 (void)fprintf(stderr, "ADDOVFLPAGE: %d->ovfl was %d is now %d\n",
michael@0 659 tmp1, tmp2, bufp->ovfl->addr);
michael@0 660 #endif
michael@0 661 ndx = sp[0];
michael@0 662 /*
michael@0 663 * Since a pair is allocated on a page only if there's room to add
michael@0 664 * an overflow page, we know that the OVFL information will fit on
michael@0 665 * the page.
michael@0 666 */
michael@0 667 sp[ndx + 4] = OFFSET(sp);
michael@0 668 sp[ndx + 3] = FREESPACE(sp) - OVFLSIZE;
michael@0 669 sp[ndx + 1] = ovfl_num;
michael@0 670 sp[ndx + 2] = OVFLPAGE;
michael@0 671 sp[0] = ndx + 2;
michael@0 672 #ifdef HASH_STATISTICS
michael@0 673 hash_overflows++;
michael@0 674 #endif
michael@0 675 return (bufp->ovfl);
michael@0 676 }
michael@0 677
michael@0 678 /*
michael@0 679 * Returns:
michael@0 680 * 0 indicates SUCCESS
michael@0 681 * -1 indicates FAILURE
michael@0 682 */
michael@0 683 extern int
michael@0 684 __get_page(HTAB *hashp,
michael@0 685 char * p,
michael@0 686 uint32 bucket,
michael@0 687 int is_bucket,
michael@0 688 int is_disk,
michael@0 689 int is_bitmap)
michael@0 690 {
michael@0 691 register int fd, page;
michael@0 692 size_t size;
michael@0 693 int rsize;
michael@0 694 uint16 *bp;
michael@0 695
michael@0 696 fd = hashp->fp;
michael@0 697 size = hashp->BSIZE;
michael@0 698
michael@0 699 if ((fd == -1) || !is_disk) {
michael@0 700 PAGE_INIT(p);
michael@0 701 return (0);
michael@0 702 }
michael@0 703 if (is_bucket)
michael@0 704 page = BUCKET_TO_PAGE(bucket);
michael@0 705 else
michael@0 706 page = OADDR_TO_PAGE(bucket);
michael@0 707 if ((MY_LSEEK(fd, (off_t)page << hashp->BSHIFT, SEEK_SET) == -1) ||
michael@0 708 ((rsize = read(fd, p, size)) == -1))
michael@0 709 return (-1);
michael@0 710
michael@0 711 bp = (uint16 *)p;
michael@0 712 if (!rsize)
michael@0 713 bp[0] = 0; /* We hit the EOF, so initialize a new page */
michael@0 714 else
michael@0 715 if ((unsigned)rsize != size) {
michael@0 716 errno = EFTYPE;
michael@0 717 return (-1);
michael@0 718 }
michael@0 719
michael@0 720 if (!is_bitmap && !bp[0]) {
michael@0 721 PAGE_INIT(p);
michael@0 722 } else {
michael@0 723
michael@0 724 #ifdef DEBUG
michael@0 725 if(BYTE_ORDER == LITTLE_ENDIAN)
michael@0 726 {
michael@0 727 int is_little_endian;
michael@0 728 is_little_endian = BYTE_ORDER;
michael@0 729 }
michael@0 730 else if(BYTE_ORDER == BIG_ENDIAN)
michael@0 731 {
michael@0 732 int is_big_endian;
michael@0 733 is_big_endian = BYTE_ORDER;
michael@0 734 }
michael@0 735 else
michael@0 736 {
michael@0 737 assert(0);
michael@0 738 }
michael@0 739 #endif
michael@0 740
michael@0 741 if (hashp->LORDER != BYTE_ORDER) {
michael@0 742 register int i, max;
michael@0 743
michael@0 744 if (is_bitmap) {
michael@0 745 max = hashp->BSIZE >> 2; /* divide by 4 */
michael@0 746 for (i = 0; i < max; i++)
michael@0 747 M_32_SWAP(((int *)p)[i]);
michael@0 748 } else {
michael@0 749 M_16_SWAP(bp[0]);
michael@0 750 max = bp[0] + 2;
michael@0 751
michael@0 752 /* bound the size of max by
michael@0 753 * the maximum number of entries
michael@0 754 * in the array
michael@0 755 */
michael@0 756 if((unsigned)max > (size / sizeof(uint16)))
michael@0 757 return(DATABASE_CORRUPTED_ERROR);
michael@0 758
michael@0 759 /* do the byte order swap
michael@0 760 */
michael@0 761 for (i = 1; i <= max; i++)
michael@0 762 M_16_SWAP(bp[i]);
michael@0 763 }
michael@0 764 }
michael@0 765
michael@0 766 /* check the validity of the page here
michael@0 767 * (after doing byte order swaping if necessary)
michael@0 768 */
michael@0 769 if(!is_bitmap && bp[0] != 0)
michael@0 770 {
michael@0 771 uint16 num_keys = bp[0];
michael@0 772 uint16 offset;
michael@0 773 uint16 i;
michael@0 774
michael@0 775 /* bp[0] is supposed to be the number of
michael@0 776 * entries currently in the page. If
michael@0 777 * bp[0] is too large (larger than the whole
michael@0 778 * page) then the page is corrupted
michael@0 779 */
michael@0 780 if(bp[0] > (size / sizeof(uint16)))
michael@0 781 return(DATABASE_CORRUPTED_ERROR);
michael@0 782
michael@0 783 /* bound free space */
michael@0 784 if(FREESPACE(bp) > size)
michael@0 785 return(DATABASE_CORRUPTED_ERROR);
michael@0 786
michael@0 787 /* check each key and data offset to make
michael@0 788 * sure they are all within bounds they
michael@0 789 * should all be less than the previous
michael@0 790 * offset as well.
michael@0 791 */
michael@0 792 offset = size;
michael@0 793 for(i=1 ; i <= num_keys; i+=2)
michael@0 794 {
michael@0 795 /* ignore overflow pages etc. */
michael@0 796 if(bp[i+1] >= REAL_KEY)
michael@0 797 {
michael@0 798
michael@0 799 if(bp[i] > offset || bp[i+1] > bp[i])
michael@0 800 return(DATABASE_CORRUPTED_ERROR);
michael@0 801
michael@0 802 offset = bp[i+1];
michael@0 803 }
michael@0 804 else
michael@0 805 {
michael@0 806 /* there are no other valid keys after
michael@0 807 * seeing a non REAL_KEY
michael@0 808 */
michael@0 809 break;
michael@0 810 }
michael@0 811 }
michael@0 812 }
michael@0 813 }
michael@0 814 return (0);
michael@0 815 }
michael@0 816
michael@0 817 /*
michael@0 818 * Write page p to disk
michael@0 819 *
michael@0 820 * Returns:
michael@0 821 * 0 ==> OK
michael@0 822 * -1 ==>failure
michael@0 823 */
michael@0 824 extern int
michael@0 825 __put_page(HTAB *hashp, char *p, uint32 bucket, int is_bucket, int is_bitmap)
michael@0 826 {
michael@0 827 register int fd, page;
michael@0 828 size_t size;
michael@0 829 int wsize;
michael@0 830 off_t offset;
michael@0 831
michael@0 832 size = hashp->BSIZE;
michael@0 833 if ((hashp->fp == -1) && open_temp(hashp))
michael@0 834 return (-1);
michael@0 835 fd = hashp->fp;
michael@0 836
michael@0 837 if (hashp->LORDER != BYTE_ORDER) {
michael@0 838 register int i;
michael@0 839 register int max;
michael@0 840
michael@0 841 if (is_bitmap) {
michael@0 842 max = hashp->BSIZE >> 2; /* divide by 4 */
michael@0 843 for (i = 0; i < max; i++)
michael@0 844 M_32_SWAP(((int *)p)[i]);
michael@0 845 } else {
michael@0 846 max = ((uint16 *)p)[0] + 2;
michael@0 847
michael@0 848 /* bound the size of max by
michael@0 849 * the maximum number of entries
michael@0 850 * in the array
michael@0 851 */
michael@0 852 if((unsigned)max > (size / sizeof(uint16)))
michael@0 853 return(DATABASE_CORRUPTED_ERROR);
michael@0 854
michael@0 855 for (i = 0; i <= max; i++)
michael@0 856 M_16_SWAP(((uint16 *)p)[i]);
michael@0 857
michael@0 858 }
michael@0 859 }
michael@0 860
michael@0 861 if (is_bucket)
michael@0 862 page = BUCKET_TO_PAGE(bucket);
michael@0 863 else
michael@0 864 page = OADDR_TO_PAGE(bucket);
michael@0 865 offset = (off_t)page << hashp->BSHIFT;
michael@0 866 if ((MY_LSEEK(fd, offset, SEEK_SET) == -1) ||
michael@0 867 ((wsize = write(fd, p, size)) == -1))
michael@0 868 /* Errno is set */
michael@0 869 return (-1);
michael@0 870 if ((unsigned)wsize != size) {
michael@0 871 errno = EFTYPE;
michael@0 872 return (-1);
michael@0 873 }
michael@0 874 #if defined(_WIN32) || defined(_WINDOWS)
michael@0 875 if (offset + size > hashp->file_size) {
michael@0 876 hashp->updateEOF = 1;
michael@0 877 }
michael@0 878 #endif
michael@0 879 /* put the page back the way it was so that it isn't byteswapped
michael@0 880 * if it remains in memory - LJM
michael@0 881 */
michael@0 882 if (hashp->LORDER != BYTE_ORDER) {
michael@0 883 register int i;
michael@0 884 register int max;
michael@0 885
michael@0 886 if (is_bitmap) {
michael@0 887 max = hashp->BSIZE >> 2; /* divide by 4 */
michael@0 888 for (i = 0; i < max; i++)
michael@0 889 M_32_SWAP(((int *)p)[i]);
michael@0 890 } else {
michael@0 891 uint16 *bp = (uint16 *)p;
michael@0 892
michael@0 893 M_16_SWAP(bp[0]);
michael@0 894 max = bp[0] + 2;
michael@0 895
michael@0 896 /* no need to bound the size if max again
michael@0 897 * since it was done already above
michael@0 898 */
michael@0 899
michael@0 900 /* do the byte order re-swap
michael@0 901 */
michael@0 902 for (i = 1; i <= max; i++)
michael@0 903 M_16_SWAP(bp[i]);
michael@0 904 }
michael@0 905 }
michael@0 906
michael@0 907 return (0);
michael@0 908 }
michael@0 909
michael@0 910 #define BYTE_MASK ((1 << INT_BYTE_SHIFT) -1)
michael@0 911 /*
michael@0 912 * Initialize a new bitmap page. Bitmap pages are left in memory
michael@0 913 * once they are read in.
michael@0 914 */
michael@0 915 extern int
michael@0 916 __ibitmap(HTAB *hashp, int pnum, int nbits, int ndx)
michael@0 917 {
michael@0 918 uint32 *ip;
michael@0 919 size_t clearbytes, clearints;
michael@0 920
michael@0 921 if ((ip = (uint32 *)malloc((size_t)hashp->BSIZE)) == NULL)
michael@0 922 return (1);
michael@0 923 hashp->nmaps++;
michael@0 924 clearints = ((nbits - 1) >> INT_BYTE_SHIFT) + 1;
michael@0 925 clearbytes = clearints << INT_TO_BYTE;
michael@0 926 (void)memset((char *)ip, 0, clearbytes);
michael@0 927 (void)memset(((char *)ip) + clearbytes, 0xFF,
michael@0 928 hashp->BSIZE - clearbytes);
michael@0 929 ip[clearints - 1] = ALL_SET << (nbits & BYTE_MASK);
michael@0 930 SETBIT(ip, 0);
michael@0 931 hashp->BITMAPS[ndx] = (uint16)pnum;
michael@0 932 hashp->mapp[ndx] = ip;
michael@0 933 return (0);
michael@0 934 }
michael@0 935
michael@0 936 static uint32
michael@0 937 first_free(uint32 map)
michael@0 938 {
michael@0 939 register uint32 i, mask;
michael@0 940
michael@0 941 mask = 0x1;
michael@0 942 for (i = 0; i < BITS_PER_MAP; i++) {
michael@0 943 if (!(mask & map))
michael@0 944 return (i);
michael@0 945 mask = mask << 1;
michael@0 946 }
michael@0 947 return (i);
michael@0 948 }
michael@0 949
michael@0 950 static uint16
michael@0 951 overflow_page(HTAB *hashp)
michael@0 952 {
michael@0 953 register uint32 *freep=NULL;
michael@0 954 register int max_free, offset, splitnum;
michael@0 955 uint16 addr;
michael@0 956 uint32 i;
michael@0 957 int bit, first_page, free_bit, free_page, in_use_bits, j;
michael@0 958 #ifdef DEBUG2
michael@0 959 int tmp1, tmp2;
michael@0 960 #endif
michael@0 961 splitnum = hashp->OVFL_POINT;
michael@0 962 max_free = hashp->SPARES[splitnum];
michael@0 963
michael@0 964 free_page = (max_free - 1) >> (hashp->BSHIFT + BYTE_SHIFT);
michael@0 965 free_bit = (max_free - 1) & ((hashp->BSIZE << BYTE_SHIFT) - 1);
michael@0 966
michael@0 967 /* Look through all the free maps to find the first free block */
michael@0 968 first_page = hashp->LAST_FREED >>(hashp->BSHIFT + BYTE_SHIFT);
michael@0 969 for ( i = first_page; i <= (unsigned)free_page; i++ ) {
michael@0 970 if (!(freep = (uint32 *)hashp->mapp[i]) &&
michael@0 971 !(freep = fetch_bitmap(hashp, i)))
michael@0 972 return (0);
michael@0 973 if (i == (unsigned)free_page)
michael@0 974 in_use_bits = free_bit;
michael@0 975 else
michael@0 976 in_use_bits = (hashp->BSIZE << BYTE_SHIFT) - 1;
michael@0 977
michael@0 978 if (i == (unsigned)first_page) {
michael@0 979 bit = hashp->LAST_FREED &
michael@0 980 ((hashp->BSIZE << BYTE_SHIFT) - 1);
michael@0 981 j = bit / BITS_PER_MAP;
michael@0 982 bit = bit & ~(BITS_PER_MAP - 1);
michael@0 983 } else {
michael@0 984 bit = 0;
michael@0 985 j = 0;
michael@0 986 }
michael@0 987 for (; bit <= in_use_bits; j++, bit += BITS_PER_MAP)
michael@0 988 if (freep[j] != ALL_SET)
michael@0 989 goto found;
michael@0 990 }
michael@0 991
michael@0 992 /* No Free Page Found */
michael@0 993 hashp->LAST_FREED = hashp->SPARES[splitnum];
michael@0 994 hashp->SPARES[splitnum]++;
michael@0 995 offset = hashp->SPARES[splitnum] -
michael@0 996 (splitnum ? hashp->SPARES[splitnum - 1] : 0);
michael@0 997
michael@0 998 #define OVMSG "HASH: Out of overflow pages. Increase page size\n"
michael@0 999 if (offset > SPLITMASK) {
michael@0 1000 if (++splitnum >= NCACHED) {
michael@0 1001 #ifndef macintosh
michael@0 1002 (void)write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
michael@0 1003 #endif
michael@0 1004 return (0);
michael@0 1005 }
michael@0 1006 hashp->OVFL_POINT = splitnum;
michael@0 1007 hashp->SPARES[splitnum] = hashp->SPARES[splitnum-1];
michael@0 1008 hashp->SPARES[splitnum-1]--;
michael@0 1009 offset = 1;
michael@0 1010 }
michael@0 1011
michael@0 1012 /* Check if we need to allocate a new bitmap page */
michael@0 1013 if (free_bit == (hashp->BSIZE << BYTE_SHIFT) - 1) {
michael@0 1014 free_page++;
michael@0 1015 if (free_page >= NCACHED) {
michael@0 1016 #ifndef macintosh
michael@0 1017 (void)write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
michael@0 1018 #endif
michael@0 1019 return (0);
michael@0 1020 }
michael@0 1021 /*
michael@0 1022 * This is tricky. The 1 indicates that you want the new page
michael@0 1023 * allocated with 1 clear bit. Actually, you are going to
michael@0 1024 * allocate 2 pages from this map. The first is going to be
michael@0 1025 * the map page, the second is the overflow page we were
michael@0 1026 * looking for. The init_bitmap routine automatically, sets
michael@0 1027 * the first bit of itself to indicate that the bitmap itself
michael@0 1028 * is in use. We would explicitly set the second bit, but
michael@0 1029 * don't have to if we tell init_bitmap not to leave it clear
michael@0 1030 * in the first place.
michael@0 1031 */
michael@0 1032 if (__ibitmap(hashp,
michael@0 1033 (int)OADDR_OF(splitnum, offset), 1, free_page))
michael@0 1034 return (0);
michael@0 1035 hashp->SPARES[splitnum]++;
michael@0 1036 #ifdef DEBUG2
michael@0 1037 free_bit = 2;
michael@0 1038 #endif
michael@0 1039 offset++;
michael@0 1040 if (offset > SPLITMASK) {
michael@0 1041 if (++splitnum >= NCACHED) {
michael@0 1042 #ifndef macintosh
michael@0 1043 (void)write(STDERR_FILENO, OVMSG,
michael@0 1044 sizeof(OVMSG) - 1);
michael@0 1045 #endif
michael@0 1046 return (0);
michael@0 1047 }
michael@0 1048 hashp->OVFL_POINT = splitnum;
michael@0 1049 hashp->SPARES[splitnum] = hashp->SPARES[splitnum-1];
michael@0 1050 hashp->SPARES[splitnum-1]--;
michael@0 1051 offset = 0;
michael@0 1052 }
michael@0 1053 } else {
michael@0 1054 /*
michael@0 1055 * Free_bit addresses the last used bit. Bump it to address
michael@0 1056 * the first available bit.
michael@0 1057 */
michael@0 1058 free_bit++;
michael@0 1059 SETBIT(freep, free_bit);
michael@0 1060 }
michael@0 1061
michael@0 1062 /* Calculate address of the new overflow page */
michael@0 1063 addr = OADDR_OF(splitnum, offset);
michael@0 1064 #ifdef DEBUG2
michael@0 1065 (void)fprintf(stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
michael@0 1066 addr, free_bit, free_page);
michael@0 1067 #endif
michael@0 1068 return (addr);
michael@0 1069
michael@0 1070 found:
michael@0 1071 bit = bit + first_free(freep[j]);
michael@0 1072 SETBIT(freep, bit);
michael@0 1073 #ifdef DEBUG2
michael@0 1074 tmp1 = bit;
michael@0 1075 tmp2 = i;
michael@0 1076 #endif
michael@0 1077 /*
michael@0 1078 * Bits are addressed starting with 0, but overflow pages are addressed
michael@0 1079 * beginning at 1. Bit is a bit addressnumber, so we need to increment
michael@0 1080 * it to convert it to a page number.
michael@0 1081 */
michael@0 1082 bit = 1 + bit + (i * (hashp->BSIZE << BYTE_SHIFT));
michael@0 1083 if (bit >= hashp->LAST_FREED)
michael@0 1084 hashp->LAST_FREED = bit - 1;
michael@0 1085
michael@0 1086 /* Calculate the split number for this page */
michael@0 1087 for (i = 0; (i < (unsigned)splitnum) && (bit > hashp->SPARES[i]); i++) {}
michael@0 1088 offset = (i ? bit - hashp->SPARES[i - 1] : bit);
michael@0 1089 if (offset >= SPLITMASK)
michael@0 1090 return (0); /* Out of overflow pages */
michael@0 1091 addr = OADDR_OF(i, offset);
michael@0 1092 #ifdef DEBUG2
michael@0 1093 (void)fprintf(stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
michael@0 1094 addr, tmp1, tmp2);
michael@0 1095 #endif
michael@0 1096
michael@0 1097 /* Allocate and return the overflow page */
michael@0 1098 return (addr);
michael@0 1099 }
michael@0 1100
michael@0 1101 /*
michael@0 1102 * Mark this overflow page as free.
michael@0 1103 */
michael@0 1104 extern void
michael@0 1105 __free_ovflpage(HTAB *hashp, BUFHEAD *obufp)
michael@0 1106 {
michael@0 1107 uint16 addr;
michael@0 1108 uint32 *freep;
michael@0 1109 uint32 bit_address, free_page, free_bit;
michael@0 1110 uint16 ndx;
michael@0 1111
michael@0 1112 if(!obufp || !obufp->addr)
michael@0 1113 return;
michael@0 1114
michael@0 1115 addr = obufp->addr;
michael@0 1116 #ifdef DEBUG1
michael@0 1117 (void)fprintf(stderr, "Freeing %d\n", addr);
michael@0 1118 #endif
michael@0 1119 ndx = (((uint16)addr) >> SPLITSHIFT);
michael@0 1120 bit_address =
michael@0 1121 (ndx ? hashp->SPARES[ndx - 1] : 0) + (addr & SPLITMASK) - 1;
michael@0 1122 if (bit_address < (uint32)hashp->LAST_FREED)
michael@0 1123 hashp->LAST_FREED = bit_address;
michael@0 1124 free_page = (bit_address >> (hashp->BSHIFT + BYTE_SHIFT));
michael@0 1125 free_bit = bit_address & ((hashp->BSIZE << BYTE_SHIFT) - 1);
michael@0 1126
michael@0 1127 if (!(freep = hashp->mapp[free_page]))
michael@0 1128 freep = fetch_bitmap(hashp, free_page);
michael@0 1129
michael@0 1130 #ifdef DEBUG
michael@0 1131 /*
michael@0 1132 * This had better never happen. It means we tried to read a bitmap
michael@0 1133 * that has already had overflow pages allocated off it, and we
michael@0 1134 * failed to read it from the file.
michael@0 1135 */
michael@0 1136 if (!freep)
michael@0 1137 {
michael@0 1138 assert(0);
michael@0 1139 return;
michael@0 1140 }
michael@0 1141 #endif
michael@0 1142 CLRBIT(freep, free_bit);
michael@0 1143 #ifdef DEBUG2
michael@0 1144 (void)fprintf(stderr, "FREE_OVFLPAGE: ADDR: %d BIT: %d PAGE %d\n",
michael@0 1145 obufp->addr, free_bit, free_page);
michael@0 1146 #endif
michael@0 1147 __reclaim_buf(hashp, obufp);
michael@0 1148 }
michael@0 1149
michael@0 1150 /*
michael@0 1151 * Returns:
michael@0 1152 * 0 success
michael@0 1153 * -1 failure
michael@0 1154 */
michael@0 1155 static int
michael@0 1156 open_temp(HTAB *hashp)
michael@0 1157 {
michael@0 1158 #ifdef XP_OS2
michael@0 1159 hashp->fp = mkstemp(NULL);
michael@0 1160 #else
michael@0 1161 #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh)
michael@0 1162 sigset_t set, oset;
michael@0 1163 #endif
michael@0 1164 #if !defined(macintosh)
michael@0 1165 char * tmpdir;
michael@0 1166 size_t len;
michael@0 1167 char last;
michael@0 1168 #endif
michael@0 1169 static const char namestr[] = "/_hashXXXXXX";
michael@0 1170 char filename[1024];
michael@0 1171
michael@0 1172 #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh)
michael@0 1173 /* Block signals; make sure file goes away at process exit. */
michael@0 1174 (void)sigfillset(&set);
michael@0 1175 (void)sigprocmask(SIG_BLOCK, &set, &oset);
michael@0 1176 #endif
michael@0 1177
michael@0 1178 filename[0] = 0;
michael@0 1179 #if defined(macintosh)
michael@0 1180 strcat(filename, namestr + 1);
michael@0 1181 #else
michael@0 1182 tmpdir = getenv("TMP");
michael@0 1183 if (!tmpdir)
michael@0 1184 tmpdir = getenv("TMPDIR");
michael@0 1185 if (!tmpdir)
michael@0 1186 tmpdir = getenv("TEMP");
michael@0 1187 if (!tmpdir)
michael@0 1188 tmpdir = ".";
michael@0 1189 len = strlen(tmpdir);
michael@0 1190 if (len && len < (sizeof filename - sizeof namestr)) {
michael@0 1191 strcpy(filename, tmpdir);
michael@0 1192 }
michael@0 1193 len = strlen(filename);
michael@0 1194 last = tmpdir[len - 1];
michael@0 1195 strcat(filename, (last == '/' || last == '\\') ? namestr + 1 : namestr);
michael@0 1196 #endif
michael@0 1197
michael@0 1198 #if defined(_WIN32) || defined(_WINDOWS)
michael@0 1199 if ((hashp->fp = mkstempflags(filename, _O_BINARY|_O_TEMPORARY)) != -1) {
michael@0 1200 if (hashp->filename) {
michael@0 1201 free(hashp->filename);
michael@0 1202 }
michael@0 1203 hashp->filename = strdup(filename);
michael@0 1204 hashp->is_temp = 1;
michael@0 1205 }
michael@0 1206 #else
michael@0 1207 if ((hashp->fp = mkstemp(filename)) != -1) {
michael@0 1208 (void)unlink(filename);
michael@0 1209 #if !defined(macintosh)
michael@0 1210 (void)fcntl(hashp->fp, F_SETFD, 1);
michael@0 1211 #endif
michael@0 1212 }
michael@0 1213 #endif
michael@0 1214
michael@0 1215 #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh)
michael@0 1216 (void)sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL);
michael@0 1217 #endif
michael@0 1218 #endif /* !OS2 */
michael@0 1219 return (hashp->fp != -1 ? 0 : -1);
michael@0 1220 }
michael@0 1221
michael@0 1222 /*
michael@0 1223 * We have to know that the key will fit, but the last entry on the page is
michael@0 1224 * an overflow pair, so we need to shift things.
michael@0 1225 */
michael@0 1226 static void
michael@0 1227 squeeze_key(uint16 *sp, const DBT * key, const DBT * val)
michael@0 1228 {
michael@0 1229 register char *p;
michael@0 1230 uint16 free_space, n, off, pageno;
michael@0 1231
michael@0 1232 p = (char *)sp;
michael@0 1233 n = sp[0];
michael@0 1234 free_space = FREESPACE(sp);
michael@0 1235 off = OFFSET(sp);
michael@0 1236
michael@0 1237 pageno = sp[n - 1];
michael@0 1238 off -= key->size;
michael@0 1239 sp[n - 1] = off;
michael@0 1240 memmove(p + off, key->data, key->size);
michael@0 1241 off -= val->size;
michael@0 1242 sp[n] = off;
michael@0 1243 memmove(p + off, val->data, val->size);
michael@0 1244 sp[0] = n + 2;
michael@0 1245 sp[n + 1] = pageno;
michael@0 1246 sp[n + 2] = OVFLPAGE;
michael@0 1247 FREESPACE(sp) = free_space - PAIRSIZE(key, val);
michael@0 1248 OFFSET(sp) = off;
michael@0 1249 }
michael@0 1250
michael@0 1251 static uint32 *
michael@0 1252 fetch_bitmap(HTAB *hashp, uint32 ndx)
michael@0 1253 {
michael@0 1254 if (ndx >= (unsigned)hashp->nmaps)
michael@0 1255 return (NULL);
michael@0 1256 if ((hashp->mapp[ndx] = (uint32 *)malloc((size_t)hashp->BSIZE)) == NULL)
michael@0 1257 return (NULL);
michael@0 1258 if (__get_page(hashp,
michael@0 1259 (char *)hashp->mapp[ndx], hashp->BITMAPS[ndx], 0, 1, 1)) {
michael@0 1260 free(hashp->mapp[ndx]);
michael@0 1261 hashp->mapp[ndx] = NULL; /* NEW: 9-11-95 */
michael@0 1262 return (NULL);
michael@0 1263 }
michael@0 1264 return (hashp->mapp[ndx]);
michael@0 1265 }
michael@0 1266
michael@0 1267 #ifdef DEBUG4
michael@0 1268 int
michael@0 1269 print_chain(int addr)
michael@0 1270 {
michael@0 1271 BUFHEAD *bufp;
michael@0 1272 short *bp, oaddr;
michael@0 1273
michael@0 1274 (void)fprintf(stderr, "%d ", addr);
michael@0 1275 bufp = __get_buf(hashp, addr, NULL, 0);
michael@0 1276 bp = (short *)bufp->page;
michael@0 1277 while (bp[0] && ((bp[bp[0]] == OVFLPAGE) ||
michael@0 1278 ((bp[0] > 2) && bp[2] < REAL_KEY))) {
michael@0 1279 oaddr = bp[bp[0] - 1];
michael@0 1280 (void)fprintf(stderr, "%d ", (int)oaddr);
michael@0 1281 bufp = __get_buf(hashp, (int)oaddr, bufp, 0);
michael@0 1282 bp = (short *)bufp->page;
michael@0 1283 }
michael@0 1284 (void)fprintf(stderr, "\n");
michael@0 1285 }
michael@0 1286 #endif

mercurial