1*7c478bd9Sstevel@tonic-gate /*- 2*7c478bd9Sstevel@tonic-gate * See the file LICENSE for redistribution information. 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * Copyright (c) 1998 5*7c478bd9Sstevel@tonic-gate * Sleepycat Software. All rights reserved. 6*7c478bd9Sstevel@tonic-gate */ 7*7c478bd9Sstevel@tonic-gate 8*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 9*7c478bd9Sstevel@tonic-gate 10*7c478bd9Sstevel@tonic-gate /* XXX Remove the global transaction and hang it off the environment. */ 11*7c478bd9Sstevel@tonic-gate #include "config.h" 12*7c478bd9Sstevel@tonic-gate 13*7c478bd9Sstevel@tonic-gate #ifndef lint 14*7c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)xa.c 10.4 (Sleepycat) 10/11/98"; 15*7c478bd9Sstevel@tonic-gate #endif /* not lint */ 16*7c478bd9Sstevel@tonic-gate 17*7c478bd9Sstevel@tonic-gate #ifndef NO_SYSTEM_INCLUDES 18*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 19*7c478bd9Sstevel@tonic-gate 20*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 21*7c478bd9Sstevel@tonic-gate #include <stdio.h> 22*7c478bd9Sstevel@tonic-gate #include <string.h> 23*7c478bd9Sstevel@tonic-gate #endif 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate #include "db_int.h" 26*7c478bd9Sstevel@tonic-gate #include "db_page.h" 27*7c478bd9Sstevel@tonic-gate #include "shqueue.h" 28*7c478bd9Sstevel@tonic-gate #include "log.h" 29*7c478bd9Sstevel@tonic-gate #include "txn.h" 30*7c478bd9Sstevel@tonic-gate #include "db_auto.h" 31*7c478bd9Sstevel@tonic-gate #include "db_ext.h" 32*7c478bd9Sstevel@tonic-gate #include "db_dispatch.h" 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate static int __db_xa_close __P((char *, int, long)); 35*7c478bd9Sstevel@tonic-gate static int __db_xa_commit __P((XID *, int, long)); 36*7c478bd9Sstevel@tonic-gate static int __db_xa_complete __P((int *, int *, int, long)); 37*7c478bd9Sstevel@tonic-gate static int __db_xa_end __P((XID *, int, long)); 38*7c478bd9Sstevel@tonic-gate static int __db_xa_forget __P((XID *, int, long)); 39*7c478bd9Sstevel@tonic-gate static int __db_xa_open __P((char *, int, long)); 40*7c478bd9Sstevel@tonic-gate static int __db_xa_prepare __P((XID *, int, long)); 41*7c478bd9Sstevel@tonic-gate static int __db_xa_recover __P((XID *, long, int, long)); 42*7c478bd9Sstevel@tonic-gate static int __db_xa_rollback __P((XID *, int, long)); 43*7c478bd9Sstevel@tonic-gate static int __db_xa_start __P((XID *, int, long)); 44*7c478bd9Sstevel@tonic-gate static void __xa_txn_end __P((DB_ENV *)); 45*7c478bd9Sstevel@tonic-gate static void __xa_txn_init __P((DB_ENV *, TXN_DETAIL *, size_t)); 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate /* 48*7c478bd9Sstevel@tonic-gate * Possible flag values: 49*7c478bd9Sstevel@tonic-gate * Dynamic registration 0 => no dynamic registration 50*7c478bd9Sstevel@tonic-gate * TMREGISTER => dynamic registration 51*7c478bd9Sstevel@tonic-gate * Asynchronous operation 0 => no support for asynchrony 52*7c478bd9Sstevel@tonic-gate * TMUSEASYNC => async support 53*7c478bd9Sstevel@tonic-gate * Migration support 0 => migration of transactions across 54*7c478bd9Sstevel@tonic-gate * threads is possible 55*7c478bd9Sstevel@tonic-gate * TMNOMIGRATE => no migration across threads 56*7c478bd9Sstevel@tonic-gate */ 57*7c478bd9Sstevel@tonic-gate const struct xa_switch_t db_xa_switch = { 58*7c478bd9Sstevel@tonic-gate "Berkeley DB", /* name[RMNAMESZ] */ 59*7c478bd9Sstevel@tonic-gate TMNOMIGRATE, /* flags */ 60*7c478bd9Sstevel@tonic-gate 0, /* version */ 61*7c478bd9Sstevel@tonic-gate __db_xa_open, /* xa_open_entry */ 62*7c478bd9Sstevel@tonic-gate __db_xa_close, /* xa_close_entry */ 63*7c478bd9Sstevel@tonic-gate __db_xa_start, /* xa_start_entry */ 64*7c478bd9Sstevel@tonic-gate __db_xa_end, /* xa_end_entry */ 65*7c478bd9Sstevel@tonic-gate __db_xa_rollback, /* xa_rollback_entry */ 66*7c478bd9Sstevel@tonic-gate __db_xa_prepare, /* xa_prepare_entry */ 67*7c478bd9Sstevel@tonic-gate __db_xa_commit, /* xa_commit_entry */ 68*7c478bd9Sstevel@tonic-gate __db_xa_recover, /* xa_recover_entry */ 69*7c478bd9Sstevel@tonic-gate __db_xa_forget, /* xa_forget_entry */ 70*7c478bd9Sstevel@tonic-gate __db_xa_complete /* xa_complete_entry */ 71*7c478bd9Sstevel@tonic-gate }; 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate /* 74*7c478bd9Sstevel@tonic-gate * __db_xa_open -- 75*7c478bd9Sstevel@tonic-gate * The open call in the XA protocol. The rmid field is an id number 76*7c478bd9Sstevel@tonic-gate * that the TM assigned us and will pass us on every xa call. We need to 77*7c478bd9Sstevel@tonic-gate * map that rmid number into a dbenv structure that we create during 78*7c478bd9Sstevel@tonic-gate * initialization. Since this id number is thread specific, we do not 79*7c478bd9Sstevel@tonic-gate * need to store it in shared memory. The file xa_map.c implements all 80*7c478bd9Sstevel@tonic-gate * such xa->db mappings. 81*7c478bd9Sstevel@tonic-gate * The xa_info field is instance specific information. We require 82*7c478bd9Sstevel@tonic-gate * that the value of DB_HOME be passed in xa_info. Since xa_info is the 83*7c478bd9Sstevel@tonic-gate * only thing that we get to pass to db_appinit, any config information 84*7c478bd9Sstevel@tonic-gate * will have to be done via a config file instead of via the db_appinit 85*7c478bd9Sstevel@tonic-gate * call. 86*7c478bd9Sstevel@tonic-gate */ 87*7c478bd9Sstevel@tonic-gate static int 88*7c478bd9Sstevel@tonic-gate __db_xa_open(xa_info, rmid, flags) 89*7c478bd9Sstevel@tonic-gate char *xa_info; 90*7c478bd9Sstevel@tonic-gate int rmid; 91*7c478bd9Sstevel@tonic-gate long flags; 92*7c478bd9Sstevel@tonic-gate { 93*7c478bd9Sstevel@tonic-gate DB_ENV *env; 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate if (LF_ISSET(TMASYNC)) 96*7c478bd9Sstevel@tonic-gate return (XAER_ASYNC); 97*7c478bd9Sstevel@tonic-gate if (flags != TMNOFLAGS) 98*7c478bd9Sstevel@tonic-gate return (XAER_INVAL); 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate /* Verify if we already have this environment open. */ 101*7c478bd9Sstevel@tonic-gate if (__db_rmid_to_env(rmid, &env, 0) == 0) 102*7c478bd9Sstevel@tonic-gate return (XA_OK); 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate /* 105*7c478bd9Sstevel@tonic-gate * Since we cannot tell whether the environment is OK or not, 106*7c478bd9Sstevel@tonic-gate * we can't actually do the db_appinit in xa_open. Instead, 107*7c478bd9Sstevel@tonic-gate * we save the mapping between the rmid and the xa_info. If 108*7c478bd9Sstevel@tonic-gate * we next get a call to __xa_recover, we do the db_appinit 109*7c478bd9Sstevel@tonic-gate * with DB_RECOVER set. If we get any other call, then we 110*7c478bd9Sstevel@tonic-gate * do the db_appinit. 111*7c478bd9Sstevel@tonic-gate */ 112*7c478bd9Sstevel@tonic-gate return (__db_map_rmid_name(rmid, xa_info)); 113*7c478bd9Sstevel@tonic-gate } 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate /* 116*7c478bd9Sstevel@tonic-gate * __db_xa_close -- 117*7c478bd9Sstevel@tonic-gate * The close call of the XA protocol. The only trickiness here 118*7c478bd9Sstevel@tonic-gate * is that if there are any active transactions, we must fail. It is 119*7c478bd9Sstevel@tonic-gate * *not* an error to call close on an environment that has already been 120*7c478bd9Sstevel@tonic-gate * closed (I am interpreting that to mean it's OK to call close on an 121*7c478bd9Sstevel@tonic-gate * environment that has never been opened). 122*7c478bd9Sstevel@tonic-gate */ 123*7c478bd9Sstevel@tonic-gate static int 124*7c478bd9Sstevel@tonic-gate __db_xa_close(xa_info, rmid, flags) 125*7c478bd9Sstevel@tonic-gate char *xa_info; 126*7c478bd9Sstevel@tonic-gate int rmid; 127*7c478bd9Sstevel@tonic-gate long flags; 128*7c478bd9Sstevel@tonic-gate { 129*7c478bd9Sstevel@tonic-gate DB_ENV *env; 130*7c478bd9Sstevel@tonic-gate int ret, t_ret; 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate COMPQUIET(xa_info, NULL); 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate if (LF_ISSET(TMASYNC)) 135*7c478bd9Sstevel@tonic-gate return (XAER_ASYNC); 136*7c478bd9Sstevel@tonic-gate if (flags != TMNOFLAGS) 137*7c478bd9Sstevel@tonic-gate return (XAER_INVAL); 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate /* If the environment is closed, then we're done. */ 140*7c478bd9Sstevel@tonic-gate if (__db_rmid_to_env(rmid, &env, 0) != 0) 141*7c478bd9Sstevel@tonic-gate return (XA_OK); 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate /* Check if there are any pending transactions. */ 144*7c478bd9Sstevel@tonic-gate if (env->xa_txn != NULL && env->xa_txn->txnid != TXN_INVALID) 145*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate /* Now, destroy the mapping and close the environment. */ 148*7c478bd9Sstevel@tonic-gate ret = __db_unmap_rmid(rmid); 149*7c478bd9Sstevel@tonic-gate if ((t_ret = db_appexit(env)) != 0 && ret == 0) 150*7c478bd9Sstevel@tonic-gate ret = t_ret; 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate __os_free(env, sizeof(DB_ENV)); 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate return (ret == 0 ? XA_OK : XAER_RMERR); 155*7c478bd9Sstevel@tonic-gate } 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate /* 158*7c478bd9Sstevel@tonic-gate * __db_xa_start -- 159*7c478bd9Sstevel@tonic-gate * Begin a transaction for the current resource manager. 160*7c478bd9Sstevel@tonic-gate */ 161*7c478bd9Sstevel@tonic-gate static int 162*7c478bd9Sstevel@tonic-gate __db_xa_start(xid, rmid, flags) 163*7c478bd9Sstevel@tonic-gate XID *xid; 164*7c478bd9Sstevel@tonic-gate int rmid; 165*7c478bd9Sstevel@tonic-gate long flags; 166*7c478bd9Sstevel@tonic-gate { 167*7c478bd9Sstevel@tonic-gate DB_ENV *env; 168*7c478bd9Sstevel@tonic-gate TXN_DETAIL *td; 169*7c478bd9Sstevel@tonic-gate size_t off; 170*7c478bd9Sstevel@tonic-gate int is_known; 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate #define OK_FLAGS (TMJOIN | TMRESUME | TMNOWAIT | TMASYNC | TMNOFLAGS) 173*7c478bd9Sstevel@tonic-gate if (LF_ISSET(~OK_FLAGS)) 174*7c478bd9Sstevel@tonic-gate return (XAER_INVAL); 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate if (LF_ISSET(TMJOIN) && LF_ISSET(TMRESUME)) 177*7c478bd9Sstevel@tonic-gate return (XAER_INVAL); 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate if (LF_ISSET(TMASYNC)) 180*7c478bd9Sstevel@tonic-gate return (XAER_ASYNC); 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate if (__db_rmid_to_env(rmid, &env, 1) != 0) 183*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate is_known = __db_xid_to_txn(env, xid, &off) == 0; 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate if (is_known && !LF_ISSET(TMRESUME) && !LF_ISSET(TMJOIN)) 188*7c478bd9Sstevel@tonic-gate return (XAER_DUPID); 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate if (!is_known && LF_ISSET(TMRESUME | TMJOIN)) 191*7c478bd9Sstevel@tonic-gate return (XAER_NOTA); 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate /* 194*7c478bd9Sstevel@tonic-gate * This can't block, so we can ignore TMNOWAIT. 195*7c478bd9Sstevel@tonic-gate * 196*7c478bd9Sstevel@tonic-gate * Other error conditions: RMERR, RMFAIL, OUTSIDE, PROTO, RB* 197*7c478bd9Sstevel@tonic-gate */ 198*7c478bd9Sstevel@tonic-gate if (is_known) { 199*7c478bd9Sstevel@tonic-gate td = (TXN_DETAIL *)((u_int8_t *)env->tx_info->region + off); 200*7c478bd9Sstevel@tonic-gate if (td->xa_status == TXN_XA_SUSPENDED && !LF_ISSET(TMRESUME)) 201*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 202*7c478bd9Sstevel@tonic-gate if (td->xa_status == TXN_XA_DEADLOCKED) 203*7c478bd9Sstevel@tonic-gate return (XA_RBDEADLOCK); 204*7c478bd9Sstevel@tonic-gate if (td->xa_status == TXN_XA_ABORTED) 205*7c478bd9Sstevel@tonic-gate return (XA_RBOTHER); 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate /* Now, fill in the global transaction structure. */ 208*7c478bd9Sstevel@tonic-gate __xa_txn_init(env, td, off); 209*7c478bd9Sstevel@tonic-gate td->xa_status = TXN_XA_STARTED; 210*7c478bd9Sstevel@tonic-gate } else { 211*7c478bd9Sstevel@tonic-gate if (__txn_xa_begin(env, env->xa_txn) != 0) 212*7c478bd9Sstevel@tonic-gate return (XAER_RMERR); 213*7c478bd9Sstevel@tonic-gate (void)__db_map_xid(env, xid, env->xa_txn->off); 214*7c478bd9Sstevel@tonic-gate td = (TXN_DETAIL *) 215*7c478bd9Sstevel@tonic-gate ((u_int8_t *)env->tx_info->region + env->xa_txn->off); 216*7c478bd9Sstevel@tonic-gate td->xa_status = TXN_XA_STARTED; 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate return (XA_OK); 219*7c478bd9Sstevel@tonic-gate } 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate /* 222*7c478bd9Sstevel@tonic-gate * __db_xa_end -- 223*7c478bd9Sstevel@tonic-gate * Disassociate the current transaction from the current process. 224*7c478bd9Sstevel@tonic-gate */ 225*7c478bd9Sstevel@tonic-gate static int 226*7c478bd9Sstevel@tonic-gate __db_xa_end(xid, rmid, flags) 227*7c478bd9Sstevel@tonic-gate XID *xid; 228*7c478bd9Sstevel@tonic-gate int rmid; 229*7c478bd9Sstevel@tonic-gate long flags; 230*7c478bd9Sstevel@tonic-gate { 231*7c478bd9Sstevel@tonic-gate DB_ENV *env; 232*7c478bd9Sstevel@tonic-gate DB_TXN *txn; 233*7c478bd9Sstevel@tonic-gate TXN_DETAIL *td; 234*7c478bd9Sstevel@tonic-gate size_t off; 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate if (flags != TMNOFLAGS && !LF_ISSET(TMSUSPEND | TMSUCCESS | TMFAIL)) 237*7c478bd9Sstevel@tonic-gate return (XAER_INVAL); 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate if (__db_rmid_to_env(rmid, &env, 0) != 0) 240*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate if (__db_xid_to_txn(env, xid, &off) != 0) 243*7c478bd9Sstevel@tonic-gate return (XAER_NOTA); 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate txn = env->xa_txn; 246*7c478bd9Sstevel@tonic-gate if (off != txn->off) 247*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate td = (TXN_DETAIL *)((u_int8_t *)env->tx_info->region + off); 250*7c478bd9Sstevel@tonic-gate if (td->xa_status == TXN_XA_DEADLOCKED) 251*7c478bd9Sstevel@tonic-gate return (XA_RBDEADLOCK); 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate if (td->status == TXN_ABORTED) 254*7c478bd9Sstevel@tonic-gate return (XA_RBOTHER); 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate if (td->xa_status != TXN_XA_STARTED) 257*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate /* Update the shared memory last_lsn field */ 260*7c478bd9Sstevel@tonic-gate td->last_lsn = txn->last_lsn; 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate /* 263*7c478bd9Sstevel@tonic-gate * If we ever support XA migration, we cannot keep SUSPEND/END 264*7c478bd9Sstevel@tonic-gate * status in the shared region; it would have to be process local. 265*7c478bd9Sstevel@tonic-gate */ 266*7c478bd9Sstevel@tonic-gate if (LF_ISSET(TMSUSPEND)) 267*7c478bd9Sstevel@tonic-gate td->xa_status = TXN_XA_SUSPENDED; 268*7c478bd9Sstevel@tonic-gate else 269*7c478bd9Sstevel@tonic-gate td->xa_status = TXN_XA_ENDED; 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate txn->txnid = TXN_INVALID; 272*7c478bd9Sstevel@tonic-gate return (XA_OK); 273*7c478bd9Sstevel@tonic-gate } 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate /* 276*7c478bd9Sstevel@tonic-gate * __db_xa_prepare -- 277*7c478bd9Sstevel@tonic-gate * Sync the log to disk so we can guarantee recoverability. 278*7c478bd9Sstevel@tonic-gate */ 279*7c478bd9Sstevel@tonic-gate static int 280*7c478bd9Sstevel@tonic-gate __db_xa_prepare(xid, rmid, flags) 281*7c478bd9Sstevel@tonic-gate XID *xid; 282*7c478bd9Sstevel@tonic-gate int rmid; 283*7c478bd9Sstevel@tonic-gate long flags; 284*7c478bd9Sstevel@tonic-gate { 285*7c478bd9Sstevel@tonic-gate DB_ENV *env; 286*7c478bd9Sstevel@tonic-gate TXN_DETAIL *td; 287*7c478bd9Sstevel@tonic-gate size_t off; 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate if (LF_ISSET(TMASYNC)) 290*7c478bd9Sstevel@tonic-gate return (XAER_ASYNC); 291*7c478bd9Sstevel@tonic-gate if (flags != TMNOFLAGS) 292*7c478bd9Sstevel@tonic-gate return (XAER_INVAL); 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate /* 295*7c478bd9Sstevel@tonic-gate * We need to know if we've ever called prepare on this. 296*7c478bd9Sstevel@tonic-gate * As part of the prepare, we set the xa_status field to 297*7c478bd9Sstevel@tonic-gate * reflect that fact that prepare has been called, and if 298*7c478bd9Sstevel@tonic-gate * it's ever called again, it's an error. 299*7c478bd9Sstevel@tonic-gate */ 300*7c478bd9Sstevel@tonic-gate if (__db_rmid_to_env(rmid, &env, 1) != 0) 301*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate if (__db_xid_to_txn(env, xid, &off) != 0) 304*7c478bd9Sstevel@tonic-gate return (XAER_NOTA); 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate td = (TXN_DETAIL *)((u_int8_t *)env->tx_info->region + off); 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate if (td->xa_status == TXN_XA_DEADLOCKED) 309*7c478bd9Sstevel@tonic-gate return (XA_RBDEADLOCK); 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate if (td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED) 312*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate /* Now, fill in the global transaction structure. */ 315*7c478bd9Sstevel@tonic-gate __xa_txn_init(env, td, off); 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate if (txn_prepare(env->xa_txn) != 0) 318*7c478bd9Sstevel@tonic-gate return (XAER_RMERR); 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate td->xa_status = TXN_XA_PREPARED; 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate /* No fatal value that would require an XAER_RMFAIL. */ 323*7c478bd9Sstevel@tonic-gate __xa_txn_end(env); 324*7c478bd9Sstevel@tonic-gate return (XA_OK); 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate /* 328*7c478bd9Sstevel@tonic-gate * __db_xa_commit -- 329*7c478bd9Sstevel@tonic-gate * Commit the transaction 330*7c478bd9Sstevel@tonic-gate */ 331*7c478bd9Sstevel@tonic-gate static int 332*7c478bd9Sstevel@tonic-gate __db_xa_commit(xid, rmid, flags) 333*7c478bd9Sstevel@tonic-gate XID *xid; 334*7c478bd9Sstevel@tonic-gate int rmid; 335*7c478bd9Sstevel@tonic-gate long flags; 336*7c478bd9Sstevel@tonic-gate { 337*7c478bd9Sstevel@tonic-gate DB_ENV *env; 338*7c478bd9Sstevel@tonic-gate TXN_DETAIL *td; 339*7c478bd9Sstevel@tonic-gate size_t off; 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate if (LF_ISSET(TMASYNC)) 342*7c478bd9Sstevel@tonic-gate return (XAER_ASYNC); 343*7c478bd9Sstevel@tonic-gate #undef OK_FLAGS 344*7c478bd9Sstevel@tonic-gate #define OK_FLAGS (TMNOFLAGS | TMNOWAIT | TMONEPHASE) 345*7c478bd9Sstevel@tonic-gate if (LF_ISSET(~OK_FLAGS)) 346*7c478bd9Sstevel@tonic-gate return (XAER_INVAL); 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate /* 349*7c478bd9Sstevel@tonic-gate * We need to know if we've ever called prepare on this. 350*7c478bd9Sstevel@tonic-gate * We can verify this by examining the xa_status field. 351*7c478bd9Sstevel@tonic-gate */ 352*7c478bd9Sstevel@tonic-gate if (__db_rmid_to_env(rmid, &env, 1) != 0) 353*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate if (__db_xid_to_txn(env, xid, &off) != 0) 356*7c478bd9Sstevel@tonic-gate return (XAER_NOTA); 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate td = (TXN_DETAIL *)((u_int8_t *)env->tx_info->region + off); 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate if (td->xa_status == TXN_XA_DEADLOCKED) 361*7c478bd9Sstevel@tonic-gate return (XA_RBDEADLOCK); 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate if (td->xa_status == TXN_XA_ABORTED) 364*7c478bd9Sstevel@tonic-gate return (XA_RBOTHER); 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate if (LF_ISSET(TMONEPHASE) && 367*7c478bd9Sstevel@tonic-gate td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED) 368*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate if (!LF_ISSET(TMONEPHASE) && td->xa_status != TXN_XA_PREPARED) 371*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate /* Now, fill in the global transaction structure. */ 374*7c478bd9Sstevel@tonic-gate __xa_txn_init(env, td, off); 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate if (txn_commit(env->xa_txn) != 0) 377*7c478bd9Sstevel@tonic-gate return (XAER_RMERR); 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate /* No fatal value that would require an XAER_RMFAIL. */ 380*7c478bd9Sstevel@tonic-gate __xa_txn_end(env); 381*7c478bd9Sstevel@tonic-gate return (XA_OK); 382*7c478bd9Sstevel@tonic-gate } 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate /* 385*7c478bd9Sstevel@tonic-gate * __db_xa_recover -- 386*7c478bd9Sstevel@tonic-gate * Returns a list of prepared and heuristically completed transactions. 387*7c478bd9Sstevel@tonic-gate * 388*7c478bd9Sstevel@tonic-gate * The return value is the number of xids placed into the xid array (less 389*7c478bd9Sstevel@tonic-gate * than or equal to the count parameter). The flags are going to indicate 390*7c478bd9Sstevel@tonic-gate * whether we are starting a scan or continuing one. 391*7c478bd9Sstevel@tonic-gate */ 392*7c478bd9Sstevel@tonic-gate static int 393*7c478bd9Sstevel@tonic-gate __db_xa_recover(xids, count, rmid, flags) 394*7c478bd9Sstevel@tonic-gate XID *xids; 395*7c478bd9Sstevel@tonic-gate long count, flags; 396*7c478bd9Sstevel@tonic-gate int rmid; 397*7c478bd9Sstevel@tonic-gate { 398*7c478bd9Sstevel@tonic-gate __txn_xa_regop_args *argp; 399*7c478bd9Sstevel@tonic-gate DBT data; 400*7c478bd9Sstevel@tonic-gate DB_ENV *env; 401*7c478bd9Sstevel@tonic-gate DB_LOG *log; 402*7c478bd9Sstevel@tonic-gate XID *xidp; 403*7c478bd9Sstevel@tonic-gate char *dbhome; 404*7c478bd9Sstevel@tonic-gate int err, ret; 405*7c478bd9Sstevel@tonic-gate u_int32_t rectype, txnid; 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate ret = 0; 408*7c478bd9Sstevel@tonic-gate xidp = xids; 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate /* 412*7c478bd9Sstevel@tonic-gate * If we are starting a scan, then we need to open the environment 413*7c478bd9Sstevel@tonic-gate * and run recovery. This recovery puts us in a state where we can 414*7c478bd9Sstevel@tonic-gate * either commit or abort any transactions that were prepared but not 415*7c478bd9Sstevel@tonic-gate * yet committed. Once we've done that, we need to figure out where 416*7c478bd9Sstevel@tonic-gate * to begin checking for such transactions. If we are not starting 417*7c478bd9Sstevel@tonic-gate * a scan, then the environment had better have already been recovered 418*7c478bd9Sstevel@tonic-gate * and we'll start from * wherever the log cursor is. Since XA apps 419*7c478bd9Sstevel@tonic-gate * cannot be threaded, we don't have to worry about someone else 420*7c478bd9Sstevel@tonic-gate * having moved it. 421*7c478bd9Sstevel@tonic-gate */ 422*7c478bd9Sstevel@tonic-gate if (LF_ISSET(TMSTARTRSCAN)) { 423*7c478bd9Sstevel@tonic-gate /* If the environment is open, we have a problem. */ 424*7c478bd9Sstevel@tonic-gate if (__db_rmid_to_env(rmid, &env, 0) == XA_OK) 425*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate if ((ret = __os_calloc(1, sizeof(DB_ENV), &env)) != 0) 428*7c478bd9Sstevel@tonic-gate return (XAER_RMERR); 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate if (__db_rmid_to_name(rmid, &dbhome) != 0) 431*7c478bd9Sstevel@tonic-gate goto err1; 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate #undef XA_FLAGS 434*7c478bd9Sstevel@tonic-gate #define XA_FLAGS DB_RECOVER | \ 435*7c478bd9Sstevel@tonic-gate DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN 436*7c478bd9Sstevel@tonic-gate if ((ret = db_appinit(dbhome, NULL, env, XA_FLAGS)) != 0) 437*7c478bd9Sstevel@tonic-gate goto err1; 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate if (__db_map_rmid(rmid, env) != 0) 440*7c478bd9Sstevel@tonic-gate goto err2; 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate /* Now figure out from where to begin scan. */ 443*7c478bd9Sstevel@tonic-gate log = env->lg_info; 444*7c478bd9Sstevel@tonic-gate if ((err = __log_findckp(log, &log->xa_first)) == DB_NOTFOUND) { 445*7c478bd9Sstevel@tonic-gate /* 446*7c478bd9Sstevel@tonic-gate * If there were no log files, then we have no 447*7c478bd9Sstevel@tonic-gate * transactions to return, so we simply return 0. 448*7c478bd9Sstevel@tonic-gate */ 449*7c478bd9Sstevel@tonic-gate return (0); 450*7c478bd9Sstevel@tonic-gate } 451*7c478bd9Sstevel@tonic-gate if ((err = __db_txnlist_init(&log->xa_info)) != 0) 452*7c478bd9Sstevel@tonic-gate goto err3; 453*7c478bd9Sstevel@tonic-gate } else { 454*7c478bd9Sstevel@tonic-gate /* We had better already know about this rmid. */ 455*7c478bd9Sstevel@tonic-gate if (__db_rmid_to_env(rmid, &env, 0) != 0) 456*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 457*7c478bd9Sstevel@tonic-gate /* 458*7c478bd9Sstevel@tonic-gate * If we are not starting a scan, the log cursor had 459*7c478bd9Sstevel@tonic-gate * better be set. 460*7c478bd9Sstevel@tonic-gate */ 461*7c478bd9Sstevel@tonic-gate log = env->lg_info; 462*7c478bd9Sstevel@tonic-gate if (IS_ZERO_LSN(log->xa_lsn)) 463*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 464*7c478bd9Sstevel@tonic-gate } 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate /* 467*7c478bd9Sstevel@tonic-gate * At this point log->xa_first contains the point in the log 468*7c478bd9Sstevel@tonic-gate * to which we need to roll back. If we are starting a scan, 469*7c478bd9Sstevel@tonic-gate * we'll start at the last record; if we're continuing a scan, 470*7c478bd9Sstevel@tonic-gate * we'll have to start at log->xa_lsn. 471*7c478bd9Sstevel@tonic-gate */ 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate memset(&data, 0, sizeof(data)); 474*7c478bd9Sstevel@tonic-gate for (err = log_get(log, &log->xa_lsn, &data, 475*7c478bd9Sstevel@tonic-gate LF_ISSET(TMSTARTRSCAN) ? DB_LAST : DB_SET); 476*7c478bd9Sstevel@tonic-gate err == 0 && log_compare(&log->xa_lsn, &log->xa_first) > 0; 477*7c478bd9Sstevel@tonic-gate err = log_get(log, &log->xa_lsn, &data, DB_PREV)) { 478*7c478bd9Sstevel@tonic-gate memcpy(&rectype, data.data, sizeof(rectype)); 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate /* 481*7c478bd9Sstevel@tonic-gate * The only record type we care about is an DB_txn_xa_regop. 482*7c478bd9Sstevel@tonic-gate * If it's a commit, we have to add it to a txnlist. If it's 483*7c478bd9Sstevel@tonic-gate * a prepare, and we don't have a commit, then we return it. 484*7c478bd9Sstevel@tonic-gate * We are redoing some of what's in the xa_regop_recovery 485*7c478bd9Sstevel@tonic-gate * code, but we have to do it here so we can get at the xid 486*7c478bd9Sstevel@tonic-gate * in the record. 487*7c478bd9Sstevel@tonic-gate */ 488*7c478bd9Sstevel@tonic-gate if (rectype != DB_txn_xa_regop && rectype != DB_txn_regop) 489*7c478bd9Sstevel@tonic-gate continue; 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate memcpy(&txnid, (u_int8_t *)data.data + sizeof(rectype), 492*7c478bd9Sstevel@tonic-gate sizeof(txnid)); 493*7c478bd9Sstevel@tonic-gate err = __db_txnlist_find(log->xa_info, txnid); 494*7c478bd9Sstevel@tonic-gate switch (rectype) { 495*7c478bd9Sstevel@tonic-gate case DB_txn_regop: 496*7c478bd9Sstevel@tonic-gate if (err == DB_NOTFOUND) 497*7c478bd9Sstevel@tonic-gate __db_txnlist_add(log->xa_info, txnid); 498*7c478bd9Sstevel@tonic-gate err = 0; 499*7c478bd9Sstevel@tonic-gate break; 500*7c478bd9Sstevel@tonic-gate case DB_txn_xa_regop: 501*7c478bd9Sstevel@tonic-gate /* 502*7c478bd9Sstevel@tonic-gate * This transaction is commited, so we needn't read 503*7c478bd9Sstevel@tonic-gate * the record and do anything. 504*7c478bd9Sstevel@tonic-gate */ 505*7c478bd9Sstevel@tonic-gate if (err == 0) 506*7c478bd9Sstevel@tonic-gate break; 507*7c478bd9Sstevel@tonic-gate if ((err = 508*7c478bd9Sstevel@tonic-gate __txn_xa_regop_read(data.data, &argp)) != 0) { 509*7c478bd9Sstevel@tonic-gate ret = XAER_RMERR; 510*7c478bd9Sstevel@tonic-gate goto out; 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate 513*7c478bd9Sstevel@tonic-gate xidp->formatID = argp->formatID; 514*7c478bd9Sstevel@tonic-gate xidp->gtrid_length = argp->gtrid; 515*7c478bd9Sstevel@tonic-gate xidp->bqual_length = argp->bqual; 516*7c478bd9Sstevel@tonic-gate memcpy(xidp->data, argp->xid.data, argp->xid.size); 517*7c478bd9Sstevel@tonic-gate ret++; 518*7c478bd9Sstevel@tonic-gate xidp++; 519*7c478bd9Sstevel@tonic-gate __os_free(argp, sizeof(*argp)); 520*7c478bd9Sstevel@tonic-gate if (ret == count) 521*7c478bd9Sstevel@tonic-gate goto done; 522*7c478bd9Sstevel@tonic-gate break; 523*7c478bd9Sstevel@tonic-gate } 524*7c478bd9Sstevel@tonic-gate } 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate if (err != 0 && err != DB_NOTFOUND) 527*7c478bd9Sstevel@tonic-gate goto out; 528*7c478bd9Sstevel@tonic-gate 529*7c478bd9Sstevel@tonic-gate done: if (LF_ISSET(TMENDRSCAN)) { 530*7c478bd9Sstevel@tonic-gate ZERO_LSN(log->xa_lsn); 531*7c478bd9Sstevel@tonic-gate ZERO_LSN(log->xa_first); 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate out: __db_txnlist_end(log->xa_info); 534*7c478bd9Sstevel@tonic-gate log->xa_info = NULL; 535*7c478bd9Sstevel@tonic-gate } 536*7c478bd9Sstevel@tonic-gate return (ret); 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate err3: (void)__db_unmap_rmid(rmid); 539*7c478bd9Sstevel@tonic-gate err2: (void)db_appexit(env); 540*7c478bd9Sstevel@tonic-gate err1: __os_free(env, sizeof(DB_ENV)); 541*7c478bd9Sstevel@tonic-gate return (XAER_RMERR); 542*7c478bd9Sstevel@tonic-gate } 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate /* 545*7c478bd9Sstevel@tonic-gate * __db_xa_rollback 546*7c478bd9Sstevel@tonic-gate * Abort an XA transaction. 547*7c478bd9Sstevel@tonic-gate */ 548*7c478bd9Sstevel@tonic-gate static int 549*7c478bd9Sstevel@tonic-gate __db_xa_rollback(xid, rmid, flags) 550*7c478bd9Sstevel@tonic-gate XID *xid; 551*7c478bd9Sstevel@tonic-gate int rmid; 552*7c478bd9Sstevel@tonic-gate long flags; 553*7c478bd9Sstevel@tonic-gate { 554*7c478bd9Sstevel@tonic-gate DB_ENV *env; 555*7c478bd9Sstevel@tonic-gate TXN_DETAIL *td; 556*7c478bd9Sstevel@tonic-gate size_t off; 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate if (LF_ISSET(TMASYNC)) 559*7c478bd9Sstevel@tonic-gate return (XAER_ASYNC); 560*7c478bd9Sstevel@tonic-gate if (flags != TMNOFLAGS) 561*7c478bd9Sstevel@tonic-gate return (XAER_INVAL); 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate if (__db_rmid_to_env(rmid, &env, 1) != 0) 564*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 565*7c478bd9Sstevel@tonic-gate 566*7c478bd9Sstevel@tonic-gate if (__db_xid_to_txn(env, xid, &off) != 0) 567*7c478bd9Sstevel@tonic-gate return (XAER_NOTA); 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate td = (TXN_DETAIL *)((u_int8_t *)env->tx_info->region + off); 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate if (td->xa_status == TXN_XA_DEADLOCKED) 572*7c478bd9Sstevel@tonic-gate return (XA_RBDEADLOCK); 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate if (td->xa_status == TXN_XA_ABORTED) 575*7c478bd9Sstevel@tonic-gate return (XA_RBOTHER); 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate if (LF_ISSET(TMONEPHASE) && 578*7c478bd9Sstevel@tonic-gate td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED) 579*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate /* Now, fill in the global transaction structure. */ 582*7c478bd9Sstevel@tonic-gate __xa_txn_init(env, td, off); 583*7c478bd9Sstevel@tonic-gate if (txn_abort(env->xa_txn) != 0) 584*7c478bd9Sstevel@tonic-gate return (XAER_RMERR); 585*7c478bd9Sstevel@tonic-gate 586*7c478bd9Sstevel@tonic-gate /* No fatal value that would require an XAER_RMFAIL. */ 587*7c478bd9Sstevel@tonic-gate __xa_txn_end(env); 588*7c478bd9Sstevel@tonic-gate return (XA_OK); 589*7c478bd9Sstevel@tonic-gate } 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate /* 592*7c478bd9Sstevel@tonic-gate * __db_xa_forget -- 593*7c478bd9Sstevel@tonic-gate * Forget about an XID for a transaction that was heuristically 594*7c478bd9Sstevel@tonic-gate * completed. Since we do not heuristically complete anything, I 595*7c478bd9Sstevel@tonic-gate * don't think we have to do anything here, but we should make sure 596*7c478bd9Sstevel@tonic-gate * that we reclaim the slots in the txnid table. 597*7c478bd9Sstevel@tonic-gate */ 598*7c478bd9Sstevel@tonic-gate static int 599*7c478bd9Sstevel@tonic-gate __db_xa_forget(xid, rmid, flags) 600*7c478bd9Sstevel@tonic-gate XID *xid; 601*7c478bd9Sstevel@tonic-gate int rmid; 602*7c478bd9Sstevel@tonic-gate long flags; 603*7c478bd9Sstevel@tonic-gate { 604*7c478bd9Sstevel@tonic-gate DB_ENV *env; 605*7c478bd9Sstevel@tonic-gate size_t off; 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate if (LF_ISSET(TMASYNC)) 608*7c478bd9Sstevel@tonic-gate return (XAER_ASYNC); 609*7c478bd9Sstevel@tonic-gate if (flags != TMNOFLAGS) 610*7c478bd9Sstevel@tonic-gate return (XAER_INVAL); 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate if (__db_rmid_to_env(rmid, &env, 1) != 0) 613*7c478bd9Sstevel@tonic-gate return (XAER_PROTO); 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate /* 616*7c478bd9Sstevel@tonic-gate * If mapping is gone, then we're done. 617*7c478bd9Sstevel@tonic-gate */ 618*7c478bd9Sstevel@tonic-gate if (__db_xid_to_txn(env, xid, &off) != 0) 619*7c478bd9Sstevel@tonic-gate return (XA_OK); 620*7c478bd9Sstevel@tonic-gate 621*7c478bd9Sstevel@tonic-gate __db_unmap_xid(env, xid, off); 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate /* No fatal value that would require an XAER_RMFAIL. */ 624*7c478bd9Sstevel@tonic-gate return (XA_OK); 625*7c478bd9Sstevel@tonic-gate } 626*7c478bd9Sstevel@tonic-gate 627*7c478bd9Sstevel@tonic-gate /* 628*7c478bd9Sstevel@tonic-gate * __db_xa_complete -- 629*7c478bd9Sstevel@tonic-gate * Used to wait for asynchronous operations to complete. Since we're 630*7c478bd9Sstevel@tonic-gate * not doing asynch, this is an invalid operation. 631*7c478bd9Sstevel@tonic-gate */ 632*7c478bd9Sstevel@tonic-gate static int 633*7c478bd9Sstevel@tonic-gate __db_xa_complete(handle, retval, rmid, flags) 634*7c478bd9Sstevel@tonic-gate int *handle, *retval, rmid; 635*7c478bd9Sstevel@tonic-gate long flags; 636*7c478bd9Sstevel@tonic-gate { 637*7c478bd9Sstevel@tonic-gate COMPQUIET(handle, NULL); 638*7c478bd9Sstevel@tonic-gate COMPQUIET(retval, NULL); 639*7c478bd9Sstevel@tonic-gate COMPQUIET(rmid, 0); 640*7c478bd9Sstevel@tonic-gate COMPQUIET(flags, 0); 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate return (XAER_INVAL); 643*7c478bd9Sstevel@tonic-gate } 644*7c478bd9Sstevel@tonic-gate 645*7c478bd9Sstevel@tonic-gate /* 646*7c478bd9Sstevel@tonic-gate * __xa_txn_init -- 647*7c478bd9Sstevel@tonic-gate * Fill in the fields of the local transaction structure given 648*7c478bd9Sstevel@tonic-gate * the detail transaction structure. 649*7c478bd9Sstevel@tonic-gate */ 650*7c478bd9Sstevel@tonic-gate static void 651*7c478bd9Sstevel@tonic-gate __xa_txn_init(env, td, off) 652*7c478bd9Sstevel@tonic-gate DB_ENV *env; 653*7c478bd9Sstevel@tonic-gate TXN_DETAIL *td; 654*7c478bd9Sstevel@tonic-gate size_t off; 655*7c478bd9Sstevel@tonic-gate { 656*7c478bd9Sstevel@tonic-gate DB_TXN *txn; 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate txn = env->xa_txn; 659*7c478bd9Sstevel@tonic-gate txn->mgrp = env->tx_info; 660*7c478bd9Sstevel@tonic-gate txn->parent = NULL; 661*7c478bd9Sstevel@tonic-gate txn->last_lsn = td->last_lsn; 662*7c478bd9Sstevel@tonic-gate txn->txnid = td->txnid; 663*7c478bd9Sstevel@tonic-gate txn->off = off; 664*7c478bd9Sstevel@tonic-gate txn->flags = 0; 665*7c478bd9Sstevel@tonic-gate } 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate /* 668*7c478bd9Sstevel@tonic-gate * __xa_txn_end -- 669*7c478bd9Sstevel@tonic-gate * Invalidate a transaction structure that was generated by xa_txn_init. 670*7c478bd9Sstevel@tonic-gate */ 671*7c478bd9Sstevel@tonic-gate static void 672*7c478bd9Sstevel@tonic-gate __xa_txn_end(env) 673*7c478bd9Sstevel@tonic-gate DB_ENV *env; 674*7c478bd9Sstevel@tonic-gate { 675*7c478bd9Sstevel@tonic-gate DB_TXN *txn; 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate txn = env->xa_txn; 678*7c478bd9Sstevel@tonic-gate if (txn != NULL) 679*7c478bd9Sstevel@tonic-gate txn->txnid = TXN_INVALID; 680*7c478bd9Sstevel@tonic-gate } 681*7c478bd9Sstevel@tonic-gate 682