txn_region.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:9k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996, 1997, 1998, 1999, 2000
  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.36 2001/01/11 18:19:55 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. #ifdef  HAVE_RPC
  26. #include "db_server.h"
  27. #endif
  28. #include "db_int.h"
  29. #include "db_page.h"
  30. #include "log.h" /* for __log_lastckp */
  31. #include "txn.h"
  32. #include "db_am.h"
  33. #ifdef HAVE_RPC
  34. #include "gen_client_ext.h"
  35. #include "rpc_client_ext.h"
  36. #endif
  37. static int __txn_init __P((DB_ENV *, DB_TXNMGR *));
  38. static int __txn_set_tx_max __P((DB_ENV *, u_int32_t));
  39. static int __txn_set_tx_recover __P((DB_ENV *,
  40.        int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops)));
  41. static int __txn_set_tx_timestamp __P((DB_ENV *, time_t *));
  42. /*
  43.  * __txn_dbenv_create --
  44.  * Transaction specific initialization of the DB_ENV structure.
  45.  *
  46.  * PUBLIC: void __txn_dbenv_create __P((DB_ENV *));
  47.  */
  48. void
  49. __txn_dbenv_create(dbenv)
  50. DB_ENV *dbenv;
  51. {
  52. dbenv->tx_max = DEF_MAX_TXNS;
  53. dbenv->set_tx_max = __txn_set_tx_max;
  54. dbenv->set_tx_recover = __txn_set_tx_recover;
  55. dbenv->set_tx_timestamp = __txn_set_tx_timestamp;
  56. #ifdef HAVE_RPC
  57. /*
  58.  * If we have a client, overwrite what we just setup to point to
  59.  * client functions.
  60.  */
  61. if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) {
  62. dbenv->set_tx_max = __dbcl_set_tx_max;
  63. dbenv->set_tx_recover = __dbcl_set_tx_recover;
  64. dbenv->set_tx_timestamp = __dbcl_set_tx_timestamp;
  65. }
  66. #endif
  67. }
  68. /*
  69.  * __txn_set_tx_max --
  70.  * Set the size of the transaction table.
  71.  */
  72. static int
  73. __txn_set_tx_max(dbenv, tx_max)
  74. DB_ENV *dbenv;
  75. u_int32_t tx_max;
  76. {
  77. ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_tx_max");
  78. dbenv->tx_max = tx_max;
  79. return (0);
  80. }
  81. /*
  82.  * __txn_set_tx_recover --
  83.  * Set the transaction abort recover function.
  84.  */
  85. static int
  86. __txn_set_tx_recover(dbenv, tx_recover)
  87. DB_ENV *dbenv;
  88. int (*tx_recover) __P((DB_ENV *, DBT *, DB_LSN *, db_recops));
  89. {
  90. dbenv->tx_recover = tx_recover;
  91. return (0);
  92. }
  93. /*
  94.  * __txn_set_tx_timestamp --
  95.  * Set the transaction recovery timestamp.
  96.  */
  97. static int
  98. __txn_set_tx_timestamp(dbenv, timestamp)
  99. DB_ENV *dbenv;
  100. time_t *timestamp;
  101. {
  102. ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_tx_timestamp");
  103. dbenv->tx_timestamp = *timestamp;
  104. return (0);
  105. }
  106. /*
  107.  * __txn_open --
  108.  * Open a transaction region.
  109.  *
  110.  * PUBLIC: int __txn_open __P((DB_ENV *));
  111.  */
  112. int
  113. __txn_open(dbenv)
  114. DB_ENV *dbenv;
  115. {
  116. DB_TXNMGR *tmgrp;
  117. int ret;
  118. /* Create/initialize the transaction manager structure. */
  119. if ((ret = __os_calloc(dbenv, 1, sizeof(DB_TXNMGR), &tmgrp)) != 0)
  120. return (ret);
  121. TAILQ_INIT(&tmgrp->txn_chain);
  122. tmgrp->dbenv = dbenv;
  123. /* Join/create the txn region. */
  124. tmgrp->reginfo.type = REGION_TYPE_TXN;
  125. tmgrp->reginfo.id = INVALID_REGION_ID;
  126. tmgrp->reginfo.mode = dbenv->db_mode;
  127. tmgrp->reginfo.flags = REGION_JOIN_OK;
  128. if (F_ISSET(dbenv, DB_ENV_CREATE))
  129. F_SET(&tmgrp->reginfo, REGION_CREATE_OK);
  130. if ((ret = __db_r_attach(dbenv,
  131.     &tmgrp->reginfo, TXN_REGION_SIZE(dbenv->tx_max))) != 0)
  132. goto err;
  133. /* If we created the region, initialize it. */
  134. if (F_ISSET(&tmgrp->reginfo, REGION_CREATE))
  135. if ((ret = __txn_init(dbenv, tmgrp)) != 0)
  136. goto err;
  137. /* Set the local addresses. */
  138. tmgrp->reginfo.primary =
  139.     R_ADDR(&tmgrp->reginfo, tmgrp->reginfo.rp->primary);
  140. /* Acquire a mutex to protect the active TXN list. */
  141. if (F_ISSET(dbenv, DB_ENV_THREAD)) {
  142. if ((ret = __db_mutex_alloc(
  143.     dbenv, &tmgrp->reginfo, &tmgrp->mutexp)) != 0)
  144. goto err;
  145. if ((ret = __db_mutex_init(
  146.     dbenv, tmgrp->mutexp, 0, MUTEX_THREAD)) != 0)
  147. goto err;
  148. }
  149. R_UNLOCK(dbenv, &tmgrp->reginfo);
  150. dbenv->tx_handle = tmgrp;
  151. return (0);
  152. err: if (tmgrp->reginfo.addr != NULL) {
  153. if (F_ISSET(&tmgrp->reginfo, REGION_CREATE))
  154. ret = __db_panic(dbenv, ret);
  155. R_UNLOCK(dbenv, &tmgrp->reginfo);
  156. (void)__db_r_detach(dbenv, &tmgrp->reginfo, 0);
  157. }
  158. if (tmgrp->mutexp != NULL)
  159. __db_mutex_free(dbenv, &tmgrp->reginfo, tmgrp->mutexp);
  160. __os_free(tmgrp, sizeof(*tmgrp));
  161. return (ret);
  162. }
  163. /*
  164.  * __txn_init --
  165.  * Initialize a transaction region in shared memory.
  166.  */
  167. static int
  168. __txn_init(dbenv, tmgrp)
  169. DB_ENV *dbenv;
  170. DB_TXNMGR *tmgrp;
  171. {
  172. DB_LSN last_ckp;
  173. DB_TXNREGION *region;
  174. int ret;
  175. ZERO_LSN(last_ckp);
  176. /*
  177.  * If possible, fetch the last checkpoint LSN from the log system
  178.  * so that the backwards chain of checkpoints is unbroken when
  179.  * the environment is removed and recreated. [#2865]
  180.  */
  181. if (LOGGING_ON(dbenv) && (ret = __log_lastckp(dbenv, &last_ckp)) != 0)
  182. return (ret);
  183. if ((ret = __db_shalloc(tmgrp->reginfo.addr,
  184.     sizeof(DB_TXNREGION), 0, &tmgrp->reginfo.primary)) != 0) {
  185. __db_err(dbenv,
  186.     "Unable to allocate memory for the transaction region");
  187. return (ret);
  188. }
  189. tmgrp->reginfo.rp->primary =
  190.     R_OFFSET(&tmgrp->reginfo, tmgrp->reginfo.primary);
  191. region = tmgrp->reginfo.primary;
  192. memset(region, 0, sizeof(*region));
  193. region->maxtxns = dbenv->tx_max;
  194. region->last_txnid = TXN_MINIMUM;
  195. ZERO_LSN(region->pending_ckp);
  196. region->last_ckp = last_ckp;
  197. region->time_ckp = time(NULL);
  198. /*
  199.  * XXX
  200.  * If we ever do more types of locking and logging, this changes.
  201.  */
  202. region->logtype = 0;
  203. region->locktype = 0;
  204. region->naborts = 0;
  205. region->ncommits = 0;
  206. region->nbegins = 0;
  207. region->nactive = 0;
  208. region->maxnactive = 0;
  209. SH_TAILQ_INIT(&region->active_txn);
  210. return (0);
  211. }
  212. /*
  213.  * __txn_close --
  214.  * Close a transaction region.
  215.  *
  216.  * PUBLIC: int __txn_close __P((DB_ENV *));
  217.  */
  218. int
  219. __txn_close(dbenv)
  220. DB_ENV *dbenv;
  221. {
  222. DB_TXN *txnp;
  223. DB_TXNMGR *tmgrp;
  224. u_int32_t txnid;
  225. int ret, t_ret;
  226. ret = 0;
  227. tmgrp = dbenv->tx_handle;
  228. /*
  229.  * This function can only be called once per process (i.e., not
  230.  * once per thread), so no synchronization is required.
  231.  *
  232.  * The caller is doing something wrong if close is called with
  233.  * active transactions.  Try and abort any active transactions,
  234.  * but it's quite likely the aborts will fail because recovery
  235.  * won't find open files.  If we can't abort any transaction,
  236.  * panic, we have to run recovery to get back to a known state.
  237.  */
  238. if (TAILQ_FIRST(&tmgrp->txn_chain) != NULL) {
  239. __db_err(dbenv,
  240. "Error: closing the transaction region with active transactionsn");
  241. ret = EINVAL;
  242. while ((txnp = TAILQ_FIRST(&tmgrp->txn_chain)) != NULL) {
  243. txnid = txnp->txnid;
  244. if ((t_ret = txn_abort(txnp)) != 0) {
  245. __db_err(dbenv,
  246.     "Unable to abort transaction 0x%x: %sn",
  247.     txnid, db_strerror(t_ret));
  248. ret = __db_panic(dbenv, t_ret);
  249. }
  250. }
  251. }
  252. /* Flush the log. */
  253. if (LOGGING_ON(dbenv) &&
  254.     (t_ret = log_flush(dbenv, NULL)) != 0 && ret == 0)
  255. ret = t_ret;
  256. /* Discard the per-thread lock. */
  257. if (tmgrp->mutexp != NULL)
  258. __db_mutex_free(dbenv, &tmgrp->reginfo, tmgrp->mutexp);
  259. /* Detach from the region. */
  260. if ((t_ret = __db_r_detach(dbenv, &tmgrp->reginfo, 0)) != 0 && ret == 0)
  261. ret = t_ret;
  262. __os_free(tmgrp, sizeof(*tmgrp));
  263. dbenv->tx_handle = NULL;
  264. return (ret);
  265. }
  266. int
  267. txn_stat(dbenv, statp, db_malloc)
  268. DB_ENV *dbenv;
  269. DB_TXN_STAT **statp;
  270. void *(*db_malloc) __P((size_t));
  271. {
  272. DB_TXNMGR *mgr;
  273. DB_TXNREGION *region;
  274. DB_TXN_STAT *stats;
  275. TXN_DETAIL *txnp;
  276. size_t nbytes;
  277. u_int32_t nactive, ndx;
  278. int ret, slop;
  279. #ifdef HAVE_RPC
  280. if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
  281. return (__dbcl_txn_stat(dbenv, statp, db_malloc));
  282. #endif
  283. PANIC_CHECK(dbenv);
  284. ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, DB_INIT_TXN);
  285. *statp = NULL;
  286. slop = 200;
  287. mgr = dbenv->tx_handle;
  288. region = mgr->reginfo.primary;
  289. retry: R_LOCK(dbenv, &mgr->reginfo);
  290. nactive = region->nactive;
  291. R_UNLOCK(dbenv, &mgr->reginfo);
  292. /*
  293.  * Allocate extra active structures to handle any transactions that
  294.  * are created while we have the region unlocked.
  295.  */
  296. nbytes = sizeof(DB_TXN_STAT) + sizeof(DB_TXN_ACTIVE) * (nactive + slop);
  297. if ((ret = __os_malloc(dbenv, nbytes, db_malloc, &stats)) != 0)
  298. return (ret);
  299. R_LOCK(dbenv, &mgr->reginfo);
  300. stats->st_last_txnid = region->last_txnid;
  301. stats->st_last_ckp = region->last_ckp;
  302. stats->st_maxtxns = region->maxtxns;
  303. stats->st_naborts = region->naborts;
  304. stats->st_nbegins = region->nbegins;
  305. stats->st_ncommits = region->ncommits;
  306. stats->st_pending_ckp = region->pending_ckp;
  307. stats->st_time_ckp = region->time_ckp;
  308. stats->st_nactive = region->nactive;
  309. if (stats->st_nactive > nactive + 200) {
  310. R_UNLOCK(dbenv, &mgr->reginfo);
  311. slop *= 2;
  312. goto retry;
  313. }
  314. stats->st_maxnactive = region->maxnactive;
  315. stats->st_txnarray = (DB_TXN_ACTIVE *)&stats[1];
  316. ndx = 0;
  317. for (txnp = SH_TAILQ_FIRST(&region->active_txn, __txn_detail);
  318.     txnp != NULL;
  319.     txnp = SH_TAILQ_NEXT(txnp, links, __txn_detail)) {
  320. stats->st_txnarray[ndx].txnid = txnp->txnid;
  321. if (txnp->parent == INVALID_ROFF)
  322. stats->st_txnarray[ndx].parentid = TXN_INVALID_ID;
  323. else
  324. stats->st_txnarray[ndx].parentid =
  325.     ((TXN_DETAIL *)R_ADDR(&mgr->reginfo,
  326.     txnp->parent))->txnid;
  327. stats->st_txnarray[ndx].lsn = txnp->begin_lsn;
  328. ndx++;
  329. if (ndx >= stats->st_nactive)
  330. break;
  331. }
  332. stats->st_region_wait = mgr->reginfo.rp->mutex.mutex_set_wait;
  333. stats->st_region_nowait = mgr->reginfo.rp->mutex.mutex_set_nowait;
  334. stats->st_regsize = mgr->reginfo.rp->size;
  335. R_UNLOCK(dbenv, &mgr->reginfo);
  336. *statp = stats;
  337. return (0);
  338. }