00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "db_config.h"
00039
00040 #ifndef NO_SYSTEM_INCLUDES
00041 #include <sys/types.h>
00042
00043 #include <string.h>
00044 #endif
00045
00046 #include "db_int.h"
00047 #include "dbinc/db_page.h"
00048 #include "dbinc/txn.h"
00049 #include "dbinc/db_am.h"
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 int
00060 __txn_regop_recover(dbenv, dbtp, lsnp, op, info)
00061 DB_ENV *dbenv;
00062 DBT *dbtp;
00063 DB_LSN *lsnp;
00064 db_recops op;
00065 void *info;
00066 {
00067 DB_TXNHEAD *headp;
00068 __txn_regop_args *argp;
00069 int ret;
00070 u_int32_t status;
00071
00072 #ifdef DEBUG_RECOVER
00073 (void)__txn_regop_print(dbenv, dbtp, lsnp, op, info);
00074 #endif
00075
00076 if ((ret = __txn_regop_read(dbenv, dbtp->data, &argp)) != 0)
00077 return (ret);
00078
00079 headp = info;
00080
00081
00082
00083
00084
00085
00086 if (op == DB_TXN_FORWARD_ROLL) {
00087
00088
00089
00090
00091
00092 if ((ret = __db_txnlist_remove(dbenv,
00093 info, argp->txnid->txnid)) != DB_NOTFOUND && ret != 0)
00094 goto err;
00095 } else if ((dbenv->tx_timestamp != 0 &&
00096 argp->timestamp > (int32_t)dbenv->tx_timestamp) ||
00097 (!IS_ZERO_LSN(headp->trunc_lsn) &&
00098 log_compare(&headp->trunc_lsn, lsnp) < 0)) {
00099
00100
00101
00102
00103 if ((ret = __db_txnlist_update(dbenv, info,
00104 argp->txnid->txnid, TXN_ABORT, NULL, &status, 1)) != 0)
00105 goto err;
00106 else if (status != TXN_IGNORE && status != TXN_OK)
00107 goto err;
00108 } else {
00109
00110 if ((ret = __db_txnlist_update(dbenv,
00111 info, argp->txnid->txnid, argp->opcode, lsnp,
00112 &status, 0)) == DB_NOTFOUND) {
00113 if ((ret = __db_txnlist_add(dbenv,
00114 info, argp->txnid->txnid,
00115 argp->opcode == TXN_ABORT ?
00116 TXN_IGNORE : argp->opcode, lsnp)) != 0)
00117 goto err;
00118 } else if (ret != 0 ||
00119 (status != TXN_IGNORE && status != TXN_OK))
00120 goto err;
00121 }
00122
00123 if (ret == 0)
00124 *lsnp = argp->prev_lsn;
00125
00126 if (0) {
00127 err: __db_err(dbenv,
00128 "txnid %lx commit record found, already on commit list",
00129 (u_long)argp->txnid->txnid);
00130 ret = EINVAL;
00131 }
00132 __os_free(dbenv, argp);
00133
00134 return (ret);
00135 }
00136
00137
00138
00139
00140
00141
00142
00143 int
00144 __txn_xa_regop_recover(dbenv, dbtp, lsnp, op, info)
00145 DB_ENV *dbenv;
00146 DBT *dbtp;
00147 DB_LSN *lsnp;
00148 db_recops op;
00149 void *info;
00150 {
00151 __txn_xa_regop_args *argp;
00152 int ret;
00153 u_int32_t status;
00154
00155 #ifdef DEBUG_RECOVER
00156 (void)__txn_xa_regop_print(dbenv, dbtp, lsnp, op, info);
00157 #endif
00158
00159 if ((ret = __txn_xa_regop_read(dbenv, dbtp->data, &argp)) != 0)
00160 return (ret);
00161
00162 if (argp->opcode != TXN_PREPARE && argp->opcode != TXN_ABORT) {
00163 ret = EINVAL;
00164 goto err;
00165 }
00166
00167
00168
00169
00170
00171
00172
00173
00174 ret = __db_txnlist_find(dbenv, info, argp->txnid->txnid, &status);
00175
00176
00177
00178
00179
00180
00181
00182
00183 if (op == DB_TXN_FORWARD_ROLL) {
00184 if ((ret = __db_txnlist_remove(dbenv,
00185 info, argp->txnid->txnid)) != 0)
00186 goto txn_err;
00187 } else if (op == DB_TXN_BACKWARD_ROLL && status == TXN_PREPARE) {
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199 if (argp->opcode == TXN_ABORT) {
00200 if ((ret = __db_txnlist_update(dbenv,
00201 info, argp->txnid->txnid,
00202 TXN_ABORT, NULL, &status, 0)) != 0 &&
00203 status != TXN_PREPARE)
00204 goto txn_err;
00205 ret = 0;
00206 }
00207
00208
00209
00210
00211
00212
00213
00214 else if ((ret = __db_txnlist_remove(dbenv,
00215 info, argp->txnid->txnid)) != 0) {
00216 txn_err: __db_err(dbenv,
00217 "Transaction not in list %x", argp->txnid->txnid);
00218 ret = DB_NOTFOUND;
00219 } else if ((ret = __db_txnlist_add(dbenv,
00220 info, argp->txnid->txnid, TXN_COMMIT, lsnp)) == 0)
00221 ret = __txn_restore_txn(dbenv, lsnp, argp);
00222 } else
00223 ret = 0;
00224
00225 if (ret == 0)
00226 *lsnp = argp->prev_lsn;
00227
00228 err: __os_free(dbenv, argp);
00229
00230 return (ret);
00231 }
00232
00233
00234
00235
00236
00237 int
00238 __txn_ckp_recover(dbenv, dbtp, lsnp, op, info)
00239 DB_ENV *dbenv;
00240 DBT *dbtp;
00241 DB_LSN *lsnp;
00242 db_recops op;
00243 void *info;
00244 {
00245 DB_REP *db_rep;
00246 REP *rep;
00247 __txn_ckp_args *argp;
00248 int ret;
00249
00250 #ifdef DEBUG_RECOVER
00251 __txn_ckp_print(dbenv, dbtp, lsnp, op, info);
00252 #endif
00253 if ((ret = __txn_ckp_read(dbenv, dbtp->data, &argp)) != 0)
00254 return (ret);
00255
00256 if (op == DB_TXN_BACKWARD_ROLL)
00257 __db_txnlist_ckp(dbenv, info, lsnp);
00258
00259 if (op == DB_TXN_FORWARD_ROLL) {
00260
00261 if (REP_ON(dbenv)) {
00262 db_rep = dbenv->rep_handle;
00263 rep = db_rep->region;
00264 if (argp->rep_gen > rep->recover_gen)
00265 rep->recover_gen = argp->rep_gen;
00266 }
00267 }
00268
00269 *lsnp = argp->last_ckp;
00270 __os_free(dbenv, argp);
00271 return (DB_TXN_CKP);
00272 }
00273
00274
00275
00276
00277
00278
00279
00280
00281 int
00282 __txn_child_recover(dbenv, dbtp, lsnp, op, info)
00283 DB_ENV *dbenv;
00284 DBT *dbtp;
00285 DB_LSN *lsnp;
00286 db_recops op;
00287 void *info;
00288 {
00289 __txn_child_args *argp;
00290 int ret, t_ret;
00291 u_int32_t c_stat, p_stat, tmpstat;
00292
00293 #ifdef DEBUG_RECOVER
00294 (void)__txn_child_print(dbenv, dbtp, lsnp, op, info);
00295 #endif
00296 if ((ret = __txn_child_read(dbenv, dbtp->data, &argp)) != 0)
00297 return (ret);
00298
00299
00300
00301
00302
00303
00304
00305
00306 if (op == DB_TXN_ABORT) {
00307 *lsnp = argp->c_lsn;
00308 ret = __db_txnlist_lsnadd(dbenv, info, &argp->prev_lsn);
00309 goto out;
00310 } else if (op == DB_TXN_BACKWARD_ROLL) {
00311
00312 ret = __db_txnlist_find(dbenv, info, argp->child, &c_stat);
00313 t_ret =
00314 __db_txnlist_find(dbenv, info, argp->txnid->txnid, &p_stat);
00315 if (ret != 0 && ret != DB_NOTFOUND)
00316 goto out;
00317 if (t_ret != 0 && t_ret != DB_NOTFOUND) {
00318 ret = t_ret;
00319 goto out;
00320 }
00321
00322
00323
00324
00325
00326 if (ret == DB_NOTFOUND ||
00327 c_stat == TXN_OK || c_stat == TXN_COMMIT) {
00328 if (t_ret == DB_NOTFOUND ||
00329 (p_stat != TXN_COMMIT && p_stat != TXN_IGNORE))
00330 c_stat = TXN_ABORT;
00331 else
00332 c_stat = p_stat;
00333
00334 if (ret == DB_NOTFOUND)
00335 ret = __db_txnlist_add(dbenv,
00336 info, argp->child, c_stat, NULL);
00337 else
00338 ret = __db_txnlist_update(dbenv, info,
00339 argp->child, c_stat, NULL, &tmpstat, 0);
00340 } else if (c_stat == TXN_EXPECTED) {
00341
00342
00343
00344
00345
00346 switch (p_stat) {
00347 case TXN_COMMIT:
00348 case TXN_IGNORE:
00349 c_stat = TXN_IGNORE;
00350 break;
00351 default:
00352 c_stat = TXN_ABORT;
00353 }
00354 ret = __db_txnlist_update(dbenv,
00355 info, argp->child, c_stat, NULL, &tmpstat, 0);
00356 } else if (c_stat == TXN_UNEXPECTED) {
00357
00358
00359
00360
00361
00362
00363
00364 ret = __db_txnlist_update(dbenv, info, argp->child,
00365 p_stat == TXN_COMMIT ? TXN_COMMIT : TXN_IGNORE,
00366 NULL, &tmpstat, 0);
00367 }
00368 } else if (op == DB_TXN_OPENFILES) {
00369
00370
00371
00372
00373 if ((ret = __db_txnlist_find(dbenv,
00374 info, argp->child, &c_stat)) == DB_NOTFOUND)
00375 ret = __db_txnlist_update(dbenv, info,
00376 argp->txnid->txnid, TXN_IGNORE,
00377 NULL, &p_stat, 1);
00378 } else if (DB_REDO(op)) {
00379
00380 if ((ret =
00381 __db_txnlist_remove(dbenv, info, argp->child)) != 0)
00382 __db_err(dbenv,
00383 "Transaction not in list %x", argp->child);
00384 }
00385
00386 if (ret == 0)
00387 *lsnp = argp->prev_lsn;
00388
00389 out: __os_free(dbenv, argp);
00390
00391 return (ret);
00392 }
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407 int
00408 __txn_restore_txn(dbenv, lsnp, argp)
00409 DB_ENV *dbenv;
00410 DB_LSN *lsnp;
00411 __txn_xa_regop_args *argp;
00412 {
00413 DB_TXNMGR *mgr;
00414 TXN_DETAIL *td;
00415 DB_TXNREGION *region;
00416 int ret;
00417
00418 if (argp->xid.size == 0)
00419 return (0);
00420
00421 mgr = dbenv->tx_handle;
00422 region = mgr->reginfo.primary;
00423 TXN_SYSTEM_LOCK(dbenv);
00424
00425
00426 if ((ret =
00427 __db_shalloc(&mgr->reginfo, sizeof(TXN_DETAIL), 0, &td)) != 0) {
00428 TXN_SYSTEM_UNLOCK(dbenv);
00429 return (ret);
00430 }
00431
00432
00433 SH_TAILQ_INSERT_HEAD(®ion->active_txn, td, links, __txn_detail);
00434
00435 td->txnid = argp->txnid->txnid;
00436 td->begin_lsn = argp->begin_lsn;
00437 td->last_lsn = *lsnp;
00438 td->parent = 0;
00439 td->status = TXN_PREPARED;
00440 td->xa_status = TXN_XA_PREPARED;
00441 memcpy(td->xid, argp->xid.data, argp->xid.size);
00442 td->bqual = argp->bqual;
00443 td->gtrid = argp->gtrid;
00444 td->format = argp->formatID;
00445 td->flags = 0;
00446 F_SET(td, TXN_DTL_RESTORED);
00447
00448 region->stat.st_nrestores++;
00449 region->stat.st_nactive++;
00450 if (region->stat.st_nactive > region->stat.st_maxnactive)
00451 region->stat.st_maxnactive = region->stat.st_nactive;
00452 TXN_SYSTEM_UNLOCK(dbenv);
00453 return (0);
00454 }
00455
00456
00457
00458
00459
00460
00461
00462
00463 int
00464 __txn_recycle_recover(dbenv, dbtp, lsnp, op, info)
00465 DB_ENV *dbenv;
00466 DBT *dbtp;
00467 DB_LSN *lsnp;
00468 db_recops op;
00469 void *info;
00470 {
00471 __txn_recycle_args *argp;
00472 int ret;
00473
00474 #ifdef DEBUG_RECOVER
00475 (void)__txn_child_print(dbenv, dbtp, lsnp, op, info);
00476 #endif
00477 if ((ret = __txn_recycle_read(dbenv, dbtp->data, &argp)) != 0)
00478 return (ret);
00479
00480 COMPQUIET(lsnp, NULL);
00481
00482 if ((ret = __db_txnlist_gen(dbenv, info,
00483 DB_UNDO(op) ? -1 : 1, argp->min, argp->max)) != 0)
00484 return (ret);
00485
00486 __os_free(dbenv, argp);
00487
00488 return (0);
00489 }