1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996, 1997, 1998 5 * Sleepycat Software. All rights reserved. 6 */ 7 /* 8 * Copyright (c) 1995, 1996 9 * Margo Seltzer. All rights reserved. 10 */ 11 /* 12 * Copyright (c) 1995, 1996 13 * The President and Fellows of Harvard University. All rights reserved. 14 * 15 * This code is derived from software contributed to Berkeley by 16 * Margo Seltzer. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer. 23 * 2. Redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution. 26 * 3. All advertising materials mentioning features or use of this software 27 * must display the following acknowledgement: 28 * This product includes software developed by the University of 29 * California, Berkeley and its contributors. 30 * 4. Neither the name of the University nor the names of its contributors 31 * may be used to endorse or promote products derived from this software 32 * without specific prior written permission. 33 * 34 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 37 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44 * SUCH DAMAGE. 45 */ 46 47 #include "config.h" 48 49 #ifndef lint 50 static const char sccsid[] = "@(#)hash_rec.c 10.22 (Sleepycat) 10/21/98"; 51 #endif /* not lint */ 52 53 #ifndef NO_SYSTEM_INCLUDES 54 #include <sys/types.h> 55 56 #include <errno.h> 57 #include <string.h> 58 #endif 59 60 #include "db_int.h" 61 #include "shqueue.h" 62 #include "db_page.h" 63 #include "hash.h" 64 #include "btree.h" 65 #include "log.h" 66 #include "common_ext.h" 67 68 /* 69 * __ham_insdel_recover -- 70 * 71 * PUBLIC: int __ham_insdel_recover 72 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 73 */ 74 int 75 __ham_insdel_recover(logp, dbtp, lsnp, redo, info) 76 DB_LOG *logp; 77 DBT *dbtp; 78 DB_LSN *lsnp; 79 int redo; 80 void *info; 81 { 82 __ham_insdel_args *argp; 83 DB *file_dbp; 84 DBC *dbc; 85 HASH_CURSOR *hcp; 86 DB_MPOOLFILE *mpf; 87 PAGE *pagep; 88 u_int32_t op; 89 int cmp_n, cmp_p, getmeta, ret; 90 91 getmeta = 0; 92 hcp = NULL; 93 REC_PRINT(__ham_insdel_print); 94 REC_INTRO(__ham_insdel_read); 95 hcp = (HASH_CURSOR *)dbc->internal; 96 97 ret = memp_fget(mpf, &argp->pgno, 0, &pagep); 98 if (ret != 0) 99 if (!redo) { 100 /* 101 * We are undoing and the page doesn't exist. That 102 * is equivalent to having a pagelsn of 0, so we 103 * would not have to undo anything. In this case, 104 * don't bother creating a page. 105 */ 106 goto done; 107 } else if ((ret = memp_fget(mpf, &argp->pgno, 108 DB_MPOOL_CREATE, &pagep)) != 0) 109 goto out; 110 111 112 GET_META(file_dbp, hcp, ret); 113 if (ret != 0) 114 goto out; 115 getmeta = 1; 116 117 cmp_n = log_compare(lsnp, &LSN(pagep)); 118 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn); 119 /* 120 * Two possible things going on: 121 * redo a delete/undo a put: delete the item from the page. 122 * redo a put/undo a delete: add the item to the page. 123 * If we are undoing a delete, then the information logged is the 124 * entire entry off the page, not just the data of a dbt. In 125 * this case, we want to copy it back onto the page verbatim. 126 * We do this by calling __putitem with the type H_OFFPAGE instead 127 * of H_KEYDATA. 128 */ 129 op = OPCODE_OF(argp->opcode); 130 131 if ((op == DELPAIR && cmp_n == 0 && !redo) || 132 (op == PUTPAIR && cmp_p == 0 && redo)) { 133 /* 134 * Need to redo a PUT or undo a delete. If we are undoing a 135 * delete, we've got to restore the item back to its original 136 * position. That's a royal pain in the butt (because we do 137 * not store item lengths on the page), but there's no choice. 138 */ 139 if (op != DELPAIR || 140 argp->ndx == (u_int32_t)H_NUMPAIRS(pagep)) { 141 __ham_putitem(pagep, &argp->key, 142 !redo || PAIR_ISKEYBIG(argp->opcode) ? 143 H_OFFPAGE : H_KEYDATA); 144 __ham_putitem(pagep, &argp->data, 145 !redo || PAIR_ISDATABIG(argp->opcode) ? 146 H_OFFPAGE : H_KEYDATA); 147 } else 148 (void) __ham_reputpair(pagep, hcp->hdr->pagesize, 149 argp->ndx, &argp->key, &argp->data); 150 151 LSN(pagep) = redo ? *lsnp : argp->pagelsn; 152 if ((ret = __ham_put_page(file_dbp, pagep, 1)) != 0) 153 goto out; 154 155 } else if ((op == DELPAIR && cmp_p == 0 && redo) 156 || (op == PUTPAIR && cmp_n == 0 && !redo)) { 157 /* Need to undo a put or redo a delete. */ 158 __ham_dpair(file_dbp, pagep, argp->ndx); 159 LSN(pagep) = redo ? *lsnp : argp->pagelsn; 160 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0) 161 goto out; 162 } else 163 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0) 164 goto out; 165 166 /* Return the previous LSN. */ 167 done: *lsnp = argp->prev_lsn; 168 ret = 0; 169 170 out: if (getmeta) 171 RELEASE_META(file_dbp, hcp); 172 REC_CLOSE; 173 } 174 175 /* 176 * __ham_newpage_recover -- 177 * This log message is used when we add/remove overflow pages. This 178 * message takes care of the pointer chains, not the data on the pages. 179 * 180 * PUBLIC: int __ham_newpage_recover 181 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 182 */ 183 int 184 __ham_newpage_recover(logp, dbtp, lsnp, redo, info) 185 DB_LOG *logp; 186 DBT *dbtp; 187 DB_LSN *lsnp; 188 int redo; 189 void *info; 190 { 191 __ham_newpage_args *argp; 192 DB *file_dbp; 193 DBC *dbc; 194 HASH_CURSOR *hcp; 195 DB_MPOOLFILE *mpf; 196 PAGE *pagep; 197 int cmp_n, cmp_p, change, getmeta, ret; 198 199 getmeta = 0; 200 hcp = NULL; 201 REC_PRINT(__ham_newpage_print); 202 REC_INTRO(__ham_newpage_read); 203 hcp = (HASH_CURSOR *)dbc->internal; 204 205 ret = memp_fget(mpf, &argp->new_pgno, 0, &pagep); 206 if (ret != 0) 207 if (!redo) { 208 /* 209 * We are undoing and the page doesn't exist. That 210 * is equivalent to having a pagelsn of 0, so we 211 * would not have to undo anything. In this case, 212 * don't bother creating a page. 213 */ 214 ret = 0; 215 goto ppage; 216 } else if ((ret = memp_fget(mpf, &argp->new_pgno, 217 DB_MPOOL_CREATE, &pagep)) != 0) 218 goto out; 219 220 GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret); 221 if (ret != 0) 222 goto out; 223 getmeta = 1; 224 225 /* 226 * There are potentially three pages we need to check: the one 227 * that we created/deleted, the one before it and the one after 228 * it. 229 */ 230 231 cmp_n = log_compare(lsnp, &LSN(pagep)); 232 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn); 233 change = 0; 234 235 if ((cmp_p == 0 && redo && argp->opcode == PUTOVFL) || 236 (cmp_n == 0 && !redo && argp->opcode == DELOVFL)) { 237 /* Redo a create new page or undo a delete new page. */ 238 P_INIT(pagep, file_dbp->pgsize, argp->new_pgno, 239 argp->prev_pgno, argp->next_pgno, 0, P_HASH); 240 change = 1; 241 } else if ((cmp_p == 0 && redo && argp->opcode == DELOVFL) || 242 (cmp_n == 0 && !redo && argp->opcode == PUTOVFL)) { 243 /* 244 * Redo a delete or undo a create new page. All we 245 * really need to do is change the LSN. 246 */ 247 change = 1; 248 } 249 250 if (!change) { 251 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0) 252 goto out; 253 } else { 254 LSN(pagep) = redo ? *lsnp : argp->pagelsn; 255 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0) 256 goto out; 257 } 258 259 /* Now do the prev page. */ 260 ppage: if (argp->prev_pgno != PGNO_INVALID) { 261 ret = memp_fget(mpf, &argp->prev_pgno, 0, &pagep); 262 263 if (ret != 0) 264 if (!redo) { 265 /* 266 * We are undoing and the page doesn't exist. 267 * That is equivalent to having a pagelsn of 0, 268 * so we would not have to undo anything. In 269 * this case, don't bother creating a page. 270 */ 271 ret = 0; 272 goto npage; 273 } else if ((ret = 274 memp_fget(mpf, &argp->prev_pgno, 275 DB_MPOOL_CREATE, &pagep)) != 0) 276 goto out; 277 278 cmp_n = log_compare(lsnp, &LSN(pagep)); 279 cmp_p = log_compare(&LSN(pagep), &argp->prevlsn); 280 change = 0; 281 282 if ((cmp_p == 0 && redo && argp->opcode == PUTOVFL) || 283 (cmp_n == 0 && !redo && argp->opcode == DELOVFL)) { 284 /* Redo a create new page or undo a delete new page. */ 285 pagep->next_pgno = argp->new_pgno; 286 change = 1; 287 } else if ((cmp_p == 0 && redo && argp->opcode == DELOVFL) || 288 (cmp_n == 0 && !redo && argp->opcode == PUTOVFL)) { 289 /* Redo a delete or undo a create new page. */ 290 pagep->next_pgno = argp->next_pgno; 291 change = 1; 292 } 293 294 if (!change) { 295 if ((ret = 296 __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0) 297 goto out; 298 } else { 299 LSN(pagep) = redo ? *lsnp : argp->prevlsn; 300 if ((ret = 301 __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0) 302 goto out; 303 } 304 } 305 306 /* Now time to do the next page */ 307 npage: if (argp->next_pgno != PGNO_INVALID) { 308 ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep); 309 310 if (ret != 0) 311 if (!redo) { 312 /* 313 * We are undoing and the page doesn't exist. 314 * That is equivalent to having a pagelsn of 0, 315 * so we would not have to undo anything. In 316 * this case, don't bother creating a page. 317 */ 318 goto done; 319 } else if ((ret = 320 memp_fget(mpf, &argp->next_pgno, 321 DB_MPOOL_CREATE, &pagep)) != 0) 322 goto out; 323 324 cmp_n = log_compare(lsnp, &LSN(pagep)); 325 cmp_p = log_compare(&LSN(pagep), &argp->nextlsn); 326 change = 0; 327 328 if ((cmp_p == 0 && redo && argp->opcode == PUTOVFL) || 329 (cmp_n == 0 && !redo && argp->opcode == DELOVFL)) { 330 /* Redo a create new page or undo a delete new page. */ 331 pagep->prev_pgno = argp->new_pgno; 332 change = 1; 333 } else if ((cmp_p == 0 && redo && argp->opcode == DELOVFL) || 334 (cmp_n == 0 && !redo && argp->opcode == PUTOVFL)) { 335 /* Redo a delete or undo a create new page. */ 336 pagep->prev_pgno = argp->prev_pgno; 337 change = 1; 338 } 339 340 if (!change) { 341 if ((ret = 342 __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0) 343 goto out; 344 } else { 345 LSN(pagep) = redo ? *lsnp : argp->nextlsn; 346 if ((ret = 347 __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0) 348 goto out; 349 } 350 } 351 done: *lsnp = argp->prev_lsn; 352 ret = 0; 353 354 out: if (getmeta) 355 RELEASE_META(file_dbp, hcp); 356 REC_CLOSE; 357 } 358 359 360 /* 361 * __ham_replace_recover -- 362 * This log message refers to partial puts that are local to a single 363 * page. You can think of them as special cases of the more general 364 * insdel log message. 365 * 366 * PUBLIC: int __ham_replace_recover 367 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 368 */ 369 int 370 __ham_replace_recover(logp, dbtp, lsnp, redo, info) 371 DB_LOG *logp; 372 DBT *dbtp; 373 DB_LSN *lsnp; 374 int redo; 375 void *info; 376 { 377 __ham_replace_args *argp; 378 DB *file_dbp; 379 DBC *dbc; 380 HASH_CURSOR *hcp; 381 DB_MPOOLFILE *mpf; 382 DBT dbt; 383 PAGE *pagep; 384 int32_t grow; 385 int change, cmp_n, cmp_p, getmeta, ret; 386 u_int8_t *hk; 387 388 getmeta = 0; 389 hcp = NULL; 390 REC_PRINT(__ham_replace_print); 391 REC_INTRO(__ham_replace_read); 392 hcp = (HASH_CURSOR *)dbc->internal; 393 394 ret = memp_fget(mpf, &argp->pgno, 0, &pagep); 395 if (ret != 0) 396 if (!redo) { 397 /* 398 * We are undoing and the page doesn't exist. That 399 * is equivalent to having a pagelsn of 0, so we 400 * would not have to undo anything. In this case, 401 * don't bother creating a page. 402 */ 403 goto done; 404 } else if ((ret = memp_fget(mpf, &argp->pgno, 405 DB_MPOOL_CREATE, &pagep)) != 0) 406 goto out; 407 408 GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret); 409 if (ret != 0) 410 goto out; 411 getmeta = 1; 412 413 cmp_n = log_compare(lsnp, &LSN(pagep)); 414 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn); 415 416 if (cmp_p == 0 && redo) { 417 change = 1; 418 /* Reapply the change as specified. */ 419 dbt.data = argp->newitem.data; 420 dbt.size = argp->newitem.size; 421 grow = argp->newitem.size - argp->olditem.size; 422 LSN(pagep) = *lsnp; 423 } else if (cmp_n == 0 && !redo) { 424 change = 1; 425 /* Undo the already applied change. */ 426 dbt.data = argp->olditem.data; 427 dbt.size = argp->olditem.size; 428 grow = argp->olditem.size - argp->newitem.size; 429 LSN(pagep) = argp->pagelsn; 430 } else { 431 change = 0; 432 grow = 0; 433 } 434 435 if (change) { 436 __ham_onpage_replace(pagep, 437 file_dbp->pgsize, argp->ndx, argp->off, grow, &dbt); 438 if (argp->makedup) { 439 hk = P_ENTRY(pagep, argp->ndx); 440 if (redo) 441 HPAGE_PTYPE(hk) = H_DUPLICATE; 442 else 443 HPAGE_PTYPE(hk) = H_KEYDATA; 444 } 445 } 446 447 if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0) 448 goto out; 449 450 done: *lsnp = argp->prev_lsn; 451 ret = 0; 452 453 out: if (getmeta) 454 RELEASE_META(file_dbp, hcp); 455 REC_CLOSE; 456 } 457 458 /* 459 * __ham_newpgno_recover -- 460 * This log message is used when allocating or deleting an overflow 461 * page. It takes care of modifying the meta data. 462 * 463 * PUBLIC: int __ham_newpgno_recover 464 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 465 */ 466 int 467 __ham_newpgno_recover(logp, dbtp, lsnp, redo, info) 468 DB_LOG *logp; 469 DBT *dbtp; 470 DB_LSN *lsnp; 471 int redo; 472 void *info; 473 { 474 __ham_newpgno_args *argp; 475 DB *file_dbp; 476 DBC *dbc; 477 HASH_CURSOR *hcp; 478 DB_MPOOLFILE *mpf; 479 PAGE *pagep; 480 int change, cmp_n, cmp_p, getmeta, ret; 481 482 getmeta = 0; 483 hcp = NULL; 484 REC_PRINT(__ham_newpgno_print); 485 REC_INTRO(__ham_newpgno_read); 486 hcp = (HASH_CURSOR *)dbc->internal; 487 488 GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret); 489 if (ret != 0) 490 goto out; 491 getmeta = 1; 492 493 /* 494 * There are two phases to the recovery here. First we need 495 * to update the meta data; then we need to update the page. 496 * We'll do the meta-data first. 497 */ 498 cmp_n = log_compare(lsnp, &hcp->hdr->lsn); 499 cmp_p = log_compare(&hcp->hdr->lsn, &argp->metalsn); 500 501 change = 0; 502 if ((cmp_p == 0 && redo && argp->opcode == ALLOCPGNO) || 503 (cmp_n == 0 && !redo && argp->opcode == DELPGNO)) { 504 /* Need to redo an allocation or undo a deletion. */ 505 hcp->hdr->last_freed = argp->free_pgno; 506 if (redo && argp->old_pgno != 0) /* Must be ALLOCPGNO */ 507 hcp->hdr->spares[hcp->hdr->ovfl_point]++; 508 change = 1; 509 } else if (cmp_p == 0 && redo && argp->opcode == DELPGNO) { 510 /* Need to redo a deletion */ 511 hcp->hdr->last_freed = argp->pgno; 512 change = 1; 513 } else if (cmp_n == 0 && !redo && argp->opcode == ALLOCPGNO) { 514 /* undo an allocation. */ 515 if (argp->old_pgno == 0) 516 hcp->hdr->last_freed = argp->pgno; 517 else { 518 hcp->hdr->spares[hcp->hdr->ovfl_point]--; 519 hcp->hdr->last_freed = 0; 520 } 521 change = 1; 522 } 523 if (change) { 524 hcp->hdr->lsn = redo ? *lsnp : argp->metalsn; 525 F_SET(hcp, H_DIRTY); 526 } 527 528 529 /* Now check the newly allocated/freed page. */ 530 ret = memp_fget(mpf, &argp->pgno, 0, &pagep); 531 532 if (ret != 0) 533 if (!redo) { 534 /* 535 * We are undoing and the page doesn't exist. That 536 * is equivalent to having a pagelsn of 0, so we 537 * would not have to undo anything. In this case, 538 * don't bother creating a page. 539 */ 540 goto done; 541 } else if ((ret = memp_fget(mpf, &argp->pgno, 542 DB_MPOOL_CREATE, &pagep)) != 0) 543 goto out; 544 545 cmp_n = log_compare(lsnp, &LSN(pagep)); 546 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn); 547 548 change = 0; 549 if (cmp_p == 0 && redo && argp->opcode == ALLOCPGNO) { 550 /* Need to redo an allocation. */ 551 P_INIT(pagep, file_dbp->pgsize, argp->pgno, PGNO_INVALID, 552 PGNO_INVALID, 0, argp->new_type); 553 change = 1; 554 } else if (cmp_n == 0 && !redo && argp->opcode == DELPGNO) { 555 /* Undoing a delete. */ 556 P_INIT(pagep, file_dbp->pgsize, argp->pgno, PGNO_INVALID, 557 argp->old_pgno, 0, argp->old_type); 558 change = 1; 559 } else if ((cmp_p == 0 && redo && argp->opcode == DELPGNO) || 560 (cmp_n == 0 && !redo && argp->opcode == ALLOCPGNO)) { 561 /* Need to redo a deletion or undo an allocation. */ 562 NEXT_PGNO(pagep) = argp->free_pgno; 563 TYPE(pagep) = P_INVALID; 564 change = 1; 565 } 566 if (change) 567 LSN(pagep) = redo ? *lsnp : argp->pagelsn; 568 569 if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0) 570 goto out; 571 572 done: *lsnp = argp->prev_lsn; 573 ret = 0; 574 575 out: if (getmeta) 576 RELEASE_META(file_dbp, hcp); 577 REC_CLOSE; 578 579 } 580 581 /* 582 * __ham_splitmeta_recover -- 583 * This is the meta-data part of the split. Records the new and old 584 * bucket numbers and the new/old mask information. 585 * 586 * PUBLIC: int __ham_splitmeta_recover 587 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 588 */ 589 int 590 __ham_splitmeta_recover(logp, dbtp, lsnp, redo, info) 591 DB_LOG *logp; 592 DBT *dbtp; 593 DB_LSN *lsnp; 594 int redo; 595 void *info; 596 { 597 __ham_splitmeta_args *argp; 598 DB *file_dbp; 599 DBC *dbc; 600 HASH_CURSOR *hcp; 601 DB_MPOOLFILE *mpf; 602 int change, cmp_n, cmp_p, getmeta, ret; 603 u_int32_t pow; 604 605 getmeta = 0; 606 hcp = NULL; 607 REC_PRINT(__ham_splitmeta_print); 608 REC_INTRO(__ham_splitmeta_read); 609 hcp = (HASH_CURSOR *)dbc->internal; 610 611 GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret); 612 if (ret != 0) 613 goto out; 614 getmeta = 1; 615 616 /* 617 * There are two phases to the recovery here. First we need 618 * to update the meta data; then we need to update the page. 619 * We'll do the meta-data first. 620 */ 621 cmp_n = log_compare(lsnp, &hcp->hdr->lsn); 622 cmp_p = log_compare(&hcp->hdr->lsn, &argp->metalsn); 623 624 change = 0; 625 if (cmp_p == 0 && redo) { 626 /* Need to redo the split information. */ 627 hcp->hdr->max_bucket = argp->bucket + 1; 628 pow = __db_log2(hcp->hdr->max_bucket + 1); 629 if (pow > hcp->hdr->ovfl_point) { 630 hcp->hdr->spares[pow] = 631 hcp->hdr->spares[hcp->hdr->ovfl_point]; 632 hcp->hdr->ovfl_point = pow; 633 } 634 if (hcp->hdr->max_bucket > hcp->hdr->high_mask) { 635 hcp->hdr->low_mask = hcp->hdr->high_mask; 636 hcp->hdr->high_mask = 637 hcp->hdr->max_bucket | hcp->hdr->low_mask; 638 } 639 change = 1; 640 } else if (cmp_n == 0 && !redo) { 641 /* Need to undo the split information. */ 642 hcp->hdr->max_bucket = argp->bucket; 643 hcp->hdr->ovfl_point = argp->ovflpoint; 644 hcp->hdr->spares[hcp->hdr->ovfl_point] = argp->spares; 645 pow = 1 << __db_log2(hcp->hdr->max_bucket + 1); 646 hcp->hdr->high_mask = pow - 1; 647 hcp->hdr->low_mask = (pow >> 1) - 1; 648 change = 1; 649 } 650 if (change) { 651 hcp->hdr->lsn = redo ? *lsnp : argp->metalsn; 652 F_SET(hcp, H_DIRTY); 653 } 654 655 done: *lsnp = argp->prev_lsn; 656 ret = 0; 657 658 out: if (getmeta) 659 RELEASE_META(file_dbp, hcp); 660 REC_CLOSE; 661 } 662 663 /* 664 * __ham_splitdata_recover -- 665 * 666 * PUBLIC: int __ham_splitdata_recover 667 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 668 */ 669 int 670 __ham_splitdata_recover(logp, dbtp, lsnp, redo, info) 671 DB_LOG *logp; 672 DBT *dbtp; 673 DB_LSN *lsnp; 674 int redo; 675 void *info; 676 { 677 __ham_splitdata_args *argp; 678 DB *file_dbp; 679 DBC *dbc; 680 HASH_CURSOR *hcp; 681 DB_MPOOLFILE *mpf; 682 PAGE *pagep; 683 int change, cmp_n, cmp_p, getmeta, ret; 684 685 getmeta = 0; 686 hcp = NULL; 687 REC_PRINT(__ham_splitdata_print); 688 REC_INTRO(__ham_splitdata_read); 689 hcp = (HASH_CURSOR *)dbc->internal; 690 691 ret = memp_fget(mpf, &argp->pgno, 0, &pagep); 692 if (ret != 0) 693 if (!redo) { 694 /* 695 * We are undoing and the page doesn't exist. That 696 * is equivalent to having a pagelsn of 0, so we 697 * would not have to undo anything. In this case, 698 * don't bother creating a page. 699 */ 700 goto done; 701 } else if ((ret = memp_fget(mpf, &argp->pgno, 702 DB_MPOOL_CREATE, &pagep)) != 0) 703 goto out; 704 705 GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret); 706 if (ret != 0) 707 goto out; 708 getmeta = 1; 709 710 cmp_n = log_compare(lsnp, &LSN(pagep)); 711 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn); 712 713 /* 714 * There are two types of log messages here, one for the old page 715 * and one for the new pages created. The original image in the 716 * SPLITOLD record is used for undo. The image in the SPLITNEW 717 * is used for redo. We should never have a case where there is 718 * a redo operation and the SPLITOLD record is on disk, but not 719 * the SPLITNEW record. Therefore, we only have work to do when 720 * redo NEW messages and undo OLD messages, but we have to update 721 * LSNs in both cases. 722 */ 723 change = 0; 724 if (cmp_p == 0 && redo) { 725 if (argp->opcode == SPLITNEW) 726 /* Need to redo the split described. */ 727 memcpy(pagep, argp->pageimage.data, 728 argp->pageimage.size); 729 LSN(pagep) = *lsnp; 730 change = 1; 731 } else if (cmp_n == 0 && !redo) { 732 if (argp->opcode == SPLITOLD) { 733 /* Put back the old image. */ 734 memcpy(pagep, argp->pageimage.data, 735 argp->pageimage.size); 736 } else 737 P_INIT(pagep, file_dbp->pgsize, argp->pgno, 738 PGNO_INVALID, PGNO_INVALID, 0, P_HASH); 739 LSN(pagep) = argp->pagelsn; 740 change = 1; 741 } 742 if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0) 743 goto out; 744 745 done: *lsnp = argp->prev_lsn; 746 ret = 0; 747 748 out: if (getmeta) 749 RELEASE_META(file_dbp, hcp); 750 REC_CLOSE; 751 } 752 753 /* 754 * __ham_ovfl_recover -- 755 * This message is generated when we initialize a set of overflow pages. 756 * 757 * PUBLIC: int __ham_ovfl_recover 758 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 759 */ 760 int 761 __ham_ovfl_recover(logp, dbtp, lsnp, redo, info) 762 DB_LOG *logp; 763 DBT *dbtp; 764 DB_LSN *lsnp; 765 int redo; 766 void *info; 767 { 768 __ham_ovfl_args *argp; 769 DB *file_dbp; 770 DBC *dbc; 771 HASH_CURSOR *hcp; 772 DB_MPOOLFILE *mpf; 773 PAGE *pagep; 774 db_pgno_t max_pgno, pgno; 775 int cmp_n, cmp_p, getmeta, ret; 776 777 getmeta = 0; 778 hcp = NULL; 779 REC_PRINT(__ham_ovfl_print); 780 REC_INTRO(__ham_ovfl_read); 781 hcp = (HASH_CURSOR *)dbc->internal; 782 783 GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret); 784 if (ret != 0) 785 goto out; 786 getmeta = 1; 787 788 cmp_n = log_compare(lsnp, &hcp->hdr->lsn); 789 cmp_p = log_compare(&hcp->hdr->lsn, &argp->metalsn); 790 791 if (cmp_p == 0 && redo) { 792 /* Redo the allocation. */ 793 hcp->hdr->last_freed = argp->start_pgno; 794 hcp->hdr->spares[argp->ovflpoint] += argp->npages; 795 hcp->hdr->lsn = *lsnp; 796 F_SET(hcp, H_DIRTY); 797 } else if (cmp_n == 0 && !redo) { 798 hcp->hdr->last_freed = argp->free_pgno; 799 hcp->hdr->spares[argp->ovflpoint] -= argp->npages; 800 hcp->hdr->lsn = argp->metalsn; 801 F_SET(hcp, H_DIRTY); 802 } 803 804 max_pgno = argp->start_pgno + argp->npages - 1; 805 ret = 0; 806 for (pgno = argp->start_pgno; pgno <= max_pgno; pgno++) { 807 if ((ret = memp_fget(mpf, &pgno, 0, &pagep)) != 0) { 808 if (!redo) { 809 ret = 0; 810 continue; 811 } 812 if ((ret = memp_fget(mpf, 813 &pgno, DB_MPOOL_CREATE, &pagep)) != 0) 814 goto out; 815 } 816 if (redo && log_compare((const DB_LSN *)lsnp, 817 (const DB_LSN *)&LSN(pagep)) > 0) { 818 P_INIT(pagep, file_dbp->pgsize, pgno, PGNO_INVALID, 819 pgno == max_pgno ? argp->free_pgno : pgno + 1, 820 0, P_HASH); 821 LSN(pagep) = *lsnp; 822 ret = __ham_put_page(file_dbp, pagep, 1); 823 } else if (!redo) { 824 ZERO_LSN(pagep->lsn); 825 ret = __ham_put_page(file_dbp, pagep, 1); 826 } else 827 ret = __ham_put_page(file_dbp, pagep, 0); 828 if (ret) 829 goto out; 830 } 831 832 done: *lsnp = argp->prev_lsn; 833 ret = 0; 834 835 out: if (getmeta) 836 RELEASE_META(file_dbp, hcp); 837 REC_CLOSE; 838 } 839 840 /* 841 * __ham_copypage_recover -- 842 * Recovery function for copypage. 843 * 844 * PUBLIC: int __ham_copypage_recover 845 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 846 */ 847 int 848 __ham_copypage_recover(logp, dbtp, lsnp, redo, info) 849 DB_LOG *logp; 850 DBT *dbtp; 851 DB_LSN *lsnp; 852 int redo; 853 void *info; 854 { 855 __ham_copypage_args *argp; 856 DB *file_dbp; 857 DBC *dbc; 858 HASH_CURSOR *hcp; 859 DB_MPOOLFILE *mpf; 860 PAGE *pagep; 861 int cmp_n, cmp_p, getmeta, modified, ret; 862 863 getmeta = 0; 864 hcp = NULL; 865 REC_PRINT(__ham_copypage_print); 866 REC_INTRO(__ham_copypage_read); 867 hcp = (HASH_CURSOR *)dbc->internal; 868 869 GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret); 870 if (ret != 0) 871 goto out; 872 getmeta = 1; 873 modified = 0; 874 875 /* This is the bucket page. */ 876 ret = memp_fget(mpf, &argp->pgno, 0, &pagep); 877 if (ret != 0) 878 if (!redo) { 879 /* 880 * We are undoing and the page doesn't exist. That 881 * is equivalent to having a pagelsn of 0, so we 882 * would not have to undo anything. In this case, 883 * don't bother creating a page. 884 */ 885 ret = 0; 886 goto donext; 887 } else if ((ret = memp_fget(mpf, &argp->pgno, 888 DB_MPOOL_CREATE, &pagep)) != 0) 889 goto out; 890 891 cmp_n = log_compare(lsnp, &LSN(pagep)); 892 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn); 893 894 if (cmp_p == 0 && redo) { 895 /* Need to redo update described. */ 896 memcpy(pagep, argp->page.data, argp->page.size); 897 LSN(pagep) = *lsnp; 898 modified = 1; 899 } else if (cmp_n == 0 && !redo) { 900 /* Need to undo update described. */ 901 P_INIT(pagep, hcp->hdr->pagesize, argp->pgno, PGNO_INVALID, 902 argp->next_pgno, 0, P_HASH); 903 LSN(pagep) = argp->pagelsn; 904 modified = 1; 905 } 906 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 907 goto out; 908 909 /* Now fix up the "next" page. */ 910 donext: ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep); 911 if (ret != 0) 912 if (!redo) { 913 /* 914 * We are undoing and the page doesn't exist. That 915 * is equivalent to having a pagelsn of 0, so we 916 * would not have to undo anything. In this case, 917 * don't bother creating a page. 918 */ 919 ret = 0; 920 goto do_nn; 921 } else if ((ret = memp_fget(mpf, &argp->next_pgno, 922 DB_MPOOL_CREATE, &pagep)) != 0) 923 goto out; 924 925 /* There is nothing to do in the REDO case; only UNDO. */ 926 927 cmp_n = log_compare(lsnp, &LSN(pagep)); 928 if (cmp_n == 0 && !redo) { 929 /* Need to undo update described. */ 930 memcpy(pagep, argp->page.data, argp->page.size); 931 modified = 1; 932 } 933 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 934 goto out; 935 936 /* Now fix up the next's next page. */ 937 do_nn: if (argp->nnext_pgno == PGNO_INVALID) 938 goto done; 939 940 ret = memp_fget(mpf, &argp->nnext_pgno, 0, &pagep); 941 if (ret != 0) 942 if (!redo) { 943 /* 944 * We are undoing and the page doesn't exist. That 945 * is equivalent to having a pagelsn of 0, so we 946 * would not have to undo anything. In this case, 947 * don't bother creating a page. 948 */ 949 goto done; 950 } else if ((ret = memp_fget(mpf, &argp->nnext_pgno, 951 DB_MPOOL_CREATE, &pagep)) != 0) 952 goto out; 953 954 cmp_n = log_compare(lsnp, &LSN(pagep)); 955 cmp_p = log_compare(&LSN(pagep), &argp->nnextlsn); 956 957 if (cmp_p == 0 && redo) { 958 /* Need to redo update described. */ 959 PREV_PGNO(pagep) = argp->pgno; 960 LSN(pagep) = *lsnp; 961 modified = 1; 962 } else if (cmp_n == 0 && !redo) { 963 /* Need to undo update described. */ 964 PREV_PGNO(pagep) = argp->next_pgno; 965 LSN(pagep) = argp->nnextlsn; 966 modified = 1; 967 } 968 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 969 goto out; 970 971 done: *lsnp = argp->prev_lsn; 972 ret = 0; 973 974 out: if (getmeta) 975 RELEASE_META(file_dbp, hcp); 976 REC_CLOSE; 977 } 978