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

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1998-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: xa.c,v 11.23 2002/08/29 14:22:25 margo Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #endif
  16. #include "db_int.h"
  17. #include "dbinc/txn.h"
  18. static int  __db_xa_close __P((char *, int, long));
  19. static int  __db_xa_commit __P((XID *, int, long));
  20. static int  __db_xa_complete __P((int *, int *, int, long));
  21. static int  __db_xa_end __P((XID *, int, long));
  22. static int  __db_xa_forget __P((XID *, int, long));
  23. static int  __db_xa_open __P((char *, int, long));
  24. static int  __db_xa_prepare __P((XID *, int, long));
  25. static int  __db_xa_recover __P((XID *, long, int, long));
  26. static int  __db_xa_rollback __P((XID *, int, long));
  27. static int  __db_xa_start __P((XID *, int, long));
  28. static void __xa_txn_end __P((DB_TXN *));
  29. /*
  30.  * Possible flag values:
  31.  * Dynamic registration 0 => no dynamic registration
  32.  * TMREGISTER => dynamic registration
  33.  * Asynchronous operation 0 => no support for asynchrony
  34.  * TMUSEASYNC => async support
  35.  * Migration support 0 => migration of transactions across
  36.  *      threads is possible
  37.  * TMNOMIGRATE => no migration across threads
  38.  */
  39. const struct xa_switch_t db_xa_switch = {
  40.  "Berkeley DB", /* name[RMNAMESZ] */
  41.  TMNOMIGRATE, /* flags */
  42.  0, /* version */
  43.  __db_xa_open, /* xa_open_entry */
  44.  __db_xa_close, /* xa_close_entry */
  45.  __db_xa_start, /* xa_start_entry */
  46.  __db_xa_end, /* xa_end_entry */
  47.  __db_xa_rollback, /* xa_rollback_entry */
  48.  __db_xa_prepare, /* xa_prepare_entry */
  49.  __db_xa_commit, /* xa_commit_entry */
  50.  __db_xa_recover, /* xa_recover_entry */
  51.  __db_xa_forget, /* xa_forget_entry */
  52.  __db_xa_complete /* xa_complete_entry */
  53. };
  54. /*
  55.  * __db_xa_open --
  56.  * The open call in the XA protocol.  The rmid field is an id number
  57.  * that the TM assigned us and will pass us on every xa call.  We need to
  58.  * map that rmid number into a dbenv structure that we create during
  59.  * initialization.  Since this id number is thread specific, we do not
  60.  * need to store it in shared memory.  The file xa_map.c implements all
  61.  * such xa->db mappings.
  62.  * The xa_info field is instance specific information.  We require
  63.  * that the value of DB_HOME be passed in xa_info.  Since xa_info is the
  64.  * only thing that we get to pass to db_env_create, any config information
  65.  * will have to be done via a config file instead of via the db_env_create
  66.  * call.
  67.  */
  68. static int
  69. __db_xa_open(xa_info, rmid, flags)
  70. char *xa_info;
  71. int rmid;
  72. long flags;
  73. {
  74. DB_ENV *env;
  75. if (LF_ISSET(TMASYNC))
  76. return (XAER_ASYNC);
  77. if (flags != TMNOFLAGS)
  78. return (XAER_INVAL);
  79. /* Verify if we already have this environment open. */
  80. if (__db_rmid_to_env(rmid, &env) == 0)
  81. return (XA_OK);
  82. if (__os_calloc(env, 1, sizeof(DB_ENV), &env) != 0)
  83. return (XAER_RMERR);
  84. /* Open a new environment. */
  85. #define XA_FLAGS 
  86. DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN
  87. if (db_env_create(&env, 0) != 0)
  88. return (XAER_RMERR);
  89. if (env->open(env, xa_info, XA_FLAGS, 0) != 0)
  90. goto err;
  91. /* Create the mapping. */
  92. if (__db_map_rmid(rmid, env) != 0)
  93. goto err;
  94. /* Allocate space for the current transaction. */
  95. if (__os_calloc(env, 1, sizeof(DB_TXN), &env->xa_txn) != 0)
  96. goto err;
  97. env->xa_txn->txnid = TXN_INVALID;
  98. return (XA_OK);
  99. err: (void)env->close(env, 0);
  100. return (XAER_RMERR);
  101. }
  102. /*
  103.  * __db_xa_close --
  104.  * The close call of the XA protocol.  The only trickiness here
  105.  * is that if there are any active transactions, we must fail.  It is
  106.  * *not* an error to call close on an environment that has already been
  107.  * closed (I am interpreting that to mean it's OK to call close on an
  108.  * environment that has never been opened).
  109.  */
  110. static int
  111. __db_xa_close(xa_info, rmid, flags)
  112. char *xa_info;
  113. int rmid;
  114. long flags;
  115. {
  116. DB_ENV *env;
  117. int ret, t_ret;
  118. COMPQUIET(xa_info, NULL);
  119. if (LF_ISSET(TMASYNC))
  120. return (XAER_ASYNC);
  121. if (flags != TMNOFLAGS)
  122. return (XAER_INVAL);
  123. /* If the environment is closed, then we're done. */
  124. if (__db_rmid_to_env(rmid, &env) != 0)
  125. return (XA_OK);
  126. /* Check if there are any pending transactions. */
  127. if (env->xa_txn != NULL && env->xa_txn->txnid != TXN_INVALID)
  128. return (XAER_PROTO);
  129. /* Destroy the mapping. */
  130. ret = __db_unmap_rmid(rmid);
  131. /* Discard space held for the current transaction. */
  132. if (env->xa_txn != NULL)
  133. __os_free(env, env->xa_txn);
  134. /* Close the environment. */
  135. if ((t_ret = env->close(env, 0)) != 0 && ret == 0)
  136. ret = t_ret;
  137. return (ret == 0 ? XA_OK : XAER_RMERR);
  138. }
  139. /*
  140.  * __db_xa_start --
  141.  * Begin a transaction for the current resource manager.
  142.  */
  143. static int
  144. __db_xa_start(xid, rmid, flags)
  145. XID *xid;
  146. int rmid;
  147. long flags;
  148. {
  149. DB_ENV *env;
  150. TXN_DETAIL *td;
  151. size_t off;
  152. int is_known;
  153. #define OK_FLAGS (TMJOIN | TMRESUME | TMNOWAIT | TMASYNC | TMNOFLAGS)
  154. if (LF_ISSET(~OK_FLAGS))
  155. return (XAER_INVAL);
  156. if (LF_ISSET(TMJOIN) && LF_ISSET(TMRESUME))
  157. return (XAER_INVAL);
  158. if (LF_ISSET(TMASYNC))
  159. return (XAER_ASYNC);
  160. if (__db_rmid_to_env(rmid, &env) != 0)
  161. return (XAER_PROTO);
  162. is_known = __db_xid_to_txn(env, xid, &off) == 0;
  163. if (is_known && !LF_ISSET(TMRESUME) && !LF_ISSET(TMJOIN))
  164. return (XAER_DUPID);
  165. if (!is_known && LF_ISSET(TMRESUME | TMJOIN))
  166. return (XAER_NOTA);
  167. /*
  168.  * This can't block, so we can ignore TMNOWAIT.
  169.  *
  170.  * Other error conditions: RMERR, RMFAIL, OUTSIDE, PROTO, RB*
  171.  */
  172. if (is_known) {
  173. td = (TXN_DETAIL *)
  174.     R_ADDR(&((DB_TXNMGR *)env->tx_handle)->reginfo, off);
  175. if (td->xa_status == TXN_XA_SUSPENDED &&
  176.     !LF_ISSET(TMRESUME | TMJOIN))
  177. return (XAER_PROTO);
  178. if (td->xa_status == TXN_XA_DEADLOCKED)
  179. return (XA_RBDEADLOCK);
  180. if (td->xa_status == TXN_XA_ABORTED)
  181. return (XA_RBOTHER);
  182. /* Now, fill in the global transaction structure. */
  183. __txn_continue(env, env->xa_txn, td, off);
  184. td->xa_status = TXN_XA_STARTED;
  185. } else {
  186. if (__txn_xa_begin(env, env->xa_txn) != 0)
  187. return (XAER_RMERR);
  188. (void)__db_map_xid(env, xid, env->xa_txn->off);
  189. td = (TXN_DETAIL *)
  190.     R_ADDR(&((DB_TXNMGR *)env->tx_handle)->reginfo,
  191.     env->xa_txn->off);
  192. td->xa_status = TXN_XA_STARTED;
  193. }
  194. return (XA_OK);
  195. }
  196. /*
  197.  * __db_xa_end --
  198.  * Disassociate the current transaction from the current process.
  199.  */
  200. static int
  201. __db_xa_end(xid, rmid, flags)
  202. XID *xid;
  203. int rmid;
  204. long flags;
  205. {
  206. DB_ENV *env;
  207. DB_TXN *txn;
  208. TXN_DETAIL *td;
  209. size_t off;
  210. if (flags != TMNOFLAGS && !LF_ISSET(TMSUSPEND | TMSUCCESS | TMFAIL))
  211. return (XAER_INVAL);
  212. if (__db_rmid_to_env(rmid, &env) != 0)
  213. return (XAER_PROTO);
  214. if (__db_xid_to_txn(env, xid, &off) != 0)
  215. return (XAER_NOTA);
  216. txn = env->xa_txn;
  217. if (off != txn->off)
  218. return (XAER_PROTO);
  219. td = (TXN_DETAIL *)R_ADDR(&((DB_TXNMGR *)env->tx_handle)->reginfo, off);
  220. if (td->xa_status == TXN_XA_DEADLOCKED)
  221. return (XA_RBDEADLOCK);
  222. if (td->status == TXN_ABORTED)
  223. return (XA_RBOTHER);
  224. if (td->xa_status != TXN_XA_STARTED)
  225. return (XAER_PROTO);
  226. /* Update the shared memory last_lsn field */
  227. td->last_lsn = txn->last_lsn;
  228. /*
  229.  * If we ever support XA migration, we cannot keep SUSPEND/END
  230.  * status in the shared region; it would have to be process local.
  231.  */
  232. if (LF_ISSET(TMSUSPEND))
  233. td->xa_status = TXN_XA_SUSPENDED;
  234. else
  235. td->xa_status = TXN_XA_ENDED;
  236. txn->txnid = TXN_INVALID;
  237. return (XA_OK);
  238. }
  239. /*
  240.  * __db_xa_prepare --
  241.  * Sync the log to disk so we can guarantee recoverability.
  242.  */
  243. static int
  244. __db_xa_prepare(xid, rmid, flags)
  245. XID *xid;
  246. int rmid;
  247. long flags;
  248. {
  249. DB_ENV *env;
  250. TXN_DETAIL *td;
  251. size_t off;
  252. if (LF_ISSET(TMASYNC))
  253. return (XAER_ASYNC);
  254. if (flags != TMNOFLAGS)
  255. return (XAER_INVAL);
  256. /*
  257.  * We need to know if we've ever called prepare on this.
  258.  * As part of the prepare, we set the xa_status field to
  259.  * reflect that fact that prepare has been called, and if
  260.  * it's ever called again, it's an error.
  261.  */
  262. if (__db_rmid_to_env(rmid, &env) != 0)
  263. return (XAER_PROTO);
  264. if (__db_xid_to_txn(env, xid, &off) != 0)
  265. return (XAER_NOTA);
  266. td = (TXN_DETAIL *)R_ADDR(&((DB_TXNMGR *)env->tx_handle)->reginfo, off);
  267. if (td->xa_status == TXN_XA_DEADLOCKED)
  268. return (XA_RBDEADLOCK);
  269. if (td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED)
  270. return (XAER_PROTO);
  271. /* Now, fill in the global transaction structure. */
  272. __txn_continue(env, env->xa_txn, td, off);
  273. if (env->xa_txn->prepare(env->xa_txn, (u_int8_t *)xid->data) != 0)
  274. return (XAER_RMERR);
  275. td->xa_status = TXN_XA_PREPARED;
  276. /* No fatal value that would require an XAER_RMFAIL. */
  277. __xa_txn_end(env->xa_txn);
  278. return (XA_OK);
  279. }
  280. /*
  281.  * __db_xa_commit --
  282.  * Commit the transaction
  283.  */
  284. static int
  285. __db_xa_commit(xid, rmid, flags)
  286. XID *xid;
  287. int rmid;
  288. long flags;
  289. {
  290. DB_ENV *env;
  291. TXN_DETAIL *td;
  292. size_t off;
  293. if (LF_ISSET(TMASYNC))
  294. return (XAER_ASYNC);
  295. #undef OK_FLAGS
  296. #define OK_FLAGS (TMNOFLAGS | TMNOWAIT | TMONEPHASE)
  297. if (LF_ISSET(~OK_FLAGS))
  298. return (XAER_INVAL);
  299. /*
  300.  * We need to know if we've ever called prepare on this.
  301.  * We can verify this by examining the xa_status field.
  302.  */
  303. if (__db_rmid_to_env(rmid, &env) != 0)
  304. return (XAER_PROTO);
  305. if (__db_xid_to_txn(env, xid, &off) != 0)
  306. return (XAER_NOTA);
  307. td = (TXN_DETAIL *)R_ADDR(&((DB_TXNMGR *)env->tx_handle)->reginfo, off);
  308. if (td->xa_status == TXN_XA_DEADLOCKED)
  309. return (XA_RBDEADLOCK);
  310. if (td->xa_status == TXN_XA_ABORTED)
  311. return (XA_RBOTHER);
  312. if (LF_ISSET(TMONEPHASE) &&
  313.     td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED)
  314. return (XAER_PROTO);
  315. if (!LF_ISSET(TMONEPHASE) && td->xa_status != TXN_XA_PREPARED)
  316. return (XAER_PROTO);
  317. /* Now, fill in the global transaction structure. */
  318. __txn_continue(env, env->xa_txn, td, off);
  319. if (env->xa_txn->commit(env->xa_txn, 0) != 0)
  320. return (XAER_RMERR);
  321. /* No fatal value that would require an XAER_RMFAIL. */
  322. __xa_txn_end(env->xa_txn);
  323. return (XA_OK);
  324. }
  325. /*
  326.  * __db_xa_recover --
  327.  * Returns a list of prepared and heuristically completed transactions.
  328.  *
  329.  * The return value is the number of xids placed into the xid array (less
  330.  * than or equal to the count parameter).  The flags are going to indicate
  331.  * whether we are starting a scan or continuing one.
  332.  */
  333. static int
  334. __db_xa_recover(xids, count, rmid, flags)
  335. XID *xids;
  336. long count, flags;
  337. int rmid;
  338. {
  339. DB_ENV *env;
  340. u_int32_t newflags;
  341. long rval;
  342. /* If the environment is closed, then we're done. */
  343. if (__db_rmid_to_env(rmid, &env) != 0)
  344. return (XAER_PROTO);
  345. if (LF_ISSET(TMSTARTRSCAN))
  346. newflags = DB_FIRST;
  347. else if (LF_ISSET(TMENDRSCAN))
  348. newflags = DB_LAST;
  349. else
  350. newflags = DB_NEXT;
  351. rval = 0;
  352. if (__txn_get_prepared(env, xids, NULL, count, &rval, newflags) != 0)
  353. return (XAER_RMERR);
  354. else
  355. return (rval);
  356. }
  357. /*
  358.  * __db_xa_rollback
  359.  * Abort an XA transaction.
  360.  */
  361. static int
  362. __db_xa_rollback(xid, rmid, flags)
  363. XID *xid;
  364. int rmid;
  365. long flags;
  366. {
  367. DB_ENV *env;
  368. TXN_DETAIL *td;
  369. size_t off;
  370. if (LF_ISSET(TMASYNC))
  371. return (XAER_ASYNC);
  372. if (flags != TMNOFLAGS)
  373. return (XAER_INVAL);
  374. if (__db_rmid_to_env(rmid, &env) != 0)
  375. return (XAER_PROTO);
  376. if (__db_xid_to_txn(env, xid, &off) != 0)
  377. return (XAER_NOTA);
  378. td = (TXN_DETAIL *)R_ADDR(&((DB_TXNMGR *)env->tx_handle)->reginfo, off);
  379. if (td->xa_status == TXN_XA_DEADLOCKED)
  380. return (XA_RBDEADLOCK);
  381. if (td->xa_status == TXN_XA_ABORTED)
  382. return (XA_RBOTHER);
  383. if (td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED
  384.     && td->xa_status != TXN_XA_PREPARED)
  385. return (XAER_PROTO);
  386. /* Now, fill in the global transaction structure. */
  387. __txn_continue(env, env->xa_txn, td, off);
  388. if (env->xa_txn->abort(env->xa_txn) != 0)
  389. return (XAER_RMERR);
  390. /* No fatal value that would require an XAER_RMFAIL. */
  391. __xa_txn_end(env->xa_txn);
  392. return (XA_OK);
  393. }
  394. /*
  395.  * __db_xa_forget --
  396.  * Forget about an XID for a transaction that was heuristically
  397.  * completed.  Since we do not heuristically complete anything, I
  398.  * don't think we have to do anything here, but we should make sure
  399.  * that we reclaim the slots in the txnid table.
  400.  */
  401. static int
  402. __db_xa_forget(xid, rmid, flags)
  403. XID *xid;
  404. int rmid;
  405. long flags;
  406. {
  407. DB_ENV *env;
  408. size_t off;
  409. if (LF_ISSET(TMASYNC))
  410. return (XAER_ASYNC);
  411. if (flags != TMNOFLAGS)
  412. return (XAER_INVAL);
  413. if (__db_rmid_to_env(rmid, &env) != 0)
  414. return (XAER_PROTO);
  415. /*
  416.  * If mapping is gone, then we're done.
  417.  */
  418. if (__db_xid_to_txn(env, xid, &off) != 0)
  419. return (XA_OK);
  420. __db_unmap_xid(env, xid, off);
  421. /* No fatal value that would require an XAER_RMFAIL. */
  422. return (XA_OK);
  423. }
  424. /*
  425.  * __db_xa_complete --
  426.  * Used to wait for asynchronous operations to complete.  Since we're
  427.  * not doing asynch, this is an invalid operation.
  428.  */
  429. static int
  430. __db_xa_complete(handle, retval, rmid, flags)
  431. int *handle, *retval, rmid;
  432. long flags;
  433. {
  434. COMPQUIET(handle, NULL);
  435. COMPQUIET(retval, NULL);
  436. COMPQUIET(rmid, 0);
  437. COMPQUIET(flags, 0);
  438. return (XAER_INVAL);
  439. }
  440. /*
  441.  * __xa_txn_end --
  442.  * Invalidate a transaction structure that was generated by __txn_continue.
  443.  */
  444. static void
  445. __xa_txn_end(txn)
  446. DB_TXN *txn;
  447. {
  448. if (txn != NULL)
  449. txn->txnid = TXN_INVALID;
  450. }