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

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. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: txn_region.c,v 11.73 2002/08/06 04:42:37 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #if TIME_WITH_SYS_TIME
  14. #include <sys/time.h>
  15. #include <time.h>
  16. #else
  17. #if HAVE_SYS_TIME_H
  18. #include <sys/time.h>
  19. #else
  20. #include <time.h>
  21. #endif
  22. #endif
  23. #include <string.h>
  24. #endif
  25. #include "db_int.h"
  26. #include "dbinc/log.h"
  27. #include "dbinc/txn.h"
  28. static int __txn_findlastckp __P((DB_ENV *, DB_LSN *));
  29. static int __txn_init __P((DB_ENV *, DB_TXNMGR *));
  30. static size_t __txn_region_size __P((DB_ENV *));
  31. /*
  32.  * __txn_open --
  33.  * Open a transaction region.
  34.  *
  35.  * PUBLIC: int __txn_open __P((DB_ENV *));
  36.  */
  37. int
  38. __txn_open(dbenv)
  39. DB_ENV *dbenv;
  40. {
  41. DB_TXNMGR *tmgrp;
  42. int ret;
  43. /* Create/initialize the transaction manager structure. */
  44. if ((ret = __os_calloc(dbenv, 1, sizeof(DB_TXNMGR), &tmgrp)) != 0)
  45. return (ret);
  46. TAILQ_INIT(&tmgrp->txn_chain);
  47. tmgrp->dbenv = dbenv;
  48. /* Join/create the txn region. */
  49. tmgrp->reginfo.type = REGION_TYPE_TXN;
  50. tmgrp->reginfo.id = INVALID_REGION_ID;
  51. tmgrp->reginfo.mode = dbenv->db_mode;
  52. tmgrp->reginfo.flags = REGION_JOIN_OK;
  53. if (F_ISSET(dbenv, DB_ENV_CREATE))
  54. F_SET(&tmgrp->reginfo, REGION_CREATE_OK);
  55. if ((ret = __db_r_attach(dbenv,
  56.     &tmgrp->reginfo, __txn_region_size(dbenv))) != 0)
  57. goto err;
  58. /* If we created the region, initialize it. */
  59. if (F_ISSET(&tmgrp->reginfo, REGION_CREATE))
  60. if ((ret = __txn_init(dbenv, tmgrp)) != 0)
  61. goto err;
  62. /* Set the local addresses. */
  63. tmgrp->reginfo.primary =
  64.     R_ADDR(&tmgrp->reginfo, tmgrp->reginfo.rp->primary);
  65. /* Acquire a mutex to protect the active TXN list. */
  66. if (F_ISSET(dbenv, DB_ENV_THREAD) &&
  67.     (ret = __db_mutex_setup(dbenv, &tmgrp->reginfo, &tmgrp->mutexp,
  68.     MUTEX_ALLOC | MUTEX_NO_RLOCK | MUTEX_THREAD)) != 0)
  69. goto err;
  70. R_UNLOCK(dbenv, &tmgrp->reginfo);
  71. dbenv->tx_handle = tmgrp;
  72. return (0);
  73. err: if (tmgrp->reginfo.addr != NULL) {
  74. if (F_ISSET(&tmgrp->reginfo, REGION_CREATE))
  75. ret = __db_panic(dbenv, ret);
  76. R_UNLOCK(dbenv, &tmgrp->reginfo);
  77. (void)__db_r_detach(dbenv, &tmgrp->reginfo, 0);
  78. }
  79. if (tmgrp->mutexp != NULL)
  80. __db_mutex_free(dbenv, &tmgrp->reginfo, tmgrp->mutexp);
  81. __os_free(dbenv, tmgrp);
  82. return (ret);
  83. }
  84. /*
  85.  * __txn_init --
  86.  * Initialize a transaction region in shared memory.
  87.  */
  88. static int
  89. __txn_init(dbenv, tmgrp)
  90. DB_ENV *dbenv;
  91. DB_TXNMGR *tmgrp;
  92. {
  93. DB_LSN last_ckp;
  94. DB_TXNREGION *region;
  95. int ret;
  96. #ifdef HAVE_MUTEX_SYSTEM_RESOURCES
  97. u_int8_t *addr;
  98. #endif
  99. /*
  100.  * Find the last checkpoint in the log.
  101.  */
  102. ZERO_LSN(last_ckp);
  103. if (LOGGING_ON(dbenv)) {
  104. /*
  105.  * The log system has already walked through the last
  106.  * file.  Get the LSN of a checkpoint it may have found.
  107.  */
  108. __log_get_cached_ckp_lsn(dbenv, &last_ckp);
  109. /*
  110.  * If that didn't work, look backwards from the beginning of
  111.  * the last log file until we find the last checkpoint.
  112.  */
  113. if (IS_ZERO_LSN(last_ckp) &&
  114.     (ret = __txn_findlastckp(dbenv, &last_ckp)) != 0)
  115. return (ret);
  116. }
  117. if ((ret = __db_shalloc(tmgrp->reginfo.addr,
  118.     sizeof(DB_TXNREGION), 0, &tmgrp->reginfo.primary)) != 0) {
  119. __db_err(dbenv,
  120.     "Unable to allocate memory for the transaction region");
  121. return (ret);
  122. }
  123. tmgrp->reginfo.rp->primary =
  124.     R_OFFSET(&tmgrp->reginfo, tmgrp->reginfo.primary);
  125. region = tmgrp->reginfo.primary;
  126. memset(region, 0, sizeof(*region));
  127. region->maxtxns = dbenv->tx_max;
  128. region->last_txnid = TXN_MINIMUM;
  129. region->cur_maxid = TXN_MAXIMUM;
  130. region->last_ckp = last_ckp;
  131. region->time_ckp = time(NULL);
  132. /*
  133.  * XXX
  134.  * If we ever do more types of locking and logging, this changes.
  135.  */
  136. region->logtype = 0;
  137. region->locktype = 0;
  138. memset(&region->stat, 0, sizeof(region->stat));
  139. region->stat.st_maxtxns = region->maxtxns;
  140. SH_TAILQ_INIT(&region->active_txn);
  141. #ifdef HAVE_MUTEX_SYSTEM_RESOURCES
  142. /* Allocate room for the txn maintenance info and initialize it. */
  143. if ((ret = __db_shalloc(tmgrp->reginfo.addr,
  144.     sizeof(REGMAINT) + TXN_MAINT_SIZE, 0, &addr)) != 0) {
  145. __db_err(dbenv,
  146.     "Unable to allocate memory for mutex maintenance");
  147. return (ret);
  148. }
  149. __db_maintinit(&tmgrp->reginfo, addr, TXN_MAINT_SIZE);
  150. region->maint_off = R_OFFSET(&tmgrp->reginfo, addr);
  151. #endif
  152. return (0);
  153. }
  154. /*
  155.  * __txn_findlastckp --
  156.  * Find the last checkpoint in the log, walking backwards from the
  157.  * beginning of the last log file.  (The log system looked through
  158.  * the last log file when it started up.)
  159.  */
  160. static int
  161. __txn_findlastckp(dbenv, lsnp)
  162. DB_ENV *dbenv;
  163. DB_LSN *lsnp;
  164. {
  165. DB_LOGC *logc;
  166. DB_LSN lsn;
  167. DBT dbt;
  168. int ret, t_ret;
  169. u_int32_t rectype;
  170. if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
  171. return (ret);
  172. /* Get the last LSN. */
  173. memset(&dbt, 0, sizeof(dbt));
  174. if ((ret = logc->get(logc, &lsn, &dbt, DB_LAST)) != 0)
  175. goto err;
  176. /*
  177.  * Twiddle the last LSN so it points to the beginning of the last
  178.  * file;  we know there's no checkpoint after that, since the log
  179.  * system already looked there.
  180.  */
  181. lsn.offset = 0;
  182. /* Read backwards, looking for checkpoints. */
  183. while ((ret = logc->get(logc, &lsn, &dbt, DB_PREV)) == 0) {
  184. if (dbt.size < sizeof(u_int32_t))
  185. continue;
  186. memcpy(&rectype, dbt.data, sizeof(u_int32_t));
  187. if (rectype == DB___txn_ckp) {
  188. *lsnp = lsn;
  189. break;
  190. }
  191. }
  192. err: if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
  193. ret = t_ret;
  194. /*
  195.  * Not finding a checkpoint is not an error;  there may not exist
  196.  * one in the log.
  197.  */
  198. return ((ret == 0 || ret == DB_NOTFOUND) ? 0 : ret);
  199. }
  200. /*
  201.  * __txn_dbenv_refresh --
  202.  * Clean up after the transaction system on a close or failed open.
  203.  * Called only from __dbenv_refresh.  (Formerly called __txn_close.)
  204.  *
  205.  * PUBLIC: int __txn_dbenv_refresh __P((DB_ENV *));
  206.  */
  207. int
  208. __txn_dbenv_refresh(dbenv)
  209. DB_ENV *dbenv;
  210. {
  211. DB_TXN *txnp;
  212. DB_TXNMGR *tmgrp;
  213. u_int32_t txnid;
  214. int ret, t_ret;
  215. ret = 0;
  216. tmgrp = dbenv->tx_handle;
  217. /*
  218.  * This function can only be called once per process (i.e., not
  219.  * once per thread), so no synchronization is required.
  220.  *
  221.  * The caller is doing something wrong if close is called with
  222.  * active transactions.  Try and abort any active transactions,
  223.  * but it's quite likely the aborts will fail because recovery
  224.  * won't find open files.  If we can't abort any transaction,
  225.  * panic, we have to run recovery to get back to a known state.
  226.  */
  227. if (TAILQ_FIRST(&tmgrp->txn_chain) != NULL) {
  228. __db_err(dbenv,
  229. "Error: closing the transaction region with active transactions");
  230. ret = EINVAL;
  231. while ((txnp = TAILQ_FIRST(&tmgrp->txn_chain)) != NULL) {
  232. txnid = txnp->txnid;
  233. if ((t_ret = txnp->abort(txnp)) != 0) {
  234. __db_err(dbenv,
  235.     "Unable to abort transaction 0x%x: %s",
  236.     txnid, db_strerror(t_ret));
  237. ret = __db_panic(dbenv, t_ret);
  238. break;
  239. }
  240. }
  241. }
  242. /* Flush the log. */
  243. if (LOGGING_ON(dbenv) &&
  244.     (t_ret = dbenv->log_flush(dbenv, NULL)) != 0 && ret == 0)
  245. ret = t_ret;
  246. /* Discard the per-thread lock. */
  247. if (tmgrp->mutexp != NULL)
  248. __db_mutex_free(dbenv, &tmgrp->reginfo, tmgrp->mutexp);
  249. /* Detach from the region. */
  250. if ((t_ret = __db_r_detach(dbenv, &tmgrp->reginfo, 0)) != 0 && ret == 0)
  251. ret = t_ret;
  252. __os_free(dbenv, tmgrp);
  253. dbenv->tx_handle = NULL;
  254. return (ret);
  255. }
  256. /*
  257.  * __txn_region_size --
  258.  *  Return the amount of space needed for the txn region.  Make the
  259.  *  region large enough to hold txn_max transaction detail structures
  260.  *  plus some space to hold thread handles and the beginning of the
  261.  *  shalloc region and anything we need for mutex system resource
  262.  *  recording.
  263.  */
  264. static size_t
  265. __txn_region_size(dbenv)
  266. DB_ENV *dbenv;
  267. {
  268. size_t s;
  269. s = sizeof(DB_TXNREGION) +
  270.     dbenv->tx_max * sizeof(TXN_DETAIL) + 10 * 1024;
  271. #ifdef HAVE_MUTEX_SYSTEM_RESOURCES
  272. if (F_ISSET(dbenv, DB_ENV_THREAD))
  273. s += sizeof(REGMAINT) + TXN_MAINT_SIZE;
  274. #endif
  275. return (s);
  276. }
  277. /*
  278.  * __txn_region_destroy
  279.  * Destroy any region maintenance info.
  280.  *
  281.  * PUBLIC: void __txn_region_destroy __P((DB_ENV *, REGINFO *));
  282.  */
  283. void
  284. __txn_region_destroy(dbenv, infop)
  285. DB_ENV *dbenv;
  286. REGINFO *infop;
  287. {
  288. __db_shlocks_destroy(infop, (REGMAINT *)R_ADDR(infop,
  289.     ((DB_TXNREGION *)R_ADDR(infop, infop->rp->primary))->maint_off));
  290. COMPQUIET(dbenv, NULL);
  291. COMPQUIET(infop, NULL);
  292. }
  293. #ifdef CONFIG_TEST
  294. /*
  295.  * __txn_id_set --
  296.  * Set the current transaction ID and current maximum unused ID (for
  297.  * testing purposes only).
  298.  *
  299.  * PUBLIC: int __txn_id_set __P((DB_ENV *, u_int32_t, u_int32_t));
  300.  */
  301. int
  302. __txn_id_set(dbenv, cur_txnid, max_txnid)
  303. DB_ENV *dbenv;
  304. u_int32_t cur_txnid, max_txnid;
  305. {
  306. DB_TXNMGR *mgr;
  307. DB_TXNREGION *region;
  308. int ret;
  309. ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, "txn_id_set", DB_INIT_TXN);
  310. mgr = dbenv->tx_handle;
  311. region = mgr->reginfo.primary;
  312. region->last_txnid = cur_txnid;
  313. region->cur_maxid = max_txnid;
  314. ret = 0;
  315. if (cur_txnid < TXN_MINIMUM) {
  316. __db_err(dbenv, "Current ID value %lu below minimum",
  317.     cur_txnid);
  318. ret = EINVAL;
  319. }
  320. if (max_txnid < TXN_MINIMUM) {
  321. __db_err(dbenv, "Maximum ID value %lu below minimum",
  322.     max_txnid);
  323. ret = EINVAL;
  324. }
  325. return (ret);
  326. }
  327. #endif