00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1996, 1997, 1998, 1999, 2000 00005 * Sleepycat Software. All rights reserved. 00006 */ 00007 00008 #include "config.h" 00009 00010 #ifndef lint 00011 static const char revid[] = "$Id: bt__rec_8c-source.html,v 1.1 2008年06月08日 10:13:39 sebdiaz Exp $"; 00012 #endif /* not lint */ 00013 00014 #ifndef NO_SYSTEM_INCLUDES 00015 #include <sys/types.h> 00016 00017 #include <string.h> 00018 #endif 00019 00020 #include "db_int.h" 00021 #include "db_page.h" 00022 #include "hash.h" 00023 #include "btree.h" 00024 #include "log.h" 00025 00026 #define IS_BTREE_PAGE(pagep) \ 00027 (TYPE(pagep) == P_IBTREE || \ 00028 TYPE(pagep) == P_LBTREE || TYPE(pagep) == P_LDUP) 00029 00030 /* 00031 * CDB___bam_pg_alloc_recover -- 00032 * Recovery function for pg_alloc. 00033 * 00034 * PUBLIC: int CDB___bam_pg_alloc_recover 00035 * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); 00036 */ 00037 int 00038 CDB___bam_pg_alloc_recover(dbenv, dbtp, lsnp, op, info) 00039 DB_ENV *dbenv; 00040 DBT *dbtp; 00041 DB_LSN *lsnp; 00042 db_recops op; 00043 void *info; 00044 { 00045 __bam_pg_alloc_args *argp; 00046 DB *file_dbp; 00047 DBC *dbc; 00048 DBMETA *meta; 00049 DB_MPOOLFILE *mpf; 00050 PAGE *pagep; 00051 db_pgno_t pgno; 00052 int cmp_n, cmp_p, modified, ret; 00053 00054 COMPQUIET(info, NULL); 00055 REC_PRINT(CDB___bam_pg_alloc_print); 00056 REC_INTRO(CDB___bam_pg_alloc_read, 0); 00057 00058 /* 00059 * Fix up the allocated page. If we're redoing the operation, we have 00060 * to get the page (creating it if it doesn't exist), and update its 00061 * LSN. If we're undoing the operation, we have to reset the page's 00062 * LSN and put it on the free list. 00063 * 00064 * Fix up the metadata page. If we're redoing the operation, we have 00065 * to get the metadata page and update its LSN and its free pointer. 00066 * If we're undoing the operation and the page was ever created, we put 00067 * it on the freelist. 00068 */ 00069 pgno = PGNO_BASE_MD; 00070 if ((ret = CDB_memp_fget(mpf, &pgno, 0, &meta)) != 0) { 00071 /* The metadata page must always exist on redo. */ 00072 if (DB_REDO(op)) { 00073 (void)CDB___db_pgerr(file_dbp, pgno); 00074 goto out; 00075 } else 00076 goto done; 00077 } 00078 if ((ret = CDB_memp_fget(mpf, &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) { 00079 /* 00080 * We specify creation and check for it later, because this 00081 * operation was supposed to create the page, and even in 00082 * the undo case it's going to get linked onto the freelist 00083 * which we're also fixing up. 00084 */ 00085 (void)CDB___db_pgerr(file_dbp, argp->pgno); 00086 (void)CDB_memp_fput(mpf, meta, 0); 00087 goto out; 00088 } 00089 00090 /* Fix up the allocated page. */ 00091 modified = 0; 00092 cmp_n = CDB_log_compare(lsnp, &LSN(pagep)); 00093 cmp_p = CDB_log_compare(&LSN(pagep), &argp->page_lsn); 00094 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->page_lsn); 00095 if (cmp_p == 0 && DB_REDO(op)) { 00096 /* Need to redo update described. */ 00097 P_INIT(pagep, file_dbp->pgsize, 00098 argp->pgno, PGNO_INVALID, PGNO_INVALID, 0, TYPE(argp), TAGS(argp)); 00099 00100 pagep->lsn = *lsnp; 00101 modified = 1; 00102 } else if (cmp_n == 0 && DB_UNDO(op)) { 00103 /* Need to undo update described. */ 00104 P_INIT(pagep, file_dbp->pgsize, 00105 argp->pgno, PGNO_INVALID, meta->free, 0, P_INVALID, 0); 00106 00107 pagep->lsn = argp->page_lsn; 00108 modified = 1; 00109 } 00110 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) { 00111 (void)CDB_memp_fput(mpf, meta, 0); 00112 goto out; 00113 } 00114 00115 /* Fix up the metadata page. */ 00116 modified = 0; 00117 cmp_n = CDB_log_compare(lsnp, &meta->alloc_lsn); 00118 cmp_p = CDB_log_compare(&meta->alloc_lsn, &argp->alloc_lsn); 00119 CHECK_LSN(op, cmp_p, &meta->alloc_lsn, &argp->alloc_lsn); 00120 if (cmp_p == 0 && DB_REDO(op)) { 00121 /* Need to redo update described. */ 00122 meta->alloc_lsn = *lsnp; 00123 if (CDB_log_compare(&LSN(meta), &argp->meta_lsn) == 0) 00124 LSN(meta) = *lsnp; 00125 meta->free = argp->next; 00126 modified = 1; 00127 } else if (cmp_n == 0 && DB_UNDO(op)) { 00128 /* Need to undo update described. */ 00129 meta->alloc_lsn = argp->alloc_lsn; 00130 if (CDB_log_compare(lsnp, &LSN(meta)) == 0) 00131 LSN(meta) = argp->meta_lsn; 00132 meta->free = argp->pgno; 00133 modified = 1; 00134 } 00135 if ((ret = CDB_memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0) 00136 goto out; 00137 /* 00138 * This could be the metapage from a subdb which is read from disk 00139 * to recover its creation. 00140 */ 00141 if (F_ISSET(file_dbp, DB_AM_SUBDB)) { 00142 switch (argp->type) { 00143 case P_HASHMETA: 00144 case P_BTREEMETA: 00145 case P_QAMMETA: 00146 file_dbp->sync(file_dbp, 0); 00147 } 00148 } 00149 00150 done: *lsnp = argp->prev_lsn; 00151 ret = 0; 00152 00153 out: REC_CLOSE; 00154 } 00155 00156 /* 00157 * CDB___bam_pg_free_recover -- 00158 * Recovery function for pg_free. 00159 * 00160 * PUBLIC: int CDB___bam_pg_free_recover 00161 * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); 00162 */ 00163 int 00164 CDB___bam_pg_free_recover(dbenv, dbtp, lsnp, op, info) 00165 DB_ENV *dbenv; 00166 DBT *dbtp; 00167 DB_LSN *lsnp; 00168 db_recops op; 00169 void *info; 00170 { 00171 __bam_pg_free_args *argp; 00172 DB *file_dbp; 00173 DBC *dbc; 00174 DBMETA *meta; 00175 DB_LSN copy_lsn; 00176 DB_MPOOLFILE *mpf; 00177 PAGE *pagep; 00178 db_pgno_t pgno; 00179 int cmp_n, cmp_p, modified, ret; 00180 00181 COMPQUIET(info, NULL); 00182 REC_PRINT(CDB___bam_pg_free_print); 00183 REC_INTRO(CDB___bam_pg_free_read, 1); 00184 00185 /* 00186 * Fix up the freed page. If we're redoing the operation we get the 00187 * page and explicitly discard its contents, then update its LSN. If 00188 * we're undoing the operation, we get the page and restore its header. 00189 */ 00190 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 00191 /* 00192 * We don't automatically create the page. The only way the 00193 * page might not exist is if the alloc never happened, and 00194 * the only way the alloc might never have happened is if we 00195 * are undoing, in which case there's no reason to create the 00196 * page. 00197 */ 00198 if (DB_UNDO(op)) 00199 goto done; 00200 (void)CDB___db_pgerr(file_dbp, argp->pgno); 00201 goto out; 00202 } 00203 modified = 0; 00204 CDB___ua_memcpy(©_lsn, &LSN(argp->header.data), sizeof(DB_LSN)); 00205 cmp_n = CDB_log_compare(lsnp, &LSN(pagep)); 00206 cmp_p = CDB_log_compare(&LSN(pagep), ©_lsn); 00207 CHECK_LSN(op, cmp_p, &LSN(pagep), ©_lsn); 00208 if (cmp_p == 0 && DB_REDO(op)) { 00209 /* Need to redo update described. */ 00210 P_INIT(pagep, file_dbp->pgsize, 00211 pagep->pgno, PGNO_INVALID, argp->next, 0, P_INVALID, 0); 00212 pagep->lsn = *lsnp; 00213 00214 modified = 1; 00215 } else if (cmp_n == 0 && DB_UNDO(op)) { 00216 /* Need to undo update described. */ 00217 memcpy(pagep, argp->header.data, argp->header.size); 00218 00219 modified = 1; 00220 } 00221 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 00222 goto out; 00223 00224 /* 00225 * Fix up the metadata page. If we're redoing or undoing the operation 00226 * we get the page and update its LSN and free pointer. 00227 */ 00228 pgno = PGNO_BASE_MD; 00229 if ((ret = CDB_memp_fget(mpf, &pgno, 0, &meta)) != 0) { 00230 /* The metadata page must always exist. */ 00231 (void)CDB___db_pgerr(file_dbp, pgno); 00232 goto out; 00233 } 00234 00235 modified = 0; 00236 cmp_n = CDB_log_compare(lsnp, &meta->alloc_lsn); 00237 cmp_p = CDB_log_compare(&meta->alloc_lsn, &argp->alloc_lsn); 00238 CHECK_LSN(op, cmp_p, &meta->alloc_lsn, &argp->alloc_lsn); 00239 if (cmp_p == 0 && DB_REDO(op)) { 00240 /* Need to redo update described. */ 00241 meta->free = argp->pgno; 00242 00243 meta->alloc_lsn = *lsnp; 00244 if (CDB_log_compare(&LSN(meta), &argp->meta_lsn) == 0) 00245 LSN(meta) = *lsnp; 00246 modified = 1; 00247 } else if (cmp_n == 0 && DB_UNDO(op)) { 00248 /* Need to undo update described. */ 00249 meta->free = argp->next; 00250 00251 meta->alloc_lsn = argp->alloc_lsn; 00252 if (CDB_log_compare(lsnp, &LSN(meta)) == 0) 00253 LSN(meta) = argp->meta_lsn; 00254 modified = 1; 00255 } 00256 if ((ret = CDB_memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0) 00257 goto out; 00258 00259 done: *lsnp = argp->prev_lsn; 00260 ret = 0; 00261 00262 out: REC_CLOSE; 00263 } 00264 00265 /* 00266 * CDB___bam_split_recover -- 00267 * Recovery function for split. 00268 * 00269 * PUBLIC: int CDB___bam_split_recover 00270 * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); 00271 */ 00272 int 00273 CDB___bam_split_recover(dbenv, dbtp, lsnp, op, info) 00274 DB_ENV *dbenv; 00275 DBT *dbtp; 00276 DB_LSN *lsnp; 00277 db_recops op; 00278 void *info; 00279 { 00280 __bam_split_args *argp; 00281 DB *file_dbp; 00282 DBC *dbc; 00283 DB_MPOOLFILE *mpf; 00284 PAGE *_lp, *lp, *np, *pp, *_rp, *rp, *sp; 00285 db_pgno_t pgno, root_pgno; 00286 u_int32_t ptype; 00287 int cmp, l_update, p_update, r_update, rc, ret, rootsplit, t_ret; 00288 00289 COMPQUIET(info, NULL); 00290 REC_PRINT(CDB___bam_split_print); 00291 00292 mpf = NULL; 00293 _lp = lp = np = pp = _rp = rp = NULL; 00294 sp = NULL; 00295 00296 REC_INTRO(CDB___bam_split_read, 1); 00297 00298 /* 00299 * There are two kinds of splits that we have to recover from. The 00300 * first is a root-page split, where the root page is split from a 00301 * leaf page into an internal page and two new leaf pages are created. 00302 * The second is where a page is split into two pages, and a new key 00303 * is inserted into the parent page. 00304 * 00305 * DBTs are not aligned in log records, so we need to copy the page 00306 * so that we can access fields within it throughout this routine. 00307 * Although we could hardcode the unaligned copies in this routine, 00308 * we will be calling into regular btree functions with this page, 00309 * so it's got to be aligned. Copying it into allocated memory is 00310 * the only way to guarantee this. 00311 */ 00312 if ((ret = CDB___os_malloc(dbenv, argp->pg.size, NULL, &sp)) != 0) 00313 goto out; 00314 memcpy(sp, argp->pg.data, argp->pg.size); 00315 00316 pgno = PGNO(sp); 00317 root_pgno = argp->root_pgno; 00318 rootsplit = pgno == root_pgno; 00319 if (CDB_memp_fget(mpf, &argp->left, 0, &lp) != 0) 00320 lp = NULL; 00321 if (CDB_memp_fget(mpf, &argp->right, 0, &rp) != 0) 00322 rp = NULL; 00323 00324 if (DB_REDO(op)) { 00325 l_update = r_update = p_update = 0; 00326 /* 00327 * Decide if we need to resplit the page. 00328 * 00329 * If this is a root split, then the root has to exist, it's 00330 * the page we're splitting and it gets modified. If this is 00331 * not a root split, then the left page has to exist, for the 00332 * same reason. 00333 */ 00334 if (rootsplit) { 00335 if ((ret = CDB_memp_fget(mpf, &pgno, 0, &pp)) != 0) { 00336 (void)CDB___db_pgerr(file_dbp, pgno); 00337 pp = NULL; 00338 goto out; 00339 } 00340 cmp = CDB_log_compare(&LSN(pp), &LSN(argp->pg.data)); 00341 CHECK_LSN(op, cmp, &LSN(pp), &LSN(argp->pg.data)); 00342 p_update = cmp == 0; 00343 } else if (lp == NULL) { 00344 (void)CDB___db_pgerr(file_dbp, argp->left); 00345 goto out; 00346 } 00347 00348 if (lp != NULL) { 00349 cmp = CDB_log_compare(&LSN(lp), &argp->llsn); 00350 CHECK_LSN(op, cmp, &LSN(lp), &argp->llsn); 00351 if (cmp == 0) 00352 l_update = 1; 00353 } else 00354 l_update = 1; 00355 00356 if (rp != NULL) { 00357 cmp = CDB_log_compare(&LSN(rp), &argp->rlsn); 00358 CHECK_LSN(op, cmp, &LSN(rp), &argp->rlsn); 00359 if (cmp == 0) 00360 r_update = 1; 00361 } else 00362 r_update = 1; 00363 if (!p_update && !l_update && !r_update) 00364 goto check_next; 00365 00366 /* Allocate and initialize new left/right child pages. */ 00367 if ((ret = 00368 CDB___os_malloc(dbenv, file_dbp->pgsize, NULL, &_lp)) != 0 00369 || (ret = 00370 CDB___os_malloc(dbenv, file_dbp->pgsize, NULL, &_rp)) != 0) 00371 goto out; 00372 if (rootsplit) { 00373 P_INIT(_lp, file_dbp->pgsize, argp->left, 00374 PGNO_INVALID, 00375 ISINTERNAL(sp) ? PGNO_INVALID : argp->right, 00376 LEVEL(sp), TYPE(sp), TAGS(sp)); 00377 P_INIT(_rp, file_dbp->pgsize, argp->right, 00378 ISINTERNAL(sp) ? PGNO_INVALID : argp->left, 00379 PGNO_INVALID, LEVEL(sp), TYPE(sp), TAGS(sp)); 00380 } else { 00381 P_INIT(_lp, file_dbp->pgsize, PGNO(sp), 00382 ISINTERNAL(sp) ? PGNO_INVALID : PREV_PGNO(sp), 00383 ISINTERNAL(sp) ? PGNO_INVALID : argp->right, 00384 LEVEL(sp), TYPE(sp), TAGS(sp)); 00385 P_INIT(_rp, file_dbp->pgsize, argp->right, 00386 ISINTERNAL(sp) ? PGNO_INVALID : sp->pgno, 00387 ISINTERNAL(sp) ? PGNO_INVALID : NEXT_PGNO(sp), 00388 LEVEL(sp), TYPE(sp), TAGS(sp)); 00389 } 00390 00391 /* Split the page. */ 00392 if ((ret = CDB___bam_copy(file_dbp, sp, _lp, 0, argp->indx)) != 0 || 00393 (ret = CDB___bam_copy(file_dbp, sp, _rp, argp->indx, 00394 NUM_ENT(sp))) != 0) 00395 goto out; 00396 00397 /* If the left child is wrong, update it. */ 00398 if (lp == NULL && (ret = 00399 CDB_memp_fget(mpf, &argp->left, DB_MPOOL_CREATE, &lp)) != 0) { 00400 (void)CDB___db_pgerr(file_dbp, argp->left); 00401 lp = NULL; 00402 goto out; 00403 } 00404 if (l_update) { 00405 memcpy(lp, _lp, file_dbp->pgsize); 00406 lp->lsn = *lsnp; 00407 if ((ret = CDB_memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0) 00408 goto out; 00409 lp = NULL; 00410 } 00411 00412 /* If the right child is wrong, update it. */ 00413 if (rp == NULL && (ret = CDB_memp_fget(mpf, 00414 &argp->right, DB_MPOOL_CREATE, &rp)) != 0) { 00415 (void)CDB___db_pgerr(file_dbp, argp->right); 00416 rp = NULL; 00417 goto out; 00418 } 00419 if (r_update) { 00420 memcpy(rp, _rp, file_dbp->pgsize); 00421 rp->lsn = *lsnp; 00422 if ((ret = CDB_memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0) 00423 goto out; 00424 rp = NULL; 00425 } 00426 00427 /* 00428 * If the parent page is wrong, update it. This is of interest 00429 * only if it was a root split, since root splits create parent 00430 * pages. All other splits modify a parent page, but those are 00431 * separately logged and recovered. 00432 */ 00433 if (rootsplit && p_update) { 00434 if (IS_BTREE_PAGE(sp)) { 00435 ptype = P_IBTREE; 00436 rc = argp->opflags & SPL_NRECS ? 1 : 0; 00437 } else { 00438 ptype = P_IRECNO; 00439 rc = 1; 00440 } 00441 00442 P_INIT(pp, file_dbp->pgsize, root_pgno, 00443 PGNO_INVALID, PGNO_INVALID, _lp->level + 1, ptype, 0); 00444 RE_NREC_SET(pp, 00445 rc ? CDB___bam_total(_lp) + CDB___bam_total(_rp) : 0); 00446 00447 pp->lsn = *lsnp; 00448 if ((ret = CDB_memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0) 00449 goto out; 00450 pp = NULL; 00451 } 00452 00453 check_next: /* 00454 * Finally, redo the next-page link if necessary. This is of 00455 * interest only if it wasn't a root split -- inserting a new 00456 * page in the tree requires that any following page have its 00457 * previous-page pointer updated to our new page. The next 00458 * page must exist because we're redoing the operation. 00459 */ 00460 if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) { 00461 if ((ret = CDB_memp_fget(mpf, &argp->npgno, 0, &np)) != 0) { 00462 (void)CDB___db_pgerr(file_dbp, argp->npgno); 00463 np = NULL; 00464 goto out; 00465 } 00466 cmp = CDB_log_compare(&LSN(np), &argp->nlsn); 00467 CHECK_LSN(op, cmp, &LSN(np), &argp->nlsn); 00468 if (cmp == 0) { 00469 PREV_PGNO(np) = argp->right; 00470 np->lsn = *lsnp; 00471 if ((ret = 00472 CDB_memp_fput(mpf, np, DB_MPOOL_DIRTY)) != 0) 00473 goto out; 00474 np = NULL; 00475 } 00476 } 00477 } else { 00478 /* 00479 * If the split page is wrong, replace its contents with the 00480 * logged page contents. If the page doesn't exist, it means 00481 * that the create of the page never happened, nor did any of 00482 * the adds onto the page that caused the split, and there's 00483 * really no undo-ing to be done. 00484 */ 00485 if ((ret = CDB_memp_fget(mpf, &pgno, 0, &pp)) != 0) { 00486 pp = NULL; 00487 goto lrundo; 00488 } 00489 if (CDB_log_compare(lsnp, &LSN(pp)) == 0) { 00490 memcpy(pp, argp->pg.data, argp->pg.size); 00491 if ((ret = CDB_memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0) 00492 goto out; 00493 pp = NULL; 00494 } 00495 00496 /* 00497 * If it's a root split and the left child ever existed, update 00498 * its LSN. (If it's not a root split, we've updated the left 00499 * page already -- it's the same as the split page.) If the 00500 * right child ever existed, root split or not, update its LSN. 00501 * The undo of the page allocation(s) will restore them to the 00502 * free list. 00503 */ 00504 lrundo: if ((rootsplit && lp != NULL) || rp != NULL) { 00505 if (rootsplit && lp != NULL && 00506 CDB_log_compare(lsnp, &LSN(lp)) == 0) { 00507 lp->lsn = argp->llsn; 00508 if ((ret = 00509 CDB_memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0) 00510 goto out; 00511 lp = NULL; 00512 } 00513 if (rp != NULL && 00514 CDB_log_compare(lsnp, &LSN(rp)) == 0) { 00515 rp->lsn = argp->rlsn; 00516 if ((ret = 00517 CDB_memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0) 00518 goto out; 00519 rp = NULL; 00520 } 00521 } 00522 00523 /* 00524 * Finally, undo the next-page link if necessary. This is of 00525 * interest only if it wasn't a root split -- inserting a new 00526 * page in the tree requires that any following page have its 00527 * previous-page pointer updated to our new page. Since it's 00528 * possible that the next-page never existed, we ignore it as 00529 * if there's nothing to undo. 00530 */ 00531 if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) { 00532 if ((ret = CDB_memp_fget(mpf, &argp->npgno, 0, &np)) != 0) { 00533 np = NULL; 00534 goto done; 00535 } 00536 if (CDB_log_compare(lsnp, &LSN(np)) == 0) { 00537 PREV_PGNO(np) = argp->left; 00538 np->lsn = argp->nlsn; 00539 if (CDB_memp_fput(mpf, np, DB_MPOOL_DIRTY)) 00540 goto out; 00541 np = NULL; 00542 } 00543 } 00544 } 00545 00546 done: *lsnp = argp->prev_lsn; 00547 ret = 0; 00548 00549 out: /* Free any pages that weren't dirtied. */ 00550 if (pp != NULL && (t_ret = CDB_memp_fput(mpf, pp, 0)) != 0 && ret == 0) 00551 ret = t_ret; 00552 if (lp != NULL && (t_ret = CDB_memp_fput(mpf, lp, 0)) != 0 && ret == 0) 00553 ret = t_ret; 00554 if (np != NULL && (t_ret = CDB_memp_fput(mpf, np, 0)) != 0 && ret == 0) 00555 ret = t_ret; 00556 if (rp != NULL && (t_ret = CDB_memp_fput(mpf, rp, 0)) != 0 && ret == 0) 00557 ret = t_ret; 00558 00559 /* Free any allocated space. */ 00560 if (_lp != NULL) 00561 CDB___os_free(_lp, file_dbp->pgsize); 00562 if (_rp != NULL) 00563 CDB___os_free(_rp, file_dbp->pgsize); 00564 if (sp != NULL) 00565 CDB___os_free(sp, argp->pg.size); 00566 00567 REC_CLOSE; 00568 } 00569 00570 /* 00571 * CDB___bam_rsplit_recover -- 00572 * Recovery function for a reverse split. 00573 * 00574 * PUBLIC: int CDB___bam_rsplit_recover 00575 * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); 00576 */ 00577 int 00578 CDB___bam_rsplit_recover(dbenv, dbtp, lsnp, op, info) 00579 DB_ENV *dbenv; 00580 DBT *dbtp; 00581 DB_LSN *lsnp; 00582 db_recops op; 00583 void *info; 00584 { 00585 __bam_rsplit_args *argp; 00586 DB *file_dbp; 00587 DBC *dbc; 00588 DB_LSN copy_lsn; 00589 DB_MPOOLFILE *mpf; 00590 PAGE *pagep; 00591 db_pgno_t pgno, root_pgno; 00592 int cmp_n, cmp_p, modified, ret; 00593 00594 COMPQUIET(info, NULL); 00595 REC_PRINT(CDB___bam_rsplit_print); 00596 REC_INTRO(CDB___bam_rsplit_read, 1); 00597 00598 /* Fix the root page. */ 00599 pgno = root_pgno = argp->root_pgno; 00600 if ((ret = CDB_memp_fget(mpf, &pgno, 0, &pagep)) != 0) { 00601 /* The root page must always exist if we are going forward. */ 00602 if (DB_REDO(op)) { 00603 CDB___db_pgerr(file_dbp, pgno); 00604 goto out; 00605 } 00606 /* This must be the root of an OPD tree. */ 00607 DB_ASSERT(root_pgno != 00608 ((BTREE *)file_dbp->bt_internal)->bt_root); 00609 ret = 0; 00610 goto done; 00611 } 00612 modified = 0; 00613 cmp_n = CDB_log_compare(lsnp, &LSN(pagep)); 00614 cmp_p = CDB_log_compare(&LSN(pagep), &argp->rootlsn); 00615 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->rootlsn); 00616 if (cmp_p == 0 && DB_REDO(op)) { 00617 /* Need to redo update described. */ 00618 memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size); 00619 pagep->pgno = root_pgno; 00620 pagep->lsn = *lsnp; 00621 modified = 1; 00622 } else if (cmp_n == 0 && DB_UNDO(op)) { 00623 /* Need to undo update described. */ 00624 P_INIT(pagep, file_dbp->pgsize, root_pgno, 00625 argp->nrec, PGNO_INVALID, pagep->level + 1, 00626 IS_BTREE_PAGE(pagep) ? P_IBTREE : P_IRECNO, 00627 TAGS(pagep)); 00628 if ((ret = CDB___db_pitem(dbc, pagep, 0, 00629 argp->rootent.size, &argp->rootent, NULL)) != 0) 00630 goto out; 00631 pagep->lsn = argp->rootlsn; 00632 modified = 1; 00633 } 00634 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 00635 goto out; 00636 00637 /* 00638 * Fix the page copied over the root page. It's possible that the 00639 * page never made it to disk, so if we're undo-ing and the page 00640 * doesn't exist, it's okay and there's nothing further to do. 00641 */ 00642 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 00643 if (DB_UNDO(op)) 00644 goto done; 00645 (void)CDB___db_pgerr(file_dbp, argp->pgno); 00646 goto out; 00647 } 00648 modified = 0; 00649 CDB___ua_memcpy(©_lsn, &LSN(argp->pgdbt.data), sizeof(DB_LSN)); 00650 cmp_n = CDB_log_compare(lsnp, &LSN(pagep)); 00651 cmp_p = CDB_log_compare(&LSN(pagep), ©_lsn); 00652 CHECK_LSN(op, cmp_p, &LSN(pagep), ©_lsn); 00653 if (cmp_p == 0 && DB_REDO(op)) { 00654 /* Need to redo update described. */ 00655 pagep->lsn = *lsnp; 00656 modified = 1; 00657 } else if (cmp_n == 0 && DB_UNDO(op)) { 00658 /* Need to undo update described. */ 00659 memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size); 00660 modified = 1; 00661 } 00662 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 00663 goto out; 00664 00665 done: *lsnp = argp->prev_lsn; 00666 ret = 0; 00667 00668 out: REC_CLOSE; 00669 } 00670 00671 /* 00672 * CDB___bam_adj_recover -- 00673 * Recovery function for adj. 00674 * 00675 * PUBLIC: int CDB___bam_adj_recover 00676 * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); 00677 */ 00678 int 00679 CDB___bam_adj_recover(dbenv, dbtp, lsnp, op, info) 00680 DB_ENV *dbenv; 00681 DBT *dbtp; 00682 DB_LSN *lsnp; 00683 db_recops op; 00684 void *info; 00685 { 00686 __bam_adj_args *argp; 00687 DB *file_dbp; 00688 DBC *dbc; 00689 DB_MPOOLFILE *mpf; 00690 PAGE *pagep; 00691 int cmp_n, cmp_p, modified, ret; 00692 00693 COMPQUIET(info, NULL); 00694 REC_PRINT(CDB___bam_adj_print); 00695 REC_INTRO(CDB___bam_adj_read, 1); 00696 00697 /* Get the page; if it never existed and we're undoing, we're done. */ 00698 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 00699 if (DB_UNDO(op)) 00700 goto done; 00701 (void)CDB___db_pgerr(file_dbp, argp->pgno); 00702 goto out; 00703 } 00704 00705 modified = 0; 00706 cmp_n = CDB_log_compare(lsnp, &LSN(pagep)); 00707 cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn); 00708 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn); 00709 if (cmp_p == 0 && DB_REDO(op)) { 00710 /* Need to redo update described. */ 00711 if ((ret = CDB___bam_adjindx(dbc, 00712 pagep, argp->indx, argp->indx_copy, argp->is_insert)) != 0) 00713 goto err; 00714 00715 LSN(pagep) = *lsnp; 00716 modified = 1; 00717 } else if (cmp_n == 0 && DB_UNDO(op)) { 00718 /* Need to undo update described. */ 00719 if ((ret = CDB___bam_adjindx(dbc, 00720 pagep, argp->indx, argp->indx_copy, !argp->is_insert)) != 0) 00721 goto err; 00722 00723 LSN(pagep) = argp->lsn; 00724 modified = 1; 00725 } 00726 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 00727 goto out; 00728 00729 done: *lsnp = argp->prev_lsn; 00730 ret = 0; 00731 00732 if (0) { 00733 err: (void)CDB_memp_fput(mpf, pagep, 0); 00734 } 00735 out: REC_CLOSE; 00736 } 00737 00738 /* 00739 * CDB___bam_cadjust_recover -- 00740 * Recovery function for the adjust of a count change in an internal 00741 * page. 00742 * 00743 * PUBLIC: int CDB___bam_cadjust_recover 00744 * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); 00745 */ 00746 int 00747 CDB___bam_cadjust_recover(dbenv, dbtp, lsnp, op, info) 00748 DB_ENV *dbenv; 00749 DBT *dbtp; 00750 DB_LSN *lsnp; 00751 db_recops op; 00752 void *info; 00753 { 00754 __bam_cadjust_args *argp; 00755 DB *file_dbp; 00756 DBC *dbc; 00757 DB_MPOOLFILE *mpf; 00758 PAGE *pagep; 00759 int cmp_n, cmp_p, modified, ret; 00760 00761 COMPQUIET(info, NULL); 00762 REC_PRINT(CDB___bam_cadjust_print); 00763 REC_INTRO(CDB___bam_cadjust_read, 1); 00764 00765 /* Get the page; if it never existed and we're undoing, we're done. */ 00766 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 00767 if (DB_UNDO(op)) 00768 goto done; 00769 (void)CDB___db_pgerr(file_dbp, argp->pgno); 00770 goto out; 00771 } 00772 00773 modified = 0; 00774 cmp_n = CDB_log_compare(lsnp, &LSN(pagep)); 00775 cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn); 00776 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn); 00777 if (cmp_p == 0 && DB_REDO(op)) { 00778 /* Need to redo update described. */ 00779 if (IS_BTREE_PAGE(pagep)) { 00780 GET_BINTERNAL(pagep, argp->indx)->nrecs += argp->adjust; 00781 if (argp->opflags & CAD_UPDATEROOT) 00782 RE_NREC_ADJ(pagep, argp->adjust); 00783 } else { 00784 GET_RINTERNAL(pagep, argp->indx)->nrecs += argp->adjust; 00785 if (argp->opflags & CAD_UPDATEROOT) 00786 RE_NREC_ADJ(pagep, argp->adjust); 00787 } 00788 00789 LSN(pagep) = *lsnp; 00790 modified = 1; 00791 } else if (cmp_n == 0 && DB_UNDO(op)) { 00792 /* Need to undo update described. */ 00793 if (IS_BTREE_PAGE(pagep)) { 00794 GET_BINTERNAL(pagep, argp->indx)->nrecs -= argp->adjust; 00795 if (argp->opflags & CAD_UPDATEROOT) 00796 RE_NREC_ADJ(pagep, argp->adjust); 00797 } else { 00798 GET_RINTERNAL(pagep, argp->indx)->nrecs -= argp->adjust; 00799 if (argp->opflags & CAD_UPDATEROOT) 00800 RE_NREC_ADJ(pagep, -(argp->adjust)); 00801 } 00802 LSN(pagep) = argp->lsn; 00803 modified = 1; 00804 } 00805 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 00806 goto out; 00807 00808 done: *lsnp = argp->prev_lsn; 00809 ret = 0; 00810 00811 out: REC_CLOSE; 00812 } 00813 00814 /* 00815 * CDB___bam_cdel_recover -- 00816 * Recovery function for the intent-to-delete of a cursor record. 00817 * 00818 * PUBLIC: int CDB___bam_cdel_recover 00819 * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); 00820 */ 00821 int 00822 CDB___bam_cdel_recover(dbenv, dbtp, lsnp, op, info) 00823 DB_ENV *dbenv; 00824 DBT *dbtp; 00825 DB_LSN *lsnp; 00826 db_recops op; 00827 void *info; 00828 { 00829 __bam_cdel_args *argp; 00830 DB *file_dbp; 00831 DBC *dbc; 00832 DB_MPOOLFILE *mpf; 00833 PAGE *pagep; 00834 u_int32_t indx; 00835 int cmp_n, cmp_p, modified, ret; 00836 00837 COMPQUIET(info, NULL); 00838 REC_PRINT(CDB___bam_cdel_print); 00839 REC_INTRO(CDB___bam_cdel_read, 1); 00840 00841 /* Get the page; if it never existed and we're undoing, we're done. */ 00842 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 00843 if (DB_UNDO(op)) 00844 goto done; 00845 (void)CDB___db_pgerr(file_dbp, argp->pgno); 00846 goto out; 00847 } 00848 00849 modified = 0; 00850 cmp_n = CDB_log_compare(lsnp, &LSN(pagep)); 00851 cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn); 00852 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn); 00853 if (cmp_p == 0 && DB_REDO(op)) { 00854 /* Need to redo update described. */ 00855 indx = argp->indx + (TYPE(pagep) == P_LBTREE ? O_INDX : 0); 00856 B_DSET(GET_BKEYDATA(pagep, indx)->type); 00857 00858 LSN(pagep) = *lsnp; 00859 modified = 1; 00860 } else if (cmp_n == 0 && DB_UNDO(op)) { 00861 /* Need to undo update described. */ 00862 indx = argp->indx + (TYPE(pagep) == P_LBTREE ? O_INDX : 0); 00863 B_DCLR(GET_BKEYDATA(pagep, indx)->type); 00864 00865 LSN(pagep) = argp->lsn; 00866 modified = 1; 00867 } 00868 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 00869 goto out; 00870 00871 done: *lsnp = argp->prev_lsn; 00872 ret = 0; 00873 00874 out: REC_CLOSE; 00875 } 00876 00877 /* 00878 * CDB___bam_repl_recover -- 00879 * Recovery function for page item replacement. 00880 * 00881 * PUBLIC: int CDB___bam_repl_recover 00882 * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); 00883 */ 00884 int 00885 CDB___bam_repl_recover(dbenv, dbtp, lsnp, op, info) 00886 DB_ENV *dbenv; 00887 DBT *dbtp; 00888 DB_LSN *lsnp; 00889 db_recops op; 00890 void *info; 00891 { 00892 __bam_repl_args *argp; 00893 BKEYDATA *bk; 00894 DB *file_dbp; 00895 DBC *dbc; 00896 DBT dbt; 00897 DB_MPOOLFILE *mpf; 00898 PAGE *pagep; 00899 int cmp_n, cmp_p, modified, ret; 00900 u_int8_t *p; 00901 00902 COMPQUIET(info, NULL); 00903 REC_PRINT(CDB___bam_repl_print); 00904 REC_INTRO(CDB___bam_repl_read, 1); 00905 00906 /* Get the page; if it never existed and we're undoing, we're done. */ 00907 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 00908 if (DB_UNDO(op)) 00909 goto done; 00910 (void)CDB___db_pgerr(file_dbp, argp->pgno); 00911 goto out; 00912 } 00913 bk = GET_BKEYDATA(pagep, argp->indx); 00914 00915 modified = 0; 00916 cmp_n = CDB_log_compare(lsnp, &LSN(pagep)); 00917 cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn); 00918 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn); 00919 if (cmp_p == 0 && DB_REDO(op)) { 00920 /* 00921 * Need to redo update described. 00922 * 00923 * Re-build the replacement item. 00924 */ 00925 memset(&dbt, 0, sizeof(dbt)); 00926 dbt.size = argp->prefix + argp->suffix + argp->repl.size; 00927 if ((ret = CDB___os_malloc(dbenv, dbt.size, NULL, &dbt.data)) != 0) 00928 goto err; 00929 p = dbt.data; 00930 memcpy(p, bk->data, argp->prefix); 00931 p += argp->prefix; 00932 memcpy(p, argp->repl.data, argp->repl.size); 00933 p += argp->repl.size; 00934 memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix); 00935 00936 ret = CDB___bam_ritem(dbc, pagep, argp->indx, &dbt); 00937 CDB___os_free(dbt.data, dbt.size); 00938 if (ret != 0) 00939 goto err; 00940 00941 LSN(pagep) = *lsnp; 00942 modified = 1; 00943 } else if (cmp_n == 0 && DB_UNDO(op)) { 00944 /* 00945 * Need to undo update described. 00946 * 00947 * Re-build the original item. 00948 */ 00949 memset(&dbt, 0, sizeof(dbt)); 00950 dbt.size = argp->prefix + argp->suffix + argp->orig.size; 00951 if ((ret = CDB___os_malloc(dbenv, dbt.size, NULL, &dbt.data)) != 0) 00952 goto err; 00953 p = dbt.data; 00954 memcpy(p, bk->data, argp->prefix); 00955 p += argp->prefix; 00956 memcpy(p, argp->orig.data, argp->orig.size); 00957 p += argp->orig.size; 00958 memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix); 00959 00960 ret = CDB___bam_ritem(dbc, pagep, argp->indx, &dbt); 00961 CDB___os_free(dbt.data, dbt.size); 00962 if (ret != 0) 00963 goto err; 00964 00965 /* Reset the deleted flag, if necessary. */ 00966 if (argp->isdeleted) 00967 B_DSET(GET_BKEYDATA(pagep, argp->indx)->type); 00968 00969 LSN(pagep) = argp->lsn; 00970 modified = 1; 00971 } 00972 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 00973 goto out; 00974 00975 done: *lsnp = argp->prev_lsn; 00976 ret = 0; 00977 00978 if (0) { 00979 err: (void)CDB_memp_fput(mpf, pagep, 0); 00980 } 00981 out: REC_CLOSE; 00982 } 00983 00984 /* 00985 * CDB___bam_root_recover -- 00986 * Recovery function for setting the root page on the meta-data page. 00987 * 00988 * PUBLIC: int CDB___bam_root_recover 00989 * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); 00990 */ 00991 int 00992 CDB___bam_root_recover(dbenv, dbtp, lsnp, op, info) 00993 DB_ENV *dbenv; 00994 DBT *dbtp; 00995 DB_LSN *lsnp; 00996 db_recops op; 00997 void *info; 00998 { 00999 __bam_root_args *argp; 01000 BTMETA *meta; 01001 DB *file_dbp; 01002 DBC *dbc; 01003 DB_MPOOLFILE *mpf; 01004 int cmp_n, cmp_p, modified, ret; 01005 01006 COMPQUIET(info, NULL); 01007 REC_PRINT(CDB___bam_root_print); 01008 REC_INTRO(CDB___bam_root_read, 0); 01009 01010 if ((ret = CDB_memp_fget(mpf, &argp->meta_pgno, 0, &meta)) != 0) { 01011 /* The metadata page must always exist on redo. */ 01012 if (DB_REDO(op)) { 01013 (void)CDB___db_pgerr(file_dbp, argp->meta_pgno); 01014 goto out; 01015 } else 01016 goto done; 01017 } 01018 01019 modified = 0; 01020 cmp_n = CDB_log_compare(lsnp, &LSN(meta)); 01021 cmp_p = CDB_log_compare(&LSN(meta), &argp->meta_lsn); 01022 CHECK_LSN(op, cmp_p, &LSN(meta), &argp->meta_lsn); 01023 if (cmp_p == 0 && DB_REDO(op)) { 01024 /* Need to redo update described. */ 01025 meta->root = argp->root_pgno; 01026 meta->dbmeta.lsn = *lsnp; 01027 ((BTREE *)file_dbp->bt_internal)->bt_root = meta->root; 01028 modified = 1; 01029 } else if (cmp_n == 0 && DB_UNDO(op)) { 01030 /* Nothing to undo except lsn. */ 01031 meta->dbmeta.lsn = argp->meta_lsn; 01032 modified = 1; 01033 } 01034 if ((ret = CDB_memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0) 01035 goto out; 01036 01037 done: *lsnp = argp->prev_lsn; 01038 ret = 0; 01039 01040 out: REC_CLOSE; 01041 }