001: /*
002: * @(#) JotmRecovery.java
003: *
004: * JOTM: Java Open Transaction Manager
005: *
006: *
007: * This module was originally developed by
008: *
009: * - Bull S.A. as part of the JOnAS application server code released in
010: * July 1999 (www.bull.com)
011: *
012: * --------------------------------------------------------------------------
013: * The original code and portions created by Bull SA are
014: * Copyright (c) 1999 BULL SA
015: * All rights reserved.
016: *
017: * Redistribution and use in source and binary forms, with or without
018: * modification, are permitted provided that the following conditions are met:
019: *
020: * -Redistributions of source code must retain the above copyright notice, this
021: * list of conditions and the following disclaimer.
022: *
023: * -Redistributions in binary form must reproduce the above copyright notice,
024: * this list of conditions and the following disclaimer in the documentation
025: * and/or other materials provided with the distribution.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
028: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
029: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
030: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
031: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
032: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
033: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
034: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
035: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
036: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
037: * POSSIBILITY OF SUCH DAMAGE.
038: *
039: * --------------------------------------------------------------------------
040: * $Id: JotmRecovery.java,v 1.6 2005/05/03 23:19:46 tonyortiz Exp $
041: * --------------------------------------------------------------------------
042: */
043:
044: package org.objectweb.jotm;
045:
046: import java.nio.ByteBuffer;
047: import java.util.Vector;
048:
049: import javax.transaction.xa.XAResource;
050: import javax.transaction.xa.Xid;
051:
052: import org.objectweb.howl.log.xa.XALogRecord;
053: import org.objectweb.howl.log.xa.XACommittingTx;
054: import javax.transaction.xa.XAException;
055:
056: /**
057: *
058: * @author Tony Ortiz
059: */
060:
061: /**
062: * Thread class used to commit an Xid of an XAResource,
063: * XAResource.commit(Xid).
064: */
065:
066: class commitXAResourceXid extends Thread {
067: XAResource commitxares = null;
068: Xid commitxid = null;
069:
070: commitXAResourceXid(XAResource pxares, Xid pxid) {
071: if (TraceTm.recovery.isDebugEnabled()) {
072: TraceTm.recovery.debug("pxares= " + pxares);
073: TraceTm.recovery.debug("pxid= " + pxid);
074: }
075: commitxares = pxares;
076: commitxid = pxid;
077: }
078:
079: public void run() {
080: if (TraceTm.recovery.isDebugEnabled()) {
081: TraceTm.recovery.debug("thread for commitXAResourceXid");
082: TraceTm.recovery.debug(" Committing xid= " + commitxid);
083: TraceTm.recovery.debug(" with XAResource= " + commitxares);
084: }
085:
086: try {
087: commitxares.commit(commitxid, false);
088: } catch (XAException e) {
089: TraceTm.recovery
090: .error("Unable to commit Xid during Recovery "
091: + e.getMessage());
092: }
093: }
094: }
095:
096: /**
097: * Thread class used to abort an Xid of an XAResource,
098: * XAResource.rollback(Xid).
099: */
100:
101: class abortXAResourceXid extends Thread {
102: XAResource abortxares = null;
103: Xid abortxid = null;
104:
105: abortXAResourceXid(XAResource pxares, Xid pxid) {
106: if (TraceTm.recovery.isDebugEnabled()) {
107: TraceTm.recovery.debug("pxares= " + pxares);
108: TraceTm.recovery.debug("pxid= " + pxid);
109: }
110: abortxares = pxares;
111: abortxid = pxid;
112: }
113:
114: public void run() {
115: if (TraceTm.recovery.isDebugEnabled()) {
116: TraceTm.recovery.debug("thread for abortXAResourceXid");
117: TraceTm.recovery.debug(" Rolling Back xid= " + abortxid);
118: TraceTm.recovery.debug(" with XAResource= " + abortxares);
119: }
120:
121: try {
122: abortxares.rollback(abortxid);
123: } catch (XAException e) {
124: TraceTm.recovery
125: .error("Unable to rollback Xid during Recovery "
126: + e.getMessage());
127: }
128: }
129: }
130:
131: /**
132: * Vector used to hold all Resource Managers that were
133: * registered when the system crashed, may have XIDs that
134: * need to be recovered.
135: */
136:
137: class RecoverRmInfo {
138:
139: private String recoverRm = null;
140: private byte[] recoverXares = null;
141: private String recoverxaresName = null;
142: private int recoverIndex = 0;
143:
144: public void addRecoverRmXaRes(String rrmName, byte[] rrmXares,
145: String rrmxaresName, int rrmIndex) {
146:
147: if (TraceTm.recovery.isDebugEnabled()) {
148: TraceTm.recovery.debug("RecoverRm Resource Manager= "
149: + rrmName);
150: TraceTm.recovery.debug("RecoverRm XAResource = "
151: + new String(rrmXares));
152: TraceTm.recovery.debug("RecoverRm Index = " + rrmIndex);
153: }
154:
155: recoverRm = rrmName;
156: recoverXares = rrmXares;
157: recoverxaresName = rrmxaresName;
158: recoverIndex = rrmIndex;
159: }
160:
161: public String getRecoverRm() {
162: if (TraceTm.recovery.isDebugEnabled()) {
163: TraceTm.recovery.debug("recoverRm= " + recoverRm);
164: }
165: return recoverRm;
166: }
167:
168: public byte[] getRecoverXaRes() {
169: if (TraceTm.recovery.isDebugEnabled()) {
170: TraceTm.recovery.debug("recoverXares= "
171: + new String(recoverXares));
172: }
173: return recoverXares;
174: }
175:
176: public String getRecoverXaResName() {
177: if (TraceTm.recovery.isDebugEnabled()) {
178: TraceTm.recovery.debug("recoverXares= "
179: + new String(recoverxaresName));
180: }
181: return recoverxaresName;
182: }
183:
184: public int getRecoverIndex() {
185: if (TraceTm.recovery.isDebugEnabled()) {
186: TraceTm.recovery.debug("recoverIncex= " + recoverIndex);
187: }
188: return recoverIndex;
189: }
190: }
191:
192: /**
193: * Vector and Array used to hold all Transactions that were
194: * in a commit pending status when the system crashed, these
195: * transactions (XIDs) may need to be recovered.
196: */
197:
198: class TxxidRecovered {
199:
200: private int txxidIndex = 0;
201: private byte[] txxidXares = null;
202: private String txxidXaresname = null;
203: private byte[] txxidXid = null;
204: private int txxidStatus = 0;
205: private int txxidAction = 0; // 0-Do nothing, implied already committed
206: // 1-Commit, 2-Rollback
207: private XAResource commitxares = null;
208: private Xid commitxid = null;
209:
210: public void addXidInfo(int pindex, byte[] pxares,
211: String pxaresname, byte[] pxid, int pstatus) {
212:
213: if (TraceTm.recovery.isDebugEnabled()) {
214: TraceTm.recovery.debug("Txxid index= " + pindex);
215: TraceTm.recovery
216: .debug("Txxid xares= " + new String(pxares));
217: TraceTm.recovery.debug("Txxid xid= " + new String(pxid));
218: TraceTm.recovery.debug("Txxid status= " + pstatus);
219: }
220:
221: txxidIndex = pindex;
222: txxidXares = pxares;
223: txxidXaresname = pxaresname;
224: txxidXid = pxid;
225: txxidStatus = pstatus;
226: }
227:
228: public int getRecoverindex() {
229: if (TraceTm.recovery.isDebugEnabled()) {
230: TraceTm.recovery.debug("txxidIndex= " + txxidIndex);
231: }
232: return txxidIndex;
233: }
234:
235: public byte[] getRecoverxares() {
236: if (TraceTm.recovery.isDebugEnabled()) {
237: TraceTm.recovery.debug("txxidXares= "
238: + new String(txxidXares));
239: }
240: return txxidXares;
241: }
242:
243: public String getRecoverxaresname() {
244: if (TraceTm.recovery.isDebugEnabled()) {
245: TraceTm.recovery.debug("txxidXaresname= " + txxidXaresname);
246: }
247: return txxidXaresname;
248: }
249:
250: public byte[] getRecoverxid() {
251: if (TraceTm.recovery.isDebugEnabled()) {
252: TraceTm.recovery.debug("txxidXid= " + new String(txxidXid));
253: }
254: return txxidXid;
255: }
256:
257: public int getRecoverstatus() {
258: if (TraceTm.recovery.isDebugEnabled()) {
259: TraceTm.recovery.debug("txxidStatus= " + txxidStatus);
260: }
261: return txxidStatus;
262: }
263:
264: public void setRecoverstatus(int pstatus) {
265: if (TraceTm.recovery.isDebugEnabled()) {
266: TraceTm.recovery.debug("pstatus= " + pstatus);
267: }
268: txxidStatus = pstatus;
269: }
270:
271: public int getRecoveraction() {
272: if (TraceTm.recovery.isDebugEnabled()) {
273: TraceTm.recovery.debug("txxidAction= " + txxidAction);
274: }
275: return txxidAction;
276: }
277:
278: public void setRecoveraction(int paction) {
279: if (TraceTm.recovery.isDebugEnabled()) {
280: TraceTm.recovery.debug("paction= " + paction);
281: }
282: txxidAction = paction;
283: }
284:
285: public XAResource getCommitxares() {
286: return commitxares;
287: }
288:
289: public void setCommitxares(XAResource pcommitxares) {
290: commitxares = pcommitxares;
291: }
292:
293: public Xid getCommitxid() {
294: return commitxid;
295: }
296:
297: public void setCommitxid(Xid pcommitxid) {
298: commitxid = pcommitxid;
299: }
300: }
301:
302: class TxRecovered {
303: private long recoverydatetime = 0L;
304: private byte[] txxid = null;
305: private String txdatetime = null;
306: private int xidcount = 0;
307: private XACommittingTx xacommittingtx = null;
308:
309: private TxxidRecovered[] xidinfo;
310:
311: public void addtxrecovered(long prdt, byte[] ptxxid, String ptdt,
312: int pxcnt, XACommittingTx pxacmtx) {
313:
314: if (TraceTm.recovery.isDebugEnabled()) {
315: TraceTm.recovery.debug("Recover tx prdt= " + prdt);
316: TraceTm.recovery.debug("Recover tx ptxxid= "
317: + new String(ptxxid));
318: TraceTm.recovery.debug("Recover tx ptdt= " + ptdt);
319: TraceTm.recovery.debug("Recover tx pxcnt= " + pxcnt);
320: TraceTm.recovery.debug("Recover tx pxacmtx= " + pxacmtx);
321: }
322:
323: recoverydatetime = prdt;
324: txxid = ptxxid;
325: txdatetime = ptdt;
326: xidcount = pxcnt;
327: xacommittingtx = pxacmtx;
328:
329: xidinfo = new TxxidRecovered[xidcount];
330: }
331:
332: public void addRecoverTxXidInfo(TxxidRecovered ptxxidr, int rindx) {
333:
334: if (TraceTm.recovery.isDebugEnabled()) {
335: TraceTm.recovery.debug("addRecoverTxXidInfo");
336: }
337: xidinfo[rindx] = ptxxidr;
338: }
339:
340: public long getrecoverdatetime() {
341: return recoverydatetime;
342: }
343:
344: public byte[] gettxxid() {
345: return txxid;
346: }
347:
348: public String gettxdatetime() {
349: return txdatetime;
350: }
351:
352: public int getxidcount() {
353: return xidcount;
354: }
355:
356: public TxxidRecovered getRecoverTxXidInfo(int rindx) {
357:
358: if (TraceTm.recovery.isDebugEnabled()) {
359: TraceTm.recovery.debug("getRecoverTxXidInfo");
360: }
361: return xidinfo[rindx];
362: }
363:
364: public XACommittingTx getXACommittingTx() {
365: if (TraceTm.recovery.isDebugEnabled()) {
366: TraceTm.recovery.debug("getXACommittingTx");
367: }
368: return xacommittingtx;
369: }
370: }
371:
372: public class JotmRecovery {
373:
374: private static JotmRecovery unique = null;
375: private static Vector vTxRecovered = new Vector();
376: private static Vector vRecoverRmInfo = new Vector();
377: private Vector userRecoveryRecords = new Vector();
378:
379: /**
380: * Constructor.
381: */
382:
383: public JotmRecovery() {
384:
385: if (TraceTm.recovery.isDebugEnabled()) {
386: TraceTm.recovery.debug("JotmRecovery constructor");
387: }
388:
389: unique = this ;
390: }
391:
392: /**
393: * Returns the unique instance of the class or <code>null</code> if not
394: * initialized.
395: *
396: * @return The <code>JotmRecovery</code> object created
397: */
398:
399: public static JotmRecovery getJotmRecovery() {
400:
401: return unique;
402: }
403:
404: /**
405: * Returns the unique instance of the class or <code>null</code> if not
406: * initialized.
407: *
408: * @return The <code>TxRecovered</code> vector created
409: */
410:
411: public static Vector getTxRecovered() {
412:
413: return vTxRecovered;
414: }
415:
416: /**
417: * Returns the unique instance of the class or <code>null</code> if not
418: * initialized.
419: *
420: * @return The <code>RecoverRmInfo</code> vector created
421: */
422:
423: public static Vector getRecoverRmInfo() {
424:
425: return vRecoverRmInfo;
426: }
427:
428: /**
429: * Returns the index of the Resource Manager's XAResource.
430: *
431: * @return Index of the Resource Manager's XAResource.
432: */
433:
434: public int getRmIndex(byte[] pxares) {
435: int numRm = vRecoverRmInfo.size();
436: RecoverRmInfo myrecoverRmInfo;
437:
438: for (int i = 0; i < numRm; i++) {
439: myrecoverRmInfo = (RecoverRmInfo) vRecoverRmInfo
440: .elementAt(i);
441: byte[] inrmxares = myrecoverRmInfo.getRecoverXaRes();
442:
443: if (TraceTm.recovery.isDebugEnabled()) {
444: TraceTm.recovery.debug("XAResource param " + pxares);
445: TraceTm.recovery.debug("XAResource in rm " + inrmxares);
446: }
447:
448: if (inrmxares == pxares) {
449: return myrecoverRmInfo.getRecoverIndex();
450: }
451: }
452: return 99;
453: }
454:
455: public Vector getUserRecoveryVector() { // currently used by test suite
456: return userRecoveryRecords;
457: }
458:
459: /**
460: * Processes an XACOMMIT entry (putCommit) that does not have an associated
461: * XADONE entry (putDone).
462: *
463: * @param lr LogRecord that was passed to onRecord() method.
464: */
465:
466: public void rebuildTransaction(XALogRecord lr) {
467:
468: if (TraceTm.recovery.isDebugEnabled()) {
469: TraceTm.recovery.debug("rebuildTransaction");
470: }
471:
472: RecoverRmInfo myrecoverRmInfo = null;
473: TxxidRecovered myrecoverTxInfo = null;
474: TxRecovered mytxRecovered = null;
475:
476: // Temporary Recovery Record
477: byte[] tempRec;
478: byte[] rt = new byte[3]; // Applies to all Records
479:
480: // Resource Manager Record Type 1 fields
481: long rmdatetime;
482: int rmcount;
483:
484: // Resource Manager Record Type 2
485: byte[] resmgr2;
486:
487: // Resource Manager Record Type 2 fields
488: int rmlength;
489: byte[] rmname = null;
490: int rmxareslength;
491: byte[] rmxares = null;
492: int rmindx;
493:
494: // Recovery Record Type 1 fields
495: long rcdatetime;
496: int txxidlength;
497: byte[] txXid = null;
498: int txdatelength;
499: byte[] txdatetime;
500: int xarescount = 0;
501:
502: // Check if there already exist a recovery record in our array with the
503: // same txXid but a older datetime. If so remove it and store this one,
504: // otherwise throw this one away.
505:
506: // Recovery Record Type 2
507: byte[] recov2;
508:
509: // Recovery Record Type 2 fields
510: byte[] rt2 = new byte[3];
511: int xaresindex;
512: int xareslength;
513: int xaresnamelength;
514: byte[] xares;
515: int xidlength;
516: byte[] xaresname;
517: byte[] recoveryxid;
518: int xidstatus;
519:
520: String trt;
521:
522: XACommittingTx myxacommittx = lr.getTx();
523: tempRec = lr.getFields()[0];
524:
525: ByteBuffer rr = ByteBuffer.wrap(tempRec);
526:
527: rr.get(rt, 0, 3);
528: trt = new String(rt);
529:
530: if (TraceTm.recovery.isDebugEnabled()) {
531: TraceTm.recovery.debug("Recovery Record type= " + trt);
532: }
533:
534: if (trt.equals("RM1")) {
535:
536: rmdatetime = rr.getLong();
537: rmcount = rr.getInt();
538:
539: if (TraceTm.recovery.isDebugEnabled()) {
540: TraceTm.recovery.debug("Resource Manager count= "
541: + rmcount);
542: }
543:
544: for (int i = 1; i <= rmcount; i++) {
545: resmgr2 = lr.getFields()[i];
546:
547: ByteBuffer resm2 = ByteBuffer.wrap(resmgr2);
548: resm2.get(rt2, 0, 3);
549: trt = new String(rt2);
550:
551: if (trt.equals("RM2")) {
552: rmlength = resm2.getInt();
553: rmname = new byte[rmlength];
554: resm2.get(rmname, 0, rmlength);
555: xareslength = resm2.getInt();
556: xares = new byte[xareslength];
557: resm2.get(xares, 0, xareslength);
558: xaresnamelength = resm2.getInt();
559: xaresname = new byte[xaresnamelength];
560: resm2.get(xaresname, 0, xaresnamelength);
561: rmindx = resm2.getInt();
562:
563: String myrmname = new String(rmname);
564: String myxares = new String(xares);
565: String myxaresname = new String(xaresname);
566: myrecoverRmInfo = new RecoverRmInfo();
567:
568: myrecoverRmInfo.addRecoverRmXaRes(myrmname, xares,
569: myxaresname, rmindx);
570: vRecoverRmInfo.addElement(myrecoverRmInfo);
571: }
572: }
573: } else if (trt.equals("RR1")) {
574: rcdatetime = rr.getLong();
575: txxidlength = rr.getInt();
576: txXid = new byte[txxidlength];
577: rr.get(txXid, 0, txxidlength);
578: txdatelength = rr.getInt();
579: txdatetime = new byte[txdatelength];
580: rr.get(txdatetime, 0, txdatelength);
581: xarescount = rr.getInt();
582:
583: String mytxXid = new String(txXid);
584: String mytxdatetime = new String(txdatetime);
585:
586: mytxRecovered = new TxRecovered();
587:
588: if (TraceTm.recovery.isDebugEnabled()) {
589: TraceTm.recovery.debug("XAResource count= "
590: + xarescount);
591: }
592:
593: mytxRecovered.addtxrecovered(rcdatetime, txXid,
594: mytxdatetime, xarescount, myxacommittx);
595:
596: for (int i = 1; i <= xarescount; i++) {
597: myrecoverTxInfo = new TxxidRecovered();
598: recov2 = lr.getFields()[i];
599:
600: ByteBuffer rr2 = ByteBuffer.wrap(recov2);
601: rr2.get(rt2, 0, 3);
602: trt = new String(rt2);
603:
604: if (trt.equals("RR2")) {
605: xaresindex = rr2.getInt();
606: xareslength = rr2.getInt();
607: xares = new byte[xareslength];
608: rr2.get(xares, 0, xareslength);
609: xaresnamelength = rr2.getInt();
610: xaresname = new byte[xaresnamelength];
611: rr2.get(xaresname, 0, xaresnamelength);
612: xidlength = rr2.getInt();
613: recoveryxid = new byte[xidlength];
614: rr2.get(recoveryxid, 0, xidlength);
615: xidstatus = rr2.getInt();
616:
617: String myxares = new String(xares);
618: String myxaresname = new String(xaresname);
619: String myrecoveryxid = new String(recoveryxid);
620:
621: myrecoverTxInfo.addXidInfo(xaresindex, xares,
622: myxaresname, recoveryxid, xidstatus);
623: mytxRecovered.addRecoverTxXidInfo(myrecoverTxInfo,
624: i - 1);
625: }
626: }
627: vTxRecovered.addElement(mytxRecovered);
628: } else if (trt.equals("RU1")) {
629: XidImpl.setUuids(rr.getLong(), rr.getLong());
630: } else {
631: if (TraceTm.recovery.isDebugEnabled()) {
632: TraceTm.recovery
633: .debug("Unknown record type during replay = "
634: + trt);
635: }
636: // add this byteBuffer of this record to a vector for user recovery
637: rr.rewind();
638: userRecoveryRecords.add(rr);
639: userRecoveryRecords.add(myxacommittx);
640: }
641: }
642:
643: public void recoverTransactions(Vector rmreg) throws XAException {
644: if (TraceTm.recovery.isDebugEnabled()) {
645: TraceTm.recovery.debug("recoverTransactions");
646: }
647:
648: RmRegistration myregisteredRmInfo = null;
649: String myregrm = null;
650: XAResource myregxares = null;
651: int rmregsize = rmreg.size(); // number of Resource Managers registered
652:
653: RecoverRmInfo myrecoverRmInfo = null;
654: String myrm = null;
655: byte[] byxares = null;
656:
657: int rcflag = 0;
658:
659: // read the tmRecovered object and determine if any of the xaResources
660: // require recovery (xares.recover call)
661:
662: int rmsize = vRecoverRmInfo.size(); // number of Resource Managers when system crashed
663:
664: if (rmsize == 0) {
665: if (TraceTm.recovery.isDebugEnabled()) {
666: TraceTm.recovery.debug("Nothing to recover");
667: }
668: return;
669: }
670:
671: if (TraceTm.recovery.isDebugEnabled()) {
672: TraceTm.recovery.debug("number Resource Manager recover= "
673: + rmsize);
674: }
675:
676: // we can only recover Resource Managers that are in our log
677: // (RecoverRmInfo) and have been registered (RmRegistered)
678:
679: for (int i = 0; i < rmregsize; i++) {
680:
681: RmRegistration myrmreg = (RmRegistration) rmreg
682: .elementAt(i);
683: myregrm = myrmreg.rmGetName();
684:
685: // checkout the XAResource, this will "lock" the XAResource
686: // must checkin later
687: myregxares = myrmreg.rmCheckoutXARes();
688:
689: for (int j = 0; j < rmsize; j++) {
690: myrecoverRmInfo = (RecoverRmInfo) vRecoverRmInfo
691: .elementAt(j);
692: myrm = myrecoverRmInfo.getRecoverRm();
693: byxares = myrecoverRmInfo.getRecoverXaRes();
694:
695: if (TraceTm.recovery.isDebugEnabled()) {
696: TraceTm.recovery
697: .debug("Registered Resource Manager "
698: + myregrm);
699: TraceTm.recovery.debug("Registered XAResource "
700: + myregxares);
701: TraceTm.recovery.debug("Recover Resource Manager "
702: + myrm);
703: TraceTm.recovery.debug("Recover XAResource "
704: + new String(byxares));
705: }
706:
707: if (myregrm.equals(myrm)) {
708: Xid[] javaxid;
709:
710: try {
711: // recover returns javax.transaction.xa.Xid objects
712: // we must cast to org.objectweb.jotm.Xid objects
713: javaxid = myregxares.recover(rcflag);
714: } catch (XAException e) {
715: throw new XAException(
716: "xaResource.recover call failed during recovery "
717: + e.getMessage());
718: }
719:
720: if (javaxid == null) {
721: if (TraceTm.recovery.isDebugEnabled()) {
722: TraceTm.recovery
723: .debug("No XIDs to recover for Xares javaxid is null");
724: }
725: break;
726: }
727:
728: if (TraceTm.recovery.isDebugEnabled()) {
729: TraceTm.recovery.debug("javaxid size= "
730: + javaxid.length);
731: }
732:
733: if (javaxid.length == 0) {
734: if (TraceTm.recovery.isDebugEnabled()) {
735: TraceTm.recovery
736: .debug("No XIDs to recover for Xares= "
737: + myregxares);
738: }
739: break;
740: }
741:
742: // set the action required for the XIDs located in our
743: // txxidRecovered (array), pointed to by TxRecovered (vector)
744: settxxidrecoveraction(myregxares, javaxid);
745: break;
746: }
747: }
748:
749: // checkin the XAResource, this will "unlock" the XAResource
750: myrmreg.rmCheckinXARes();
751: }
752:
753: // We can now walk through TxRecovered and perform the action on
754: // each of the Xids stored in TxxidRecovered.
755:
756: doActionXidRecover();
757:
758: // We can now walk through TxRecovered and delete (howl done) any TxRecovered
759: // entries that have had all their Xids (TxxidRecovered) committed or rolled
760: // back successfully.
761: // If any Xids have not been committed or rolledback, create a new TxRecovered
762: // entry (howl commit) with the Xids (TxxidRecovered) that are still pending.
763:
764: doCleanupXidRecover();
765: }
766:
767: private void settxxidrecoveraction(XAResource actxares,
768: Xid[] actionxid) {
769: if (TraceTm.recovery.isDebugEnabled()) {
770: TraceTm.recovery.debug("settxxidrecoveraction");
771: }
772:
773: TxxidRecovered mytxxidRecovered = null;
774: TxRecovered mytxRecovered = null;
775:
776: for (int i = 0; i < actionxid.length; i++) {
777: boolean xidfound = false;
778: Xid myjavaxid = actionxid[i];
779: org.objectweb.jotm.Xid myxid = new XidImpl(myjavaxid);
780: byte[] mybrqu = myxid.getBranchQualifier();
781:
782: for (int j = 0; j < vTxRecovered.size(); j++) {
783: mytxRecovered = (TxRecovered) vTxRecovered.elementAt(j);
784:
785: if (mytxRecovered != null) {
786:
787: for (int k = 0; k < mytxRecovered.getxidcount(); k++) {
788: mytxxidRecovered = mytxRecovered
789: .getRecoverTxXidInfo(k);
790:
791: if (mytxxidRecovered != null) {
792: byte[] mytxxid = mytxxidRecovered
793: .getRecoverxid();
794: org.objectweb.jotm.Xid mymytxxid = new XidImpl(
795: mytxxid);
796:
797: if (mymytxxid.IsThisOneOfOurs(mybrqu)) {
798:
799: if (TraceTm.recovery.isDebugEnabled()) {
800: TraceTm.recovery
801: .debug("mymytxxid= "
802: + mymytxxid
803: .toString(true));
804: TraceTm.recovery.debug("myxid = "
805: + myxid.toString(true));
806: }
807:
808: if ((new String(mytxxid)).equals(myxid
809: .toString(true))) {
810: xidfound = true;
811: int myaction = 1; // Commit
812: mytxxidRecovered
813: .setRecoveraction(myaction);
814: mytxxidRecovered
815: .setCommitxares(actxares);
816: mytxxidRecovered
817: .setCommitxid(myjavaxid);
818: mytxRecovered.addRecoverTxXidInfo(
819: mytxxidRecovered, k);
820: break;
821: }
822: } else {
823: if (TraceTm.recovery.isDebugEnabled()) {
824: TraceTm.recovery
825: .debug("Xid is not one of ours");
826: }
827: }
828: }
829: }
830:
831: if (xidfound) { // xid found in a TxxidRecovered of the TxRecovered vector
832: break;
833: }
834: }
835:
836: if (xidfound) { // xid found in a TxxidRecovered of the TxRecovered vector
837: break;
838: } else { // xid not found in any TxxidRecovered of the TxRecovered vector
839: abortimmediate(actxares, myjavaxid);
840: }
841: }
842: }
843: }
844:
845: private void doActionXidRecover() {
846: if (TraceTm.recovery.isDebugEnabled()) {
847: TraceTm.recovery.debug("doActionXidRecover");
848: }
849:
850: TxxidRecovered mytxxidRecovered = null;
851: TxRecovered mytxRecovered = null;
852:
853: for (int i = 0; i < vTxRecovered.size(); i++) {
854: mytxRecovered = (TxRecovered) vTxRecovered.elementAt(i);
855: XAResource commitxares = null;
856: Xid commitxid = null;
857:
858: for (int j = 0; j < mytxRecovered.getxidcount(); j++) {
859: mytxxidRecovered = mytxRecovered.getRecoverTxXidInfo(j);
860:
861: if (mytxxidRecovered != null) {
862:
863: // If action = 0; XAResource is known but the XID associated
864: // to is was not returned in the xares.recover call. This implies
865: // that the XID was already committed, just ignore.
866: // If action = 1; XAResource is known and the xares.recover call
867: // returned the specifed XID. This implies that we should attempt
868: // to commit the XID (if possible).
869:
870: if (mytxxidRecovered.getRecoveraction() == 1) { // Commit
871: byte[] myrcxid = mytxxidRecovered
872: .getRecoverxid();
873: commitxares = mytxxidRecovered.getCommitxares();
874: commitxid = mytxxidRecovered.getCommitxid();
875:
876: new commitXAResourceXid(commitxares, commitxid)
877: .start();
878: }
879: }
880: }
881: }
882: }
883:
884: private void abortimmediate(XAResource abortxares, Xid abortxid) {
885: if (TraceTm.recovery.isDebugEnabled()) {
886: TraceTm.recovery.debug("abortimmediate");
887: }
888:
889: new abortXAResourceXid(abortxares, abortxid).start();
890: }
891:
892: private void doCleanupXidRecover() {
893: if (TraceTm.recovery.isDebugEnabled()) {
894: TraceTm.recovery.debug("doCleanupXidRecover");
895: }
896:
897: TxxidRecovered myTxxidRecovered = null;
898: TxRecovered mytxRecovered = null;
899:
900: // for (int i=0; i<vTxRecovered.size(); i++){
901: // We must go upward (last element to first) since we may remove
902: // elements of the vTxRecovered vector.
903:
904: if (TraceTm.recovery.isDebugEnabled()) {
905: TraceTm.recovery.debug("vTxRecovered.size= "
906: + vTxRecovered.size());
907: }
908:
909: for (int i = vTxRecovered.size() - 1; i >= 0; i--) {
910: boolean possibleheuristic = false;
911: XACommittingTx myxacommittingtx = null;
912: mytxRecovered = (TxRecovered) vTxRecovered.elementAt(i);
913:
914: if (TraceTm.recovery.isDebugEnabled()) {
915: TraceTm.recovery.debug("mytxRecovered.xidcount= "
916: + mytxRecovered.getxidcount());
917: }
918:
919: for (int j = 0; j < mytxRecovered.getxidcount(); j++) {
920: myTxxidRecovered = mytxRecovered.getRecoverTxXidInfo(j);
921:
922: if (myTxxidRecovered != null) {
923: if ((myTxxidRecovered.getRecoveraction() == 0) || // Xid already committed, ignore
924: (myTxxidRecovered.getRecoveraction() == 1)) { // Xid just committed
925: ;
926: } else {
927: if (TraceTm.recovery.isDebugEnabled()) {
928: TraceTm.recovery.debug("possibleheuristic");
929: }
930:
931: possibleheuristic = true;
932: }
933: }
934: }
935:
936: // We cannot remove the vTxRecovered vector element if there
937: // exists the possibility of a heuristic transaction.
938:
939: if (!possibleheuristic) {
940:
941: if (TraceTm.recovery.isDebugEnabled()) {
942: TraceTm.recovery.debug("write howlDonelog");
943: }
944:
945: myxacommittingtx = mytxRecovered.getXACommittingTx();
946: byte[] rmDone = new byte[11];
947: byte[][] rmDoneRecord = new byte[1][11];
948:
949: rmDone = "RR3JOTMDONE".getBytes();
950:
951: try {
952: rmDoneRecord[0] = rmDone;
953: TransactionRecoveryImpl
954: .getTransactionRecovery()
955: .howlDoneLog(rmDoneRecord, myxacommittingtx);
956: } catch (Exception f) {
957: String howlerror = "Cannot howlDoneLog:" + f + "--"
958: + f.getMessage();
959: TraceTm.jotm
960: .error("Got LogException from howlDoneLog: "
961: + howlerror);
962: }
963:
964: if (TraceTm.recovery.isDebugEnabled()) {
965: TraceTm.recovery.debug("remove txRecovered entry");
966: }
967: vTxRecovered.remove(i);
968: }
969: }
970: }
971: }
|