[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