[jbosscache-commits] JBoss Cache SVN: r5915 - in core/trunk/src: main/java/org/jboss/cache/lock and 1 other directories.
jbosscache-commits at lists.jboss.org
jbosscache-commits at lists.jboss.org
Thu May 29 09:51:25 EDT 2008
Author: manik.surtani at jboss.com
Date: 2008-05-29 09:51:25 -0400 (Thu, 29 May 2008)
New Revision: 5915
Added:
core/trunk/src/test/java/org/jboss/cache/loader/ConcurrentPutRemoveEvictTest.java
Modified:
core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
core/trunk/src/main/java/org/jboss/cache/lock/LockManager.java
core/trunk/src/main/java/org/jboss/cache/lock/NodeBasedLockManager.java
Log:
JBCACHE-1355 - race conditions in the CacheLoaderInterceptor
Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java 2008-05-29 13:02:52 UTC (rev 5914)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java 2008-05-29 13:51:25 UTC (rev 5915)
@@ -28,6 +28,7 @@
import org.jboss.cache.loader.CacheLoaderManager;
import org.jboss.cache.lock.LockManager;
import org.jboss.cache.lock.LockType;
+import org.jboss.cache.lock.TimeoutException;
import org.jboss.cache.notifications.NotifierImpl;
import org.jboss.cache.transaction.TransactionEntry;
import org.jboss.cache.transaction.TransactionTable;
@@ -243,8 +244,23 @@
private void loadIfNeeded(InvocationContext ctx, Fqn fqn, Object key, boolean allKeys, boolean initNode, boolean acquireLock, TransactionEntry entry, boolean recursive, boolean isMove, boolean bypassLoadingData) throws Throwable
{
NodeSPI n = dataContainer.peek(fqn, true, true);
+ Object lockOwner = lockManager.getLockOwner(ctx);
+ boolean needLock = n != null && !lockManager.ownsLock(fqn, lockOwner);
+ boolean mustLoad = false;
+ try
+ {
+ if (needLock)
+ {
+ if (!lockManager.lock(n, LockType.READ, lockOwner))
+ throw new TimeoutException("Unable to acquire lock on " + fqn + ". Lock info: " + lockManager.printLockInfo(n));
+ }
+ mustLoad = mustLoad(n, key, allKeys || isMove);
+ }
+ finally
+ {
+ if (needLock) lockManager.unlock(n, lockOwner);
+ }
- boolean mustLoad = mustLoad(n, key, allKeys || isMove);
if (trace)
{
log.trace("load element " + fqn + " mustLoad=" + mustLoad);
Modified: core/trunk/src/main/java/org/jboss/cache/lock/LockManager.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/lock/LockManager.java 2008-05-29 13:02:52 UTC (rev 5914)
+++ core/trunk/src/main/java/org/jboss/cache/lock/LockManager.java 2008-05-29 13:51:25 UTC (rev 5915)
@@ -47,6 +47,16 @@
boolean lock(Fqn fqn, LockType lockType, Object owner, long timeout);
/**
+ * As {@link #lock(org.jboss.cache.Fqn, LockType, Object)} except that a NodeSPI is passed in instead of an Fqn.
+ *
+ * @param node node to lock
+ * @param lockType type of lock to acquire
+ * @param owner owner to acquire the lock for
+ * @return true if the lock was acquired, false otherwise.
+ */
+ boolean lock(NodeSPI node, LockType lockType, Object owner);
+
+ /**
* As {@link #lock(org.jboss.cache.Fqn, LockType, Object, long)} except that a NodeSPI is passed in instead of an Fqn.
*
* @param node node to lock
@@ -233,6 +243,15 @@
boolean ownsLock(Fqn fqn, Object owner);
/**
+ * Tests whether a given owner owns any sort of lock on a particular Fqn.
+ *
+ * @param node to test
+ * @param owner owner
+ * @return true if the owner does own the specified lock type on the specified node, false otherwise.
+ */
+ boolean ownsLock(NodeSPI node, Object owner);
+
+ /**
* Returns true if the node is locked (either for reading or writing) by anyone, and false otherwise.
*
* @param n node to inspect
Modified: core/trunk/src/main/java/org/jboss/cache/lock/NodeBasedLockManager.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/lock/NodeBasedLockManager.java 2008-05-29 13:02:52 UTC (rev 5914)
+++ core/trunk/src/main/java/org/jboss/cache/lock/NodeBasedLockManager.java 2008-05-29 13:51:25 UTC (rev 5915)
@@ -93,6 +93,11 @@
return acquireLock(fqn, lockType, owner, timeout) != null;
}
+ public boolean lock(NodeSPI node, LockType lockType, Object owner)
+ {
+ return acquireLock(node, lockType, owner, lockAcquisitionTimeout) != null;
+ }
+
public boolean lock(NodeSPI node, LockType lockType, Object owner, long timeout)
{
return acquireLock(node, lockType, owner, timeout) != null;
@@ -156,6 +161,7 @@
public void unlock(NodeSPI node, Object owner)
{
+ if (node == null) return;
unlock(node.getLock(), owner);
}
@@ -255,7 +261,11 @@
public boolean ownsLock(Fqn fqn, Object owner)
{
- NodeSPI node = dataContainer.peek(fqn);
+ return ownsLock(dataContainer.peek(fqn), owner);
+ }
+
+ public boolean ownsLock(NodeSPI node, Object owner)
+ {
return node != null && node.getLock().isOwner(owner);
}
Added: core/trunk/src/test/java/org/jboss/cache/loader/ConcurrentPutRemoveEvictTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/loader/ConcurrentPutRemoveEvictTest.java (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/loader/ConcurrentPutRemoveEvictTest.java 2008-05-29 13:51:25 UTC (rev 5915)
@@ -0,0 +1,131 @@
+package org.jboss.cache.loader;
+
+import org.jboss.cache.Cache;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.config.CacheLoaderConfig;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.util.TestingUtil;
+import org.testng.annotations.AfterTest;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * To test JBCACHE-1355
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 2.2.0
+ */
+ at Test(groups = "functional")
+public class ConcurrentPutRemoveEvictTest extends AbstractCacheLoaderTestBase
+{
+ Cache<String, String> cache;
+ Fqn fqn = Fqn.fromString("/a");
+ String key = "key";
+ boolean run = true;
+ Set<Exception> exceptions = new HashSet<Exception>();
+
+ @BeforeTest
+ public void setUp() throws Exception
+ {
+ CacheLoaderConfig cacheLoaderConfig = getSingleCacheLoaderConfig("", DummyInMemoryCacheLoader.class.getName(), "", false, false, false);
+ Configuration cfg = new Configuration();
+ cfg.setCacheLoaderConfig(cacheLoaderConfig);
+ cache = new DefaultCacheFactory<String, String>().createCache(cfg);
+ cache.put(fqn, key, "value");
+ }
+
+ @AfterTest
+ public void tearDown()
+ {
+ TestingUtil.killCaches(cache);
+ }
+
+ public void doTest() throws Exception
+ {
+ List<Thread> threads = new ArrayList<Thread>();
+
+ threads.add(new Getter());
+ threads.add(new RandomAdder());
+ threads.add(new Evicter());
+
+ for (Thread t : threads) t.start();
+
+ // let these run for a while.
+ TestingUtil.sleepThread(10000);
+
+ run = false;
+
+ for (Thread t : threads) t.join();
+
+ if (!exceptions.isEmpty())
+ {
+ for (Exception e : exceptions) throw e;
+ }
+ }
+
+ private class RandomAdder extends Thread
+ {
+ public void run()
+ {
+ int i = 0;
+ while (run)
+ {
+ try
+ {
+ cache.put(fqn, key + (i++), "");
+ }
+ catch (Exception e)
+ {
+ // ignore
+ }
+ }
+ }
+ }
+
+
+ private class Getter extends Thread
+ {
+ public void run()
+ {
+ while (run)
+ {
+ try
+ {
+ // note that we sometimes get a null back. This is incorrect and inconsistent, but has to do with locks being held
+ // on nodes. Very similar to http://jira.jboss.org/jira/browse/JBCACHE-1165
+ String value = cache.get(fqn, key);
+ System.out.println("Thread " + getName() + " got value " + value);
+ }
+ catch (Exception e)
+ {
+ exceptions.add(e);
+ }
+ }
+ }
+ }
+
+ private class Evicter extends Thread
+ {
+ public void run()
+ {
+ while (run)
+ {
+ try
+ {
+ cache.evict(fqn);
+ }
+ catch (Exception e)
+ {
+ // who cares
+ }
+ }
+ }
+ }
+
+}
More information about the jbosscache-commits
mailing list