[jboss-svn-commits] JBL Code SVN: r23376 - in labs/jbosstm/trunk: ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator and 5 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Wed Oct 8 08:50:50 EDT 2008


Author: jhalliday
Date: 2008-10-08 08:50:50 -0400 (Wed, 08 Oct 2008)
New Revision: 23376

Modified:
   labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/Environment.java
   labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/TxControl.java
   labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/recovery/TransactionStatusConnectionManager.java
   labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/recovery/PeriodicRecovery.java
   labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/recovery/RecoveryManagerImple.java
   labs/jbosstm/trunk/ArjunaCore/arjuna/etc/default-RecoveryManager-properties.xml
   labs/jbosstm/trunk/ArjunaCore/arjuna/etc/default-arjuna-properties.xml
   labs/jbosstm/trunk/ArjunaCore/docs/user_guide/FailureRecoveryGuide.odt
   labs/jbosstm/trunk/ArjunaCore/docs/user_guide/FailureRecoveryGuide.pdf
   labs/jbosstm/trunk/ArjunaJTA/jta/etc/default-RecoveryManager-properties.xml
Log:
Updated the recovery system to allow for use without TCP/IP sockets when the transaction manager and recovery manager are co-located. JBTM-389


Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/Environment.java
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/Environment.java	2008-10-08 11:40:00 UTC (rev 23375)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/Environment.java	2008-10-08 12:50:50 UTC (rev 23376)
@@ -137,10 +137,12 @@
     public static final String OBJECTSTORE_SHARE = "com.arjuna.ats.arjuna.objectstore.share";
     public static final String OBJECTSTORE_HIERARCHY_RETRY = "com.arjuna.ats.arjuna.objectstore.hierarchyRetry";
     public static final String OBJECTSTORE_HIERARCHY_TIMEOUT = "com.arjuna.ats.arjuna.objectstore.hierarchyTimeout";
+    public static final String RECOVERY_MANAGER_LISTENER = "com.arjuna.ats.arjuna.recovery.recoveryListener";
     public static final String RECOVERY_MANAGER_PORT = "com.arjuna.ats.arjuna.recovery.recoveryPort";
     public static final String RECOVERY_MANAGER_ADDRESS = "com.arjuna.ats.arjuna.recovery.recoveryAddress";
     public static final String XA_NODE_IDENTIFIER = "com.arjuna.ats.arjuna.xa.nodeIdentifier";
     public static final String DEFAULT_TIMEOUT = "com.arjuna.ats.arjuna.coordinator.defaultTimeout";
+    public static final String TRANSACTION_STATUS_MANAGER_ENABLE = "com.arjuna.ats.arjuna.coordinator.transactionStatusManagerEnable";
     public static final String TRANSACTION_STATUS_MANAGER_PORT = "com.arjuna.ats.arjuna.recovery.transactionStatusManagerPort";
     public static final String TRANSACTION_STATUS_MANAGER_ADDRESS = "com.arjuna.ats.arjuna.recovery.transactionStatusManagerAddress";
     public static final String SOCKET_PROCESS_ID_PORT= "com.arjuna.ats.internal.arjuna.utils.SocketProcessIdPort";

Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/TxControl.java
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/TxControl.java	2008-10-08 11:40:00 UTC (rev 23375)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/TxControl.java	2008-10-08 12:50:50 UTC (rev 23376)
@@ -186,7 +186,7 @@
 
 	static boolean enable = true;
 
-	static TransactionStatusManager transactionStatusManager = null;
+	private static TransactionStatusManager transactionStatusManager = null;
 
 	static ClassName actionStoreType = null;
 
@@ -350,7 +350,10 @@
 					Environment.XA_NODE_IDENTIFIER, new String(xaNodeName));
 		}
 
-		if (transactionStatusManager == null)
+        
+        String enableTSM = arjPropertyManager.propertyManager.getProperty(Environment.TRANSACTION_STATUS_MANAGER_ENABLE);
+        // run the TSM by default, unless it's turned off explicitly.
+        if (transactionStatusManager == null && !"NO".equalsIgnoreCase(enableTSM))
 		{
 			transactionStatusManager = new TransactionStatusManager();
 

Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/recovery/TransactionStatusConnectionManager.java
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/recovery/TransactionStatusConnectionManager.java	2008-10-08 11:40:00 UTC (rev 23375)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/recovery/TransactionStatusConnectionManager.java	2008-10-08 12:50:50 UTC (rev 23376)
@@ -87,72 +87,100 @@
 	
 	return status ;
     }
-   
+
     /**
      * Obtain the transaction status for the specified transaction type
      * and transaction.
      */
     public int getTransactionStatus( String transactionType, Uid tranUid )
     {
-	int status = ActionStatus.INVALID ;
-	
-	// extract process id from uid, use to index into
-	// hash table to obtain transaction status connector
-	// with which to retrieve the transaction status.
-	
-	String process_id = get_process_id ( tranUid ) ;
-	
-	if ( ! _tscTable.containsKey ( process_id ) )
-	{
-	    updateTSMI();
-	}
+        int status = ActionStatus.INVALID ;
 
-	if ( _tscTable.containsKey ( process_id ) )
-	    {
-		TransactionStatusConnector tsc = (TransactionStatusConnector) _tscTable.get( process_id ) ;
-		
-		if ( tsc.isDead() )
-		{
-		    _tscTable.remove( process_id ) ;
-		    tsc.delete() ;
-		    tsc = null ;
-		}
-		else
-		{
-		    status = tsc.getTransactionStatus( transactionType, tranUid ) ;
-		}
-	    }
+        // extract process id from uid
+        String process_id = get_process_id ( tranUid ) ;
 
-	/*
-	 * Try to read status from disc locally if invalid status,
-	 * as TransactionStatusManager may have died or comms may 
-	 * have failed.
-	 * Use an ActionStatusService instance as that's what the remote
-	 * recovery manager would have used, and it contains all of the logic
-	 * to find and map the state type.
-	 */
+        // if the tx is in the same JVM we rely on ActionStatusService directly.
+        // This skips the communication with TransactionStatusManager, which is just backed
+        // by ActionStatusService anyhow. That allows TSM to be turned off for local only cases if desired.
+        // Note: condition assumes ObjectStore is not shared between machines i.e. that processId is globally uniq.
+        if(! process_id.equals( get_process_id(_localUid) )) {
+            status = getRemoteTransactionStatus(process_id, transactionType, tranUid);
+        }
 
-	if ( status == ActionStatus.INVALID )
-	{
-	    ActionStatusService ass = new ActionStatusService();
-	    
-	    try
-	    {
-		status = ass.getTransactionStatus(transactionType, tranUid.stringForm());
-	    }
-	    catch ( Exception ex )
-	    {
-		if (tsLogger.arjLoggerI18N.isWarnEnabled())
-		{
-		    tsLogger.arjLoggerI18N.warn("com.arjuna.ats.arjuna.recovery.TransactionStatusConnectionManager_1", ex);
-		}
-	    }
-	}
+        /*
+         * Try to read status from disc locally if invalid status,
+         * as the tx may be local or, if it is remote, the
+         * TransactionStatusManager may have died or comms may
+         * have failed.
+         * Use an ActionStatusService instance as that's what the remote
+         * recovery manager would have used, and it contains all of the logic
+         * to find and map the state type.
+         */
 
-	return status ;
+        if ( status == ActionStatus.INVALID )
+        {
+            ActionStatusService ass = new ActionStatusService();
+
+            try
+            {
+                status = ass.getTransactionStatus(transactionType, tranUid.stringForm());
+            }
+            catch ( Exception ex )
+            {
+                if (tsLogger.arjLoggerI18N.isWarnEnabled())
+                {
+                    tsLogger.arjLoggerI18N.warn("com.arjuna.ats.arjuna.recovery.TransactionStatusConnectionManager_1", ex);
+                }
+            }
+        }
+
+        return status ;
     }
-   
+
     /**
+     * Use the TransactionStatusConnector to remotly query a transaction manager to get the tx status.
+     *
+     * @param process_id
+     * @param transactionType
+     * @param tranUid
+     * @return
+     */
+    private int getRemoteTransactionStatus(String process_id, String transactionType, Uid tranUid ) {
+
+        int status = ActionStatus.INVALID ;
+
+        // tx is not local, so use process id to index into
+        // hash table to obtain transaction status connector
+        // with which to retrieve the transaction status.
+
+        // Note: assumes ObjectStore is not shared between machienes
+        // otherwise we need to key on hostname,process_id tuple.
+
+        if ( ! _tscTable.containsKey ( process_id ) )
+        {
+            updateTSMI();
+        }
+
+        if ( _tscTable.containsKey ( process_id ) )
+        {
+            TransactionStatusConnector tsc = (TransactionStatusConnector) _tscTable.get( process_id ) ;
+
+            if ( tsc.isDead() )
+            {
+                _tscTable.remove( process_id ) ;
+                tsc.delete() ;
+                tsc = null ;
+            }
+            else
+            {
+                status = tsc.getTransactionStatus( transactionType, tranUid ) ;
+            }
+        }
+
+        return status;
+    }
+    
+    /**
      * Examine the Object Store for any new TrasactionStatusManagerItem
      * objects, and add to local hash table.
      */
@@ -274,7 +302,7 @@
     // Reference to object store.
     private static ObjectStore _objStore = null ;
       
-    
+    private static Uid _localUid = new Uid();
 }
 	  
 

Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/recovery/PeriodicRecovery.java
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/recovery/PeriodicRecovery.java	2008-10-08 11:40:00 UTC (rev 23375)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/recovery/PeriodicRecovery.java	2008-10-08 12:50:50 UTC (rev 23376)
@@ -142,55 +142,66 @@
         private Mode() { }
     }
 
-   public PeriodicRecovery (boolean threaded)
-   {
-      initialise();
+    /**
+     *
+     *
+     * @param threaded
+     * @param useListener  if true, start a socket based listener.
+     */
+    public PeriodicRecovery (boolean threaded, boolean useListener)
+    {
+        initialise();
 
-      // Load the recovery modules that actually do the work.
+        // Load the recovery modules that actually do the work.
 
-      loadModules();
+        loadModules();
 
-      try
-      {
-	  _workerService = new WorkerService(this);
+        if (useListener)
+        {
+            try
+            {
+                _workerService = new WorkerService(this);
 
-	  _listener = new Listener(getServerSocket(), _workerService);
-	  _listener.setDaemon(true);
+                _listener = new Listener(getServerSocket(), _workerService);
+                _listener.setDaemon(true);
 
-      if (tsLogger.arjLoggerI18N.isInfoEnabled())
-          tsLogger.arjLoggerI18N.info(
-                  "com.arjuna.ats.internal.arjuna.recovery.PeriodicRecovery_13",
-                  new Object[] {
-                          _socket.getInetAddress().getHostAddress(), _socket.getLocalPort()
-                  });
-      }
-      catch (Exception ex)
-      {
-	  if (tsLogger.arjLoggerI18N.isWarnEnabled())
-	  {
-	      tsLogger.arjLoggerI18N.warn("com.arjuna.ats.internal.arjuna.recovery.PeriodicRecovery_9", new Object[]{ex});
-	  }
-      }
+                if (tsLogger.arjLoggerI18N.isInfoEnabled())
+                    tsLogger.arjLoggerI18N.info(
+                            "com.arjuna.ats.internal.arjuna.recovery.PeriodicRecovery_13",
+                            new Object[] {
+                                    _socket.getInetAddress().getHostAddress(), _socket.getLocalPort()
+                            });
+            }
+            catch (Exception ex)
+            {
+                if (tsLogger.arjLoggerI18N.isWarnEnabled())
+                {
+                    tsLogger.arjLoggerI18N.warn("com.arjuna.ats.internal.arjuna.recovery.PeriodicRecovery_9", new Object[]{ex});
+                }
+            }
+        }
 
-      if (threaded)
-      {
-          if (tsLogger.arjLogger.isDebugEnabled())
-          {
-                 tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
-                         FacilityCode.FAC_CRASH_RECOVERY, "PeriodicRecovery: starting background scanner thread" );
-          }
-	  start();
-      }
+        if (threaded)
+        {
+            if (tsLogger.arjLogger.isDebugEnabled())
+            {
+                tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
+                        FacilityCode.FAC_CRASH_RECOVERY, "PeriodicRecovery: starting background scanner thread" );
+            }
+            start();
+        }
 
-       if (tsLogger.arjLogger.isDebugEnabled())
-       {
-              tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
-                      FacilityCode.FAC_CRASH_RECOVERY, "PeriodicRecovery: starting listener worker thread" );
-       }
+        if(useListener)
+        {
+            if (tsLogger.arjLogger.isDebugEnabled())
+            {
+                tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
+                        FacilityCode.FAC_CRASH_RECOVERY, "PeriodicRecovery: starting listener worker thread" );
+            }
+            _listener.start();
+        }
+    }
 
-      _listener.start();
-   }
-
     /**
      * initiate termination of the periodic recovery thread and stop any subsequent scan requests from proceeding.
      *
@@ -816,7 +827,10 @@
                 tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
                         FacilityCode.FAC_CRASH_RECOVERY, "PeriodicRecovery: scan thread signals listener worker");
             }
-            _workerService.signalDone();
+            if(_workerService != null)
+            {
+                _workerService.signalDone();
+            }
             _workerScanRequested = false;
         }
     }

Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/recovery/RecoveryManagerImple.java
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/recovery/RecoveryManagerImple.java	2008-10-08 11:40:00 UTC (rev 23375)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/recovery/RecoveryManagerImple.java	2008-10-08 12:50:50 UTC (rev 23376)
@@ -37,6 +37,7 @@
 import com.arjuna.common.util.propertyservice.PropertyManagerFactory;
 
 import com.arjuna.ats.arjuna.common.arjPropertyManager;
+import com.arjuna.ats.arjuna.common.Environment;
 import com.arjuna.ats.arjuna.exceptions.FatalError;
 import com.arjuna.ats.arjuna.recovery.RecoveryConfiguration;
 import com.arjuna.ats.arjuna.recovery.RecoveryModule;
@@ -72,9 +73,12 @@
 	 * @message com.arjuna.ats.internal.arjuna.recovery.RecoveryManagerImple_2
 	 *          [com.arjuna.ats.internal.arjuna.recovery.RecoveryManagerImple_2] -
 	 *          socket io exception {0}
-	 * @message com.arjuna.ats.internal.arjuna.recovery.ready
-	 *          [com.arjuna.ats.internal.arjuna.recovery.ready]
+	 * @message com.arjuna.ats.internal.arjuna.recovery.socketready
+	 *          [com.arjuna.ats.internal.arjuna.recovery.socketready]
 	 *          RecoveryManagerImple is ready on port {0}
+     * @message com.arjuna.ats.internal.arjuna.recovery.localready
+	 *          [com.arjuna.ats.internal.arjuna.recovery.localready]
+	 *          RecoveryManagerImple is ready. Socket listener is turned off.
      * @message com.arjuna.ats.internal.arjuna.recovery.fail
 	 *          [com.arjuna.ats.internal.arjuna.recovery.fail]
 	 *          RecoveryManagerImple: cannot bind to socket on address {0} and port {1}
@@ -114,12 +118,27 @@
 
 		Implementations.initialise();
 
-		/*
+
+        // by default we use a socket based listener, but it can be turned off if not required.
+        boolean useListener = true;
+        if("NO".equalsIgnoreCase(arjPropertyManager.propertyManager.getProperty(Environment.RECOVERY_MANAGER_LISTENER))) {
+            useListener = false;
+        }
+        
+        /*
 		 * Check whether there is a recovery daemon running - only allow one per
 		 * object store
+		 *
+		 * Note: this does not actually check if a recovery manager is running for the same ObjectStore,
+		 * only if one is on the same port as our confgiuration. Thus it's not particularly robust.
+		 * TODO: add a lock file to the ObjectStore as a belt and braces approach?
+		 *
+		 * This check works by trying to bind the server socket, so don't do it if we are running local only
+		 * (yup, that means there is a greater chance of winding up with more than one recovery manager if
+		 * we are running without a listener. See comment on robustness and file locking.)
 		 */
 
-		if (isRecoveryManagerEndPointInUse())
+		if (useListener && isRecoveryManagerEndPointInUse())
 		{
             if (tsLogger.arjLoggerI18N.isFatalEnabled())
             {
@@ -159,17 +178,25 @@
 		// start the periodic recovery thread
 		// (don't start this until just about to go on to the other stuff)
 
-		_periodicRecovery = new PeriodicRecovery(threaded);
+		_periodicRecovery = new PeriodicRecovery(threaded, useListener);
 
 		try
 		{
 			if (tsLogger.arjLogger.isInfoEnabled())
 			{
-				tsLogger.arjLoggerI18N.info(
-						"com.arjuna.ats.internal.arjuna.recovery.ready",
-						new Object[] { new Integer(_periodicRecovery
-								.getServerSocket().getLocalPort()) });
-			}
+				if(useListener)
+                {
+                    tsLogger.arjLoggerI18N.info(
+                            "com.arjuna.ats.internal.arjuna.recovery.socketready",
+                            new Object[] { new Integer(_periodicRecovery
+                                    .getServerSocket().getLocalPort()) });
+                }
+                else
+                {
+                    tsLogger.arjLoggerI18N.info(
+                            "com.arjuna.ats.internal.arjuna.recovery.localready");
+                }
+            }
 		}
 		catch (IOException ex)
 		{

Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/etc/default-RecoveryManager-properties.xml
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/etc/default-RecoveryManager-properties.xml	2008-10-08 11:40:00 UTC (rev 23375)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/etc/default-RecoveryManager-properties.xml	2008-10-08 12:50:50 UTC (rev 23376)
@@ -116,5 +116,15 @@
         name="com.arjuna.ats.arjuna.recovery.transactionStatusManagerAddress"
         value=""/>
 
+        <!--
+          For cases where the recovery manager is in process with the transaction manager and nothing else uses
+          the ObjectStore, it is possible to disable the socket based recovery listener by setting this to NO.
+          Caution: use of this property can allow multiple recovery processes to run on the same ObjectStore
+          if you are not careful. That in turn can lead to incorrect transaction processing. Use with care.
+        -->
+      <property
+          name="com.arjuna.ats.arjuna.recovery.recoveryListener"
+          value="YES"/>
+
     </properties>
 </transaction-service>

Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/etc/default-arjuna-properties.xml
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/etc/default-arjuna-properties.xml	2008-10-08 11:40:00 UTC (rev 23375)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/etc/default-arjuna-properties.xml	2008-10-08 12:50:50 UTC (rev 23376)
@@ -144,6 +144,17 @@
         name="com.arjuna.ats.internal.arjuna.utils.SocketProcessIdMaxPorts"
         value="1"/>
 
+      <!--
+        Run the TransactionStatusManager to allow out-of-process recovery managers to query
+        the status of transactions owned by this coordinator.  Default is YES.
+        This can be set to NO in cases where an ObjectStore is used only by one transaction manager
+        and the recovery manager for that store is in the same JVM. In any other cases disabling the
+        TransactionStatusManager may cause crash recovery to misbehave.
+      -->
+      <property
+        name="com.arjuna.ats.arjuna.coordinator.transactionStatusManagerEnable"
+        value="YES"/>
+
       <!-- property
         name="com.arjuna.ats.arjuna.coordinator.actionStore"
 		value="HashedActionStore"

Modified: labs/jbosstm/trunk/ArjunaCore/docs/user_guide/FailureRecoveryGuide.odt
===================================================================
(Binary files differ)

Modified: labs/jbosstm/trunk/ArjunaCore/docs/user_guide/FailureRecoveryGuide.pdf
===================================================================
(Binary files differ)

Modified: labs/jbosstm/trunk/ArjunaJTA/jta/etc/default-RecoveryManager-properties.xml
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/etc/default-RecoveryManager-properties.xml	2008-10-08 11:40:00 UTC (rev 23375)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/etc/default-RecoveryManager-properties.xml	2008-10-08 12:50:50 UTC (rev 23376)
@@ -122,5 +122,15 @@
         name="com.arjuna.ats.arjuna.recovery.transactionStatusManagerAddress"
         value=""/>
 
+        <!--
+          For cases where the recovery manager is in process with the transaction manager and nothing else uses
+          the ObjectStore, it is possible to disable the socket based recovery listener by setting this to NO.
+          Caution: use of this property can allow multiple recovery processes to run on the same ObjectStore
+          if you are not careful. That in turn can lead to incorrect transaction processing. Use with care.
+        -->
+        <property
+            name="com.arjuna.ats.arjuna.recovery.recoveryListener"
+            value="YES"/>
+
     </properties>
 </transaction-service>




More information about the jboss-svn-commits mailing list