[jboss-svn-commits] JBL Code SVN: r33314 - in labs/jbosstm/trunk/txbridge: tests and 2 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Wed Jun 2 13:03:52 EDT 2010
Author: jhalliday
Date: 2010-06-02 13:03:51 -0400 (Wed, 02 Jun 2010)
New Revision: 33314
Modified:
labs/jbosstm/trunk/txbridge/src/org/jboss/jbossts/txbridge/outbound/BridgeXAResource.java
labs/jbosstm/trunk/txbridge/src/org/jboss/jbossts/txbridge/outbound/OutboundBridgeRecoveryManager.java
labs/jbosstm/trunk/txbridge/tests/build.xml
labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/inbound/junit/BasicTests.java
labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/junit/CrashRecoveryTests.java
Log:
Improved txbridge outbound crash recovery. JBTM-44
Modified: labs/jbosstm/trunk/txbridge/src/org/jboss/jbossts/txbridge/outbound/BridgeXAResource.java
===================================================================
--- labs/jbosstm/trunk/txbridge/src/org/jboss/jbossts/txbridge/outbound/BridgeXAResource.java 2010-06-02 16:20:36 UTC (rev 33313)
+++ labs/jbosstm/trunk/txbridge/src/org/jboss/jbossts/txbridge/outbound/BridgeXAResource.java 2010-06-02 17:03:51 UTC (rev 33314)
@@ -38,6 +38,10 @@
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
/**
* Provides method call mapping between JTA parent coordinator and WS-AT subordinate transaction.
@@ -51,12 +55,17 @@
private static final Logger log = Logger.getLogger(BridgeXAResource.class);
+ private static final List<BridgeXAResource> xaResourcesAwaitingRecovery =
+ Collections.synchronizedList(new LinkedList<BridgeXAResource>());
+
private transient volatile BridgeWrapper bridgeWrapper;
private volatile Uid externalTxId; // JTA i.e. parent id
private volatile String bridgeWrapperId; // XTS i.e. subordinate.
+ private transient volatile boolean isAwaitingRecovery = false;
+
/**
* Create a new XAResource which wraps the subordinate WS-AT transaction.
*
@@ -103,6 +112,12 @@
externalTxId = (Uid)in.readObject();
bridgeWrapperId = (String)in.readObject();
+ // this readObject method executes only when a log is being read at recovery time:
+ isAwaitingRecovery = true;
+ synchronized(xaResourcesAwaitingRecovery) {
+ xaResourcesAwaitingRecovery.add(this);
+ }
+
try
{
bridgeWrapper = BridgeWrapper.recover(bridgeWrapperId);
@@ -169,7 +184,7 @@
log.trace("prepare returning XAResource.XA_OK");
return XAResource.XA_OK;
case TwoPhaseOutcome.PREPARE_READONLY:
- OutboundBridgeManager.removeMapping(externalTxId);
+ cleanupRefs();
log.trace("prepare returning XAResource.XA_RDONLY");
return XAResource.XA_RDONLY;
default:
@@ -183,6 +198,45 @@
}
/**
+ * Release any BridgeXAResource instances that have been driven
+ * through to completion by their parent JTA transaction.
+ */
+ public static void cleanupRecoveredXAResources()
+ {
+ log.trace("cleanupRecoveredXAResources()");
+
+ synchronized(xaResourcesAwaitingRecovery) {
+ Iterator<BridgeXAResource> iter = xaResourcesAwaitingRecovery.iterator();
+ while(iter.hasNext()) {
+ BridgeXAResource xaResource = iter.next();
+ if(!xaResource.isAwaitingRecovery()) {
+ iter.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * Determine if the specified BridgeWrapper is awaiting recovery or not.
+ *
+ * @param bridgeWrapperId the Id to search for.
+ * @return true if the BridgeWrapper is known to be awaiting recovery, false otherwise.
+ */
+ public static boolean isAwaitingRecovery(String bridgeWrapperId)
+ {
+ synchronized(xaResourcesAwaitingRecovery) {
+ for(BridgeXAResource bridgeXAResource : xaResourcesAwaitingRecovery) {
+ if(bridgeXAResource.bridgeWrapperId.equals(bridgeWrapperId)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
* Informs the resource manager to roll back work done on behalf of a transaction branch.
*
* @param xid A global transaction identifier
@@ -202,7 +256,7 @@
}
finally
{
- OutboundBridgeManager.removeMapping(externalTxId);
+ cleanupRefs();
}
}
@@ -235,7 +289,7 @@
}
finally
{
- OutboundBridgeManager.removeMapping(externalTxId);
+ cleanupRefs();
}
}
@@ -321,4 +375,16 @@
return 0; // TODO
}
+
+ public boolean isAwaitingRecovery() {
+ return isAwaitingRecovery;
+ }
+
+ private void cleanupRefs()
+ {
+ log.trace("cleanupRefs()");
+
+ OutboundBridgeManager.removeMapping(externalTxId);
+ isAwaitingRecovery = false;
+ }
}
Modified: labs/jbosstm/trunk/txbridge/src/org/jboss/jbossts/txbridge/outbound/OutboundBridgeRecoveryManager.java
===================================================================
--- labs/jbosstm/trunk/txbridge/src/org/jboss/jbossts/txbridge/outbound/OutboundBridgeRecoveryManager.java 2010-06-02 16:20:36 UTC (rev 33313)
+++ labs/jbosstm/trunk/txbridge/src/org/jboss/jbossts/txbridge/outbound/OutboundBridgeRecoveryManager.java 2010-06-02 17:03:51 UTC (rev 33314)
@@ -25,6 +25,11 @@
import org.apache.log4j.Logger;
import org.jboss.jbossts.xts.bridge.at.BridgeWrapper;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
/**
* Integrates with JBossAS MC lifecycle and JBossTS recovery manager to provide
* recovery services for outbound bridged transactions.
@@ -37,6 +42,8 @@
private final RecoveryManager acRecoveryManager = RecoveryManager.manager();
+ private volatile boolean orphanedBridgeWrappersAreIdentifiable = false;
+
/**
* MC lifecycle callback, used to register components with the recovery manager.
*/
@@ -75,18 +82,22 @@
@Override
public void periodicWorkSecondPass()
{
- // by the time we are called, the JTA tx recovery module has already been called, as it is registered
- // and hence ordered before us. Therefore by the time we get here any BridgeWrappers belonging to
- // a parent that was logged, will have been resolved top down. Anything left at this point can therefore
- // be assumed orphaned and hence we apply presumed abort.
-
log.trace("periodicWorkSecondPass()");
+ BridgeXAResource.cleanupRecoveredXAResources();
+
+ // the JTA top level tx recovery module is registered and hence run before us. Therefore by the time
+ // we get here we know readObject has been called for any BridgeXAResource for which a log exists.
+ // thus if it's not in our xaResourcesAwaitingRecovery list by now, it's presumed rollback.
+ orphanedBridgeWrappersAreIdentifiable = true;
+
BridgeWrapper[] bridgeWrappers = BridgeWrapper.scan(OutboundBridgeManager.BRIDGEWRAPPER_PREFIX);
for(BridgeWrapper bridgeWrapper : bridgeWrappers) {
- log.info("rolling back orphaned subordinate BridgeWrapper "+bridgeWrapper.getIdentifier());
- bridgeWrapper.rollback();
+ if( !BridgeXAResource.isAwaitingRecovery(bridgeWrapper.getIdentifier()) ) {
+ log.info("rolling back orphaned subordinate BridgeWrapper "+bridgeWrapper.getIdentifier());
+ bridgeWrapper.rollback();
+ }
}
}
}
Modified: labs/jbosstm/trunk/txbridge/tests/build.xml
===================================================================
--- labs/jbosstm/trunk/txbridge/tests/build.xml 2010-06-02 16:20:36 UTC (rev 33313)
+++ labs/jbosstm/trunk/txbridge/tests/build.xml 2010-06-02 17:03:51 UTC (rev 33314)
@@ -198,8 +198,8 @@
</batchtest>
<jvmarg value="-Djava.rmi.server.codebase=file://build/classes/"/>
- <jvmarg value="-Xdebug"/>
- <jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"/>
+ <!--<jvmarg value="-Xdebug"/>-->
+ <!--<jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"/>-->
<additional.jvmargs/>
</junit>
</sequential>
Modified: labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/inbound/junit/BasicTests.java
===================================================================
--- labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/inbound/junit/BasicTests.java 2010-06-02 16:20:36 UTC (rev 33313)
+++ labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/inbound/junit/BasicTests.java 2010-06-02 17:03:51 UTC (rev 33314)
@@ -62,9 +62,7 @@
instrumentedTestSynchronization = instrumentor.instrumentClass(TestSynchronization.class);
instrumentedTestXAResource = instrumentor.instrumentClass(TestXAResource.class);
- //instrumentor.captureLogging(TestSynchronization.class, null, org.apache.log4j.Logger.class, "error");
instrumentor.injectOnCall(TestServiceImpl.class, "doNothing", "$0.enlistSynchronization(1), $0.enlistXAResource(1)");
-
}
@After
Modified: labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/junit/CrashRecoveryTests.java
===================================================================
--- labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/junit/CrashRecoveryTests.java 2010-06-02 16:20:36 UTC (rev 33313)
+++ labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/junit/CrashRecoveryTests.java 2010-06-02 17:03:51 UTC (rev 33314)
@@ -184,7 +184,7 @@
manager.startServer("default");
}
- //@Test
+ @Test
public void testCrashOneLog() throws Exception {
instrumentor.injectOnCall(TestClient.class, "terminateTransaction", "$1 = true"); // shouldCommit=true
@@ -245,7 +245,7 @@
}
// this one requires <property name="commitOnePhase">false</property> on CoordinatorEnvironmentBean
- //@Test
+ @Test
public void testCrashThreeLogs() throws Exception {
instrumentor.injectOnCall(TestClient.class, "terminateTransaction", "$1 = true"); // shouldCommit=true
More information about the jboss-svn-commits
mailing list