
org.objectweb.jotm.JotmRecovery Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jotm-core Show documentation
Show all versions of jotm-core Show documentation
JOTM: Java Open Transaction Manager - Core
/* * @(#) JotmRecovery.java * * JOTM: Java Open Transaction Manager * * * This module was originally developed by * * - Bull S.A. as part of the JOnAS application server code released in * July 1999 (www.bull.com) * * -------------------------------------------------------------------------- * The original code and portions created by Bull SA are * Copyright (c) 1999 BULL SA * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * -------------------------------------------------------------------------- * $Id: JotmRecovery.java,v 1.9 2005-09-14 22:23:57 tonyortiz Exp $ * -------------------------------------------------------------------------- */ package org.objectweb.jotm; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Vector; import java.util.List; import java.util.Iterator; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; import org.objectweb.howl.log.xa.XALogRecord; import org.objectweb.howl.log.xa.XACommittingTx; import javax.transaction.xa.XAException; /** * * @author Tony Ortiz */ /** * Thread class used to manage Resource Manager Registration. */ class processResourceManager extends Thread { private ThreadGroup xaResourceThreadGroup = null; Vector txrecovered = null; Vector rminfo = null; Vector rmreg = null; int rmsize = 0; int rmindex = 0; processResourceManager (ThreadGroup prmThreadGroup, Vector pvtxrecovered, Vector prminfo, Vector prmreg, int prmsize, int prmindex) { xaResourceThreadGroup = new ThreadGroup(prmThreadGroup, "XAResourceTG"); if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("new processResourceManager"); } txrecovered = pvtxrecovered; rminfo = prminfo; rmreg = prmreg; rmsize = prmsize; rmindex = prmindex;; } public void run() { if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("thread for processResourceManager"); } XAResource myregxares = null; RecoverRmInfo myrecoverRmInfo = null; String myrm = null; String myregrm = null; byte[] byxares = null; RmRegistration myrmreg = (RmRegistration) rmreg.elementAt(rmindex); myregrm = myrmreg.rmGetName(); for (int j=0; j
if not * initialized. * * @return Thenull JotmRecovery
object created */ public static JotmRecovery getJotmRecovery() { return unique; } /** * Returns the unique instance of the class ornull
if not * initialized. * * @return TheTxRecovered
vector created */ public static Vector getTxRecovered() { return vTxRecovered; } /** * Returns the unique instance of the class ornull
if not * initialized. * * @return TheRecoverRmInfo
vector created */ public static Vector getRecoverRmInfo() { return vRecoverRmInfo; } public Vector getmyRecoverRmInfo() { return vRecoverRmInfo; } /** * Returns the index of the Resource Manager's XAResource. * * @return Index of the Resource Manager's XAResource. */ public int getRmIndex(byte [] pxares) { int numRm = vRecoverRmInfo.size(); RecoverRmInfo myrecoverRmInfo; for (int i = 0; i < numRm; i++) { myrecoverRmInfo = (RecoverRmInfo) vRecoverRmInfo.elementAt(i); byte [] inrmxares = myrecoverRmInfo.getRecoverXaRes(); if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("XAResource param " + pxares); TraceTm.recovery.debug("XAResource in rm " + inrmxares); } if (inrmxares == pxares) { return myrecoverRmInfo.getRecoverIndex(); } } return 99; } public Vector getUserRecoveryVector() { // currently used by test suite return userRecoveryRecords; } /** * Processes an XACOMMIT entry (putCommit) that does not have an associated * XADONE entry (putDone). * * @param lr LogRecord that was passed to onRecord() method. */ public void rebuildTransaction(XALogRecord lr) { if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("rebuildTransaction"); } RecoverRmInfo myrecoverRmInfo = null; TxxidRecovered myrecoverTxInfo = null; TxRecovered mytxRecovered = null; // Temporary Recovery Record byte [] tempRec; byte [] rt = new byte [3]; // Applies to all Records // Resource Manager Record Type 1 fields long rmdatetime; int rmcount; // Resource Manager Record Type 2 byte [] resmgr2; // Resource Manager Record Type 2 fields int rmlength; byte [] rmname = null; int rmindx; // Recovery Record Type 1 fields long rcdatetime; byte [] txXid = null; int txdatelength; byte [] txdatetime; int xarescount = 0; // Check if there already exist a recovery record in our array with the // same txXid but a older datetime. If so remove it and store this one, // otherwise throw this one away. // Recovery Record Type 2 byte [] recov2; // Recovery Record Type 2 fields byte [] rt2 = new byte [3]; int xaresindex; int xareslength; int xaresnamelength; byte [] xares; byte [] xaresname; byte [] recoveryxid; int xidstatus; XACommittingTx myxacommittx = lr.getTx(); tempRec = lr.getFields() [0]; ByteBuffer rr = ByteBuffer.wrap(tempRec); rr.get(rt, 0, 3); String trt = new String(rt); if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("Recovery Record type= " + trt); } if (trt.equals("RM1")) { rmdatetime = rr.getLong(); rmcount = rr.getInt(); if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("Resource Manager count= " + rmcount); } for (int i = 1; i <= rmcount; i++) { resmgr2 = lr.getFields()[i]; ByteBuffer resm2 = ByteBuffer.wrap(resmgr2); resm2.get(rt2, 0, 3); trt = new String (rt2); if (trt.equals("RM2")) { rmlength = resm2.getInt(); rmname = new byte[rmlength]; resm2.get(rmname, 0, rmlength); xareslength = resm2.getInt(); xares = new byte[xareslength]; resm2.get(xares, 0, xareslength); xaresnamelength = resm2.getInt(); xaresname = new byte[xaresnamelength]; resm2.get(xaresname, 0, xaresnamelength); rmindx = resm2.getInt(); String myrmname = new String(rmname); String myxaresname = new String(xaresname); myrecoverRmInfo = new RecoverRmInfo(); myrecoverRmInfo.addRecoverRmXaRes (myrmname, xares, myxaresname, rmindx); vRecoverRmInfo.addElement(myrecoverRmInfo); } } } else if (trt.equals("RR1")) { rcdatetime = rr.getLong(); int intmfi = rr.getInt(); int gtilen = rr.getInt(); byte [] mgti = new byte[gtilen]; rr.get(mgti, 0, gtilen); int bqlen = rr.getInt(); byte [] mbq = new byte[bqlen]; rr.get(mbq, 0, bqlen); byte[] gtrid_local = new byte[64]; byte[] bqual_local = new byte[64]; // Buffers need two hex characters per byte StringBuffer str_buff_gtrid = new StringBuffer(64 * 2); StringBuffer str_buff_bqual = new StringBuffer(64 * 2); ByteBuffer aa = ByteBuffer.wrap(gtrid_local); System.arraycopy(mgti, 0, gtrid_local, 0, gtilen); for (int i=0; i < gtilen; i++) { byteToHex(aa.get(), str_buff_gtrid ); } if (bqlen != 0) { bqual_local = new byte[64]; ByteBuffer bb = ByteBuffer.wrap(bqual_local); System.arraycopy(mbq, 0, bqual_local, 0, bqlen); for (int i=0; i < bqlen; i++) { byteToHex(bb.get(), str_buff_bqual); } } byte[] bc = ":".getBytes(); int bclen = bc.length; String sxid = Long.toHexString(intmfi) + ":" + Long.toHexString(gtilen) + ":" + Long.toHexString(bqlen) + ":" + str_buff_gtrid.toString() + ":" + str_buff_bqual.toString(); txXid = new byte[4+bclen+4+bclen+4+gtilen+bclen+bqlen]; txXid = sxid.getBytes(); txdatelength = rr.getInt(); txdatetime = new byte[txdatelength]; rr.get(txdatetime, 0, txdatelength); xarescount = rr.getInt(); if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("Rebuilt tx prdt= " + rcdatetime); TraceTm.recovery.debug("Rebuilt tx ptxxid= " + new String(txXid)); TraceTm.recovery.debug("Rebuilt tx ptdt= " + new String(txdatetime)); } String mytxXid = new String(txXid); String mytxdatetime = new String(txdatetime); mytxRecovered = new TxRecovered(); if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("MyTxXid= " + mytxXid); TraceTm.recovery.debug("XAResource count= " + xarescount); } mytxRecovered.addtxrecovered (rcdatetime, txXid, mytxdatetime, xarescount, myxacommittx); for (int i=1; i <= xarescount; i++) { myrecoverTxInfo = new TxxidRecovered(); recov2 = lr.getFields()[i]; ByteBuffer rr2 = ByteBuffer.wrap(recov2); rr2.get(rt2, 0, 3); trt = new String (rt2); if (trt.equals("RR2")) { xaresindex = rr2.getInt(); xareslength = rr2.getInt(); xares = new byte[xareslength]; rr2.get(xares, 0, xareslength); xaresnamelength = rr2.getInt(); xaresname = new byte[xaresnamelength]; rr2.get(xaresname, 0, xaresnamelength); int intmfi2 = rr2.getInt(); int gtilen2 = rr2.getInt(); byte [] mgti2 = new byte[gtilen2]; rr2.get(mgti2, 0, gtilen2); int bqlen2 = rr2.getInt(); byte [] mbq2 = new byte[bqlen2]; rr2.get(mbq2, 0, bqlen2); xidstatus = rr2.getInt(); byte[] gtrid_local2 = new byte[64]; byte[] bqual_local2 = new byte[64]; // Buffers need two hex characters per byte StringBuffer str_buff_gtrid2 = new StringBuffer(64 * 2); StringBuffer str_buff_bqual2 = new StringBuffer(64 * 2); ByteBuffer aa2 = ByteBuffer.wrap(gtrid_local2); System.arraycopy(mgti2, 0, gtrid_local2, 0, gtilen2); for (int i2=0; i2 < gtilen2; i2++) { byteToHex(aa2.get(), str_buff_gtrid2 ); } if (bqlen2 != 0) { bqual_local2 = new byte[64]; ByteBuffer bb2 = ByteBuffer.wrap(bqual_local2); System.arraycopy(mbq2, 0, bqual_local2, 0, bqlen2); for (int i2=0; i2 < bqlen2; i2++) { byteToHex(bb2.get(), str_buff_bqual2); } } String sxid2 = Long.toHexString(intmfi2) + ":" + Long.toHexString(gtilen2) + ":" + Long.toHexString(bqlen2) + ":" + str_buff_gtrid2.toString() + ":" + str_buff_bqual2.toString(); recoveryxid = new byte[4+bclen+4+bclen+4+gtilen2+bclen+bqlen2]; recoveryxid = sxid2.getBytes(); String myxaresname = new String(xaresname); myrecoverTxInfo.addXidInfo (xaresindex, xares, myxaresname, recoveryxid, xidstatus); mytxRecovered.setRecoverTxXidInfo (myrecoverTxInfo, i-1); } } vTxRecovered.addElement(mytxRecovered); } else if (trt.equals("RU1")) { XidImpl.setUuids( rr.getLong(), rr.getLong()); } else { if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("Unknown record type during replay = " + trt); } // add this byteBuffer of this record to a vector for user recovery rr.rewind(); userRecoveryRecords.add( rr ); userRecoveryRecords.add( myxacommittx ); } } public void recoverTransactions (Vector rmreg) throws XAException { if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("recoverTransactions"); } int rmregsize = rmreg.size(); // number of Resource Managers registered // read the tmRecovered object and determine if any of the xaResources // require recovery (xares.recover call) int rmsize = vRecoverRmInfo.size(); // number of Resource Managers when system crashed if (rmsize == 0) { if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("Nothing to recover"); } return; } if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("number Resource Manager recover= " + rmsize); } // we can only recover Resource Managers that are in our log // (RecoverRmInfo) and have been registered (RmRegistered) ThreadGroup resourceManagerThreadGroup = new ThreadGroup("ResourceManagerTG"); for (int i = 0; i < rmregsize; i++) { RmRegistration myrmreg = (RmRegistration) rmreg.elementAt(i); String myregrm = myrmreg.rmGetName(); processResourceManager rmthread = new processResourceManager (resourceManagerThreadGroup, vTxRecovered, vRecoverRmInfo, rmreg, rmsize, i); Thread processrm = new Thread (resourceManagerThreadGroup, rmthread, myregrm + "-" + i); processrm.start(); } for (int w = 0; w < 10; w++) { // only do it 10 times) boolean rmsinthread = false; int numThreads = resourceManagerThreadGroup.activeCount(); if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("resourceManager active count= "+ numThreads); } if (numThreads == 0) { break; } Thread[] listOfThreads = new Thread[numThreads]; resourceManagerThreadGroup.enumerate(listOfThreads); for (int i = 0; i < numThreads; i++) { if (listOfThreads[i] != null) { if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("resourceManager in thread= "+ listOfThreads[i].getName()); } try { Thread.sleep(1000); // 1 second } catch (InterruptedException e) { ; } rmsinthread = true; break; } } if (!rmsinthread) { break; } } // We can now walk through TxRecovered and delete (howl done) any TxRecovered // entries that have had all their Xids (TxxidRecovered) committed or rolled // back successfully. // If any Xids have not been committed or rolledback, create a new TxRecovered // entry (howl commit) with the Xids (TxxidRecovered) that are still pending. doCleanupXidRecover (); for (int i = 0; i < rmregsize; i++) { RmRegistration myrmreg = (RmRegistration) rmreg.elementAt(i); myrmreg.rmSetRmRecovered(true); } } private void doCleanupXidRecover () { if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("doCleanupXidRecover"); } TxxidRecovered myTxxidRecovered = null; TxRecovered mytxRecovered = null; // We must go upward (last element to first) since we may remove // elements of the vTxRecovered vector. if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("vTxRecovered.size= " +vTxRecovered.size()); } for (int i = vTxRecovered.size() - 1; i >= 0; i--) { boolean possibleheuristic = false; XACommittingTx myxacommittingtx = null; mytxRecovered = (TxRecovered) vTxRecovered.elementAt(i); if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("mytxRecovered.xidcount= " +mytxRecovered.getxidcount()); } for (int j = 0; j < mytxRecovered.getxidcount(); j++) { myTxxidRecovered = mytxRecovered.getRecoverTxXidInfo(j); if (myTxxidRecovered != null) { if ((myTxxidRecovered.getRecoveraction() == 0) || // Xid already committed, ignore (myTxxidRecovered.getRecoveraction() == 1)) { // Xid just committed ; } else { if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("possibleheuristic"); } possibleheuristic = true; } } } // We cannot remove the vTxRecovered vector element if there // exists the possibility of a heuristic transaction. if (!possibleheuristic) { if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("write howlDonelog"); } myxacommittingtx = mytxRecovered.getXACommittingTx(); byte [] rmDone = new byte [11]; byte [] [] rmDoneRecord = new byte [1] [11]; rmDone = "RR3JOTMDONE".getBytes(); try { rmDoneRecord [0] = rmDone; TransactionRecoveryImpl.getTransactionRecovery().howlDoneLog (rmDoneRecord, myxacommittingtx); } catch (Exception f) { String howlerror = "Cannot howlDoneLog:" + f + "--" + f.getMessage(); if (TraceTm.recovery.isDebugEnabled()) { TraceTm.jotm.debug("Got LogException from howlDoneLog: "+ howlerror); } } if (TraceTm.recovery.isDebugEnabled()) { TraceTm.recovery.debug("remove txRecovered entry"); } vTxRecovered.remove(i); } } } static String HexDigits[] = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af", "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf", "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df", "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff" }; /** * Hex Dump of byte */ static final void byteToHex( byte inbyte, StringBuffer str_buff ) { int myByte = 0xFF & inbyte; str_buff.append( HexDigits[myByte] ); return; } }
© 2015 - 2025 Weber Informatics LLC | Privacy Policy