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: db__rec_8c-source.html,v 1.1 2008年06月08日 10:18:14 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 "log.h" 00023 #include "hash.h" 00024 00025 /* 00026 * PUBLIC: int CDB___db_addrem_recover 00027 * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); 00028 * 00029 * This log message is generated whenever we add or remove a duplicate 00030 * to/from a duplicate page. On recover, we just do the opposite. 00031 */ 00032 int 00033 CDB___db_addrem_recover(dbenv, dbtp, lsnp, op, info) 00034 DB_ENV *dbenv; 00035 DBT *dbtp; 00036 DB_LSN *lsnp; 00037 db_recops op; 00038 void *info; 00039 { 00040 __db_addrem_args *argp; 00041 DB *file_dbp; 00042 DBC *dbc; 00043 DB_MPOOLFILE *mpf; 00044 PAGE *pagep; 00045 u_int32_t change; 00046 int cmp_n, cmp_p, ret; 00047 00048 COMPQUIET(info, NULL); 00049 REC_PRINT(CDB___db_addrem_print); 00050 REC_INTRO(CDB___db_addrem_read, 1); 00051 00052 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 00053 if (DB_UNDO(op)) { 00054 /* 00055 * We are undoing and the page doesn't exist. That 00056 * is equivalent to having a pagelsn of 0, so we 00057 * would not have to undo anything. In this case, 00058 * don't bother creating a page. 00059 */ 00060 goto done; 00061 } else 00062 if ((ret = CDB_memp_fget(mpf, 00063 &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) 00064 goto out; 00065 } 00066 00067 cmp_n = CDB_log_compare(lsnp, &LSN(pagep)); 00068 cmp_p = CDB_log_compare(&LSN(pagep), &argp->pagelsn); 00069 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn); 00070 change = 0; 00071 if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_DUP) || 00072 (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_REM_DUP)) { 00073 00074 /* Need to redo an add, or undo a delete. */ 00075 if ((ret = CDB___db_pitem(dbc, pagep, argp->indx, argp->nbytes, 00076 argp->hdr.size == 0 ? NULL : &argp->hdr, 00077 argp->dbt.size == 0 ? NULL : &argp->dbt)) != 0) 00078 goto out; 00079 00080 change = DB_MPOOL_DIRTY; 00081 00082 } else if ((cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_ADD_DUP) || 00083 (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_REM_DUP)) { 00084 /* Need to undo an add, or redo a delete. */ 00085 if ((ret = CDB___db_ditem(dbc, 00086 pagep, argp->indx, argp->nbytes)) != 0) 00087 goto out; 00088 change = DB_MPOOL_DIRTY; 00089 } 00090 00091 if (change) { 00092 if (DB_REDO(op)) 00093 LSN(pagep) = *lsnp; 00094 else 00095 LSN(pagep) = argp->pagelsn; 00096 } 00097 00098 if ((ret = CDB_memp_fput(mpf, pagep, change)) != 0) 00099 goto out; 00100 00101 done: *lsnp = argp->prev_lsn; 00102 ret = 0; 00103 00104 out: REC_CLOSE; 00105 } 00106 00107 /* 00108 * PUBLIC: int CDB___db_big_recover 00109 * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); 00110 */ 00111 int 00112 CDB___db_big_recover(dbenv, dbtp, lsnp, op, info) 00113 DB_ENV *dbenv; 00114 DBT *dbtp; 00115 DB_LSN *lsnp; 00116 db_recops op; 00117 void *info; 00118 { 00119 __db_big_args *argp; 00120 DB *file_dbp; 00121 DBC *dbc; 00122 DB_MPOOLFILE *mpf; 00123 PAGE *pagep; 00124 u_int32_t change; 00125 int cmp_n, cmp_p, ret; 00126 00127 COMPQUIET(info, NULL); 00128 REC_PRINT(CDB___db_big_print); 00129 REC_INTRO(CDB___db_big_read, 1); 00130 00131 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 00132 if (DB_UNDO(op)) { 00133 /* 00134 * We are undoing and the page doesn't exist. That 00135 * is equivalent to having a pagelsn of 0, so we 00136 * would not have to undo anything. In this case, 00137 * don't bother creating a page. 00138 */ 00139 ret = 0; 00140 goto ppage; 00141 } else 00142 if ((ret = CDB_memp_fget(mpf, 00143 &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) 00144 goto out; 00145 } 00146 00147 /* 00148 * There are three pages we need to check. The one on which we are 00149 * adding data, the previous one whose next_pointer may have 00150 * been updated, and the next one whose prev_pointer may have 00151 * been updated. 00152 */ 00153 cmp_n = CDB_log_compare(lsnp, &LSN(pagep)); 00154 cmp_p = CDB_log_compare(&LSN(pagep), &argp->pagelsn); 00155 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn); 00156 change = 0; 00157 if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_BIG) || 00158 (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_REM_BIG)) { 00159 /* We are either redo-ing an add, or undoing a delete. */ 00160 P_INIT(pagep, file_dbp->pgsize, argp->pgno, argp->prev_pgno, 00161 argp->next_pgno, 0, P_OVERFLOW, TAGS(argp)); 00162 OV_LEN(pagep) = argp->dbt.size; 00163 OV_REF(pagep) = 1; 00164 memcpy((u_int8_t *)pagep + P_OVERHEAD, argp->dbt.data, 00165 argp->dbt.size); 00166 PREV_PGNO(pagep) = argp->prev_pgno; 00167 change = DB_MPOOL_DIRTY; 00168 } else if ((cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_ADD_BIG) || 00169 (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_REM_BIG)) { 00170 /* 00171 * We are either undo-ing an add or redo-ing a delete. 00172 * The page is about to be reclaimed in either case, so 00173 * there really isn't anything to do here. 00174 */ 00175 change = DB_MPOOL_DIRTY; 00176 } 00177 if (change) 00178 LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn; 00179 00180 if ((ret = CDB_memp_fput(mpf, pagep, change)) != 0) 00181 goto out; 00182 00183 /* Now check the previous page. */ 00184 ppage: if (argp->prev_pgno != PGNO_INVALID) { 00185 change = 0; 00186 if ((ret = CDB_memp_fget(mpf, &argp->prev_pgno, 0, &pagep)) != 0) { 00187 if (DB_UNDO(op)) { 00188 /* 00189 * We are undoing and the page doesn't exist. 00190 * That is equivalent to having a pagelsn of 0, 00191 * so we would not have to undo anything. In 00192 * this case, don't bother creating a page. 00193 */ 00194 *lsnp = argp->prev_lsn; 00195 ret = 0; 00196 goto npage; 00197 } else 00198 if ((ret = CDB_memp_fget(mpf, &argp->prev_pgno, 00199 DB_MPOOL_CREATE, &pagep)) != 0) 00200 goto out; 00201 } 00202 00203 cmp_n = CDB_log_compare(lsnp, &LSN(pagep)); 00204 cmp_p = CDB_log_compare(&LSN(pagep), &argp->prevlsn); 00205 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->prevlsn); 00206 00207 if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_BIG) || 00208 (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_REM_BIG)) { 00209 /* Redo add, undo delete. */ 00210 NEXT_PGNO(pagep) = argp->pgno; 00211 change = DB_MPOOL_DIRTY; 00212 } else if ((cmp_n == 0 && 00213 DB_UNDO(op) && argp->opcode == DB_ADD_BIG) || 00214 (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_REM_BIG)) { 00215 /* Redo delete, undo add. */ 00216 NEXT_PGNO(pagep) = argp->next_pgno; 00217 change = DB_MPOOL_DIRTY; 00218 } 00219 if (change) 00220 LSN(pagep) = DB_REDO(op) ? *lsnp : argp->prevlsn; 00221 if ((ret = CDB_memp_fput(mpf, pagep, change)) != 0) 00222 goto out; 00223 } 00224 00225 /* Now check the next page. Can only be set on a delete. */ 00226 npage: if (argp->next_pgno != PGNO_INVALID) { 00227 change = 0; 00228 if ((ret = CDB_memp_fget(mpf, &argp->next_pgno, 0, &pagep)) != 0) { 00229 if (DB_UNDO(op)) { 00230 /* 00231 * We are undoing and the page doesn't exist. 00232 * That is equivalent to having a pagelsn of 0, 00233 * so we would not have to undo anything. In 00234 * this case, don't bother creating a page. 00235 */ 00236 goto done; 00237 } else 00238 if ((ret = CDB_memp_fget(mpf, &argp->next_pgno, 00239 DB_MPOOL_CREATE, &pagep)) != 0) 00240 goto out; 00241 } 00242 00243 cmp_n = CDB_log_compare(lsnp, &LSN(pagep)); 00244 cmp_p = CDB_log_compare(&LSN(pagep), &argp->nextlsn); 00245 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nextlsn); 00246 if (cmp_p == 0 && DB_REDO(op)) { 00247 PREV_PGNO(pagep) = PGNO_INVALID; 00248 change = DB_MPOOL_DIRTY; 00249 } else if (cmp_n == 0 && DB_UNDO(op)) { 00250 PREV_PGNO(pagep) = argp->pgno; 00251 change = DB_MPOOL_DIRTY; 00252 } 00253 if (change) 00254 LSN(pagep) = DB_REDO(op) ? *lsnp : argp->nextlsn; 00255 if ((ret = CDB_memp_fput(mpf, pagep, change)) != 0) 00256 goto out; 00257 } 00258 00259 done: *lsnp = argp->prev_lsn; 00260 ret = 0; 00261 00262 out: REC_CLOSE; 00263 } 00264 00265 /* 00266 * CDB___db_ovref_recover -- 00267 * Recovery function for CDB___db_ovref(). 00268 * 00269 * PUBLIC: int CDB___db_ovref_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); 00270 */ 00271 int 00272 CDB___db_ovref_recover(dbenv, dbtp, lsnp, op, info) 00273 DB_ENV *dbenv; 00274 DBT *dbtp; 00275 DB_LSN *lsnp; 00276 db_recops op; 00277 void *info; 00278 { 00279 __db_ovref_args *argp; 00280 DB *file_dbp; 00281 DBC *dbc; 00282 DB_MPOOLFILE *mpf; 00283 PAGE *pagep; 00284 int cmp, modified, ret; 00285 00286 COMPQUIET(info, NULL); 00287 REC_PRINT(CDB___db_ovref_print); 00288 REC_INTRO(CDB___db_ovref_read, 1); 00289 00290 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 00291 (void)CDB___db_pgerr(file_dbp, argp->pgno); 00292 goto out; 00293 } 00294 00295 modified = 0; 00296 cmp = CDB_log_compare(&LSN(pagep), &argp->lsn); 00297 CHECK_LSN(op, cmp, &LSN(pagep), &argp->lsn); 00298 if (cmp == 0 && DB_REDO(op)) { 00299 /* Need to redo update described. */ 00300 OV_REF(pagep) += argp->adjust; 00301 00302 pagep->lsn = *lsnp; 00303 modified = 1; 00304 } else if (CDB_log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) { 00305 /* Need to undo update described. */ 00306 OV_REF(pagep) -= argp->adjust; 00307 00308 pagep->lsn = argp->lsn; 00309 modified = 1; 00310 } 00311 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 00312 goto out; 00313 00314 done: *lsnp = argp->prev_lsn; 00315 ret = 0; 00316 00317 out: REC_CLOSE; 00318 } 00319 00320 /* 00321 * CDB___db_relink_recover -- 00322 * Recovery function for relink. 00323 * 00324 * PUBLIC: int CDB___db_relink_recover 00325 * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); 00326 */ 00327 int 00328 CDB___db_relink_recover(dbenv, dbtp, lsnp, op, info) 00329 DB_ENV *dbenv; 00330 DBT *dbtp; 00331 DB_LSN *lsnp; 00332 db_recops op; 00333 void *info; 00334 { 00335 __db_relink_args *argp; 00336 DB *file_dbp; 00337 DBC *dbc; 00338 DB_MPOOLFILE *mpf; 00339 PAGE *pagep; 00340 int cmp_n, cmp_p, modified, ret; 00341 00342 COMPQUIET(info, NULL); 00343 REC_PRINT(CDB___db_relink_print); 00344 REC_INTRO(CDB___db_relink_read, 1); 00345 00346 /* 00347 * There are up to three pages we need to check -- the page, and the 00348 * previous and next pages, if they existed. For a page add operation, 00349 * the current page is the result of a split and is being recovered 00350 * elsewhere, so all we need do is recover the next page. 00351 */ 00352 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { 00353 if (DB_REDO(op)) { 00354 (void)CDB___db_pgerr(file_dbp, argp->pgno); 00355 goto out; 00356 } 00357 goto next2; 00358 } 00359 modified = 0; 00360 if (argp->opcode == DB_ADD_PAGE) 00361 goto next1; 00362 00363 cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn); 00364 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn); 00365 if (cmp_p == 0 && DB_REDO(op)) { 00366 /* Redo the relink. */ 00367 pagep->lsn = *lsnp; 00368 modified = 1; 00369 } else if (CDB_log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) { 00370 /* Undo the relink. */ 00371 pagep->next_pgno = argp->next; 00372 pagep->prev_pgno = argp->prev; 00373 00374 pagep->lsn = argp->lsn; 00375 modified = 1; 00376 } 00377 next1: if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 00378 goto out; 00379 00380 next2: if ((ret = CDB_memp_fget(mpf, &argp->next, 0, &pagep)) != 0) { 00381 if (DB_REDO(op)) { 00382 (void)CDB___db_pgerr(file_dbp, argp->next); 00383 goto out; 00384 } 00385 goto prev; 00386 } 00387 modified = 0; 00388 cmp_n = CDB_log_compare(lsnp, &LSN(pagep)); 00389 cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn_next); 00390 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn_next); 00391 if ((argp->opcode == DB_REM_PAGE && cmp_p == 0 && DB_REDO(op)) || 00392 (argp->opcode == DB_ADD_PAGE && cmp_n == 0 && DB_UNDO(op))) { 00393 /* Redo the remove or undo the add. */ 00394 pagep->prev_pgno = argp->prev; 00395 00396 modified = 1; 00397 } else if ((argp->opcode == DB_REM_PAGE && cmp_n == 0 && DB_UNDO(op)) || 00398 (argp->opcode == DB_ADD_PAGE && cmp_p == 0 && DB_REDO(op))) { 00399 /* Undo the remove or redo the add. */ 00400 pagep->prev_pgno = argp->pgno; 00401 00402 modified = 1; 00403 } 00404 if (modified == 1) { 00405 if (DB_UNDO(op)) 00406 pagep->lsn = argp->lsn_next; 00407 else 00408 pagep->lsn = *lsnp; 00409 } 00410 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 00411 goto out; 00412 if (argp->opcode == DB_ADD_PAGE) 00413 goto done; 00414 00415 prev: if ((ret = CDB_memp_fget(mpf, &argp->prev, 0, &pagep)) != 0) { 00416 if (DB_REDO(op)) { 00417 (void)CDB___db_pgerr(file_dbp, argp->prev); 00418 goto out; 00419 } 00420 goto done; 00421 } 00422 modified = 0; 00423 cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn_prev); 00424 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn_prev); 00425 if (cmp_p == 0 && DB_REDO(op)) { 00426 /* Redo the relink. */ 00427 pagep->next_pgno = argp->next; 00428 00429 modified = 1; 00430 } else if (CDB_log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) { 00431 /* Undo the relink. */ 00432 pagep->next_pgno = argp->pgno; 00433 00434 modified = 1; 00435 } 00436 if (modified == 1) { 00437 if (DB_UNDO(op)) 00438 pagep->lsn = argp->lsn_prev; 00439 else 00440 pagep->lsn = *lsnp; 00441 } 00442 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) 00443 goto out; 00444 00445 done: *lsnp = argp->prev_lsn; 00446 ret = 0; 00447 00448 out: REC_CLOSE; 00449 } 00450 00451 /* 00452 * CDB___db_debug_recover -- 00453 * Recovery function for debug. 00454 * 00455 * PUBLIC: int CDB___db_debug_recover __P((DB_ENV *, 00456 * PUBLIC: DBT *, DB_LSN *, db_recops, void *)); 00457 */ 00458 int 00459 CDB___db_debug_recover(dbenv, dbtp, lsnp, op, info) 00460 DB_ENV *dbenv; 00461 DBT *dbtp; 00462 DB_LSN *lsnp; 00463 db_recops op; 00464 void *info; 00465 { 00466 __db_debug_args *argp; 00467 int ret; 00468 00469 COMPQUIET(op, 0); 00470 COMPQUIET(dbenv, NULL); 00471 COMPQUIET(info, NULL); 00472 00473 REC_PRINT(CDB___db_debug_print); 00474 REC_NOOP_INTRO(CDB___db_debug_read); 00475 00476 *lsnp = argp->prev_lsn; 00477 ret = 0; 00478 00479 REC_NOOP_CLOSE; 00480 } 00481 00482 /* 00483 * CDB___db_noop_recover -- 00484 * Recovery function for noop. 00485 * 00486 * PUBLIC: int CDB___db_noop_recover __P((DB_ENV *, 00487 * PUBLIC: DBT *, DB_LSN *, db_recops, void *)); 00488 */ 00489 int 00490 CDB___db_noop_recover(dbenv, dbtp, lsnp, op, info) 00491 DB_ENV *dbenv; 00492 DBT *dbtp; 00493 DB_LSN *lsnp; 00494 db_recops op; 00495 void *info; 00496 { 00497 __db_noop_args *argp; 00498 DB *file_dbp; 00499 DBC *dbc; 00500 DB_MPOOLFILE *mpf; 00501 PAGE *pagep; 00502 u_int32_t change; 00503 int cmp_n, cmp_p, ret; 00504 00505 COMPQUIET(info, NULL); 00506 REC_PRINT(CDB___db_noop_print); 00507 REC_INTRO(CDB___db_noop_read, 0); 00508 00509 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) 00510 goto out; 00511 00512 cmp_n = CDB_log_compare(lsnp, &LSN(pagep)); 00513 cmp_p = CDB_log_compare(&LSN(pagep), &argp->prevlsn); 00514 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->prevlsn); 00515 change = 0; 00516 if (cmp_p == 0 && DB_REDO(op)) { 00517 LSN(pagep) = *lsnp; 00518 change = DB_MPOOL_DIRTY; 00519 } else if (cmp_n == 0 && DB_UNDO(op)) { 00520 LSN(pagep) = argp->prevlsn; 00521 change = DB_MPOOL_DIRTY; 00522 } 00523 ret = CDB_memp_fput(mpf, pagep, change); 00524 00525 done: *lsnp = argp->prev_lsn; 00526 out: REC_CLOSE; 00527 }