[infinispan-commits] Infinispan SVN: r1799 - in trunk/core/src: main/java/org/infinispan/notifications and 2 other directories.

infinispan-commits at lists.jboss.org infinispan-commits at lists.jboss.org
Mon May 17 13:36:16 EDT 2010


Author: manik.surtani at jboss.com
Date: 2010-05-17 13:36:15 -0400 (Mon, 17 May 2010)
New Revision: 1799

Added:
   trunk/core/src/test/java/org/infinispan/context/InvocationContextTest.java
Removed:
   trunk/core/src/test/java/org/infinispan/context/InvocationContextResumeTest.java
Modified:
   trunk/core/src/main/java/org/infinispan/interceptors/InterceptorChain.java
   trunk/core/src/main/java/org/infinispan/interceptors/InvocationContextInterceptor.java
   trunk/core/src/main/java/org/infinispan/notifications/AbstractListenerImpl.java
   trunk/core/src/main/java/org/infinispan/util/concurrent/locks/containers/AbstractPerEntryLockContainer.java
   trunk/core/src/main/java/org/infinispan/util/concurrent/locks/containers/AbstractStripedLockContainer.java
Log:
[ISPN-444] (Release lock when thread is interrupted) Added tests

Modified: trunk/core/src/main/java/org/infinispan/interceptors/InterceptorChain.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/interceptors/InterceptorChain.java	2010-05-17 16:51:57 UTC (rev 1798)
+++ trunk/core/src/main/java/org/infinispan/interceptors/InterceptorChain.java	2010-05-17 17:36:15 UTC (rev 1799)
@@ -69,12 +69,14 @@
 
    /**
     * Ensures that the interceptor of type passed in isn't already added
+    *
     * @param clazz type of interceptor to check for
     */
    private void assertNotAdded(Class<? extends CommandInterceptor> clazz) {
       CommandInterceptor next = firstInChain;
       while (next != null) {
-         if (next.getClass().equals(clazz)) throw new ConfigurationException("Detected interceptor of type [" + clazz.getName() + "] being added to the interceptor chain more than once!");
+         if (next.getClass().equals(clazz))
+            throw new ConfigurationException("Detected interceptor of type [" + clazz.getName() + "] being added to the interceptor chain more than once!");
          next = next.getNext();
       }
    }
@@ -221,11 +223,11 @@
       }
       return false;
    }
-   
+
    /**
     * Replaces an existing interceptor of the given type in the interceptor chain with a new interceptor instance passed as parameter.
-    * 
-    * @param replacingInterceptor the interceptor to add to the interceptor chain
+    *
+    * @param replacingInterceptor        the interceptor to add to the interceptor chain
     * @param toBeReplacedInterceptorType the type of interceptor that should be swapped with the new one
     * @return true if the interceptor was replaced
     */
@@ -267,14 +269,13 @@
    public Object invoke(InvocationContext ctx, VisitableCommand command) {
       try {
          return command.acceptVisitor(ctx, firstInChain);
-      }
-      catch (CacheException e) {
+      } catch (CacheException e) {
+         if (e.getCause() instanceof InterruptedException)
+            Thread.currentThread().interrupt();
          throw e;
-      }
-      catch (RuntimeException e) {
+      } catch (RuntimeException e) {
          throw e;
-      }
-      catch (Throwable t) {
+      } catch (Throwable t) {
          throw new CacheException(t);
       }
    }
@@ -282,6 +283,7 @@
    /**
     * @return the first interceptor in the chain.
     */
+
    public CommandInterceptor getFirstInChain() {
       return firstInChain;
    }

Modified: trunk/core/src/main/java/org/infinispan/interceptors/InvocationContextInterceptor.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/interceptors/InvocationContextInterceptor.java	2010-05-17 16:51:57 UTC (rev 1798)
+++ trunk/core/src/main/java/org/infinispan/interceptors/InvocationContextInterceptor.java	2010-05-17 17:36:15 UTC (rev 1799)
@@ -22,6 +22,7 @@
 package org.infinispan.interceptors;
 
 
+import org.infinispan.CacheException;
 import org.infinispan.commands.VisitableCommand;
 import org.infinispan.context.Flag;
 import org.infinispan.context.InvocationContext;
@@ -57,7 +58,6 @@
          return invokeNextInterceptor(ctx, command);
       }
       catch (Throwable th) {
-
          // make sure we release locks for all keys locked in this invocation!
          for (Object key: ctx.getKeysAddedInCurrentInvocation()) {
             if (ctx.hasLockedKey(key)) {
@@ -77,6 +77,7 @@
             return null;
          } else {
             log.error("Execution error: ", th);
+
             throw th;
          }
       } finally {

Modified: trunk/core/src/main/java/org/infinispan/notifications/AbstractListenerImpl.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/notifications/AbstractListenerImpl.java	2010-05-17 16:51:57 UTC (rev 1798)
+++ trunk/core/src/main/java/org/infinispan/notifications/AbstractListenerImpl.java	2010-05-17 17:36:15 UTC (rev 1799)
@@ -175,11 +175,8 @@
                   method.invoke(target, event);
                }
                catch (InvocationTargetException exception) {
-                  Throwable cause = exception.getCause();
-                  if (cause != null)
-                     throw new CacheException("Caught exception invoking method " + method + " on listener instance " + target, cause);
-                  else
-                     throw new CacheException("Caught exception invoking method " + method + " on listener instance " + target, exception);
+                  Throwable cause = getRealException(exception);
+                  throw new CacheException("Caught exception invoking method " + method + " on listener instance " + target, cause);
                }
                catch (IllegalAccessException exception) {
                   getLog().warn("Unable to invoke method " + method + " on Object instance " + target + " - removing this target object from list of listeners!", exception);
@@ -194,4 +191,14 @@
             asyncProcessor.execute(r);
       }
    }
+
+   private Throwable getRealException(Throwable re) {
+      if (re.getCause() == null) return re;
+      Throwable cause = re.getCause();
+      if (cause instanceof CacheException || cause instanceof RuntimeException)
+         return getRealException(cause);
+      else
+         return re;
+   }
+
 }

Modified: trunk/core/src/main/java/org/infinispan/util/concurrent/locks/containers/AbstractPerEntryLockContainer.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/util/concurrent/locks/containers/AbstractPerEntryLockContainer.java	2010-05-17 16:51:57 UTC (rev 1798)
+++ trunk/core/src/main/java/org/infinispan/util/concurrent/locks/containers/AbstractPerEntryLockContainer.java	2010-05-17 17:36:15 UTC (rev 1799)
@@ -49,6 +49,9 @@
          boolean locked = false;
          try {
             locked = lock.tryLock(timeout, unit);
+         } catch (InterruptedException ie) {
+            safeRelease(lock);
+            throw ie;
          } catch (Throwable th) {
             safeRelease(lock);
             locked = false;

Modified: trunk/core/src/main/java/org/infinispan/util/concurrent/locks/containers/AbstractStripedLockContainer.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/util/concurrent/locks/containers/AbstractStripedLockContainer.java	2010-05-17 16:51:57 UTC (rev 1798)
+++ trunk/core/src/main/java/org/infinispan/util/concurrent/locks/containers/AbstractStripedLockContainer.java	2010-05-17 17:36:15 UTC (rev 1799)
@@ -84,6 +84,9 @@
       boolean locked = false;
       try {
          locked = lock.tryLock(timeout, unit);
+      } catch (InterruptedException ie) {
+         safeRelease(lock);
+         throw ie;
       } catch (Throwable th) {
          safeRelease(lock);
          locked = false;

Deleted: trunk/core/src/test/java/org/infinispan/context/InvocationContextResumeTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/context/InvocationContextResumeTest.java	2010-05-17 16:51:57 UTC (rev 1798)
+++ trunk/core/src/test/java/org/infinispan/context/InvocationContextResumeTest.java	2010-05-17 17:36:15 UTC (rev 1799)
@@ -1,70 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
- * individual contributors as indicated by the @author tags. See the
- * copyright.txt file in the distribution for a full listing of
- * individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY 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 along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.infinispan.context;
-
-import org.infinispan.Cache;
-import org.infinispan.CacheException;
-import org.infinispan.config.Configuration;
-import org.infinispan.context.Flag;
-import org.infinispan.notifications.Listener;
-import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified;
-import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
-import org.infinispan.test.MultipleCacheManagersTest;
-import org.infinispan.test.fwk.TestCacheManagerFactory;
-import org.infinispan.util.logging.Log;
-import org.infinispan.util.logging.LogFactory;
-import org.testng.annotations.Test;
-
- at Test(groups = {"functional"}, testName = "context.InvocationContextResumeTest")
-public class InvocationContextResumeTest extends MultipleCacheManagersTest {
-   private static final Log log = LogFactory.getLog(InvocationContextResumeTest.class);
-
-   @Override
-   protected void createCacheManagers() throws Throwable {
-      Configuration cfg = TestCacheManagerFactory.getDefaultConfiguration(true);
-      cfg.setSyncCommitPhase(true);
-      cfg.setSyncRollbackPhase(true);
-      createClusteredCaches(1, "timestamps", cfg);
-   }
-
-   public void testMishavingListenerResumesContext() {
-      Cache cache = cache(0, "timestamps");
-      cache.addListener(new CacheListener());
-      try {
-         cache.getAdvancedCache().withFlags(Flag.CACHE_MODE_LOCAL).put("k", "v");
-      } catch (CacheException ce) {
-         assert ce.getCause() instanceof NullPointerException;
-      }
-   }
-
-   @Listener
-   public static class CacheListener {
-      @CacheEntryModified
-      public void entryModified(CacheEntryModifiedEvent event) {
-         if (!event.isPre()) {
-            log.debug("Entry modified: {0}, let's throw an NPE!!", event);
-            throw new NullPointerException();
-         }
-      }
-   }
-}

Copied: trunk/core/src/test/java/org/infinispan/context/InvocationContextTest.java (from rev 1793, trunk/core/src/test/java/org/infinispan/context/InvocationContextResumeTest.java)
===================================================================
--- trunk/core/src/test/java/org/infinispan/context/InvocationContextTest.java	                        (rev 0)
+++ trunk/core/src/test/java/org/infinispan/context/InvocationContextTest.java	2010-05-17 17:36:15 UTC (rev 1799)
@@ -0,0 +1,163 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY 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 along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.context;
+
+import org.infinispan.Cache;
+import org.infinispan.CacheException;
+import org.infinispan.config.Configuration;
+import org.infinispan.notifications.Listener;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified;
+import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
+import org.infinispan.test.MultipleCacheManagersTest;
+import org.infinispan.test.fwk.TestCacheManagerFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+import org.testng.annotations.Test;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+ at Test(groups = {"functional"}, testName = "context.InvocationContextTest")
+public class InvocationContextTest extends MultipleCacheManagersTest {
+   private static final Log log = LogFactory.getLog(InvocationContextTest.class);
+
+   @Override
+   protected void createCacheManagers() throws Throwable {
+      Configuration cfg = TestCacheManagerFactory.getDefaultConfiguration(true);
+      cfg.setSyncCommitPhase(true);
+      cfg.setSyncRollbackPhase(true);
+      createClusteredCaches(1, "timestamps", cfg);
+   }
+
+   public void testMishavingListenerResumesContext() {
+      Cache cache = cache(0, "timestamps");
+      cache.addListener(new CacheListener());
+      try {
+         cache.getAdvancedCache().withFlags(Flag.CACHE_MODE_LOCAL).put("k", "v");
+      } catch (CacheException ce) {
+         assert ce.getCause() instanceof NullPointerException;
+      }
+   }
+
+   public void testThreadInterruptedDuringLocking() throws Throwable {
+      final Cache cache = cache(0, "timestamps");
+      cache.put("k", "v");
+      // now acquire a lock on k so that subsequent threads will block
+      TransactionManager tm = cache.getAdvancedCache().getTransactionManager();
+      tm.begin();
+      cache.put("k", "v2");
+      Transaction tx = tm.suspend();
+      final List<Throwable> throwables = new LinkedList<Throwable>();
+
+      Thread th = new Thread() {
+         public void run() {
+            try {
+               cache.put("k", "v3");
+            } catch (Throwable th) {
+               throwables.add(th);
+            }
+         }
+      };
+
+      th.start();
+      // th will now block trying to acquire the lock.
+      th.interrupt();
+      th.join();
+      tm.resume(tx);
+      tm.rollback();
+      assert throwables.size() == 1;
+
+      for (Throwable thr : throwables) thr.printStackTrace();
+      assert throwables.get(0) instanceof CacheException;
+      assert ((CacheException) throwables.get(0)).getCause() instanceof InterruptedException;
+   }
+
+
+   public void testThreadInterruptedAfterLocking() throws Throwable {
+      final Cache cache = cache(0, "timestamps");
+      cache.put("k", "v");
+      CountDownLatch willTimeoutLatch = new CountDownLatch(1);
+      CountDownLatch lockAquiredSignal = new CountDownLatch(1);
+      DelayingListener dl = new DelayingListener(lockAquiredSignal, willTimeoutLatch);
+      cache.addListener(dl);
+      final List<Throwable> throwables = new LinkedList<Throwable>();
+
+      Thread th = new Thread() {
+         public void run() {
+            try {
+               cache.put("k", "v3");
+            } catch (Throwable th) {
+               throwables.add(th);
+            }
+         }
+      };
+
+      th.start();
+      // wait for th to acquire the lock
+      lockAquiredSignal.await();
+
+      // and now interrupt the thread.
+      th.interrupt();
+      th.join();
+      assert throwables.size() == 1;
+
+      for (Throwable thr : throwables) thr.printStackTrace();
+      assert throwables.get(0) instanceof CacheException;
+   }
+
+   @Listener
+   public static class DelayingListener {
+      CountDownLatch lockAcquiredLatch, waitLatch;
+
+      public DelayingListener(CountDownLatch lockAcquiredLatch, CountDownLatch waitLatch) {
+         this.lockAcquiredLatch = lockAcquiredLatch;
+         this.waitLatch = waitLatch;
+      }
+
+      @CacheEntryModified
+      public void entryModified(CacheEntryModifiedEvent event) {
+         if (!event.isPre()) {
+            lockAcquiredLatch.countDown();
+            try {
+               waitLatch.await();
+            } catch (InterruptedException e) {
+               throw new RuntimeException(e);
+            }
+         }
+      }
+   }
+
+   @Listener
+   public static class CacheListener {
+      @CacheEntryModified
+      public void entryModified(CacheEntryModifiedEvent event) {
+         if (!event.isPre()) {
+            log.debug("Entry modified: {0}, let's throw an NPE!!", event);
+            throw new NullPointerException();
+         }
+      }
+   }
+}



More information about the infinispan-commits mailing list