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

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 2001-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: txn_util.c,v 11.18 2002/08/06 06:25:12 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #endif
  15. #include "db_int.h"
  16. #include "dbinc/db_shash.h"
  17. #include "dbinc/lock.h"
  18. #include "dbinc/txn.h"
  19. typedef struct __txn_event TXN_EVENT;
  20. struct __txn_event {
  21. TXN_EVENT_T op;
  22. TAILQ_ENTRY(__txn_event) links;
  23. union {
  24. struct {
  25. /* Delayed remove. */
  26. char *name;
  27. u_int8_t *fileid;
  28. } r;
  29. struct {
  30. /* Lock event. */
  31. DB_LOCK lock;
  32. u_int32_t locker;
  33. DB *dbp;
  34. } t;
  35. } u;
  36. };
  37. /*
  38.  * __txn_remevent --
  39.  *
  40.  * Creates a remove event that can be added to the commit list.
  41.  *
  42.  * PUBLIC: int __txn_remevent __P((DB_ENV *,
  43.  * PUBLIC:       DB_TXN *, const char *, u_int8_t*));
  44.  */
  45. int
  46. __txn_remevent(dbenv, txn, name, fileid)
  47. DB_ENV *dbenv;
  48. DB_TXN *txn;
  49. const char *name;
  50. u_int8_t *fileid;
  51. {
  52. int ret;
  53. TXN_EVENT *e;
  54. e = NULL;
  55. if ((ret = __os_calloc(dbenv, 1, sizeof(TXN_EVENT), &e)) != 0)
  56. return (ret);
  57. if ((ret = __os_strdup(dbenv, name, &e->u.r.name)) != 0)
  58. goto err;
  59. if (fileid != NULL) {
  60. if ((ret = __os_calloc(dbenv,
  61.     1, DB_FILE_ID_LEN, &e->u.r.fileid)) != 0)
  62. return (ret);
  63. memcpy(e->u.r.fileid, fileid, DB_FILE_ID_LEN);
  64. }
  65. e->op = TXN_REMOVE;
  66. TAILQ_INSERT_TAIL(&txn->events, e, links);
  67. return (0);
  68. err: if (e != NULL)
  69. __os_free(dbenv, e);
  70. return (ret);
  71. }
  72. /*
  73.  * __txn_lockevent --
  74.  *
  75.  * Add a lockevent to the commit-queue.  The lock event indicates a locker
  76.  * trade.
  77.  *
  78.  * PUBLIC: int __txn_lockevent __P((DB_ENV *,
  79.  * PUBLIC:     DB_TXN *, DB *, DB_LOCK *, u_int32_t));
  80.  */
  81. int
  82. __txn_lockevent(dbenv, txn, dbp, lock, locker)
  83. DB_ENV *dbenv;
  84. DB_TXN *txn;
  85. DB *dbp;
  86. DB_LOCK *lock;
  87. u_int32_t locker;
  88. {
  89. int ret;
  90. TXN_EVENT *e;
  91. if (!LOCKING_ON(dbenv))
  92. return (0);
  93. e = NULL;
  94. if ((ret = __os_calloc(dbenv, 1, sizeof(TXN_EVENT), &e)) != 0)
  95. return (ret);
  96. e->u.t.locker = locker;
  97. e->u.t.lock = *lock;
  98. e->u.t.dbp = dbp;
  99. e->op = TXN_TRADE;
  100. TAILQ_INSERT_TAIL(&txn->events, e, links);
  101. return (0);
  102. }
  103. /*
  104.  * __txn_remlock --
  105.  * Remove a lock event because the locker is going away.  We can remove
  106.  * by lock (using offset) or by locker_id (or by both).
  107.  *
  108.  * PUBLIC: void __txn_remlock __P((DB_ENV *, DB_TXN *, DB_LOCK *, u_int32_t));
  109.  */
  110. void
  111. __txn_remlock(dbenv, txn, lock, locker)
  112. DB_ENV *dbenv;
  113. DB_TXN *txn;
  114. DB_LOCK *lock;
  115. u_int32_t locker;
  116. {
  117. TXN_EVENT *e, *next_e;
  118. for (e = TAILQ_FIRST(&txn->events); e != NULL; e = next_e) {
  119. next_e = TAILQ_NEXT(e, links);
  120. if ((e->op != TXN_TRADE && e->op != TXN_TRADED) ||
  121.     (e->u.t.lock.off != lock->off && e->u.t.locker != locker))
  122. continue;
  123. TAILQ_REMOVE(&txn->events, e, links);
  124. __os_free(dbenv, e);
  125. }
  126. return;
  127. }
  128. /*
  129.  * __txn_doevents --
  130.  * Process the list of events associated with a transaction.  On commit,
  131.  * apply the events; on abort, just toss the entries.
  132.  *
  133.  * PUBLIC: int __txn_doevents __P((DB_ENV *, DB_TXN *, int, int));
  134.  */
  135. #define DO_TRADE do {
  136. memset(&req, 0, sizeof(req));
  137. req.lock = e->u.t.lock;
  138. req.op = DB_LOCK_TRADE;
  139. t_ret = __lock_vec(dbenv, e->u.t.locker, 0, &req, 1, NULL);
  140. if (t_ret == 0)
  141. e->u.t.dbp->cur_lid = e->u.t.locker;
  142. else if (t_ret == DB_NOTFOUND)
  143. t_ret = 0;
  144. if (t_ret != 0 && ret == 0)
  145. ret = t_ret;
  146. e->op = TXN_TRADED;
  147. } while (0)
  148. int
  149. __txn_doevents(dbenv, txn, is_commit, preprocess)
  150. DB_ENV *dbenv;
  151. DB_TXN *txn;
  152. int is_commit, preprocess;
  153. {
  154. DB_LOCKREQ req;
  155. TXN_EVENT *e;
  156. int ret, t_ret;
  157. ret = 0;
  158. /*
  159.  * This phase only gets called if we have a phase where we
  160.  * release read locks.  Since not all paths will call this
  161.  * phase, we have to check for it below as well.  So, when
  162.  * we do the trade, we update the opcode of the entry so that
  163.  * we don't try the trade again.
  164.  */
  165. if (preprocess) {
  166. for (e = TAILQ_FIRST(&txn->events);
  167.     e != NULL; e = TAILQ_NEXT(e, links)) {
  168. if (e->op != TXN_TRADE)
  169. continue;
  170. DO_TRADE;
  171. }
  172. return (ret);
  173. }
  174. while ((e = TAILQ_FIRST(&txn->events)) != NULL) {
  175. TAILQ_REMOVE(&txn->events, e, links);
  176. if (!is_commit)
  177. goto dofree;
  178. switch (e->op) {
  179. case TXN_REMOVE:
  180. if (e->u.r.fileid != NULL) {
  181. if ((t_ret = dbenv->memp_nameop(dbenv,
  182.     e->u.r.fileid,
  183.     NULL, e->u.r.name, NULL)) != 0 && ret == 0)
  184. ret = t_ret;
  185. __os_free(dbenv, e->u.r.fileid);
  186. } else if ((t_ret =
  187.     __os_unlink(dbenv, e->u.r.name)) != 0 && ret == 0)
  188. ret = t_ret;
  189. __os_free(dbenv, e->u.r.name);
  190. break;
  191. case TXN_TRADE:
  192. DO_TRADE;
  193. /* Fall through */
  194. case TXN_TRADED:
  195. /* Downgrade the lock. */
  196. if ((t_ret = __lock_downgrade(dbenv,
  197.     &e->u.t.lock, DB_LOCK_READ, 0)) != 0 && ret == 0)
  198. ret = t_ret;
  199. break;
  200. default:
  201. /* This had better never happen. */
  202. DB_ASSERT(0);
  203. }
  204. dofree: __os_free(dbenv, e);
  205. }
  206. return (ret);
  207. }