You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-commits@db.apache.org by mz...@apache.org on 2006/03/09 21:03:12 UTC

svn commit: r384593 - /db/jdo/trunk/tck20/src/java/org/apache/jdo/tck/api/persistencemanager/ThreadSafe.java

Author: mzaun
Date: Thu Mar  9 12:03:10 2006
New Revision: 384593

URL: http://svn.apache.org/viewcvs?rev=384593&view=rev
Log:
JDO-238 - fixed TCK test case ThreadSafe

Modified:
    db/jdo/trunk/tck20/src/java/org/apache/jdo/tck/api/persistencemanager/ThreadSafe.java

Modified: db/jdo/trunk/tck20/src/java/org/apache/jdo/tck/api/persistencemanager/ThreadSafe.java
URL: http://svn.apache.org/viewcvs/db/jdo/trunk/tck20/src/java/org/apache/jdo/tck/api/persistencemanager/ThreadSafe.java?rev=384593&r1=384592&r2=384593&view=diff
==============================================================================
--- db/jdo/trunk/tck20/src/java/org/apache/jdo/tck/api/persistencemanager/ThreadSafe.java (original)
+++ db/jdo/trunk/tck20/src/java/org/apache/jdo/tck/api/persistencemanager/ThreadSafe.java Thu Mar  9 12:03:10 2006
@@ -28,6 +28,7 @@
 import org.apache.jdo.tck.pc.mylib.PCPoint;
 import org.apache.jdo.tck.util.BatchTestRunner;
 import org.apache.jdo.tck.util.ThreadExceptionHandler;
+import org.apache.jdo.tck.util.RogueBarrier;
 
 /**
  *<B>Title:</B> Thread Safe
@@ -40,8 +41,6 @@
 It is a requirement for all JDO implementations to be thread-safe. That is, the behavior of the implementation must be predictable in the presence of multiple application threads.  This assertion will generate multiple test cases to be evaluated.
 
  */
-
-
 public class ThreadSafe extends PersistenceManagerTest {
     
     /** */
@@ -57,118 +56,143 @@
         BatchTestRunner.run(ThreadSafe.class);
     }
 
-    private PersistenceManagerFactory   pmf;
-    PCPoint p1 = null;
-    private int totalThreadCount = 10;
-    private int completedThreadCount = 0;
-    private int succeeds = 0;
-    private int catchNumber = 0;
+    private final int threadCount = 10;
+    private final ThreadExceptionHandler group = new ThreadExceptionHandler();
+    private final RogueBarrier barrier = new RogueBarrier(threadCount);
+    private int successCount = 0;
+    private int exceptionCount = 0;
 
     /** */
     public void testThreadSafe() throws Exception  {
-        if(debug) logger.debug("\nSTART testThreadSafe");
-        pmf = getPMF();
+        if (debug) logger.debug("\nSTART testThreadSafe");
+        
+        // test thread-safety of PMF.getPersistenceManager():
+        //   pmf.getPM(), pm.close() 
+        final PCPoint[] nullPC = new PCPoint[threadCount];
+        runThreads(nullPC, "Concurrent PMF.getPersistenceManager()",
+                   threadCount);
+
+        // test thread-safety of PMF.getPersistenceManager():
+        //   pmf.getPM(), pm.makePersistent(private transient PC), pm.close() 
+        final PCPoint[] localPC = new PCPoint[threadCount];
+        for (int i = 0; i < threadCount; i++) {
+            localPC[i] = new PCPoint(1,i);
+        }
+        runThreads(localPC, "Concurrent PMF.getPersistenceManager()"
+                   + ".makePersistent()", threadCount);
 
-        p1 = new PCPoint(3,3);
+        // test thread-safety of PM.makePersistent():
+        //   pmf.getPM(), pm.makePersistent(shared transient PC), pm.close() 
+        final PCPoint[] sharedPC = new PCPoint[threadCount];
+        final PCPoint p1 = new PCPoint(3,3);
+        for (int i = 0; i < threadCount; i++) {
+            sharedPC[i] = p1;
+        }
+        runThreads(sharedPC, "Concurrent PM.makePersistent("
+                   + "shared transient PC)", 1);
+    }
 
-        ThreadExceptionHandler group = new ThreadExceptionHandler();
-        Thread[] threads = new Thread[totalThreadCount];
-        for (int i=0; i < totalThreadCount; i++) {
-            Thread t = new Thread(group, new PMThread(pmf, p1));
+    /** */
+    public void runThreads(Object[] pc, String header, int toSucceed) {
+        // start threads with their pc instance
+        final Thread[] threads = new Thread[threadCount];
+        for (int i = 0; i < threadCount; i++) {
+            Thread t = new Thread(group, new PMThread(pc[i]));
             t.setName("ThreadSafeID-" + i);
             threads[i] = t;
             t.start();
         }
 
-        for (int i = 0; i < totalThreadCount; i++) {
-            try {   
-                threads[i].join();
-            } 
-            catch (InterruptedException e) { 
-                // ignored
+        // wait for all threads to finish
+        for (int i = 0; i < threadCount; i++) {
+            while (true) {
+                try {
+                    threads[i].join();
+                    break;
+                } catch (InterruptedException e) { // swallow
+                }
             }
-       }
-        
-        checkResults(group);
-    }
+        }
 
-    /** */
-    protected synchronized void complete() {
-        completedThreadCount++;
-    }
-    
-    /** */
-    protected synchronized void winning(PCPoint pc) {
-        if (debug)
-            logger.debug("[" + Thread.currentThread().getName()  + "]: succeeds");
-        succeeds++;
+        checkResults(header, toSucceed);
     }
 
     /** */
-    public void checkResults(ThreadExceptionHandler group) {
+    protected synchronized void checkResults(String header, int toSucceed) {
         // check unhandled exceptions
-        Set uncaught = group.getAllUncaughtExceptions();
+        final Set uncaught = group.getAllUncaughtExceptions();
         if ((uncaught != null) && !uncaught.isEmpty()) {
             StringBuffer report = new StringBuffer("Uncaught exceptions:\n");
             for (Iterator i = uncaught.iterator(); i.hasNext();) {
                 Map.Entry next = (Map.Entry)i.next();
                 Thread thread = (Thread)next.getKey();
                 Throwable problem = (Throwable)next.getValue();
-                report.append(
-                     "Uncaught exception " + problem + " in thread " + thread + "\n");
+                report.append(header + ": Uncaught exception " + problem
+                              + " in thread " + thread + "\n");
             }
             fail(ASSERTION_FAILED, report.toString());
+            group.clear();
         }
-
-        if (succeeds != 1) {
-            fail(ASSERTION_FAILED,
-                 "Only one thread should succeed, number of succeeded threads is " + succeeds);
+        
+        // check success count
+        if (successCount != toSucceed) {
+            fail(ASSERTION_FAILED, header + ": Incorrect number of "
+                 + "\"succeeding\" threads; expected=" + toSucceed
+                 + " found=" + successCount);
         }
+        successCount = 0;
         
-        if (catchNumber != totalThreadCount - 1) {
-            fail(ASSERTION_FAILED,
-                 "All but one threads should throw exceptions, expected " + 
-                 (totalThreadCount - 1) + ", got " + catchNumber);
+        // check exception count
+        final int toExcept = threadCount - toSucceed;
+        if (exceptionCount != toExcept) {
+            fail(ASSERTION_FAILED, header + ": Incorrect number of "
+                 + "\"failing\" threads; expected=" + toExcept
+                 + " found=" + exceptionCount);
         }
+        exceptionCount = 0;
+    }
+
+    /** */
+    protected synchronized void markSuccess() {
+        logger.debug("[" + Thread.currentThread().getName() + "]: success");
+        successCount++;
+    }
+
+    /** */
+    protected synchronized void markExpectedException() {
+        logger.debug("[" + Thread.currentThread().getName() + "]: expected exception");
+        exceptionCount++;
     }
 
-/** */
+    /** */
     class PMThread implements Runnable {
-        private final PersistenceManager pm;
         private final Object pc;
 
         /** */
-        PMThread(PersistenceManagerFactory pmf, PCPoint pc) {
-            this.pm = pmf.getPersistenceManager();
+        PMThread(Object pc) {
             this.pc = pc;
         }
 
         /** */
         public void run() {
-            String threadName = Thread.currentThread().getName();
-            Transaction tx = pm.currentTransaction();
+            ThreadSafe.this.logger.debug("[" + Thread.currentThread().getName()
+                                         + "]: running");
+            final PersistenceManager pm = pmf.getPersistenceManager();
             try {
-                ThreadSafe.this.logger.debug("[" + threadName + "]: running");
+                Transaction tx = pm.currentTransaction();
                 tx.begin();
-                pm.makePersistent(pc);
-                tx.commit();
-                tx = null;
-                winning((PCPoint) pc);
-                complete();
-            } 
-            catch (JDOUserException ex) {
-                ThreadSafe.this.logger.debug("[" + threadName +
-                                             "]: throws expected " + ex);
-                catchNumber++;
-                complete();
-            } 
-            finally {
-                if ((tx != null) && tx.isActive()) {
-                    tx.rollback();
+                if (pc != null) {
+                    pm.makePersistent(pc);
                 }
-                pm.close();
+                tx.commit();
+                markSuccess();
+            } catch (JDOUserException ex) {
+                markExpectedException();
+            } finally {
+                barrier.await();
+                cleanupPM(pm);
             }
-        }		// run
-    }  // class PMThread
+        }
+    }
 }