[jboss-svn-commits] JBL Code SVN: r37757 - labs/jbosstm/branches/JBOSSTS_4_6_1_GA_CP11_JBTM-842_JBTM-924/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Thu Dec 1 05:05:07 EST 2011


Author: raggz
Date: 2011-12-01 05:05:07 -0500 (Thu, 01 Dec 2011)
New Revision: 37757

Modified:
   labs/jbosstm/branches/JBOSSTS_4_6_1_GA_CP11_JBTM-842_JBTM-924/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/RecoveryXids.java
   labs/jbosstm/branches/JBOSSTS_4_6_1_GA_CP11_JBTM-842_JBTM-924/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/XARecoveryModule.java
Log:
Back port of JBTM-842. Second attempt.


Modified: labs/jbosstm/branches/JBOSSTS_4_6_1_GA_CP11_JBTM-842_JBTM-924/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/RecoveryXids.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_6_1_GA_CP11_JBTM-842_JBTM-924/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/RecoveryXids.java	2011-12-01 09:59:57 UTC (rev 37756)
+++ labs/jbosstm/branches/JBOSSTS_4_6_1_GA_CP11_JBTM-842_JBTM-924/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/RecoveryXids.java	2011-12-01 10:05:07 UTC (rev 37757)
@@ -1,20 +1,20 @@
 /*
  * JBoss, Home of Professional Open Source
- * Copyright 2006, Red Hat Middleware LLC, and individual contributors 
- * as indicated by the @author tags. 
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags.
  * See the copyright.txt in the distribution for a
- * full listing of individual contributors. 
+ * full listing of individual contributors.
  * This copyrighted material is made available to anyone wishing to use,
  * modify, copy, or redistribute it subject to the terms and conditions
  * of the GNU Lesser General Public License, v. 2.1.
- * This program is distributed in the hope that it will be useful, but WITHOUT A 
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
  * You should have received a copy of the GNU Lesser General Public License,
  * v.2.1 along with this distribution; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  * MA  02110-1301, USA.
- * 
+ *
  * (C) 2005-2006,
  * @author JBoss Inc.
  */
@@ -31,14 +31,8 @@
 
 package com.arjuna.ats.internal.jta.recovery.arjunacore;
 
-import com.arjuna.ats.jta.recovery.*;
+import com.arjuna.ats.jta.xa.XidImple;
 
-import com.arjuna.ats.jta.utils.XAHelper;
-
-import com.arjuna.ats.internal.jta.resources.arjunacore.XAResourceRecord;
-
-import com.arjuna.ats.arjuna.common.*;
-
 import java.util.*;
 import javax.transaction.xa.*;
 
@@ -49,7 +43,7 @@
     {
 	_xares = xares;
     }
-    
+
     public boolean equals (Object obj)
     {
 	if (obj instanceof RecoveryXids)
@@ -66,88 +60,57 @@
 	return false;
     }
 
+    /**
+     * Update our tracking with results of a new recovery scan pass
+     * @param trans the Xids seen during the new scan.
+     */
     public final void nextScan (Xid[] trans)
     {
-	/*
-	 * Rather than recover now, wait until the next scan to
-	 * give any transactions a chance to finish.
-	 */
+        long currentTime = System.currentTimeMillis();
 
-	_scanHoldNumber++;
+        // record the new information:
+        if(trans != null) {
+            for(Xid xid : trans) {
+                XidImple xidImple = new XidImple(xid);
+                if(!_whenFirstSeen.containsKey(xidImple)) {
+                    _whenFirstSeen.put(xidImple, currentTime);
+                }
+                _whenLastSeen.put(xidImple, currentTime);
+            }
+        }
 
-	/*
-	 * We keep a list of all Xids that are returned from all
-	 * XAResource instances. Because we never know when exactly we 
-	 * can get rid of them (because of the multi-pass approach to
-	 * determining those that need to be recovered), we only keep the
-	 * cache for a maximum number of scans. After that, we zero it and
-	 * start from scratch again. This may mean that we take an extra pass
-	 * to recover some transactions.
-	 */
-
-	if (_scanHoldNumber > MAX_SCAN_HOLD)
-	    _scanM = null;
-
-	if (_scanM == null)
-	    _scanM = _scanN;
-	else
-	{
-	    if ((_scanM != null) && (_scanN != null))
-	    {
-		int newArraySize = _scanM.length + _scanN.length;
-		Xid[] copy = new Xid[newArraySize];
-		
-		System.arraycopy(_scanM, 0, copy, 0, _scanM.length);
-		System.arraycopy(_scanN, 0, copy, _scanM.length, _scanN.length);
-
-		_scanM = copy;
-	    }
-	}
-	    
-	_scanN = trans;
+        // garbage collect the stale information:
+        Set<XidImple> candidates = new HashSet<XidImple>(_whenFirstSeen.keySet());
+        for(XidImple candidate : candidates) {
+            if(_whenLastSeen.get(candidate) != currentTime) {
+                // seen it previously but it's gone now so we can forget it:
+                _whenFirstSeen.remove(candidate);
+                _whenLastSeen.remove(candidate);
+            }
+        }
+        // gc note: transient errors in distributed RMs may cause values to disappear in one scan and then reappear later.
+        // under the current model we'll recover Xids only if they stick around for enough consecutive scans to
+        // span the safely interval. In the unlikely event that causes problems, we'll need to postpone gc for a given
+        // interval and take care to include only Xids seen in the most recent scan when returning candidates for recovery.
     }
 
-    /*
-     * Go through the current list of inflight transactions and look for
-     * the same entries in the previous scan. If we find them, then we will
-     * try to recover them. Then move the current list into the old list
-     * for next time. We could prune out those transactions we manage to
-     * recover, but this will happen automatically at the next scan since
-     * they won't appear in the next new list of inflight transactions.
-     */
 
-    public final java.lang.Object[] toRecover ()
+    /**
+     * Return any Xids that should be considered for recovery.
+     * @return Xids that are old enough to be eligible for recovery.
+     */
+    public final Xid[] toRecover ()
     {
-        final int numScanN = (_scanN == null ? 0 : _scanN.length) ;
-        final int numScanM = (_scanM == null ? 0 : _scanM.length) ;
-        final int numScan = Math.min(numScanN, numScanM) ;
+        List<Xid> oldEnoughXids = new LinkedList<Xid>();
+        long currentTime = System.currentTimeMillis();
 
-        if (numScan == 0)
-        {
-            return null ;
-        }
-
-        final List<Xid> workingList = new ArrayList<Xid>(numScanN) ;
-
-        for(int i = 0; i < numScanN; i++)
-        {
-            // JBTM-823 / JBPAPP-5195 : don't assume list order/content match.
-            // the list is (hopefully) small and we don't entirely trust 3rd party
-            // Xid hashcode behaviour, so we just do this the brute force way...
-            for(int j = 0; j < numScanM; j++)
-            {
-                if (XAHelper.sameXID(_scanN[i], _scanM[j]))
-                {
-                    workingList.add(_scanN[i]);
-                    // any given id should be in _scanN only once, but _scanM may have dupls as
-                    // it's actually a combination of prev runs, per the array copy in nextScan.
-                    // we drop out here as we want each Xid only once in the return set:
-                    break;
-                }
+        for(Map.Entry<XidImple,Long> entry : _whenFirstSeen.entrySet()) {
+            if(entry.getValue() + safetyIntervalMillis <= currentTime) {
+                oldEnoughXids.add(entry.getKey());
             }
         }
 
-        return workingList.toArray(new Xid[workingList.size()]);
+        return oldEnoughXids.toArray(new Xid[oldEnoughXids.size()]);
     }
 
     public final boolean isSameRM (XAResource xares)
@@ -164,30 +127,14 @@
 	    return false;
 	}
     }
-    
+
     public boolean contains (Xid xid)
     {
-	if (_scanN != null)
-	{
-	    for (int i = 0; i < _scanN.length; i++)
-	    {
-		if (XAHelper.sameXID(xid, _scanN[i]))
-		    return true;
-	    }
-	}
-	
-	if (_scanM != null)
-	{
-	    for (int i = 0; i < _scanM.length; i++)
-	    {
-		if (XAHelper.sameXID(xid, _scanM[i]))
-		    return true;
-	    }
-	}
+        XidImple xidImple = new XidImple(xid);
 
-	return false;
+        return _whenFirstSeen.containsKey(xidImple);
     }
-	
+
     /**
      * If supplied xids contains any values seen on prev scans, replace the existing
      * XAResource with the supplied one and return true. Otherwise, return false.
@@ -212,11 +159,12 @@
         return false;
     }
 
-    private Xid[]      _scanN;
-    private Xid[]      _scanM;
+    // record when we first saw and most recently saw a given Xid. time in system clock (milliseconds).
+    // since we don't trust 3rd party hashcode/equals we convert to our own wrapper class.
+    private final Map<XidImple,Long> _whenFirstSeen = new HashMap<XidImple, Long>();
+    private final Map<XidImple,Long> _whenLastSeen = new HashMap<XidImple, Long>();
+
     private XAResource _xares;
-    private int        _scanHoldNumber;
 
-    private static final int MAX_SCAN_HOLD = 10;  // number of scans we hold the cache for before flushing;
-
-}
+    private static final int safetyIntervalMillis = 10000; // may eventually want to make this configurable?
+}
\ No newline at end of file

Modified: labs/jbosstm/branches/JBOSSTS_4_6_1_GA_CP11_JBTM-842_JBTM-924/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/XARecoveryModule.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_6_1_GA_CP11_JBTM-842_JBTM-924/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/XARecoveryModule.java	2011-12-01 09:59:57 UTC (rev 37756)
+++ labs/jbosstm/branches/JBOSSTS_4_6_1_GA_CP11_JBTM-842_JBTM-924/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/XARecoveryModule.java	2011-12-01 10:05:07 UTC (rev 37757)
@@ -810,7 +810,7 @@
 			else
 			{
                 refreshXidScansForEquivalentXAResourceImpl(xares, trans);
-                
+
 				xidsToRecover = (RecoveryXids) _xidScans.get(xares);
 
 				if (xidsToRecover == null)
@@ -844,7 +844,7 @@
 
 			xidsToRecover.nextScan(trans);
 
-			Object[] xids = xidsToRecover.toRecover();
+			Xid[] xids = xidsToRecover.toRecover();
 
 			if (xids != null)
 			{
@@ -872,7 +872,7 @@
 					{
 						// is the xid known to be one that couldn't be recovered
 
-						recordUid = previousFailure((Xid) xids[j]);
+						recordUid = previousFailure(xids[j]);
 
 						if ((recordUid == null) && (foundTransaction))
 							break; // end
@@ -900,7 +900,7 @@
 							}
 
 							String nodeName = XAUtils
-									.getXANodeName((Xid) xids[j]);
+									.getXANodeName(xids[j]);
 							boolean doRecovery = false;
 
 							if (jtaLogger.loggerI18N.isDebugEnabled())
@@ -1008,7 +1008,7 @@
 							{
                                 if (doRecovery)
                                 {
-                                    if (!transactionLog((Xid) xids[j]))
+                                    if (!transactionLog(xids[j]))
                                     {
                                         if (jtaLogger.loggerI18N.isInfoEnabled())
                                         {
@@ -1017,10 +1017,10 @@
                                                             "com.arjuna.ats.internal.jta.recovery.info.rollingback",
                                                             new Object[]
                                                                     { XAHelper
-                                                                            .xidToString((Xid) xids[j]) });
+                                                                            .xidToString(xids[j]) });
                                         }
 
-                                        xares.rollback((Xid) xids[j]);
+                                        xares.rollback(xids[j]);
                                     }
                                     else
                                     {
@@ -1031,7 +1031,7 @@
                                                             "com.arjuna.ats.internal.jta.recovery.info.rollingbackignore",
                                                             new Object[]
                                                                     { XAHelper
-                                                                            .xidToString((Xid) xids[j]) });
+                                                                            .xidToString(xids[j]) });
                                         }
 
                                         /*
@@ -1049,7 +1049,7 @@
 														"com.arjuna.ats.internal.jta.recovery.info.notrollback",
 														new Object[]
 														{ XAHelper
-																.xidToString((Xid) xids[j]) });
+																.xidToString(xids[j]) });
 									}
 								}
 							}



More information about the jboss-svn-commits mailing list