txn_rec.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:12k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. /*
  8.  * Copyright (c) 1996
  9.  * The President and Fellows of Harvard University.  All rights reserved.
  10.  *
  11.  * Redistribution and use in source and binary forms, with or without
  12.  * modification, are permitted provided that the following conditions
  13.  * are met:
  14.  * 1. Redistributions of source code must retain the above copyright
  15.  *    notice, this list of conditions and the following disclaimer.
  16.  * 2. Redistributions in binary form must reproduce the above copyright
  17.  *    notice, this list of conditions and the following disclaimer in the
  18.  *    documentation and/or other materials provided with the distribution.
  19.  * 3. Neither the name of the University nor the names of its contributors
  20.  *    may be used to endorse or promote products derived from this software
  21.  *    without specific prior written permission.
  22.  *
  23.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  24.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  27.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33.  * SUCH DAMAGE.
  34.  */
  35. #include "db_config.h"
  36. #ifndef lint
  37. static const char revid[] = "$Id: txn_rec.c,v 11.41 2002/08/06 04:42:37 bostic Exp $";
  38. #endif /* not lint */
  39. #ifndef NO_SYSTEM_INCLUDES
  40. #include <sys/types.h>
  41. #include <string.h>
  42. #endif
  43. #include "db_int.h"
  44. #include "dbinc/db_page.h"
  45. #include "dbinc/txn.h"
  46. #include "dbinc/db_am.h"
  47. #include "dbinc/db_dispatch.h"
  48. #define IS_XA_TXN(R) (R->xid.size != 0)
  49. /*
  50.  * PUBLIC: int __txn_regop_recover
  51.  * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  52.  *
  53.  * These records are only ever written for commits.  Normally, we redo any
  54.  * committed transaction, however if we are doing recovery to a timestamp, then
  55.  * we may treat transactions that commited after the timestamp as aborted.
  56.  */
  57. int
  58. __txn_regop_recover(dbenv, dbtp, lsnp, op, info)
  59. DB_ENV *dbenv;
  60. DBT *dbtp;
  61. DB_LSN *lsnp;
  62. db_recops op;
  63. void *info;
  64. {
  65. DB_TXNHEAD *headp;
  66. __txn_regop_args *argp;
  67. int ret;
  68. #ifdef DEBUG_RECOVER
  69. (void)__txn_regop_print(dbenv, dbtp, lsnp, op, info);
  70. #endif
  71. if ((ret = __txn_regop_read(dbenv, dbtp->data, &argp)) != 0)
  72. return (ret);
  73. headp = info;
  74. /*
  75.  * We are only ever called during FORWARD_ROLL or BACKWARD_ROLL.
  76.  * We check for the former explicitly and the last two clauses
  77.  * apply to the BACKWARD_ROLL case.
  78.  */
  79. if (op == DB_TXN_FORWARD_ROLL)
  80. /*
  81.  * If this was a 2-phase-commit transaction, then it
  82.  * might already have been removed from the list, and
  83.  * that's OK.  Ignore the return code from remove.
  84.  */
  85. (void)__db_txnlist_remove(dbenv, info, argp->txnid->txnid);
  86. else if ((dbenv->tx_timestamp != 0 &&
  87.     argp->timestamp > (int32_t)dbenv->tx_timestamp) ||
  88.     (!IS_ZERO_LSN(headp->trunc_lsn) &&
  89.     log_compare(&headp->trunc_lsn, lsnp) < 0)) {
  90. /*
  91.  * We failed either the timestamp check or the trunc_lsn check,
  92.  * so we treat this as an abort even if it was a commit record.
  93.  */
  94. ret = __db_txnlist_update(dbenv,
  95.     info, argp->txnid->txnid, TXN_ABORT, NULL);
  96. if (ret == TXN_NOTFOUND)
  97. ret = __db_txnlist_add(dbenv,
  98.     info, argp->txnid->txnid, TXN_IGNORE, NULL);
  99. else if (ret != TXN_OK)
  100. goto err;
  101. /* else ret = 0; Not necessary because TXN_OK == 0 */
  102. } else {
  103. /* This is a normal commit; mark it appropriately. */
  104. ret = __db_txnlist_update(dbenv,
  105.     info, argp->txnid->txnid, argp->opcode, lsnp);
  106. if (ret == TXN_NOTFOUND)
  107. ret = __db_txnlist_add(dbenv,
  108.     info, argp->txnid->txnid,
  109.     argp->opcode == TXN_ABORT ?
  110.     TXN_IGNORE : argp->opcode, lsnp);
  111. else if (ret != TXN_OK)
  112. goto err;
  113. /* else ret = 0; Not necessary because TXN_OK == 0 */
  114. }
  115. if (ret == 0)
  116. *lsnp = argp->prev_lsn;
  117. if (0) {
  118. err: __db_err(dbenv,
  119.     "txnid %lx commit record found, already on commit list",
  120.     argp->txnid->txnid);
  121. ret = EINVAL;
  122. }
  123. __os_free(dbenv, argp);
  124. return (ret);
  125. }
  126. /*
  127.  * PUBLIC: int __txn_xa_regop_recover
  128.  * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  129.  *
  130.  * These records are only ever written for prepares.
  131.  */
  132. int
  133. __txn_xa_regop_recover(dbenv, dbtp, lsnp, op, info)
  134. DB_ENV *dbenv;
  135. DBT *dbtp;
  136. DB_LSN *lsnp;
  137. db_recops op;
  138. void *info;
  139. {
  140. __txn_xa_regop_args *argp;
  141. int ret;
  142. #ifdef DEBUG_RECOVER
  143. (void)__txn_xa_regop_print(dbenv, dbtp, lsnp, op, info);
  144. #endif
  145. if ((ret = __txn_xa_regop_read(dbenv, dbtp->data, &argp)) != 0)
  146. return (ret);
  147. if (argp->opcode != TXN_PREPARE) {
  148. ret = EINVAL;
  149. goto err;
  150. }
  151. ret = __db_txnlist_find(dbenv, info, argp->txnid->txnid);
  152. /*
  153.  * If we are rolling forward, then an aborted prepare
  154.  * indicates that this may the last record we'll see for
  155.  * this transaction ID, so we should remove it from the
  156.  * list.
  157.  */
  158. if (op == DB_TXN_FORWARD_ROLL) {
  159. if ((ret = __db_txnlist_remove(dbenv,
  160.     info, argp->txnid->txnid)) != TXN_OK)
  161. goto txn_err;
  162. } else if (op == DB_TXN_BACKWARD_ROLL && ret == TXN_PREPARE) {
  163. /*
  164.  * On the backward pass, we have three possibilities:
  165.  * 1. The transaction is already committed, no-op.
  166.  * 2. The transaction is already aborted, no-op.
  167.  * 3. The transaction is neither committed nor aborted.
  168.  *  Treat this like a commit and roll forward so that
  169.  *  the transaction can be resurrected in the region.
  170.  * We handle case 3 here; cases 1 and 2 are the final clause
  171.  * below.
  172.  * This is prepared, but not yet committed transaction.  We
  173.  * need to add it to the transaction list, so that it gets
  174.  * rolled forward. We also have to add it to the region's
  175.  * internal state so it can be properly aborted or committed
  176.  * after recovery (see txn_recover).
  177.  */
  178. if ((ret = __db_txnlist_remove(dbenv,
  179.    info, argp->txnid->txnid)) != TXN_OK) {
  180. txn_err: __db_err(dbenv,
  181.     "Transaction not in list %x", argp->txnid->txnid);
  182. ret = DB_NOTFOUND;
  183. } else if ((ret = __db_txnlist_add(dbenv,
  184.    info, argp->txnid->txnid, TXN_COMMIT, lsnp)) == 0)
  185. ret = __txn_restore_txn(dbenv, lsnp, argp);
  186. } else
  187. ret = 0;
  188. if (ret == 0)
  189. *lsnp = argp->prev_lsn;
  190. err: __os_free(dbenv, argp);
  191. return (ret);
  192. }
  193. /*
  194.  * PUBLIC: int __txn_ckp_recover
  195.  * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  196.  */
  197. int
  198. __txn_ckp_recover(dbenv, dbtp, lsnp, op, info)
  199. DB_ENV *dbenv;
  200. DBT *dbtp;
  201. DB_LSN *lsnp;
  202. db_recops op;
  203. void *info;
  204. {
  205. __txn_ckp_args *argp;
  206. int ret;
  207. #ifdef DEBUG_RECOVER
  208. __txn_ckp_print(dbenv, dbtp, lsnp, op, info);
  209. #endif
  210. COMPQUIET(dbenv, NULL);
  211. if ((ret = __txn_ckp_read(dbenv, dbtp->data, &argp)) != 0)
  212. return (ret);
  213. if (op == DB_TXN_BACKWARD_ROLL)
  214. __db_txnlist_ckp(dbenv, info, lsnp);
  215. *lsnp = argp->last_ckp;
  216. __os_free(dbenv, argp);
  217. return (DB_TXN_CKP);
  218. }
  219. /*
  220.  * __txn_child_recover
  221.  * Recover a commit record for a child transaction.
  222.  *
  223.  * PUBLIC: int __txn_child_recover
  224.  * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  225.  */
  226. int
  227. __txn_child_recover(dbenv, dbtp, lsnp, op, info)
  228. DB_ENV *dbenv;
  229. DBT *dbtp;
  230. DB_LSN *lsnp;
  231. db_recops op;
  232. void *info;
  233. {
  234. __txn_child_args *argp;
  235. int c_stat, p_stat, ret;
  236. #ifdef DEBUG_RECOVER
  237. (void)__txn_child_print(dbenv, dbtp, lsnp, op, info);
  238. #endif
  239. if ((ret = __txn_child_read(dbenv, dbtp->data, &argp)) != 0)
  240. return (ret);
  241. /*
  242.  * This is a record in a PARENT's log trail indicating that a
  243.  * child commited.  If we are aborting, we need to update the
  244.  * parent's LSN array.  If we are in recovery, then if the
  245.  * parent is commiting, we set ourselves up to commit, else
  246.  * we do nothing.
  247.  */
  248. if (op == DB_TXN_ABORT) {
  249. /* Note that __db_txnlist_lsnadd rewrites its LSN
  250.  * parameter, so you cannot reuse the argp->c_lsn field.
  251.  */
  252. ret = __db_txnlist_lsnadd(dbenv,
  253.     info, &argp->c_lsn, TXNLIST_NEW);
  254. } else if (op == DB_TXN_BACKWARD_ROLL) {
  255. /* Child might exist -- look for it. */
  256. c_stat = __db_txnlist_find(dbenv, info, argp->child);
  257. p_stat = __db_txnlist_find(dbenv, info, argp->txnid->txnid);
  258. if (c_stat == TXN_EXPECTED) {
  259. /*
  260.  * The open after this create succeeded.  If the
  261.  * parent succeeded, we don't want to redo; if the
  262.  * parent aborted, we do want to undo.
  263.  */
  264. ret = __db_txnlist_update(dbenv,
  265.     info, argp->child,
  266.     p_stat == TXN_COMMIT ? TXN_IGNORE : TXN_ABORT,
  267.     NULL);
  268. if (ret > 0)
  269. ret = 0;
  270. } else if (c_stat == TXN_UNEXPECTED) {
  271. /*
  272.  * The open after this create failed.  If the parent
  273.  * is rolling forward, we need to roll forward.  If
  274.  * the parent failed, then we do not want to abort
  275.  * (because the file may not be the one in which we
  276.  * are interested).
  277.  */
  278. ret = __db_txnlist_update(dbenv, info, argp->child,
  279.     p_stat == TXN_COMMIT ? TXN_COMMIT : TXN_IGNORE,
  280.     NULL);
  281. if (ret > 0)
  282. ret = 0;
  283. } else if (c_stat != TXN_IGNORE) {
  284. ret = __db_txnlist_add(dbenv, info, argp->child,
  285.     p_stat == TXN_COMMIT ? TXN_COMMIT : TXN_ABORT,
  286.     NULL);
  287. }
  288. } else {
  289. /* Forward Roll */
  290. if ((ret =
  291.     __db_txnlist_remove(dbenv, info, argp->child)) != TXN_OK) {
  292. __db_err(dbenv,
  293.     "Transaction not in list %x", argp->txnid->txnid);
  294. ret = DB_NOTFOUND;
  295. }
  296. }
  297. if (ret == 0)
  298. *lsnp = argp->prev_lsn;
  299. __os_free(dbenv, argp);
  300. return (ret);
  301. }
  302. /*
  303.  * __txn_restore_txn --
  304.  * Using only during XA recovery.  If we find any transactions that are
  305.  * prepared, but not yet committed, then we need to restore the transaction's
  306.  * state into the shared region, because the TM is going to issue an abort
  307.  * or commit and we need to respond correctly.
  308.  *
  309.  * lsnp is the LSN of the returned LSN
  310.  * argp is the perpare record (in an appropriate structure)
  311.  *
  312.  * PUBLIC: int __txn_restore_txn __P((DB_ENV *,
  313.  * PUBLIC:     DB_LSN *, __txn_xa_regop_args *));
  314.  */
  315. int
  316. __txn_restore_txn(dbenv, lsnp, argp)
  317. DB_ENV *dbenv;
  318. DB_LSN *lsnp;
  319. __txn_xa_regop_args *argp;
  320. {
  321. DB_TXNMGR *mgr;
  322. TXN_DETAIL *td;
  323. DB_TXNREGION *region;
  324. int ret;
  325. if (argp->xid.size == 0)
  326. return (0);
  327. mgr = dbenv->tx_handle;
  328. region = mgr->reginfo.primary;
  329. R_LOCK(dbenv, &mgr->reginfo);
  330. /* Allocate a new transaction detail structure. */
  331. if ((ret =
  332.     __db_shalloc(mgr->reginfo.addr, sizeof(TXN_DETAIL), 0, &td)) != 0) {
  333. R_UNLOCK(dbenv, &mgr->reginfo);
  334. return (ret);
  335. }
  336. /* Place transaction on active transaction list. */
  337. SH_TAILQ_INSERT_HEAD(&region->active_txn, td, links, __txn_detail);
  338. td->txnid = argp->txnid->txnid;
  339. td->begin_lsn = argp->begin_lsn;
  340. td->last_lsn = *lsnp;
  341. td->parent = 0;
  342. td->status = TXN_PREPARED;
  343. td->xa_status = TXN_XA_PREPARED;
  344. memcpy(td->xid, argp->xid.data, argp->xid.size);
  345. td->bqual = argp->bqual;
  346. td->gtrid = argp->gtrid;
  347. td->format = argp->formatID;
  348. td->flags = 0;
  349. F_SET(td, TXN_RESTORED);
  350. region->stat.st_nrestores++;
  351. region->stat.st_nactive++;
  352. if (region->stat.st_nactive > region->stat.st_maxnactive)
  353. region->stat.st_maxnactive = region->stat.st_nactive;
  354. R_UNLOCK(dbenv, &mgr->reginfo);
  355. return (0);
  356. }
  357. /*
  358.  * __txn_recycle_recover --
  359.  * Recovery function for recycle.
  360.  *
  361.  * PUBLIC: int __txn_recycle_recover
  362.  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  363.  */
  364. int
  365. __txn_recycle_recover(dbenv, dbtp, lsnp, op, info)
  366. DB_ENV *dbenv;
  367. DBT *dbtp;
  368. DB_LSN *lsnp;
  369. db_recops op;
  370. void *info;
  371. {
  372. __txn_recycle_args *argp;
  373. int ret;
  374. #ifdef DEBUG_RECOVER
  375. (void)__txn_child_print(dbenv, dbtp, lsnp, op, info);
  376. #endif
  377. if ((ret = __txn_recycle_read(dbenv, dbtp->data, &argp)) != 0)
  378. return (ret);
  379. COMPQUIET(lsnp, NULL);
  380. if ((ret = __db_txnlist_gen(dbenv, info,
  381.     DB_UNDO(op) ? -1 : 1, argp->min, argp->max)) != 0)
  382. return (ret);
  383. __os_free(dbenv, argp);
  384. return (0);
  385. }