[jboss-svn-commits] JBL Code SVN: r17348 - labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Thu Dec 20 19:16:58 EST 2007


Author: mark.little at jboss.com
Date: 2007-12-20 19:16:57 -0500 (Thu, 20 Dec 2007)
New Revision: 17348

Modified:
   labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/TwoPhaseCoordinator.java
Log:
http://jira.jboss.com/jira/browse/JBTM-316

Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/TwoPhaseCoordinator.java
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/TwoPhaseCoordinator.java	2007-12-20 20:43:54 UTC (rev 17347)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/TwoPhaseCoordinator.java	2007-12-21 00:16:57 UTC (rev 17348)
@@ -210,81 +210,99 @@
 	{
 		boolean problem = false;
 
-		/*
-		 * If we have a synchronization list then we must be top-level.
-		 */
-
-		if (_synchs != null)
+		synchronized (_syncLock)
 		{
-			/*
-			 * We must always call afterCompletion() methods, so just catch (and
-			 * log) any exceptions/errors from beforeCompletion() methods.
-			 *
-			 * If one of the Syncs throws an error the Record wrapper returns false
-			 * and we will rollback. Hence we don't then bother to call beforeCompletion
-			 * on the remaining records (it's not done for rollabcks anyhow).
-			 *
-			 * Since Synchronizations may add register other Synchronizations, we can't simply
-			 * iterate the collection. Instead we work from an ordered copy, which we periodically
-			 * check for freshness. The addSynchronization method uses _currentRecord to disallow
-			 * adding records in the part of the array we have already traversed, thus all
-			 * Synchronization will be called and the (jta only) rules on ordering of interposed
-			 * Synchronization will be respected.
-			 */
+			if (!_beforeCalled)
+			{
+				_beforeCalled = true;
+		
+				/*
+				 * If we have a synchronization list then we must be top-level.
+				 */
 
-			int lastIndexProcessed = -1;
-			SynchronizationRecord[] copiedSynchs = (SynchronizationRecord[])_synchs.toArray(new SynchronizationRecord[] {});
+				if (_synchs != null)
+				{
+					/*
+					 * We must always call afterCompletion() methods, so just catch (and
+					 * log) any exceptions/errors from beforeCompletion() methods.
+					 *
+					 * If one of the Syncs throws an error the Record wrapper returns false
+					 * and we will rollback. Hence we don't then bother to call beforeCompletion
+					 * on the remaining records (it's not done for rollabcks anyhow).
+					 *
+					 * Since Synchronizations may add register other Synchronizations, we can't simply
+					 * iterate the collection. Instead we work from an ordered copy, which we periodically
+					 * check for freshness. The addSynchronization method uses _currentRecord to disallow
+					 * adding records in the part of the array we have already traversed, thus all
+					 * Synchronization will be called and the (jta only) rules on ordering of interposed
+					 * Synchronization will be respected.
+					 */
 
-			while( (lastIndexProcessed < _synchs.size()-1) && !problem) {
+					int lastIndexProcessed = -1;
+					SynchronizationRecord[] copiedSynchs = (SynchronizationRecord[])_synchs.toArray(new SynchronizationRecord[] {});
 
-				// if new Synchronization have been registered, refresh our copy of the collection:
-				if(copiedSynchs.length != _synchs.size()) {
-					copiedSynchs = (SynchronizationRecord[])_synchs.toArray(new SynchronizationRecord[] {});
-				}
+					while( (lastIndexProcessed < _synchs.size()-1) && !problem) {
 
-				lastIndexProcessed = lastIndexProcessed+1;
-				_currentRecord = copiedSynchs[lastIndexProcessed];
+						// if new Synchronization have been registered, refresh our copy of the collection:
+						if(copiedSynchs.length != _synchs.size()) {
+							copiedSynchs = (SynchronizationRecord[])_synchs.toArray(new SynchronizationRecord[] {});
+						}
 
-				try
-				{
-					problem = !_currentRecord.beforeCompletion();
+						lastIndexProcessed = lastIndexProcessed+1;
+						_currentRecord = copiedSynchs[lastIndexProcessed];
 
-					// if something goes wrong, we can't just throw the exception, we need to continue to
-					// complete the transaction. However, the exception may have interesting information that
-					// we want later, so we keep a reference to it as well as logging it.
+						try
+						{
+							problem = !_currentRecord.beforeCompletion();
 
-				}
-				catch (Exception ex)
-				{
-					tsLogger.arjLoggerI18N.warn("com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_2", new Object[]
-					{ _currentRecord }, ex);
-					if(_deferredThrowable == null) {
-						_deferredThrowable = ex;
+							// if something goes wrong, we can't just throw the exception, we need to continue to
+							// complete the transaction. However, the exception may have interesting information that
+							// we want later, so we keep a reference to it as well as logging it.
+
+						}
+						catch (Exception ex)
+						{
+							tsLogger.arjLoggerI18N.warn("com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_2", new Object[]
+							                                                                                                  { _currentRecord }, ex);
+							if(_deferredThrowable == null) {
+								_deferredThrowable = ex;
+							}
+							problem = true;
+						}
+						catch (Error er)
+						{
+							tsLogger.arjLoggerI18N.warn("com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_2", new Object[]
+							                                                                                                  { _currentRecord }, er);
+							if(_deferredThrowable == null) {
+								_deferredThrowable = er;
+							}
+							problem = true;
+						}
 					}
-					problem = true;
-				}
-				catch (Error er)
-				{
-					tsLogger.arjLoggerI18N.warn("com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_2", new Object[]
-					{ _currentRecord }, er);
-					if(_deferredThrowable == null) {
-						_deferredThrowable = er;
+
+					if (problem)
+					{
+						if (!preventCommit())
+						{
+							/*
+							 * This should not happen. If it does, continue with commit
+							 * to tidy-up.
+							 */
+
+							tsLogger.arjLoggerI18N.warn("com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_1");
+						}
 					}
-					problem = true;
 				}
 			}
-
-			if (problem)
+			else
 			{
-				if (!preventCommit())
-				{
-					/*
-					 * This should not happen. If it does, continue with commit
-					 * to tidy-up.
-					 */
-
-					tsLogger.arjLoggerI18N.warn("com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_1");
-				}
+				/*
+				 * beforeCompletions already called. Assume everything is alright
+				 * to proceed to commit. The TM instance will flag the outcome. If
+				 * it's rolling back, then we'll get an exception. If it's committing
+				 * then we'll be blocked until the commit (assuming we're still the
+				 * slower thread).
+				 */
 			}
 		}
 
@@ -319,51 +337,64 @@
 
 		boolean problem = false;
 
-		if (_synchs != null)
+		synchronized (_syncLock)
 		{
-			// afterCompletions should run in reverse order compared to beforeCompletions
-			Stack stack = new Stack();
-			Iterator iterator = _synchs.iterator();
-			while(iterator.hasNext()) {
-				stack.push(iterator.next());
-			}
-
-			iterator = stack.iterator();
-
-			/*
-			 * Regardless of failures, we must tell all synchronizations what
-			 * happened.
-			 */
-			while(!stack.isEmpty())
+			if (!_afterCalled)
 			{
-				SynchronizationRecord record = (SynchronizationRecord)stack.pop();
+				_afterCalled = true;
 
-				try
+				if (_synchs != null)
 				{
-					if (!record.afterCompletion(myStatus))
+					// afterCompletions should run in reverse order compared to
+					// beforeCompletions
+					Stack stack = new Stack();
+					Iterator iterator = _synchs.iterator();
+					while(iterator.hasNext()) {
+						stack.push(iterator.next());
+					}
+		
+					iterator = stack.iterator();
+		
+					/*
+					 * Regardless of failures, we must tell all synchronizations what
+					 * happened.
+					 */
+					while(!stack.isEmpty())
 					{
-						tsLogger.arjLoggerI18N.warn("com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_4", new Object[]
-						{ record });
-
-						problem = true;
+						SynchronizationRecord record = (SynchronizationRecord)stack.pop();
+		
+						try
+						{
+							if (!record.afterCompletion(myStatus))
+							{
+								tsLogger.arjLoggerI18N.warn("com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_4", new Object[]
+								{ record });
+		
+								problem = true;
+							}
+						}
+						catch (Exception ex)
+						{
+							tsLogger.arjLoggerI18N.warn("com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_4a", new Object[]
+							{ record, ex });
+							problem = true;
+						}
+						catch (Error er)
+						{
+							tsLogger.arjLoggerI18N.warn("com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_4b", new Object[]
+							{ record, er });
+							problem = true;
+						}
 					}
+		
+					_synchs = null;
+					_currentRecord = null;
 				}
-				catch (Exception ex)
-				{
-					tsLogger.arjLoggerI18N.warn("com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_4a", new Object[]
-					{ record, ex });
-					problem = true;
-				}
-				catch (Error er)
-				{
-					tsLogger.arjLoggerI18N.warn("com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_4b", new Object[]
-					{ record, er });
-					problem = true;
-				}
 			}
-
-			_synchs = null;
-			_currentRecord = null;
+			else
+			{
+				
+			}
 		}
 
 		return !problem;
@@ -372,4 +403,9 @@
 	private SortedSet _synchs;
 	private SynchronizationRecord _currentRecord; // the most recently processed Synchronization.
 	private Throwable _deferredThrowable;
+	
+	private Object _syncLock = new Object();
+	
+	private boolean _beforeCalled = false;
+	private boolean _afterCalled = false;
 }




More information about the jboss-svn-commits mailing list