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 #include "config.h" 9 10 #ifndef lint 11 static const char sccsid[] = "@(#)bt_rec.c 10.28 (Sleepycat) 9/27/98"; 12 #endif /* not lint */ 13 14 #ifndef NO_SYSTEM_INCLUDES 15 #include <sys/types.h> 16 17 #include <errno.h> 18 #include <string.h> 19 #endif 20 21 #include "db_int.h" 22 #include "db_page.h" 23 #include "shqueue.h" 24 #include "hash.h" 25 #include "btree.h" 26 #include "log.h" 27 #include "common_ext.h" 28 29 /* 30 * __bam_pg_alloc_recover -- 31 * Recovery function for pg_alloc. 32 * 33 * PUBLIC: int __bam_pg_alloc_recover 34 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 35 */ 36 int 37 __bam_pg_alloc_recover(logp, dbtp, lsnp, redo, info) 38 DB_LOG *logp; 39 DBT *dbtp; 40 DB_LSN *lsnp; 41 int redo; 42 void *info; 43 { 44 __bam_pg_alloc_args *argp; 45 BTMETA *meta; 46 DB_MPOOLFILE *mpf; 47 PAGE *pagep; 48 DB *file_dbp; 49 DBC *dbc; 50 db_pgno_t pgno; 51 int cmp_n, cmp_p, modified, ret; 52 53 REC_PRINT(__bam_pg_alloc_print); 54 REC_INTRO(__bam_pg_alloc_read); 55 56 /* 57 * Fix up the allocated page. If we're redoing the operation, we have 58 * to get the page (creating it if it doesn't exist), and update its 59 * LSN. If we're undoing the operation, we have to reset the page's 60 * LSN and put it on the free list. 61 * 62 * Fix up the metadata page. If we're redoing the operation, we have 63 * to get the metadata page and update its LSN and its free pointer. 64 * If we're undoing the operation and the page was ever created, we put 65 * it on the freelist. 66 */ 67 pgno = PGNO_METADATA; 68 if ((ret = memp_fget(mpf, &pgno, 0, &meta)) != 0) { 69 /* The metadata page must always exist. */ 70 (void)__db_pgerr(file_dbp, pgno); 71 goto out; 72 } 73 if ((ret = memp_fget(mpf, &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) { 74 /* 75 * We specify creation and check for it later, because this 76 * operation was supposed to create the page, and even in 77 * the undo case it's going to get linked onto the freelist 78 * which we're also fixing up. 79 */ 80 (void)__db_pgerr(file_dbp, argp->pgno); 81 (void)memp_fput(mpf, meta, 0); 82 goto out; 83 } 84 85 /* Fix up the allocated page. */ 86 modified = 0; 87 cmp_n = log_compare(lsnp, &LSN(pagep)); 88 cmp_p = log_compare(&LSN(pagep), &argp->page_lsn); 89 if (cmp_p == 0 && redo) { 90 /* Need to redo update described. */ 91 P_INIT(pagep, file_dbp->pgsize, 92 argp->pgno, PGNO_INVALID, PGNO_INVALID, 0, argp->ptype); 93 94 pagep->lsn = *lsnp; 95 modified = 1; 96 } else if (cmp_n == 0 && !redo) { 97 /* Need to undo update described. */ 98 P_INIT(pagep, file_dbp->pgsize, 99 argp->pgno, PGNO_INVALID, meta->free, 0, P_INVALID); 100 101 pagep->lsn = argp->page_lsn; 102 modified = 1; 103 } 104 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) { 105 (void)memp_fput(mpf, meta, 0); 106 goto out; 107 } 108 109 /* Fix up the metadata page. */ 110 modified = 0; 111 cmp_n = log_compare(lsnp, &LSN(meta)); 112 cmp_p = log_compare(&LSN(meta), &argp->meta_lsn); 113 if (cmp_p == 0 && redo) { 114 /* Need to redo update described. */ 115 meta->lsn = *lsnp; 116 meta->free = argp->next; 117 modified = 1; 118 } else if (cmp_n == 0 && !redo) { 119 /* Need to undo update described. */ 120 meta->lsn = argp->meta_lsn; 121 meta->free = argp->pgno; 122 modified = 1; 123 } 124 if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0) 125 goto out; 126 127 done: *lsnp = argp->prev_lsn; 128 ret = 0; 129 130 out: REC_CLOSE; 131 } 132 133 /* 134 * __bam_pg_free_recover -- 135 * Recovery function for pg_free. 136 * 137 * PUBLIC: int __bam_pg_free_recover 138 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 139 */ 140 int 141 __bam_pg_free_recover(logp, dbtp, lsnp, redo, info) 142 DB_LOG *logp; 143 DBT *dbtp; 144 DB_LSN *lsnp; 145 int redo; 146 void *info; 147 { 148 __bam_pg_free_args *argp; 149 BTMETA *meta; 150 DB *file_dbp; 151 DBC *dbc; 152 DB_MPOOLFILE *mpf; 153 PAGE *pagep; 154 db_pgno_t pgno; 155 int cmp_n, cmp_p, modified, ret; 156 157 REC_PRINT(__bam_pg_free_print); 158 REC_INTRO(__bam_pg_free_read); 159 160 /* 161 * Fix up the freed page. If we're redoing the operation we get the 162 * page and explicitly discard its contents, then update its LSN. If 163 * we're undoing the operation, we get the page and restore its header. 164 */ 165 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 166 /* 167 * We don't automatically create the page. The only way the 168 * page might not exist is if the alloc never happened, and 169 * the only way the alloc might never have happened is if we 170 * are undoing, in which case there's no reason to create the 171 * page. 172 */ 173 if (!redo) 174 goto done; 175 (void)__db_pgerr(file_dbp, argp->pgno); 176 goto out; 177 } 178 modified = 0; 179 cmp_n = log_compare(lsnp, &LSN(pagep)); 180 cmp_p = log_compare(&LSN(pagep), &LSN(argp->header.data)); 181 if (cmp_p == 0 && redo) { 182 /* Need to redo update described. */ 183 P_INIT(pagep, file_dbp->pgsize, 184 pagep->pgno, PGNO_INVALID, argp->next, 0, P_INVALID); 185 pagep->lsn = *lsnp; 186 187 modified = 1; 188 } else if (cmp_n == 0 && !redo) { 189 /* Need to undo update described. */ 190 memcpy(pagep, argp->header.data, argp->header.size); 191 192 modified = 1; 193 } 194 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 195 goto out; 196 197 /* 198 * Fix up the metadata page. If we're redoing or undoing the operation 199 * we get the page and update its LSN and free pointer. 200 */ 201 pgno = PGNO_METADATA; 202 if ((ret = memp_fget(mpf, &pgno, 0, &meta)) != 0) { 203 /* The metadata page must always exist. */ 204 (void)__db_pgerr(file_dbp, pgno); 205 goto out; 206 } 207 208 modified = 0; 209 cmp_n = log_compare(lsnp, &LSN(meta)); 210 cmp_p = log_compare(&LSN(meta), &argp->meta_lsn); 211 if (cmp_p == 0 && redo) { 212 /* Need to redo update described. */ 213 meta->free = argp->pgno; 214 215 meta->lsn = *lsnp; 216 modified = 1; 217 } else if (cmp_n == 0 && !redo) { 218 /* Need to undo update described. */ 219 meta->free = argp->next; 220 221 meta->lsn = argp->meta_lsn; 222 modified = 1; 223 } 224 if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0) 225 goto out; 226 227 done: *lsnp = argp->prev_lsn; 228 ret = 0; 229 230 out: REC_CLOSE; 231 } 232 233 /* 234 * __bam_split_recover -- 235 * Recovery function for split. 236 * 237 * PUBLIC: int __bam_split_recover 238 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 239 */ 240 int 241 __bam_split_recover(logp, dbtp, lsnp, redo, info) 242 DB_LOG *logp; 243 DBT *dbtp; 244 DB_LSN *lsnp; 245 int redo; 246 void *info; 247 { 248 __bam_split_args *argp; 249 DB *file_dbp; 250 DBC *dbc; 251 DB_MPOOLFILE *mpf; 252 PAGE *_lp, *lp, *np, *pp, *_rp, *rp, *sp; 253 db_pgno_t pgno; 254 int l_update, p_update, r_update, ret, rootsplit, t_ret; 255 256 REC_PRINT(__bam_split_print); 257 258 mpf = NULL; 259 _lp = lp = np = pp = _rp = rp = NULL; 260 261 REC_INTRO(__bam_split_read); 262 263 /* 264 * There are two kinds of splits that we have to recover from. The 265 * first is a root-page split, where the root page is split from a 266 * leaf page into an internal page and two new leaf pages are created. 267 * The second is where a page is split into two pages, and a new key 268 * is inserted into the parent page. 269 */ 270 sp = argp->pg.data; 271 pgno = PGNO(sp); 272 rootsplit = pgno == PGNO_ROOT; 273 if (memp_fget(mpf, &argp->left, 0, &lp) != 0) 274 lp = NULL; 275 if (memp_fget(mpf, &argp->right, 0, &rp) != 0) 276 rp = NULL; 277 278 if (redo) { 279 l_update = r_update = p_update = 0; 280 /* 281 * Decide if we need to resplit the page. 282 * 283 * If this is a root split, then the root has to exist, it's 284 * the page we're splitting and it gets modified. If this is 285 * not a root split, then the left page has to exist, for the 286 * same reason. 287 */ 288 if (rootsplit) { 289 if ((ret = memp_fget(mpf, &pgno, 0, &pp)) != 0) { 290 (void)__db_pgerr(file_dbp, pgno); 291 pp = NULL; 292 goto out; 293 } 294 p_update = 295 log_compare(&LSN(pp), &LSN(argp->pg.data)) == 0; 296 } else 297 if (lp == NULL) { 298 (void)__db_pgerr(file_dbp, argp->left); 299 goto out; 300 } 301 if (lp == NULL || log_compare(&LSN(lp), &argp->llsn) == 0) 302 l_update = 1; 303 if (rp == NULL || log_compare(&LSN(rp), &argp->rlsn) == 0) 304 r_update = 1; 305 if (!p_update && !l_update && !r_update) 306 goto done; 307 308 /* Allocate and initialize new left/right child pages. */ 309 if ((ret = __os_malloc(file_dbp->pgsize, NULL, &_lp)) != 0 || 310 (ret = __os_malloc(file_dbp->pgsize, NULL, &_rp)) != 0) 311 goto out; 312 if (rootsplit) { 313 P_INIT(_lp, file_dbp->pgsize, argp->left, 314 PGNO_INVALID, 315 ISINTERNAL(sp) ? PGNO_INVALID : argp->right, 316 LEVEL(sp), TYPE(sp)); 317 P_INIT(_rp, file_dbp->pgsize, argp->right, 318 ISINTERNAL(sp) ? PGNO_INVALID : argp->left, 319 PGNO_INVALID, LEVEL(sp), TYPE(sp)); 320 } else { 321 P_INIT(_lp, file_dbp->pgsize, PGNO(sp), 322 ISINTERNAL(sp) ? PGNO_INVALID : PREV_PGNO(sp), 323 ISINTERNAL(sp) ? PGNO_INVALID : argp->right, 324 LEVEL(sp), TYPE(sp)); 325 P_INIT(_rp, file_dbp->pgsize, argp->right, 326 ISINTERNAL(sp) ? PGNO_INVALID : sp->pgno, 327 ISINTERNAL(sp) ? PGNO_INVALID : NEXT_PGNO(sp), 328 LEVEL(sp), TYPE(sp)); 329 } 330 331 /* Split the page. */ 332 if ((ret = __bam_copy(file_dbp, sp, _lp, 0, argp->indx)) != 0 || 333 (ret = __bam_copy(file_dbp, sp, _rp, argp->indx, 334 NUM_ENT(sp))) != 0) 335 goto out; 336 337 /* If the left child is wrong, update it. */ 338 if (lp == NULL && (ret = 339 memp_fget(mpf, &argp->left, DB_MPOOL_CREATE, &lp)) != 0) { 340 (void)__db_pgerr(file_dbp, argp->left); 341 lp = NULL; 342 goto out; 343 } 344 if (l_update) { 345 memcpy(lp, _lp, file_dbp->pgsize); 346 lp->lsn = *lsnp; 347 if ((ret = memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0) 348 goto out; 349 lp = NULL; 350 } 351 352 /* If the right child is wrong, update it. */ 353 if (rp == NULL && (ret = memp_fget(mpf, 354 &argp->right, DB_MPOOL_CREATE, &rp)) != 0) { 355 (void)__db_pgerr(file_dbp, argp->right); 356 rp = NULL; 357 goto out; 358 } 359 if (r_update) { 360 memcpy(rp, _rp, file_dbp->pgsize); 361 rp->lsn = *lsnp; 362 if ((ret = memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0) 363 goto out; 364 rp = NULL; 365 } 366 367 /* 368 * If the parent page is wrong, update it. This is of interest 369 * only if it was a root split, since root splits create parent 370 * pages. All other splits modify a parent page, but those are 371 * separately logged and recovered. 372 */ 373 if (rootsplit && p_update) { 374 if (file_dbp->type == DB_BTREE) 375 P_INIT(pp, file_dbp->pgsize, 376 PGNO_ROOT, PGNO_INVALID, PGNO_INVALID, 377 _lp->level + 1, P_IBTREE); 378 else 379 P_INIT(pp, file_dbp->pgsize, 380 PGNO_ROOT, PGNO_INVALID, PGNO_INVALID, 381 _lp->level + 1, P_IRECNO); 382 RE_NREC_SET(pp, 383 file_dbp->type == DB_RECNO || 384 F_ISSET(file_dbp, DB_BT_RECNUM) ? 385 __bam_total(_lp) + __bam_total(_rp) : 0); 386 pp->lsn = *lsnp; 387 if ((ret = memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0) 388 goto out; 389 pp = NULL; 390 } 391 392 /* 393 * Finally, redo the next-page link if necessary. This is of 394 * interest only if it wasn't a root split -- inserting a new 395 * page in the tree requires that any following page have its 396 * previous-page pointer updated to our new page. The next 397 * page must exist because we're redoing the operation. 398 */ 399 if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) { 400 if ((ret = memp_fget(mpf, &argp->npgno, 0, &np)) != 0) { 401 (void)__db_pgerr(file_dbp, argp->npgno); 402 np = NULL; 403 goto out; 404 } 405 if (log_compare(&LSN(np), &argp->nlsn) == 0) { 406 PREV_PGNO(np) = argp->right; 407 np->lsn = *lsnp; 408 if ((ret = 409 memp_fput(mpf, np, DB_MPOOL_DIRTY)) != 0) 410 goto out; 411 np = NULL; 412 } 413 } 414 } else { 415 /* 416 * If the split page is wrong, replace its contents with the 417 * logged page contents. If the page doesn't exist, it means 418 * that the create of the page never happened, nor did any of 419 * the adds onto the page that caused the split, and there's 420 * really no undo-ing to be done. 421 */ 422 if ((ret = memp_fget(mpf, &pgno, 0, &pp)) != 0) { 423 pp = NULL; 424 goto lrundo; 425 } 426 if (log_compare(lsnp, &LSN(pp)) == 0) { 427 memcpy(pp, argp->pg.data, argp->pg.size); 428 if ((ret = memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0) 429 goto out; 430 pp = NULL; 431 } 432 433 /* 434 * If it's a root split and the left child ever existed, update 435 * its LSN. (If it's not a root split, we've updated the left 436 * page already -- it's the same as the split page.) If the 437 * right child ever existed, root split or not, update its LSN. 438 * The undo of the page allocation(s) will restore them to the 439 * free list. 440 */ 441 lrundo: if ((rootsplit && lp != NULL) || rp != NULL) { 442 if (rootsplit && lp != NULL && 443 log_compare(lsnp, &LSN(lp)) == 0) { 444 lp->lsn = argp->llsn; 445 if ((ret = 446 memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0) 447 goto out; 448 lp = NULL; 449 } 450 if (rp != NULL && 451 log_compare(lsnp, &LSN(rp)) == 0) { 452 rp->lsn = argp->rlsn; 453 if ((ret = 454 memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0) 455 goto out; 456 rp = NULL; 457 } 458 } 459 460 /* 461 * Finally, undo the next-page link if necessary. This is of 462 * interest only if it wasn't a root split -- inserting a new 463 * page in the tree requires that any following page have its 464 * previous-page pointer updated to our new page. Since it's 465 * possible that the next-page never existed, we ignore it as 466 * if there's nothing to undo. 467 */ 468 if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) { 469 if ((ret = memp_fget(mpf, &argp->npgno, 0, &np)) != 0) { 470 np = NULL; 471 goto done; 472 } 473 if (log_compare(lsnp, &LSN(np)) == 0) { 474 PREV_PGNO(np) = argp->left; 475 np->lsn = argp->nlsn; 476 if (memp_fput(mpf, np, DB_MPOOL_DIRTY)) 477 goto out; 478 np = NULL; 479 } 480 } 481 } 482 483 done: *lsnp = argp->prev_lsn; 484 ret = 0; 485 486 out: /* Free any pages that weren't dirtied. */ 487 if (pp != NULL && (t_ret = memp_fput(mpf, pp, 0)) != 0 && ret == 0) 488 ret = t_ret; 489 if (lp != NULL && (t_ret = memp_fput(mpf, lp, 0)) != 0 && ret == 0) 490 ret = t_ret; 491 if (np != NULL && (t_ret = memp_fput(mpf, np, 0)) != 0 && ret == 0) 492 ret = t_ret; 493 if (rp != NULL && (t_ret = memp_fput(mpf, rp, 0)) != 0 && ret == 0) 494 ret = t_ret; 495 496 /* Free any allocated space. */ 497 if (_lp != NULL) 498 __os_free(_lp, file_dbp->pgsize); 499 if (_rp != NULL) 500 __os_free(_rp, file_dbp->pgsize); 501 502 REC_CLOSE; 503 } 504 505 /* 506 * __bam_rsplit_recover -- 507 * Recovery function for a reverse split. 508 * 509 * PUBLIC: int __bam_rsplit_recover 510 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 511 */ 512 int 513 __bam_rsplit_recover(logp, dbtp, lsnp, redo, info) 514 DB_LOG *logp; 515 DBT *dbtp; 516 DB_LSN *lsnp; 517 int redo; 518 void *info; 519 { 520 __bam_rsplit_args *argp; 521 DB *file_dbp; 522 DBC *dbc; 523 DB_MPOOLFILE *mpf; 524 PAGE *pagep; 525 db_pgno_t pgno; 526 int cmp_n, cmp_p, modified, ret; 527 528 REC_PRINT(__bam_rsplit_print); 529 REC_INTRO(__bam_rsplit_read); 530 531 /* Fix the root page. */ 532 pgno = PGNO_ROOT; 533 if ((ret = memp_fget(mpf, &pgno, 0, &pagep)) != 0) { 534 /* The root page must always exist. */ 535 __db_pgerr(file_dbp, pgno); 536 goto out; 537 } 538 modified = 0; 539 cmp_n = log_compare(lsnp, &LSN(pagep)); 540 cmp_p = log_compare(&LSN(pagep), &argp->rootlsn); 541 if (cmp_p == 0 && redo) { 542 /* Need to redo update described. */ 543 memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size); 544 pagep->pgno = PGNO_ROOT; 545 pagep->lsn = *lsnp; 546 modified = 1; 547 } else if (cmp_n == 0 && !redo) { 548 /* Need to undo update described. */ 549 P_INIT(pagep, file_dbp->pgsize, PGNO_ROOT, 550 argp->nrec, PGNO_INVALID, pagep->level + 1, 551 file_dbp->type == DB_BTREE ? P_IBTREE : P_IRECNO); 552 if ((ret = __db_pitem(dbc, pagep, 0, 553 argp->rootent.size, &argp->rootent, NULL)) != 0) 554 goto out; 555 pagep->lsn = argp->rootlsn; 556 modified = 1; 557 } 558 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 559 goto out; 560 561 /* 562 * Fix the page copied over the root page. It's possible that the 563 * page never made it to disk, so if we're undo-ing and the page 564 * doesn't exist, it's okay and there's nothing further to do. 565 */ 566 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 567 if (!redo) 568 goto done; 569 (void)__db_pgerr(file_dbp, argp->pgno); 570 goto out; 571 } 572 modified = 0; 573 cmp_n = log_compare(lsnp, &LSN(pagep)); 574 cmp_p = log_compare(&LSN(pagep), &LSN(argp->pgdbt.data)); 575 if (cmp_p == 0 && redo) { 576 /* Need to redo update described. */ 577 pagep->lsn = *lsnp; 578 modified = 1; 579 } else if (cmp_n == 0 && !redo) { 580 /* Need to undo update described. */ 581 memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size); 582 modified = 1; 583 } 584 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 585 goto out; 586 587 done: *lsnp = argp->prev_lsn; 588 ret = 0; 589 590 out: REC_CLOSE; 591 } 592 593 /* 594 * __bam_adj_recover -- 595 * Recovery function for adj. 596 * 597 * PUBLIC: int __bam_adj_recover 598 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 599 */ 600 int 601 __bam_adj_recover(logp, dbtp, lsnp, redo, info) 602 DB_LOG *logp; 603 DBT *dbtp; 604 DB_LSN *lsnp; 605 int redo; 606 void *info; 607 { 608 __bam_adj_args *argp; 609 DB *file_dbp; 610 DBC *dbc; 611 DB_MPOOLFILE *mpf; 612 PAGE *pagep; 613 int cmp_n, cmp_p, modified, ret; 614 615 REC_PRINT(__bam_adj_print); 616 REC_INTRO(__bam_adj_read); 617 618 /* Get the page; if it never existed and we're undoing, we're done. */ 619 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 620 if (!redo) 621 goto done; 622 (void)__db_pgerr(file_dbp, argp->pgno); 623 goto out; 624 } 625 626 modified = 0; 627 cmp_n = log_compare(lsnp, &LSN(pagep)); 628 cmp_p = log_compare(&LSN(pagep), &argp->lsn); 629 if (cmp_p == 0 && redo) { 630 /* Need to redo update described. */ 631 if ((ret = __bam_adjindx(dbc, 632 pagep, argp->indx, argp->indx_copy, argp->is_insert)) != 0) 633 goto err; 634 635 LSN(pagep) = *lsnp; 636 modified = 1; 637 } else if (cmp_n == 0 && !redo) { 638 /* Need to undo update described. */ 639 if ((ret = __bam_adjindx(dbc, 640 pagep, argp->indx, argp->indx_copy, !argp->is_insert)) != 0) 641 goto err; 642 643 LSN(pagep) = argp->lsn; 644 modified = 1; 645 } 646 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 647 goto out; 648 649 done: *lsnp = argp->prev_lsn; 650 ret = 0; 651 652 if (0) { 653 err: (void)memp_fput(mpf, pagep, 0); 654 } 655 out: REC_CLOSE; 656 } 657 658 /* 659 * __bam_cadjust_recover -- 660 * Recovery function for the adjust of a count change in an internal 661 * page. 662 * 663 * PUBLIC: int __bam_cadjust_recover 664 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 665 */ 666 int 667 __bam_cadjust_recover(logp, dbtp, lsnp, redo, info) 668 DB_LOG *logp; 669 DBT *dbtp; 670 DB_LSN *lsnp; 671 int redo; 672 void *info; 673 { 674 __bam_cadjust_args *argp; 675 DB *file_dbp; 676 DBC *dbc; 677 DB_MPOOLFILE *mpf; 678 PAGE *pagep; 679 int cmp_n, cmp_p, modified, ret; 680 681 REC_PRINT(__bam_cadjust_print); 682 REC_INTRO(__bam_cadjust_read); 683 684 /* Get the page; if it never existed and we're undoing, we're done. */ 685 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 686 if (!redo) 687 goto done; 688 (void)__db_pgerr(file_dbp, argp->pgno); 689 goto out; 690 } 691 692 modified = 0; 693 cmp_n = log_compare(lsnp, &LSN(pagep)); 694 cmp_p = log_compare(&LSN(pagep), &argp->lsn); 695 if (cmp_p == 0 && redo) { 696 /* Need to redo update described. */ 697 if (file_dbp->type == DB_BTREE && 698 F_ISSET(file_dbp, DB_BT_RECNUM)) { 699 GET_BINTERNAL(pagep, argp->indx)->nrecs += argp->adjust; 700 if (argp->total && PGNO(pagep) == PGNO_ROOT) 701 RE_NREC_ADJ(pagep, argp->adjust); 702 } 703 if (file_dbp->type == DB_RECNO) { 704 GET_RINTERNAL(pagep, argp->indx)->nrecs += argp->adjust; 705 if (argp->total && PGNO(pagep) == PGNO_ROOT) 706 RE_NREC_ADJ(pagep, argp->adjust); 707 } 708 709 LSN(pagep) = *lsnp; 710 modified = 1; 711 } else if (cmp_n == 0 && !redo) { 712 /* Need to undo update described. */ 713 if (file_dbp->type == DB_BTREE && 714 F_ISSET(file_dbp, DB_BT_RECNUM)) { 715 GET_BINTERNAL(pagep, argp->indx)->nrecs -= argp->adjust; 716 if (argp->total && PGNO(pagep) == PGNO_ROOT) 717 RE_NREC_ADJ(pagep, argp->adjust); 718 } 719 if (file_dbp->type == DB_RECNO) { 720 GET_RINTERNAL(pagep, argp->indx)->nrecs -= argp->adjust; 721 if (argp->total && PGNO(pagep) == PGNO_ROOT) 722 RE_NREC_ADJ(pagep, -(argp->adjust)); 723 } 724 LSN(pagep) = argp->lsn; 725 modified = 1; 726 } 727 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 728 goto out; 729 730 done: *lsnp = argp->prev_lsn; 731 ret = 0; 732 733 out: REC_CLOSE; 734 } 735 736 /* 737 * __bam_cdel_recover -- 738 * Recovery function for the intent-to-delete of a cursor record. 739 * 740 * PUBLIC: int __bam_cdel_recover 741 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 742 */ 743 int 744 __bam_cdel_recover(logp, dbtp, lsnp, redo, info) 745 DB_LOG *logp; 746 DBT *dbtp; 747 DB_LSN *lsnp; 748 int redo; 749 void *info; 750 { 751 __bam_cdel_args *argp; 752 DB *file_dbp; 753 DBC *dbc; 754 DB_MPOOLFILE *mpf; 755 PAGE *pagep; 756 int cmp_n, cmp_p, modified, ret; 757 758 REC_PRINT(__bam_cdel_print); 759 REC_INTRO(__bam_cdel_read); 760 761 /* Get the page; if it never existed and we're undoing, we're done. */ 762 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 763 if (!redo) 764 goto done; 765 (void)__db_pgerr(file_dbp, argp->pgno); 766 goto out; 767 } 768 769 modified = 0; 770 cmp_n = log_compare(lsnp, &LSN(pagep)); 771 cmp_p = log_compare(&LSN(pagep), &argp->lsn); 772 if (cmp_p == 0 && redo) { 773 /* Need to redo update described. */ 774 if (pagep->type == P_DUPLICATE) 775 B_DSET(GET_BKEYDATA(pagep, argp->indx)->type); 776 else 777 B_DSET(GET_BKEYDATA(pagep, argp->indx + O_INDX)->type); 778 779 LSN(pagep) = *lsnp; 780 modified = 1; 781 } else if (cmp_n == 0 && !redo) { 782 /* Need to undo update described. */ 783 if (pagep->type == P_DUPLICATE) 784 B_DCLR(GET_BKEYDATA(pagep, argp->indx)->type); 785 else 786 B_DCLR(GET_BKEYDATA(pagep, argp->indx + O_INDX)->type); 787 788 LSN(pagep) = argp->lsn; 789 modified = 1; 790 } 791 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 792 goto out; 793 794 done: *lsnp = argp->prev_lsn; 795 ret = 0; 796 797 out: REC_CLOSE; 798 } 799 800 /* 801 * __bam_repl_recover -- 802 * Recovery function for page item replacement. 803 * 804 * PUBLIC: int __bam_repl_recover 805 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 806 */ 807 int 808 __bam_repl_recover(logp, dbtp, lsnp, redo, info) 809 DB_LOG *logp; 810 DBT *dbtp; 811 DB_LSN *lsnp; 812 int redo; 813 void *info; 814 { 815 __bam_repl_args *argp; 816 BKEYDATA *bk; 817 DB *file_dbp; 818 DBC *dbc; 819 DBT dbt; 820 DB_MPOOLFILE *mpf; 821 PAGE *pagep; 822 int cmp_n, cmp_p, modified, ret; 823 u_int8_t *p; 824 825 REC_PRINT(__bam_repl_print); 826 REC_INTRO(__bam_repl_read); 827 828 /* Get the page; if it never existed and we're undoing, we're done. */ 829 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 830 if (!redo) 831 goto done; 832 (void)__db_pgerr(file_dbp, argp->pgno); 833 goto out; 834 } 835 bk = GET_BKEYDATA(pagep, argp->indx); 836 837 modified = 0; 838 cmp_n = log_compare(lsnp, &LSN(pagep)); 839 cmp_p = log_compare(&LSN(pagep), &argp->lsn); 840 if (cmp_p == 0 && redo) { 841 /* 842 * Need to redo update described. 843 * 844 * Re-build the replacement item. 845 */ 846 memset(&dbt, 0, sizeof(dbt)); 847 dbt.size = argp->prefix + argp->suffix + argp->repl.size; 848 if ((ret = __os_malloc(dbt.size, NULL, &dbt.data)) != 0) 849 goto err; 850 p = dbt.data; 851 memcpy(p, bk->data, argp->prefix); 852 p += argp->prefix; 853 memcpy(p, argp->repl.data, argp->repl.size); 854 p += argp->repl.size; 855 memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix); 856 857 ret = __bam_ritem(dbc, pagep, argp->indx, &dbt); 858 __os_free(dbt.data, dbt.size); 859 if (ret != 0) 860 goto err; 861 862 LSN(pagep) = *lsnp; 863 modified = 1; 864 } else if (cmp_n == 0 && !redo) { 865 /* 866 * Need to undo update described. 867 * 868 * Re-build the original item. 869 */ 870 memset(&dbt, 0, sizeof(dbt)); 871 dbt.size = argp->prefix + argp->suffix + argp->orig.size; 872 if ((ret = __os_malloc(dbt.size, NULL, &dbt.data)) != 0) 873 goto err; 874 p = dbt.data; 875 memcpy(p, bk->data, argp->prefix); 876 p += argp->prefix; 877 memcpy(p, argp->orig.data, argp->orig.size); 878 p += argp->orig.size; 879 memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix); 880 881 ret = __bam_ritem(dbc, pagep, argp->indx, &dbt); 882 __os_free(dbt.data, dbt.size); 883 if (ret != 0) 884 goto err; 885 886 /* Reset the deleted flag, if necessary. */ 887 if (argp->isdeleted) 888 B_DSET(GET_BKEYDATA(pagep, argp->indx)->type); 889 890 LSN(pagep) = argp->lsn; 891 modified = 1; 892 } 893 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 894 goto out; 895 896 done: *lsnp = argp->prev_lsn; 897 ret = 0; 898 899 if (0) { 900 err: (void)memp_fput(mpf, pagep, 0); 901 } 902 out: REC_CLOSE; 903 } 904