001: /*
002:
003: Derby - Class org.apache.derby.impl.store.raw.xact.XactXAResourceManager
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.store.raw.xact;
023:
024: import org.apache.derby.iapi.reference.SQLState;
025:
026: import org.apache.derby.iapi.services.context.ContextManager;
027:
028: import org.apache.derby.iapi.services.sanity.SanityManager;
029:
030: import org.apache.derby.iapi.error.StandardException;
031:
032: import org.apache.derby.iapi.store.access.xa.XAResourceManager;
033: import org.apache.derby.iapi.store.access.xa.XAXactId;
034: import org.apache.derby.iapi.store.access.AccessFactoryGlobals;
035:
036: import org.apache.derby.iapi.store.raw.GlobalTransactionId;
037: import org.apache.derby.iapi.store.raw.RawStoreFactory;
038: import org.apache.derby.iapi.store.raw.Transaction;
039:
040: import org.apache.derby.impl.store.raw.xact.GlobalXactId;
041: import org.apache.derby.impl.store.raw.xact.TransactionTable;
042: import org.apache.derby.impl.store.raw.xact.TransactionTableEntry;
043: import org.apache.derby.impl.store.raw.xact.Xact;
044:
045: import java.util.Enumeration;
046: import java.util.Hashtable;
047:
048: import javax.transaction.xa.Xid;
049: import javax.transaction.xa.XAResource;
050:
051: /**
052:
053: The XactXAResourceManager implements the Access XAResource interface, which
054: provides offline control over two phase commit transactions. It is expected
055: to be used by TM's (transaction manager's), to recover if systems fail while
056: transactions are still in-doubt (prepared).
057: <P>
058: This interface allows access to commit,prepare,abort global transactions
059: as part of a two phase commit protocol. These interfaces have been chosen
060: to be exact implementations required to implement the XAResource interfaces
061: as part of the JTA standard extension.
062: <P>
063: It is expected that the following interfaces are only used during the
064: recovery portion of 2 phase commit, when the transaction manager is
065: cleaning up after a runtime crash - it is expected that no current context
066: managers exist for the Xid's being operated on. The "online" two phase commit
067: protocol will be implemented by calls directly on a TransactionController.
068: <P>
069: The XAResource interface is a Java mapping of the industry standard XA resource
070: manager interface. Please refer to: X/Open CAE Specification - Distributed
071: Transaction Processing: The XA Specification, X/Open Document No. XO/CAE/91/300
072: or ISBN 1 872630 24 3.
073:
074: @see org.apache.derby.iapi.store.access.xa.XAResourceManager
075:
076: **/
077:
078: public class XactXAResourceManager implements XAResourceManager {
079: /**************************************************************************
080: * Fields of the class
081: **************************************************************************
082: */
083: private TransactionTable transaction_table;
084: private RawStoreFactory rsf;
085:
086: /**************************************************************************
087: * Constructors for This class:
088: **************************************************************************
089: */
090: public XactXAResourceManager(RawStoreFactory rsf,
091: TransactionTable tt) {
092: this .rsf = rsf;
093: this .transaction_table = tt;
094: }
095:
096: /**************************************************************************
097: * Private/Protected methods of This class:
098: **************************************************************************
099: */
100:
101: /**************************************************************************
102: * Public Methods implementing XAResourceManager interface
103: **************************************************************************
104: */
105:
106: /**
107: * This method is called to commit the global transaction specified by xid.
108: * <p>
109: * RESOLVE - how do we map to the "right" XAExceptions.
110: * <p>
111: *
112: * @param cm The ContextManager returned from the find() call.
113: * @param xid A global transaction identifier.
114: * @param onePhase If true, the resource manager should use a one-phase
115: * commit protocol to commit the work done on behalf of
116: * xid.
117: *
118: * @exception StandardException Standard exception policy.
119: **/
120: public void commit(ContextManager cm, Xid xid, boolean onePhase)
121: throws StandardException {
122: Transaction rawtran = rsf.findUserTransaction(cm,
123: AccessFactoryGlobals.USER_TRANS_NAME);
124:
125: // This may happen if somehow the transaction was committed between
126: // the find() call and now.
127: if (rawtran == null) {
128: throw StandardException
129: .newException(SQLState.STORE_XA_PROTOCOL_VIOLATION);
130: }
131:
132: if (SanityManager.DEBUG) {
133: SanityManager.ASSERT(rawtran != null);
134:
135: SanityManager.ASSERT((new GlobalXactId(xid.getFormatId(),
136: xid.getGlobalTransactionId(), xid
137: .getBranchQualifier())).equals(rawtran
138: .getGlobalId()));
139: }
140:
141: rawtran.xa_commit(onePhase);
142: }
143:
144: /**
145: * Find the given Xid in the transaction table.
146: * <p>
147: * This routine is used to find a in-doubt transaction from the list
148: * of Xid's returned from the recover() routine.
149: * <p>
150: * In the current implementation it is up to the calling routine
151: * to make the returned ContextManager the "current" ContextManager
152: * before calls to commit,abort, or forget. The caller is responsible
153: * for error handling, ie. calling cleanupOnError() on the correct
154: * ContextManager.
155: * <p>
156: * If the Xid is not in the system, "null" is returned.
157: * RESOLVE - find out from sku if she wants a exception instead?
158: * <p>
159: *
160: * @param xid A global transaction identifier.
161: *
162: **/
163: public ContextManager find(Xid xid) {
164: return (transaction_table
165: .findTransactionContextByGlobalId(new GlobalXactId(xid
166: .getFormatId(), xid.getGlobalTransactionId(),
167: xid.getBranchQualifier())));
168: }
169:
170: /**
171: * This method is called to remove the given transaction
172: * from the transaction table/log.
173: * <p>
174: * Used to let the store remove all record from log and transaction
175: * table of the given transaction. This should only be used to
176: * clean up heuristically completed transactions, otherwise commit or
177: * abort should be used to act on other transactions.
178: * <p>
179: *
180: * @param cm The ContextManager returned from the find() call.
181: * @param xid A global transaction identifier.
182: *
183: * @exception StandardException Standard exception policy.
184: **/
185: public void forget(ContextManager cm, Xid xid)
186: throws StandardException {
187: Transaction rawtran = rsf.findUserTransaction(cm,
188: AccessFactoryGlobals.USER_TRANS_NAME);
189:
190: if (SanityManager.DEBUG) {
191: SanityManager.ASSERT(new GlobalXactId(xid.getFormatId(),
192: xid.getGlobalTransactionId(), xid
193: .getBranchQualifier()).equals(rawtran
194: .getGlobalId()));
195: }
196:
197: // forget should only be called on heuristically completed xacts, which
198: // should not exist in our system.
199: throw StandardException
200: .newException(SQLState.STORE_XA_PROTOCOL_VIOLATION);
201: }
202:
203: /**
204: * This method is called to obtain a list of prepared transactions.
205: * <p>
206: * This call returns a complete list of global transactions which are
207: * either prepared or heuristically complete.
208: * <p>
209: * The XAResource interface expects a scan type interface, but our
210: * implementation only returns a complete list of transactions. So to
211: * simulate the scan the following state is maintained. If TMSTARTSCAN
212: * is specified the complete list is returned. If recover is called with
213: * TMNOFLAGS is ever called a 0 length array is returned.
214: *
215: * @return Return a array with 0 or more Xid's which are currently in
216: * prepared or heuristically completed state. If an error occurs
217: * during the operation, an appropriate error is thrown.
218: *
219: * @param flags combination of the following flags
220: * XAResource.{TMSTARTRSCAN,TMENDRSCAN,TMNOFLAGS}.
221: * TMNOFLAGS must be used when no other flags are used.
222: *
223: * @exception StandardException Standard exception policy.
224: **/
225: public Xid[] recover(int flags) throws StandardException {
226: XAXactId[] ret_xid_list;
227:
228: if ((flags & XAResource.TMSTARTRSCAN) != 0) {
229: Hashtable trans_hashtable = transaction_table
230: .getTableForXA();
231: XAXactId[] xid_list = new XAXactId[trans_hashtable.size()];
232: int num_prepared = 0;
233:
234: // Need to hold sync while linear searching the hash table.
235: synchronized (trans_hashtable) {
236: int i = 0;
237:
238: for (Enumeration e = trans_hashtable.elements(); e
239: .hasMoreElements(); i++) {
240: Xact xact = ((TransactionTableEntry) e
241: .nextElement()).getXact();
242:
243: if (xact.isPrepared()) {
244: GlobalTransactionId xa_id = xact.getGlobalId();
245:
246: xid_list[i] = new XAXactId(
247: xa_id.getFormat_Id(), xa_id
248: .getGlobalTransactionId(),
249: xa_id.getBranchQualifier());
250: num_prepared++;
251: }
252: }
253: }
254:
255: // now need to squish the nulls out of the array to return.
256: ret_xid_list = new XAXactId[num_prepared];
257: int ret_index = 0;
258: for (int i = xid_list.length; i-- > 0;) {
259: if (xid_list[i] != null)
260: ret_xid_list[ret_index++] = xid_list[i];
261: }
262:
263: if (SanityManager.DEBUG) {
264: SanityManager.ASSERT(ret_index == num_prepared);
265: }
266: } else {
267: ret_xid_list = new XAXactId[0];
268: }
269:
270: return (ret_xid_list);
271: }
272:
273: /**
274: * rollback the transaction identified by Xid.
275: * <p>
276: * The given transaction is roll'ed back and it's history is not
277: * maintained in the transaction table or long term log.
278: * <p>
279: *
280: * @param cm The ContextManager returned from the find() call.
281: * @param xid A global transaction identifier.
282: *
283: * @exception StandardException Standard exception policy.
284: **/
285: public void rollback(ContextManager cm, Xid xid)
286: throws StandardException {
287: Transaction rawtran = rsf.findUserTransaction(cm,
288: AccessFactoryGlobals.USER_TRANS_NAME);
289:
290: // This may happen if somehow the transaction was committed between
291: // the find() call and now.
292: if (rawtran == null) {
293: throw StandardException
294: .newException(SQLState.STORE_XA_PROTOCOL_VIOLATION);
295: }
296:
297: if (SanityManager.DEBUG) {
298:
299: SanityManager.ASSERT(new GlobalXactId(xid.getFormatId(),
300: xid.getGlobalTransactionId(), xid
301: .getBranchQualifier()).equals(rawtran
302: .getGlobalId()));
303: }
304:
305: rawtran.xa_rollback();
306: }
307:
308: /**************************************************************************
309: * Public Methods of XXXX class:
310: **************************************************************************
311: */
312: }
|