00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "db_config.h"
00011
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #endif
00018
00019 #include "db_int.h"
00020 #include "dbinc/txn.h"
00021
00022 static int __db_xa_close __P((char *, int, long));
00023 static int __db_xa_commit __P((XID *, int, long));
00024 static int __db_xa_complete __P((int *, int *, int, long));
00025 static int __db_xa_end __P((XID *, int, long));
00026 static int __db_xa_forget __P((XID *, int, long));
00027 static int __db_xa_open __P((char *, int, long));
00028 static int __db_xa_prepare __P((XID *, int, long));
00029 static int __db_xa_recover __P((XID *, long, int, long));
00030 static int __db_xa_rollback __P((XID *, int, long));
00031 static int __db_xa_start __P((XID *, int, long));
00032 static int __xa_put_txn __P((DB_ENV *, DB_TXN *));
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 const struct xa_switch_t db_xa_switch = {
00045 "Berkeley DB",
00046 TMNOMIGRATE,
00047 0,
00048 __db_xa_open,
00049 __db_xa_close,
00050 __db_xa_start,
00051 __db_xa_end,
00052 __db_xa_rollback,
00053 __db_xa_prepare,
00054 __db_xa_commit,
00055 __db_xa_recover,
00056 __db_xa_forget,
00057 __db_xa_complete
00058 };
00059
00060
00061
00062
00063
00064
00065
00066
00067 #undef XA_MULTI_THREAD
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 int
00078 __xa_get_txn(dbenv, txnp, do_init)
00079 DB_ENV *dbenv;
00080 DB_TXN **txnp;
00081 int do_init;
00082 {
00083 #ifdef XA_MULTI_THREAD
00084 DB_TXN *t;
00085 DB_TXNMGR *mgr;
00086 TXN_DETAIL *td;
00087 db_threadid_t tid;
00088 pid_t pid;
00089 #endif
00090 int ret;
00091
00092 ret = 0;
00093
00094 #ifdef XA_MULTI_THREAD
00095 dbenv->thread_id(dbenv, &pid, &tid);
00096 *txnp = NULL;
00097
00098 DB_ASSERT(dbenv->tx_handle != NULL);
00099 mgr = (DB_TXNMGR *)dbenv->tx_handle;
00100
00101
00102
00103
00104
00105
00106 MUTEX_LOCK(dbenv, mgr->mutex);
00107 for (t = TAILQ_FIRST(&dbenv->xa_txn);
00108 t != NULL;
00109 t = TAILQ_NEXT(t, xalinks)) {
00110 td = t->td;
00111 if (td->pid != pid)
00112 continue;
00113 #ifdef HAVE_INTEGRAL_THREAD_TYPE
00114 if (t->tid == tid) {
00115 *txnp = t;
00116 break;
00117 }
00118 #else
00119 if (memcmp(&t->tid, &tid, sizeof(tid)) == 0) {
00120 *txnp = t;
00121 break;
00122 }
00123 #endif
00124 }
00125 MUTEX_UNLOCK(dbenv, mgr->mutex);
00126
00127 if (*txnp == NULL) {
00128 if (!do_init)
00129 ret = EINVAL;
00130 else if ((ret =
00131 __os_malloc(dbenv, sizeof(DB_TXN), txnp)) == 0) {
00132 (*txnp)->tid = tid;
00133 MUTEX_LOCK(dbenv, mgr->mutex);
00134 TAILQ_INSERT_HEAD(&dbenv->xa_txn, *txnp, xalinks);
00135 MUTEX_UNLOCK(dbenv, mgr->mutex);
00136 }
00137 }
00138 #else
00139 COMPQUIET(do_init, 0);
00140
00141 *txnp = TAILQ_FIRST(&dbenv->xa_txn);
00142 if (*txnp == NULL &&
00143 (ret = __os_calloc(dbenv, 1, sizeof(DB_TXN), txnp)) == 0) {
00144 (*txnp)->txnid = TXN_INVALID;
00145 TAILQ_INSERT_HEAD(&dbenv->xa_txn, *txnp, xalinks);
00146 }
00147 #endif
00148
00149 return (ret);
00150 }
00151
00152 static int
00153 __xa_put_txn(dbenv, txnp)
00154 DB_ENV *dbenv;
00155 DB_TXN *txnp;
00156 {
00157 #ifdef XA_MULTI_THREAD
00158 DB_TXNMGR *mgr;
00159 mgr = (DB_TXNMGR *)dbenv->tx_handle;
00160
00161 MUTEX_LOCK(dbenv, mgr->mutex);
00162 TAILQ_REMOVE(&dbenv->xa_txn, txnp, xalinks);
00163 MUTEX_UNLOCK(dbenv, mgr->mutex);
00164 __os_free(dbenv, txnp);
00165 #else
00166 COMPQUIET(dbenv, NULL);
00167 txnp->txnid = TXN_INVALID;
00168 #endif
00169 return (0);
00170 }
00171
00172 #ifdef XA_MULTI_THREAD
00173 #define XA_FLAGS \
00174 (DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | \
00175 DB_INIT_TXN | DB_THREAD)
00176 #else
00177 #define XA_FLAGS \
00178 (DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | \
00179 DB_INIT_TXN)
00180 #endif
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196 static int
00197 __db_xa_open(xa_info, rmid, arg_flags)
00198 char *xa_info;
00199 int rmid;
00200 long arg_flags;
00201 {
00202 DB_ENV *dbenv;
00203 u_long flags;
00204
00205 flags = (u_long)arg_flags;
00206
00207 if (LF_ISSET(TMASYNC))
00208 return (XAER_ASYNC);
00209 if (flags != TMNOFLAGS)
00210 return (XAER_INVAL);
00211
00212
00213 if (__db_rmid_to_env(rmid, &dbenv) == 0)
00214 return (XA_OK);
00215
00216
00217 if (db_env_create(&dbenv, 0) != 0)
00218 return (XAER_RMERR);
00219 if (dbenv->open(dbenv, xa_info, XA_FLAGS, 0) != 0)
00220 goto err;
00221
00222
00223 if (__db_map_rmid(rmid, dbenv) != 0)
00224 goto err;
00225
00226
00227 TAILQ_INIT(&dbenv->xa_txn);
00228
00229 return (XA_OK);
00230
00231 err: (void)dbenv->close(dbenv, 0);
00232
00233 return (XAER_RMERR);
00234 }
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244 static int
00245 __db_xa_close(xa_info, rmid, arg_flags)
00246 char *xa_info;
00247 int rmid;
00248 long arg_flags;
00249 {
00250 DB_ENV *dbenv;
00251 DB_TXN *t;
00252 int ret, t_ret;
00253 u_long flags;
00254
00255 COMPQUIET(xa_info, NULL);
00256
00257 flags = (u_long)arg_flags;
00258
00259 if (LF_ISSET(TMASYNC))
00260 return (XAER_ASYNC);
00261 if (flags != TMNOFLAGS)
00262 return (XAER_INVAL);
00263
00264
00265 if (__db_rmid_to_env(rmid, &dbenv) != 0)
00266 return (XA_OK);
00267
00268
00269 if ((t = TAILQ_FIRST(&dbenv->xa_txn)) != NULL &&
00270 t->txnid != TXN_INVALID)
00271 return (XAER_PROTO);
00272
00273
00274 ret = __db_unmap_rmid(rmid);
00275
00276
00277 while ((t = TAILQ_FIRST(&dbenv->xa_txn)) != NULL) {
00278 TAILQ_REMOVE(&dbenv->xa_txn, t, xalinks);
00279 __os_free(dbenv, t);
00280 }
00281
00282
00283 if ((t_ret = dbenv->close(dbenv, 0)) != 0 && ret == 0)
00284 ret = t_ret;
00285
00286 return (ret == 0 ? XA_OK : XAER_RMERR);
00287 }
00288
00289
00290
00291
00292
00293 static int
00294 __db_xa_start(xid, rmid, arg_flags)
00295 XID *xid;
00296 int rmid;
00297 long arg_flags;
00298 {
00299 DB_ENV *dbenv;
00300 DB_TXN *txnp;
00301 TXN_DETAIL *td;
00302 roff_t off;
00303 u_long flags;
00304 int is_known;
00305
00306 flags = (u_long)arg_flags;
00307
00308 #define OK_FLAGS (TMJOIN | TMRESUME | TMNOWAIT | TMASYNC | TMNOFLAGS)
00309 if (LF_ISSET(~OK_FLAGS))
00310 return (XAER_INVAL);
00311
00312 if (LF_ISSET(TMJOIN) && LF_ISSET(TMRESUME))
00313 return (XAER_INVAL);
00314
00315 if (LF_ISSET(TMASYNC))
00316 return (XAER_ASYNC);
00317
00318 if (__db_rmid_to_env(rmid, &dbenv) != 0)
00319 return (XAER_PROTO);
00320
00321 is_known = __db_xid_to_txn(dbenv, xid, &off) == 0;
00322
00323 if (is_known && !LF_ISSET(TMRESUME) && !LF_ISSET(TMJOIN))
00324 return (XAER_DUPID);
00325
00326 if (!is_known && LF_ISSET(TMRESUME | TMJOIN))
00327 return (XAER_NOTA);
00328
00329
00330
00331
00332
00333
00334 if (is_known) {
00335 td = R_ADDR(&((DB_TXNMGR *)dbenv->tx_handle)->reginfo, off);
00336 if (td->xa_status == TXN_XA_SUSPENDED &&
00337 !LF_ISSET(TMRESUME | TMJOIN))
00338 return (XAER_PROTO);
00339 if (td->xa_status == TXN_XA_DEADLOCKED)
00340 return (XA_RBDEADLOCK);
00341 if (td->xa_status == TXN_XA_ABORTED)
00342 return (XA_RBOTHER);
00343
00344
00345 if (__xa_get_txn(dbenv, &txnp, 1) != 0)
00346 return (XAER_RMERR);
00347 __txn_continue(dbenv, txnp, td);
00348 td->xa_status = TXN_XA_STARTED;
00349 } else {
00350 if (__xa_get_txn(dbenv, &txnp, 1) != 0)
00351 return (XAER_RMERR);
00352 if (__txn_xa_begin(dbenv, txnp))
00353 return (XAER_RMERR);
00354 (void)__db_map_xid(dbenv, xid, txnp->td);
00355 td = txnp->td;
00356 td->xa_status = TXN_XA_STARTED;
00357 }
00358 return (XA_OK);
00359 }
00360
00361
00362
00363
00364
00365 static int
00366 __db_xa_end(xid, rmid, flags)
00367 XID *xid;
00368 int rmid;
00369 long flags;
00370 {
00371 DB_ENV *dbenv;
00372 DB_TXN *txn;
00373 TXN_DETAIL *td;
00374 roff_t off;
00375
00376 if (flags != TMNOFLAGS && !LF_ISSET(TMSUSPEND | TMSUCCESS | TMFAIL))
00377 return (XAER_INVAL);
00378
00379 if (__db_rmid_to_env(rmid, &dbenv) != 0)
00380 return (XAER_PROTO);
00381
00382 if (__db_xid_to_txn(dbenv, xid, &off) != 0)
00383 return (XAER_NOTA);
00384
00385 if (__xa_get_txn(dbenv, &txn, 0) != 0)
00386 return (XAER_RMERR);
00387
00388 td = R_ADDR(&((DB_TXNMGR *)dbenv->tx_handle)->reginfo, off);
00389 if (td != txn->td)
00390 return (XAER_PROTO);
00391
00392 if (td->xa_status == TXN_XA_DEADLOCKED)
00393 return (XA_RBDEADLOCK);
00394
00395 if (td->status == TXN_ABORTED)
00396 return (XA_RBOTHER);
00397
00398 if (td->xa_status != TXN_XA_STARTED)
00399 return (XAER_PROTO);
00400
00401
00402
00403
00404
00405 if (LF_ISSET(TMSUSPEND))
00406 td->xa_status = TXN_XA_SUSPENDED;
00407 else
00408 td->xa_status = TXN_XA_ENDED;
00409
00410
00411
00412
00413
00414 (void)__xa_put_txn(dbenv, txn);
00415 return (XA_OK);
00416 }
00417
00418
00419
00420
00421
00422 static int
00423 __db_xa_prepare(xid, rmid, arg_flags)
00424 XID *xid;
00425 int rmid;
00426 long arg_flags;
00427 {
00428 DB_ENV *dbenv;
00429 DB_TXN *txnp;
00430 TXN_DETAIL *td;
00431 roff_t off;
00432 u_long flags;
00433
00434 flags = (u_long)arg_flags;
00435
00436 if (LF_ISSET(TMASYNC))
00437 return (XAER_ASYNC);
00438 if (flags != TMNOFLAGS)
00439 return (XAER_INVAL);
00440
00441
00442
00443
00444
00445
00446
00447 if (__db_rmid_to_env(rmid, &dbenv) != 0)
00448 return (XAER_PROTO);
00449
00450 if (__db_xid_to_txn(dbenv, xid, &off) != 0)
00451 return (XAER_NOTA);
00452 td = R_ADDR(&((DB_TXNMGR *)dbenv->tx_handle)->reginfo, off);
00453 if (td->xa_status == TXN_XA_DEADLOCKED)
00454 return (XA_RBDEADLOCK);
00455
00456 if (td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED)
00457 return (XAER_PROTO);
00458
00459
00460 if (__xa_get_txn(dbenv, &txnp, 0) != 0)
00461 return (XAER_PROTO);
00462 __txn_continue(dbenv, txnp, td);
00463
00464 if (txnp->prepare(txnp, (u_int8_t *)xid->data) != 0)
00465 return (XAER_RMERR);
00466
00467 td->xa_status = TXN_XA_PREPARED;
00468
00469
00470
00471
00472
00473 (void)__xa_put_txn(dbenv, txnp);
00474 return (XA_OK);
00475 }
00476
00477
00478
00479
00480
00481 static int
00482 __db_xa_commit(xid, rmid, arg_flags)
00483 XID *xid;
00484 int rmid;
00485 long arg_flags;
00486 {
00487 DB_ENV *dbenv;
00488 DB_TXN *txnp;
00489 TXN_DETAIL *td;
00490 roff_t off;
00491 u_long flags;
00492
00493 flags = (u_long)arg_flags;
00494
00495 if (LF_ISSET(TMASYNC))
00496 return (XAER_ASYNC);
00497 #undef OK_FLAGS
00498 #define OK_FLAGS (TMNOFLAGS | TMNOWAIT | TMONEPHASE)
00499 if (LF_ISSET(~OK_FLAGS))
00500 return (XAER_INVAL);
00501
00502
00503
00504
00505
00506 if (__db_rmid_to_env(rmid, &dbenv) != 0)
00507 return (XAER_PROTO);
00508
00509 if (__db_xid_to_txn(dbenv, xid, &off) != 0)
00510 return (XAER_NOTA);
00511
00512 td = R_ADDR(&((DB_TXNMGR *)dbenv->tx_handle)->reginfo, off);
00513 if (td->xa_status == TXN_XA_DEADLOCKED)
00514 return (XA_RBDEADLOCK);
00515
00516 if (td->xa_status == TXN_XA_ABORTED)
00517 return (XA_RBOTHER);
00518
00519 if (LF_ISSET(TMONEPHASE) &&
00520 td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED)
00521 return (XAER_PROTO);
00522
00523 if (!LF_ISSET(TMONEPHASE) && td->xa_status != TXN_XA_PREPARED)
00524 return (XAER_PROTO);
00525
00526
00527 if (__xa_get_txn(dbenv, &txnp, 0) != 0)
00528 return (XAER_RMERR);
00529 __txn_continue(dbenv, txnp, td);
00530
00531 if (txnp->commit(txnp, 0) != 0)
00532 return (XAER_RMERR);
00533
00534
00535
00536
00537
00538 (void)__xa_put_txn(dbenv, txnp);
00539 return (XA_OK);
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550 static int
00551 __db_xa_recover(xids, count, rmid, flags)
00552 XID *xids;
00553 long count, flags;
00554 int rmid;
00555 {
00556 DB_ENV *dbenv;
00557 u_int32_t newflags;
00558 long rval;
00559
00560
00561 if (__db_rmid_to_env(rmid, &dbenv) != 0)
00562 return (XAER_PROTO);
00563
00564 if (LF_ISSET(TMSTARTRSCAN))
00565 newflags = DB_FIRST;
00566 else if (LF_ISSET(TMENDRSCAN))
00567 newflags = DB_LAST;
00568 else
00569 newflags = DB_NEXT;
00570
00571 rval = 0;
00572 if (__txn_get_prepared(dbenv, xids, NULL, count, &rval, newflags) != 0)
00573 return (XAER_RMERR);
00574 else
00575 return (rval);
00576 }
00577
00578
00579
00580
00581
00582 static int
00583 __db_xa_rollback(xid, rmid, arg_flags)
00584 XID *xid;
00585 int rmid;
00586 long arg_flags;
00587 {
00588 DB_ENV *dbenv;
00589 DB_TXN *txnp;
00590 TXN_DETAIL *td;
00591 roff_t off;
00592 u_long flags;
00593
00594 flags = (u_long)arg_flags;
00595
00596 if (LF_ISSET(TMASYNC))
00597 return (XAER_ASYNC);
00598 if (flags != TMNOFLAGS)
00599 return (XAER_INVAL);
00600
00601 if (__db_rmid_to_env(rmid, &dbenv) != 0)
00602 return (XAER_PROTO);
00603
00604 if (__db_xid_to_txn(dbenv, xid, &off) != 0)
00605 return (XAER_NOTA);
00606
00607 td = R_ADDR(&((DB_TXNMGR *)dbenv->tx_handle)->reginfo, off);
00608 if (td->xa_status == TXN_XA_DEADLOCKED)
00609 return (XA_RBDEADLOCK);
00610
00611 if (td->xa_status == TXN_XA_ABORTED)
00612 return (XA_RBOTHER);
00613
00614 if (td->xa_status != TXN_XA_ENDED &&
00615 td->xa_status != TXN_XA_SUSPENDED &&
00616 td->xa_status != TXN_XA_PREPARED)
00617 return (XAER_PROTO);
00618
00619
00620 if (__xa_get_txn(dbenv, &txnp, 0) != 0)
00621 return (XAER_RMERR);
00622 __txn_continue(dbenv, txnp, td);
00623 if (txnp->abort(txnp) != 0)
00624 return (XAER_RMERR);
00625
00626
00627
00628
00629
00630 (void)__xa_put_txn(dbenv, txnp);
00631 return (XA_OK);
00632 }
00633
00634
00635
00636
00637
00638
00639
00640
00641 static int
00642 __db_xa_forget(xid, rmid, arg_flags)
00643 XID *xid;
00644 int rmid;
00645 long arg_flags;
00646 {
00647 DB_ENV *dbenv;
00648 roff_t off;
00649 u_long flags;
00650
00651 flags = (u_long)arg_flags;
00652
00653 if (LF_ISSET(TMASYNC))
00654 return (XAER_ASYNC);
00655 if (flags != TMNOFLAGS)
00656 return (XAER_INVAL);
00657
00658 if (__db_rmid_to_env(rmid, &dbenv) != 0)
00659 return (XAER_PROTO);
00660
00661
00662
00663
00664 if (__db_xid_to_txn(dbenv, xid, &off) != 0)
00665 return (XA_OK);
00666
00667 __db_unmap_xid(dbenv, xid, off);
00668
00669
00670 return (XA_OK);
00671 }
00672
00673
00674
00675
00676
00677
00678 static int
00679 __db_xa_complete(handle, retval, rmid, flags)
00680 int *handle, *retval, rmid;
00681 long flags;
00682 {
00683 COMPQUIET(handle, NULL);
00684 COMPQUIET(retval, NULL);
00685 COMPQUIET(rmid, 0);
00686 COMPQUIET(flags, 0);
00687
00688 return (XAER_INVAL);
00689 }