You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by sc...@apache.org on 2007/05/10 16:01:06 UTC

svn commit: r536868 - in /incubator/uima/uimaj/trunk/uimaj-core/src: main/java/org/apache/uima/analysis_engine/impl/ main/java/org/apache/uima/internal/util/ test/java/org/apache/uima/analysis_engine/impl/

Author: schor
Date: Thu May 10 07:01:04 2007
New Revision: 536868

URL: http://svn.apache.org/viewvc?view=rev&rev=536868
Log:
[UIMA-367] augment test case to make it more likely to catch deadlocks.  Fix the underlying
code to prevent deadlocks.  Fix: for calls to multiprocessorEngine's "process(cas, result-spec)"
and the trace form, override this method in the super to 1) check out an instance of the
ae, 2) set the result spec on it, 3) call the process method on that ae, and then release
the ae back to the pool.  For setResultSpec calls, get the ae's one at a time, set the
result spec, and release back to the pool.

There were a bunch of other methods (such as reconfigure, etc.) that grab all instances,
do the call on all, and release all.  These were synchronized - so only one of these
will run at a time. 

Modified:
    incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/MultiprocessingAnalysisEngine_impl.java
    incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/AnalysisEnginePool.java
    incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/ResourcePool.java
    incubator/uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/MultiprocessingAnalysisEngine_implTest.java

Modified: incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/MultiprocessingAnalysisEngine_impl.java
URL: http://svn.apache.org/viewvc/incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/MultiprocessingAnalysisEngine_impl.java?view=diff&rev=536868&r1=536867&r2=536868
==============================================================================
--- incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/MultiprocessingAnalysisEngine_impl.java (original)
+++ incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/MultiprocessingAnalysisEngine_impl.java Thu May 10 07:01:04 2007
@@ -25,6 +25,7 @@
 import org.apache.uima.analysis_engine.AnalysisEngine;
 import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
 import org.apache.uima.analysis_engine.CasIterator;
+import org.apache.uima.analysis_engine.ResultNotSupportedException;
 import org.apache.uima.analysis_engine.ResultSpecification;
 import org.apache.uima.analysis_engine.TextAnalysisEngine;
 import org.apache.uima.cas.CAS;
@@ -33,6 +34,7 @@
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.resource.ResourceSpecifier;
 import org.apache.uima.util.Logger;
+import org.apache.uima.util.ProcessTrace;
 
 /**
  * An {@link AnalysisEngine} implementation that can process multiple {@link CAS} objects
@@ -93,8 +95,34 @@
     return true;
   }
 
-  public CasIterator processAndOutputNewCASes(CAS aCAS) throws AnalysisEngineProcessException {
-    enterProcess(); // start timer for collecting performance stats
+  /**
+   * @see org.apache.uima.analysis_engine.AnalysisEngine#process(org.apache.uima.cas.CAS,
+   *      org.apache.uima.analysis_engine.ResultSpecification)
+   */
+  public ProcessTrace process(CAS aCAS, ResultSpecification aResultSpec)
+          throws ResultNotSupportedException, AnalysisEngineProcessException {
+    AnalysisEngine ae = null;
+    try {
+      ae = mPool.getAnalysisEngine(mTimeout);
+      if (ae == null) // timeout elapsed
+      {
+        throw new AnalysisEngineProcessException(AnalysisEngineProcessException.TIMEOUT_ELAPSED,
+                new Object[] { new Integer(getTimeout()) });
+      }       
+      return ae.process(aCAS, aResultSpec);
+    } finally {
+      if (ae != null) {
+        mPool.releaseAnalysisEngine(ae);
+      }
+    }
+  }
+
+  /**
+   * @see org.apache.uima.analysis_engine.AnalysisEngine#process(org.apache.uima.cas.CAS,
+   *      org.apache.uima.analysis_engine.ResultSpecification, org.apache.uima.util.ProcessTrace)
+   */
+  public void process(CAS aCAS, ResultSpecification aResultSpec, ProcessTrace aTrace)
+          throws ResultNotSupportedException, AnalysisEngineProcessException {
     AnalysisEngine ae = null;
     try {
       ae = mPool.getAnalysisEngine(mTimeout);
@@ -102,8 +130,27 @@
       {
         throw new AnalysisEngineProcessException(AnalysisEngineProcessException.TIMEOUT_ELAPSED,
                 new Object[] { new Integer(getTimeout()) });
+      }       
+      ae.process(aCAS, aResultSpec);
+      buildProcessTraceFromMBeanStats(aTrace);
+    } finally {
+      if (ae != null) {
+        mPool.releaseAnalysisEngine(ae);
       }
+    }
+  }
 
+  
+  public CasIterator processAndOutputNewCASes(CAS aCAS) throws AnalysisEngineProcessException {
+    enterProcess(); // start timer for collecting performance stats
+    AnalysisEngine ae = null;
+    try {
+      ae = mPool.getAnalysisEngine(mTimeout);
+      if (ae == null) // timeout elapsed
+      {
+        throw new AnalysisEngineProcessException(AnalysisEngineProcessException.TIMEOUT_ELAPSED,
+                new Object[] { new Integer(getTimeout()) });
+      }       
       return ae.processAndOutputNewCASes(aCAS);
     } finally {
       if (ae != null) {
@@ -113,13 +160,14 @@
     }
   }
 
+  
   /*
    * (non-Javadoc)
    * 
    * @see org.apache.uima.analysis_engine.AnalysisEngine#setResultSpecification(org.apache.uima.analysis_engine.ResultSpecification)
    */
   public void setResultSpecification(ResultSpecification aResultSpec) {
-    mPool.setResultSpecification(aResultSpec);
+   mPool.setResultSpecification(aResultSpec);
   }
 
   /**

Modified: incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/AnalysisEnginePool.java
URL: http://svn.apache.org/viewvc/incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/AnalysisEnginePool.java?view=diff&rev=536868&r1=536867&r2=536868
==============================================================================
--- incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/AnalysisEnginePool.java (original)
+++ incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/AnalysisEnginePool.java Thu May 10 07:01:04 2007
@@ -24,6 +24,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Vector;
 
 import org.apache.uima.analysis_engine.AnalysisEngine;
 import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
@@ -89,7 +90,6 @@
     // initialize ResourcePool
     mPool = new ResourcePool(aNumInstances, aResourceSpecifier, getResourceClass(),
             aResourceInitParams);
-
   }
 
   /**
@@ -145,34 +145,43 @@
 
   /**
    * @see org.apache.uima.analysis_engine.AnalysisEngine#setResultSpecification(ResultSpecification)
+   * This version only called for setResultSpecification called from an appl on the
+   * MultiprocessingAnalysisEngine directly.  process(cas, result-spec) calls
+   * setResultSpecification on the individual analysis engine from the pool.
    */
   public void setResultSpecification(ResultSpecification aResultSpec) {
+    
     // set Result Spec on each AnalysisEngine in the pool
-    List toRelease = new ArrayList();
-    try {
-      for (int i = 0; i < mPool.getSize(); i++) {
-        // get an Analysis Engine from the pool
-        AnalysisEngine ae = (AnalysisEngine) mPool.getResource(0); // wait forever
 
-        // store AE instance on List to be released later
-        toRelease.add(ae);
-
-        // set result spec
-        ae.setResultSpecification(aResultSpec);
-      }
-    } finally {
-      // release all AnalysisEngines back to pool
-      Iterator it = toRelease.iterator();
-      while (it.hasNext()) {
-        mPool.releaseResource((AnalysisEngine) it.next());
+    Vector allInstances = mPool.getAllInstances();
+    for (int i = 0; i < mPool.getSize(); i++) {
+      AnalysisEngine ae = (AnalysisEngine)allInstances.get(i);
+      
+      mPool.checkoutSpecificResource(ae);
+      
+      try {
+      //    set result spec
+      ae.setResultSpecification(aResultSpec);
+      } finally {
+      mPool.releaseResource(ae);
       }
     }
+ 
   }
 
+//  public void setResultSpecForAeIfPending(AnalysisEngine ae) {
+//    Vector allInstances = mPool.getAllInstances();
+//    int i = allInstances.indexOf(ae);
+//    if (resultSpecChanged[i]) {
+//      resultSpecChanged[i] = false;
+//      ae.setResultSpecification(sharedResultSpec);
+//    }  
+//  }
+  
   /**
    * @see org.apache.uima.analysis_engine.MultithreadableAnalysisEngine#reconfigure()
    */
-  public void reconfigure() throws ResourceConfigurationException {
+  public synchronized void reconfigure() throws ResourceConfigurationException {
     // reconfigure each AnalysisEngine in the pool
     List toRelease = new ArrayList();
     try {
@@ -198,7 +207,7 @@
   /**
    * Calls batchProcessComplete on all AEs in pool.
    */
-  public void batchProcessComplete() throws AnalysisEngineProcessException {
+  public synchronized void batchProcessComplete() throws AnalysisEngineProcessException {
     List toRelease = new ArrayList();
     try {
       for (int i = 0; i < mPool.getSize(); i++) {
@@ -222,7 +231,7 @@
   /**
    * Calls collectionProcessComplete on all AEs in pool.
    */
-  public void collectionProcessComplete() throws AnalysisEngineProcessException {
+  public synchronized void collectionProcessComplete() throws AnalysisEngineProcessException {
     List toRelease = new ArrayList();
     try {
       for (int i = 0; i < mPool.getSize(); i++) {
@@ -256,7 +265,7 @@
   /**
    * Sets logger for all AnalysisEngines in pool.
    */
-  public void setLogger(Logger aLogger) {
+  public synchronized void setLogger(Logger aLogger) {
     List toRelease = new ArrayList();
     try {
       for (int i = 0; i < mPool.getSize(); i++) {

Modified: incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/ResourcePool.java
URL: http://svn.apache.org/viewvc/incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/ResourcePool.java?view=diff&rev=536868&r1=536867&r2=536868
==============================================================================
--- incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/ResourcePool.java (original)
+++ incubator/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/ResourcePool.java Thu May 10 07:01:04 2007
@@ -174,6 +174,21 @@
     return resource;
   }
 
+  /*
+   * Checks out a specific resource from the pool, waiting as long as needed until it is free
+   * @param r
+   */
+
+  public synchronized void checkoutSpecificResource(Resource r) {
+    while (!mFreeInstances.contains(r)) {
+      try {
+        wait();
+      } catch (InterruptedException e) {
+      }
+    }
+    mFreeInstances.remove(r);
+  }
+  
   /**
    * Destroys all Resources in this pool.
    */

Modified: incubator/uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/MultiprocessingAnalysisEngine_implTest.java
URL: http://svn.apache.org/viewvc/incubator/uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/MultiprocessingAnalysisEngine_implTest.java?view=diff&rev=536868&r1=536867&r2=536868
==============================================================================
--- incubator/uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/MultiprocessingAnalysisEngine_implTest.java (original)
+++ incubator/uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/MultiprocessingAnalysisEngine_implTest.java Thu May 10 07:01:04 2007
@@ -19,9 +19,9 @@
 
 package org.apache.uima.analysis_engine.impl;
 
-import java.io.FileNotFoundException;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Random;
 
 import junit.framework.Assert;
 import junit.framework.TestCase;
@@ -198,23 +198,36 @@
       
       final int NUM_THREADS = 4;
       ProcessThread[] threads = new ProcessThread[NUM_THREADS];
-      for (int i = 0; i < NUM_THREADS; i++) {
-        threads[i] = new ProcessThread(ae);
-        threads[i].start();
-      }
+      Random random = new Random();
+      for (int repetitions = 0; repetitions < 4; repetitions++) {
+        for (int i = 0; i < NUM_THREADS; i++) {
+          threads[i] = new ProcessThread(ae);
+          threads[i].start();
+          Thread.sleep(random.nextInt(2));  // delay between 0 and 2 milliseconds
+        }
+
+        // wait for threads to finish and check if they got exceptions
+        for (int i = 0; i < NUM_THREADS; i++) {
+          try {
+            threads[i].join(10000);
+          } catch (InterruptedException ie) {
+            System.err.println("got unexpected Interrupted exception " + ie);
+          }
+          if (threads[i].isAlive()) {
+            System.err.println("timeout waiting for thread to complete " + i);
+            fail("timeout waiting for thread to complete " + i);
+          }
 
-      // wait for threads to finish and check if they got exceptions
-      for (int i = 0; i < NUM_THREADS; i++) {
-        threads[i].join();
-        Throwable failure = threads[i].getFailure();
-        if (failure != null) {
-          if (failure instanceof Exception) {
-            throw (Exception)failure;
-          } else {
-            fail(failure.getMessage());
+          Throwable failure = threads[i].getFailure();
+          if (failure != null) {
+            if (failure instanceof Exception) {
+              throw (Exception) failure;
+            } else {
+              fail(failure.getMessage());
+            }
           }
         }
-      }     
+      }
       
       //Check TestAnnotator fields only at the very end of processing,
       //we can't test from the threads themsleves since the state of