xa.c

Go to the documentation of this file.
00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1998, 1999, 2000
00005  *      Sleepycat Software.  All rights reserved.
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 /* not lint */
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  * Possible flag values:
00043  *      Dynamic registration    0 => no dynamic registration
00044  *                              TMREGISTER => dynamic registration
00045  *      Asynchronous operation  0 => no support for asynchrony
00046  *                              TMUSEASYNC => async support
00047  *      Migration support       0 => migration of transactions across
00048  *                                   threads is possible
00049  *                              TMNOMIGRATE => no migration across threads
00050  */
00051 const struct xa_switch_t CDB_db_xa_switch = {
00052          "Berkeley DB",         /* name[RMNAMESZ] */
00053          TMNOMIGRATE,           /* flags */
00054          0,                     /* version */
00055          __db_xa_open,          /* xa_open_entry */
00056          __db_xa_close,         /* xa_close_entry */
00057          __db_xa_start,         /* xa_start_entry */
00058          __db_xa_end,           /* xa_end_entry */
00059          __db_xa_rollback,      /* xa_rollback_entry */
00060          __db_xa_prepare,       /* xa_prepare_entry */
00061          __db_xa_commit,        /* xa_commit_entry */
00062          __db_xa_recover,       /* xa_recover_entry */
00063          __db_xa_forget,        /* xa_forget_entry */
00064          __db_xa_complete       /* xa_complete_entry */
00065 };
00066 
00067 /*
00068  * __db_xa_open --
00069  *      The open call in the XA protocol.  The rmid field is an id number
00070  * that the TM assigned us and will pass us on every xa call.  We need to
00071  * map that rmid number into a dbenv structure that we create during
00072  * initialization.  Since this id number is thread specific, we do not
00073  * need to store it in shared memory.  The file xa_map.c implements all
00074  * such xa->db mappings.
00075  *      The xa_info field is instance specific information.  We require
00076  * that the value of DB_HOME be passed in xa_info.  Since xa_info is the
00077  * only thing that we get to pass to CDB_db_env_create, any config information
00078  * will have to be done via a config file instead of via the CDB_db_env_create
00079  * call.
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         /* Verify if we already have this environment open. */
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         /* Open a new environment. */
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         /* Create the mapping. */
00109         if (CDB___db_map_rmid(rmid, env) != 0)
00110                 goto err;
00111 
00112         /* Allocate space for the current transaction. */
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  * __db_xa_close --
00126  *      The close call of the XA protocol.  The only trickiness here
00127  * is that if there are any active transactions, we must fail.  It is
00128  * *not* an error to call close on an environment that has already been
00129  * closed (I am interpreting that to mean it's OK to call close on an
00130  * environment that has never been opened).
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         /* If the environment is closed, then we're done. */
00149         if (CDB___db_rmid_to_env(rmid, &env) != 0)
00150                 return (XA_OK);
00151 
00152         /* Check if there are any pending transactions. */
00153         if (env->xa_txn != NULL && env->xa_txn->txnid != TXN_INVALID)
00154                 return (XAER_PROTO);
00155 
00156         /* Destroy the mapping. */
00157         ret = CDB___db_unmap_rmid(rmid);
00158 
00159         /* Discard space held for the current transaction. */
00160         if (env->xa_txn != NULL)
00161                 CDB___os_free(env->xa_txn, sizeof(DB_TXN));
00162 
00163         /* Close the environment. */
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  * __db_xa_start --
00172  *      Begin a transaction for the current resource manager.
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          * This can't block, so we can ignore TMNOWAIT.
00208          *
00209          * Other error conditions: RMERR, RMFAIL, OUTSIDE, PROTO, RB*
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                 /* Now, fill in the global transaction structure. */
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  * __db_xa_end --
00239  *      Disassociate the current transaction from the current process.
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         /* Update the shared memory last_lsn field */
00276         td->last_lsn = txn->last_lsn;
00277 
00278         /*
00279          * If we ever support XA migration, we cannot keep SUSPEND/END
00280          * status in the shared region; it would have to be process local.
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  * __db_xa_prepare --
00293  *      Sync the log to disk so we can guarantee recoverability.
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          * We need to know if we've ever called prepare on this.
00312          * As part of the prepare, we set the xa_status field to
00313          * reflect that fact that prepare has been called, and if
00314          * it's ever called again, it's an error.
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         /* Now, fill in the global transaction structure. */
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         /* No fatal value that would require an XAER_RMFAIL. */
00338         __xa_txn_end(env);
00339         return (XA_OK);
00340 }
00341 
00342 /*
00343  * __db_xa_commit --
00344  *      Commit the transaction
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          * We need to know if we've ever called prepare on this.
00365          * We can verify this by examining the xa_status field.
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         /* Now, fill in the global transaction structure. */
00388         __xa_txn_init(env, td, off);
00389 
00390         if (CDB_txn_commit(env->xa_txn, 0) != 0)
00391                 return (XAER_RMERR);
00392 
00393         /* No fatal value that would require an XAER_RMFAIL. */
00394         __xa_txn_end(env);
00395         return (XA_OK);
00396 }
00397 
00398 /*
00399  * __db_xa_recover --
00400  *      Returns a list of prepared and heuristically completed transactions.
00401  *
00402  * The return value is the number of xids placed into the xid array (less
00403  * than or equal to the count parameter).  The flags are going to indicate
00404  * whether we are starting a scan or continuing one.
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         /* If the environment is closed, then we're done. */
00424         if (CDB___db_rmid_to_env(rmid, &env) != 0)
00425                 return (XAER_PROTO);
00426 
00427         /*
00428          * If we are starting a scan, then we need to figure out where
00429          * to begin.  If we are not starting a scan, we'll start from
00430          * wherever the log cursor is.  Since XA apps cannot be threaded,
00431          * we don't have to worry about someone else having moved it.
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                          * If there were no log files, then we have no
00438                          * transactions to return, so we simply return 0.
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                  * If we are not starting a scan, the log cursor had
00447                  * better be set.
00448                  */
00449                 if (IS_ZERO_LSN(log->xa_lsn))
00450                         return (XAER_PROTO);
00451         }
00452 
00453         /*
00454          * At this point log->xa_first contains the point in the log
00455          * to which we need to roll back.  If we are starting a scan,
00456          * we'll start at the last record; if we're continuing a scan,
00457          * we'll have to start at log->xa_lsn.
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                  * The only record type we care about is an DB_txn_xa_regop.
00469                  * If it's a commit, we have to add it to a txnlist.  If it's
00470                  * a prepare, and we don't have a commit, then we return it.
00471                  * We are redoing some of what's in the xa_regop_recovery
00472                  * code, but we have to do it here so we can get at the xid
00473                  * in the record.
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                          * This transaction is committed, so we needn't read
00490                          * the record and do anything.
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  * __db_xa_rollback
00528  *      Abort an XA transaction.
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         /* Now, fill in the global transaction structure. */
00563         __xa_txn_init(env, td, off);
00564         if (CDB_txn_abort(env->xa_txn) != 0)
00565                 return (XAER_RMERR);
00566 
00567         /* No fatal value that would require an XAER_RMFAIL. */
00568         __xa_txn_end(env);
00569         return (XA_OK);
00570 }
00571 
00572 /*
00573  * __db_xa_forget --
00574  *      Forget about an XID for a transaction that was heuristically
00575  * completed.  Since we do not heuristically complete anything, I
00576  * don't think we have to do anything here, but we should make sure
00577  * that we reclaim the slots in the txnid table.
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          * If mapping is gone, then we're done.
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         /* No fatal value that would require an XAER_RMFAIL. */
00605         return (XA_OK);
00606 }
00607 
00608 /*
00609  * __db_xa_complete --
00610  *      Used to wait for asynchronous operations to complete.  Since we're
00611  *      not doing asynch, this is an invalid operation.
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  * __xa_txn_init --
00628  *      Fill in the fields of the local transaction structure given
00629  *      the detail transaction structure.
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  * __xa_txn_end --
00650  *      Invalidate a transaction structure that was generated by xa_txn_init.
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 }

Generated on Sun Jun 8 10:56:39 2008 for GNUmifluz by  doxygen 1.5.5