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