JBoss Cache SVN: r7965 - in core/trunk/src: test/java/org/jboss/cache/loader and 1 other directory.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2009-04-02 05:46:44 -0400 (Thu, 02 Apr 2009)
New Revision: 7965
Added:
core/trunk/src/test/java/org/jboss/cache/loader/AddRemoveNodeDeadlockTest.java
Modified:
core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java
Log:
JBCACHE-1497 - When adding node, CacheLoaderInterceptor locks child node before MVCCLockingInterceptor locks parent
Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java 2009-04-02 09:29:34 UTC (rev 7964)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java 2009-04-02 09:46:44 UTC (rev 7965)
@@ -237,8 +237,14 @@
}
}
+
// see if we need to force the lock on nonexistent nodes.
- if (n == null && force) acquireLock(context, fqn);
+ if (n == null && force)
+ {
+ parentFqn = fqn.getParent();
+ if (isParentLockNeeded(parentFqn, context)) wrapNodeForWriting(context, parentFqn, true, false, includeInvalidNodes, false, force);
+ acquireLock(context, fqn);
+ }
// now test if we need to lock the parent as well.
if ((n != null || force) && forRemoval && (parentFqn == null ? parentFqn = fqn.getParent() : parentFqn) != null && isParentLockNeeded(parentFqn, context))
Added: core/trunk/src/test/java/org/jboss/cache/loader/AddRemoveNodeDeadlockTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/loader/AddRemoveNodeDeadlockTest.java (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/loader/AddRemoveNodeDeadlockTest.java 2009-04-02 09:46:44 UTC (rev 7965)
@@ -0,0 +1,162 @@
+package org.jboss.cache.loader;
+
+import org.jboss.cache.AbstractSingleCacheTest;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.UnitTestCacheFactory;
+import org.jboss.cache.config.CacheLoaderConfig;
+import org.jboss.cache.factories.UnitTestConfigurationFactory;
+import org.jboss.cache.loader.testloaders.DummyInMemoryCacheLoader;
+import org.testng.annotations.Test;
+
+import javax.transaction.TransactionManager;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@Test(groups = "functional", testName = "loader.AddRemoveNodeDeadlockTest")
+public class AddRemoveNodeDeadlockTest extends AbstractSingleCacheTest
+{
+ private static final Fqn<String> FQN = Fqn.fromElements("a");
+ private CacheSPI<String, String> cache;
+ private TransactionManager tm;
+
+ public CacheSPI createCache() throws Exception
+ {
+ UnitTestCacheFactory<String, String> cf = new UnitTestCacheFactory<String, String>();
+ cache = (CacheSPI<String, String>) cf.createCache("configs/local-tx.xml", false, getClass());
+ cache.getConfiguration().setLockAcquisitionTimeout(4000);
+ cache.getConfiguration().setEvictionConfig(null);
+ // !
+ cache.getConfiguration().setLockParentForChildInsertRemove(true);
+ // !
+ CacheLoaderConfig cacheLoaderConfig = UnitTestConfigurationFactory.buildSingleCacheLoaderConfig(false, "", DummyInMemoryCacheLoader.class.getName(), "", false, true, false, false, false);
+ cache.getConfiguration().setCacheLoaderConfig(cacheLoaderConfig);
+
+ cache.start();
+ tm = cache.getTransactionManager();
+
+ return cache;
+ }
+
+ private void await(CountDownLatch latch, boolean expect, String message) throws InterruptedException, TimeoutException
+ {
+ assert latch.await(cache.getConfiguration().getLockAcquisitionTimeout() / 2, TimeUnit.MILLISECONDS) == expect
+ : message;
+ }
+
+ public void testAdd() throws Exception
+ {
+ cache.put(FQN.getParent(), "x", "a");
+ doTest(true);
+ }
+
+ public void testRemove() throws Exception
+ {
+ cache.put(FQN, "x", "a");
+ doTest(false);
+ }
+
+ private void doTest(final boolean isAdd) throws Exception
+ {
+ ExecutorService exec = Executors.newFixedThreadPool(2);
+ try
+ {
+ final CountDownLatch init = new CountDownLatch(1);
+ final CountDownLatch parentLocked = new CountDownLatch(1);
+ final CountDownLatch childLocked = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+
+ /*
+ * The procedure:
+ * 1) t1 locks the parent node
+ * 2) t2 tries to add/remove the child
+ * Under normal circumstances t2 should block on parent before adding/removing the child.
+ * If there's a deadlock condition, it will lock the child first and then proceed to lock the parent (and block).
+ * 3) t1 adds/removes the child
+ * Normally this should succeed as t1 already holds parent's lock.
+ * Under deadlock condition it will be blocked by t2's lock on child.
+ */
+
+ // t1
+ Future<?> f1 = exec.submit(new Callable<Void>()
+ {
+ public Void call() throws Exception
+ {
+ tm.begin();
+ try
+ {
+ await(init, true, "init t1");
+ cache.put(FQN.getParent(), "x", "b");
+ parentLocked.countDown();
+
+ // this will time out because there's no one who can ping the latch, but that's expected
+ await(childLocked, false, "child was locked by t2");
+ cache.put(FQN, "x", "b");
+ done.countDown();
+
+ tm.commit();
+ }
+ finally
+ {
+ if (tm.getTransaction() != null)
+ {
+ tm.rollback();
+ }
+ }
+
+ return null;
+ }
+ });
+
+ // t2
+ Future<?> f2 = exec.submit(new Callable<Void>()
+ {
+ public Void call() throws Exception
+ {
+ tm.begin();
+ try
+ {
+ init.countDown();
+ await(parentLocked, true, "t2 parent lock");
+ // uncomment following line to simulate proper locking order
+// cache.put(FQN.getParent(), "x", "a");
+ if (isAdd)
+ {
+ // the deadlock exception would be here:
+ cache.put(FQN, "x", "a");
+ }
+ else
+ {
+ cache.removeNode(FQN);
+ }
+ childLocked.countDown();
+ await(done, true, "t2 done");
+
+ tm.commit();
+ }
+ finally
+ {
+ if (tm.getTransaction() != null)
+ {
+ tm.rollback();
+ }
+ }
+
+ return null;
+ }
+ });
+
+ f1.get(cache.getConfiguration().getLockAcquisitionTimeout() * 3, TimeUnit.MILLISECONDS);
+ f2.get(cache.getConfiguration().getLockAcquisitionTimeout() * 3, TimeUnit.MILLISECONDS);
+ }
+ finally
+ {
+ exec.shutdown();
+ }
+ }
+}
15 years, 5 months
JBoss Cache SVN: r7964 - core/trunk/src/main/java/org/jboss/cache/loader.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2009-04-02 05:29:34 -0400 (Thu, 02 Apr 2009)
New Revision: 7964
Modified:
core/trunk/src/main/java/org/jboss/cache/loader/JDBCCacheLoaderConfig.java
Log:
JBCACHE-1501 - Make JDBCCacheLoader easily subclassable
Modified: core/trunk/src/main/java/org/jboss/cache/loader/JDBCCacheLoaderConfig.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/loader/JDBCCacheLoaderConfig.java 2009-04-02 09:26:48 UTC (rev 7963)
+++ core/trunk/src/main/java/org/jboss/cache/loader/JDBCCacheLoaderConfig.java 2009-04-02 09:29:34 UTC (rev 7964)
@@ -152,7 +152,8 @@
return "SELECT " + fqnColumn + "," + nodeColumn + " FROM " + table + " WHERE " + fqnColumn + " = ? OR " + fqnColumn + " LIKE ?";
}
- private String constructDeleteNodeSql()
+ @Override
+ protected String constructDeleteNodeSql()
{
return "DELETE FROM " + table + " WHERE " + fqnColumn + " = ? OR " + fqnColumn + " LIKE ?";
}
15 years, 5 months
JBoss Cache SVN: r7963 - core/trunk/src/main/java/org/jboss/cache/loader.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2009-04-02 05:26:48 -0400 (Thu, 02 Apr 2009)
New Revision: 7963
Modified:
core/trunk/src/main/java/org/jboss/cache/loader/AdjListJDBCCacheLoaderConfig.java
Log:
JBCACHE-1501 - Make JDBCCacheLoader easily subclassable
Modified: core/trunk/src/main/java/org/jboss/cache/loader/AdjListJDBCCacheLoaderConfig.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/loader/AdjListJDBCCacheLoaderConfig.java 2009-04-02 04:39:45 UTC (rev 7962)
+++ core/trunk/src/main/java/org/jboss/cache/loader/AdjListJDBCCacheLoaderConfig.java 2009-04-02 09:26:48 UTC (rev 7963)
@@ -472,12 +472,12 @@
connectionFactoryClass = props.getProperty("cache.jdbc.connection.factory", "org.jboss.cache.loader.NonManagedConnectionFactory");
}
- private String constructDropTableDDL()
+ protected String constructDropTableDDL()
{
return "DROP TABLE " + table;
}
- private String constructCreateTableDDL()
+ protected String constructCreateTableDDL()
{
// removed CONSTRAINT clause as this causes problems with some databases, like Informix.
return "CREATE TABLE " + table + "(" + fqnColumn + " " + fqnType + " NOT NULL, " + nodeColumn + " " + nodeType +
@@ -556,37 +556,37 @@
return (AdjListJDBCCacheLoaderConfig) super.clone();
}
- private String constructSelectNodeSql()
+ protected String constructSelectNodeSql()
{
return "SELECT " + nodeColumn + " FROM " + table + " WHERE " + fqnColumn + " = ?";
}
- private String constructUpdateNodeSql()
+ protected String constructUpdateNodeSql()
{
return "UPDATE " + table + " SET " + nodeColumn + " = ? WHERE " + fqnColumn + " = ?";
}
- private String constructDeleteAllSql()
+ protected String constructDeleteAllSql()
{
return "DELETE FROM " + table;
}
- private String constructDeleteNodeSql()
+ protected String constructDeleteNodeSql()
{
return "DELETE FROM " + table + " WHERE " + fqnColumn + " = ?";
}
- private String constructSelectChildNamesSql()
+ protected String constructSelectChildNamesSql()
{
return "SELECT " + fqnColumn + " FROM " + table + " WHERE " + parentColumn + " = ?";
}
- private String constructExistsSql()
+ protected String constructExistsSql()
{
return "SELECT '1' FROM " + table + " WHERE " + fqnColumn + " = ?";
}
- private String constructInsertNodeSql()
+ protected String constructInsertNodeSql()
{
// This SQL string takes in 4 params - fqn, node (serialized data), parent, and fqn AGAIN.
// the benefit of this is is that it will run without failing even if the row already exists, so you don't need
15 years, 5 months
JBoss Cache SVN: r7962 - core/support-branches/1.4.1.SP11_JBCACHE-1483/src/org/jboss/cache.
by jbosscache-commits@lists.jboss.org
Author: jiwils
Date: 2009-04-02 00:39:45 -0400 (Thu, 02 Apr 2009)
New Revision: 7962
Modified:
core/support-branches/1.4.1.SP11_JBCACHE-1483/src/org/jboss/cache/Version.java
Log:
Changed version information to reflect JIRA issue and support case.
Modified: core/support-branches/1.4.1.SP11_JBCACHE-1483/src/org/jboss/cache/Version.java
===================================================================
--- core/support-branches/1.4.1.SP11_JBCACHE-1483/src/org/jboss/cache/Version.java 2009-04-02 04:34:20 UTC (rev 7961)
+++ core/support-branches/1.4.1.SP11_JBCACHE-1483/src/org/jboss/cache/Version.java 2009-04-02 04:39:45 UTC (rev 7962)
@@ -10,7 +10,7 @@
*/
public class Version
{
- public static final String version = "1.4.1.SP11";
+ public static final String version = "1.4.1.SP11+JBCACHE-1483 (#265738)";
public static final String codename = "Cayenne";
public static byte[] version_id = {'0', '1', '4', '1', 'S', 'P', '1', '1'};
public static final String cvs = "$Id$";
15 years, 5 months
JBoss Cache SVN: r7961 - in core/support-branches/1.4.1.SP11_JBCACHE-1483: tests/functional/org/jboss/cache and 1 other directory.
by jbosscache-commits@lists.jboss.org
Author: jiwils
Date: 2009-04-02 00:34:20 -0400 (Thu, 02 Apr 2009)
New Revision: 7961
Modified:
core/support-branches/1.4.1.SP11_JBCACHE-1483/src/org/jboss/cache/TreeCache.java
core/support-branches/1.4.1.SP11_JBCACHE-1483/tests/functional/org/jboss/cache/TreeCacheFunctionalTest.java
Log:
findNode now correctly handles situations where findInternal returns null. Added test TreeCacheFunctionalTest.testFindNodeWhenFindInternalReturnsNull.
Modified: core/support-branches/1.4.1.SP11_JBCACHE-1483/src/org/jboss/cache/TreeCache.java
===================================================================
--- core/support-branches/1.4.1.SP11_JBCACHE-1483/src/org/jboss/cache/TreeCache.java 2009-04-02 04:29:06 UTC (rev 7960)
+++ core/support-branches/1.4.1.SP11_JBCACHE-1483/src/org/jboss/cache/TreeCache.java 2009-04-02 04:34:20 UTC (rev 7961)
@@ -113,8 +113,8 @@
private static final String JGROUPS_JMX_DOMAIN = "jboss.jgroups";
private static final String CHANNEL_JMX_ATTRIBUTES = "type=channel,cluster=";
private static final String PROTOCOL_JMX_ATTRIBUTES = "type=protocol,cluster=";
-
-
+
+
private boolean forceAnycast = false;
/**
* Default replication version, from {@link Version#getVersionShort}.
@@ -285,7 +285,7 @@
* Require write locks on parents before adding or removing children. Default false.
*/
protected boolean lockParentForChildInsertRemove = false;
-
+
/**
* This ThreadLocal contains an {@see InvocationContext} object, which holds
* invocation-specific details.
@@ -436,15 +436,15 @@
* will be ignored by _getState().
*/
protected final Set activationChangeNodes = new HashSet();
-
+
/**
- * The JGroups 2.4.1 or higher "callRemoteMethods" overload that
+ * The JGroups 2.4.1 or higher "callRemoteMethods" overload that
* provides Anycast support.
*/
protected Method anycastMethod;
-
+
/** Did we register our channel in JMX ourself? */
- protected boolean channelRegistered;
+ protected boolean channelRegistered;
/** Did we register our channel's protocols in JMX ourself? */
protected boolean protocolsRegistered;
@@ -1126,7 +1126,7 @@
public IsolationLevel getIsolationLevelClass()
{
return isolationLevel;
- }
+ }
/**
* Gets whether inserting or removing a node requires a write lock
@@ -1475,7 +1475,7 @@
channel = new JChannel(cluster_props);
// JBCACHE-1048 Hack to register the channel
registerChannelInJmx();
-
+
// Only set GET_STATE_EVENTS if the JGroups version is < 2.3
int jgVer= org.jgroups.Version.version;
while (jgVer >= 100)
@@ -1498,7 +1498,7 @@
*/
disp = new RpcDispatcher(channel, ml, this, this);
disp.setMarshaller(getMarshaller());
-
+
// See if Anycast is supported
try
{
@@ -1506,7 +1506,7 @@
}
catch (Throwable ignored)
{
- log.debug("JGroups release " + org.jgroups.Version.version +
+ log.debug("JGroups release " + org.jgroups.Version.version +
" does not support anycast; will not use it");
}
break;
@@ -1990,13 +1990,13 @@
{
// Get the state from each DataOwner and integrate in their
// respective buddy backup tree
- List buddies = buddyManager.getBackupDataOwners();
+ List buddies = buddyManager.getBackupDataOwners();
for (Iterator it = buddies.iterator(); it.hasNext();)
{
Address buddy = (Address) it.next();
if (getMembers() == null || !getMembers().contains(buddy))
continue;
-
+
Object[] sources = {buddy};
Fqn base = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, BuddyManager.getGroupNameFromAddress(buddy));
Fqn buddyRoot = new Fqn(base, fqn);
@@ -2302,7 +2302,7 @@
child = factory.createDataNode(type, name,
subtree.getFqnChild(i + 1),
parent, null, this);
- // Add uninitialized flag so that data stored at the root of the
+ // Add uninitialized flag so that data stored at the root of the
// region can be loaded/preloaded from the cache loader.
child.put(UNINITIALIZED, null);
parent.addChild(name, child);
@@ -3366,7 +3366,7 @@
// No one provided us with state. We need to find out if that's because
// we are the coordinator. But we don't know if the viewAccepted() callback
// has been invoked, so call determineCoordinator(), which will block until
- // viewAccepted() is called at least once
+ // viewAccepted() is called at least once
determineCoordinator();
if (isCoordinator())
@@ -5088,16 +5088,16 @@
* Internal evict method called by eviction policy provider.
*
* @param fqn removes everything assoicated with this FQN
- *
- * @return <code>true</code> if the node has been completely removed,
+ *
+ * @return <code>true</code> if the node has been completely removed,
* <code>false</code> if only the data map was removed, due
* to the presence of children
- *
+ *
* @throws CacheException
*/
public boolean _evict(Fqn fqn) throws CacheException
{
- if (!exists(fqn))
+ if (!exists(fqn))
return true; // node does not exist. Maybe it has been recursively removed.
// use remove method now if there is a child node. Otherwise, it is removed
boolean create_undo_ops = false;
@@ -5122,16 +5122,16 @@
*
* @param fqn
* @param version
- *
- * @return <code>true</code> if the node has been completely removed,
+ *
+ * @return <code>true</code> if the node has been completely removed,
* <code>false</code> if only the data map was removed, due
* to the presence of children
- *
+ *
* @throws CacheException
*/
public boolean _evict(Fqn fqn, DataVersion version) throws CacheException
{
- if (!exists(fqn))
+ if (!exists(fqn))
return true; // node does not exist
boolean create_undo_ops = false;
@@ -5762,7 +5762,7 @@
// Now that we have a view, figure out if we are the coordinator
coordinator = (members.size() != 0 && members.get(0).equals(getLocalAddress()));
- // now notify listeners - *after* updating the coordinator. - JBCACHE-662
+ // now notify listeners - *after* updating the coordinator. - JBCACHE-662
if (needNotification) notifyViewChange(new_view);
// Wake up any threads that are waiting to know who the members
@@ -5869,7 +5869,7 @@
catch (SystemException e)
{
}
-
+
// JBCACHE-982 -- don't complain if COMMITTED
if (status != Status.STATUS_COMMITTED)
{
@@ -5879,7 +5879,7 @@
{
log.trace("status is COMMITTED; returning null");
}
-
+
return null;
}
@@ -6016,7 +6016,7 @@
Node toReturn = findInternal(fqn, false);
- if (version != null)
+ if (toReturn != null && version != null)
{
// we need to check the version of the data node...
DataVersion nodeVersion = ((OptimisticTreeNode) toReturn).getVersion();
@@ -6311,7 +6311,7 @@
if (curr == null) return;
notifyNodeCreated(curr.getFqn());
-
+
if ((children = curr.getChildren()) != null)
{
for (Iterator it = children.values().iterator(); it.hasNext();)
@@ -6719,7 +6719,7 @@
return (MBeanServer) servers.get(0);
}
-
+
protected void registerChannelInJmx()
{
if (server != null)
@@ -6729,7 +6729,7 @@
String protocolPrefix = JGROUPS_JMX_DOMAIN + ":" + PROTOCOL_JMX_ATTRIBUTES + getClusterName();
JmxConfigurator.registerProtocols(server, channel, protocolPrefix);
protocolsRegistered = true;
-
+
String name = JGROUPS_JMX_DOMAIN + ":" + CHANNEL_JMX_ATTRIBUTES + getClusterName();
JmxConfigurator.registerChannel(channel, server, name);
channelRegistered = true;
@@ -6740,12 +6740,12 @@
}
}
}
-
+
protected void unregisterChannelFromJmx()
{
ObjectName on = null;
if (channelRegistered)
- {
+ {
// Unregister the channel itself
try
{
@@ -6760,7 +6760,7 @@
log.error("Caught exception unregistering channel", e);
}
}
-
+
if (protocolsRegistered)
{
// Unregister the protocols
Modified: core/support-branches/1.4.1.SP11_JBCACHE-1483/tests/functional/org/jboss/cache/TreeCacheFunctionalTest.java
===================================================================
--- core/support-branches/1.4.1.SP11_JBCACHE-1483/tests/functional/org/jboss/cache/TreeCacheFunctionalTest.java 2009-04-02 04:29:06 UTC (rev 7960)
+++ core/support-branches/1.4.1.SP11_JBCACHE-1483/tests/functional/org/jboss/cache/TreeCacheFunctionalTest.java 2009-04-02 04:34:20 UTC (rev 7961)
@@ -160,8 +160,18 @@
return tmptx;
}
+ public void testFindNodeWhenFindInternalReturnsNull() throws CacheException {
+ try {
+ // This remove causes findNode to be invoked and findInternal to return null
+ // which used to throw an NPE since findNode didn't handle the situation. See
+ // JBCACHE-1483 for more information.
+ cache._remove(null, FQN, false, false, true, new org.jboss.cache.optimistic.DefaultDataVersion());
+ }
+ catch (NullPointerException npe) {
+ fail("cache.findNode threw an NPE when cache.findInternal returned null.");
+ }
+ }
-
public static Test suite() {
return new TestSuite(TreeCacheFunctionalTest.class);
}
15 years, 5 months
JBoss Cache SVN: r7960 - core/support-branches.
by jbosscache-commits@lists.jboss.org
Author: jiwils
Date: 2009-04-02 00:29:06 -0400 (Thu, 02 Apr 2009)
New Revision: 7960
Added:
core/support-branches/1.4.1.SP11_JBCACHE-1483/
Log:
Branch created for JBCACHE-1483 in EAP CP04 (JBPAPP-1857).
Copied: core/support-branches/1.4.1.SP11_JBCACHE-1483 (from rev 7959, core/tags/1.4.1.SP11)
15 years, 5 months
JBoss Cache SVN: r7959 - in core/branches/1.4.X: tests/functional/org/jboss/cache and 1 other directory.
by jbosscache-commits@lists.jboss.org
Author: jiwils
Date: 2009-04-01 23:34:16 -0400 (Wed, 01 Apr 2009)
New Revision: 7959
Modified:
core/branches/1.4.X/src/org/jboss/cache/TreeCache.java
core/branches/1.4.X/tests/functional/org/jboss/cache/TreeCacheFunctionalTest.java
Log:
Fix for JBCACHE-1483. findNode didn't correctly handle situations when optimistic locking was used and findInternal returned null.
Modified: core/branches/1.4.X/src/org/jboss/cache/TreeCache.java
===================================================================
--- core/branches/1.4.X/src/org/jboss/cache/TreeCache.java 2009-03-31 05:46:19 UTC (rev 7958)
+++ core/branches/1.4.X/src/org/jboss/cache/TreeCache.java 2009-04-02 03:34:16 UTC (rev 7959)
@@ -113,8 +113,8 @@
private static final String JGROUPS_JMX_DOMAIN = "jboss.jgroups";
private static final String CHANNEL_JMX_ATTRIBUTES = "type=channel,cluster=";
private static final String PROTOCOL_JMX_ATTRIBUTES = "type=protocol,cluster=";
-
-
+
+
private boolean forceAnycast = false;
/**
* Default replication version, from {@link Version#getVersionShort}.
@@ -285,7 +285,7 @@
* Require write locks on parents before adding or removing children. Default false.
*/
protected boolean lockParentForChildInsertRemove = false;
-
+
/**
* This ThreadLocal contains an {@see InvocationContext} object, which holds
* invocation-specific details.
@@ -436,15 +436,15 @@
* will be ignored by _getState().
*/
protected final Set activationChangeNodes = new HashSet();
-
+
/**
- * The JGroups 2.4.1 or higher "callRemoteMethods" overload that
+ * The JGroups 2.4.1 or higher "callRemoteMethods" overload that
* provides Anycast support.
*/
protected Method anycastMethod;
-
+
/** Did we register our channel in JMX ourself? */
- protected boolean channelRegistered;
+ protected boolean channelRegistered;
/** Did we register our channel's protocols in JMX ourself? */
protected boolean protocolsRegistered;
@@ -1126,7 +1126,7 @@
public IsolationLevel getIsolationLevelClass()
{
return isolationLevel;
- }
+ }
/**
* Gets whether inserting or removing a node requires a write lock
@@ -1475,7 +1475,7 @@
channel = new JChannel(cluster_props);
// JBCACHE-1048 Hack to register the channel
registerChannelInJmx();
-
+
// Only set GET_STATE_EVENTS if the JGroups version is < 2.3
int jgVer= org.jgroups.Version.version;
while (jgVer >= 100)
@@ -1498,7 +1498,7 @@
*/
disp = new RpcDispatcher(channel, ml, this, this);
disp.setMarshaller(getMarshaller());
-
+
// See if Anycast is supported
try
{
@@ -1506,7 +1506,7 @@
}
catch (Throwable ignored)
{
- log.debug("JGroups release " + org.jgroups.Version.version +
+ log.debug("JGroups release " + org.jgroups.Version.version +
" does not support anycast; will not use it");
}
break;
@@ -1990,13 +1990,13 @@
{
// Get the state from each DataOwner and integrate in their
// respective buddy backup tree
- List buddies = buddyManager.getBackupDataOwners();
+ List buddies = buddyManager.getBackupDataOwners();
for (Iterator it = buddies.iterator(); it.hasNext();)
{
Address buddy = (Address) it.next();
if (getMembers() == null || !getMembers().contains(buddy))
continue;
-
+
Object[] sources = {buddy};
Fqn base = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, BuddyManager.getGroupNameFromAddress(buddy));
Fqn buddyRoot = new Fqn(base, fqn);
@@ -2302,7 +2302,7 @@
child = factory.createDataNode(type, name,
subtree.getFqnChild(i + 1),
parent, null, this);
- // Add uninitialized flag so that data stored at the root of the
+ // Add uninitialized flag so that data stored at the root of the
// region can be loaded/preloaded from the cache loader.
child.put(UNINITIALIZED, null);
parent.addChild(name, child);
@@ -3366,7 +3366,7 @@
// No one provided us with state. We need to find out if that's because
// we are the coordinator. But we don't know if the viewAccepted() callback
// has been invoked, so call determineCoordinator(), which will block until
- // viewAccepted() is called at least once
+ // viewAccepted() is called at least once
determineCoordinator();
if (isCoordinator())
@@ -5088,16 +5088,16 @@
* Internal evict method called by eviction policy provider.
*
* @param fqn removes everything assoicated with this FQN
- *
- * @return <code>true</code> if the node has been completely removed,
+ *
+ * @return <code>true</code> if the node has been completely removed,
* <code>false</code> if only the data map was removed, due
* to the presence of children
- *
+ *
* @throws CacheException
*/
public boolean _evict(Fqn fqn) throws CacheException
{
- if (!exists(fqn))
+ if (!exists(fqn))
return true; // node does not exist. Maybe it has been recursively removed.
// use remove method now if there is a child node. Otherwise, it is removed
boolean create_undo_ops = false;
@@ -5122,16 +5122,16 @@
*
* @param fqn
* @param version
- *
- * @return <code>true</code> if the node has been completely removed,
+ *
+ * @return <code>true</code> if the node has been completely removed,
* <code>false</code> if only the data map was removed, due
* to the presence of children
- *
+ *
* @throws CacheException
*/
public boolean _evict(Fqn fqn, DataVersion version) throws CacheException
{
- if (!exists(fqn))
+ if (!exists(fqn))
return true; // node does not exist
boolean create_undo_ops = false;
@@ -5762,7 +5762,7 @@
// Now that we have a view, figure out if we are the coordinator
coordinator = (members.size() != 0 && members.get(0).equals(getLocalAddress()));
- // now notify listeners - *after* updating the coordinator. - JBCACHE-662
+ // now notify listeners - *after* updating the coordinator. - JBCACHE-662
if (needNotification) notifyViewChange(new_view);
// Wake up any threads that are waiting to know who the members
@@ -5869,7 +5869,7 @@
catch (SystemException e)
{
}
-
+
// JBCACHE-982 -- don't complain if COMMITTED
if (status != Status.STATUS_COMMITTED)
{
@@ -5879,7 +5879,7 @@
{
log.trace("status is COMMITTED; returning null");
}
-
+
return null;
}
@@ -6016,7 +6016,7 @@
Node toReturn = findInternal(fqn, false);
- if (version != null)
+ if (toReturn != null && version != null)
{
// we need to check the version of the data node...
DataVersion nodeVersion = ((OptimisticTreeNode) toReturn).getVersion();
@@ -6311,7 +6311,7 @@
if (curr == null) return;
notifyNodeCreated(curr.getFqn());
-
+
if ((children = curr.getChildren()) != null)
{
for (Iterator it = children.values().iterator(); it.hasNext();)
@@ -6719,7 +6719,7 @@
return (MBeanServer) servers.get(0);
}
-
+
protected void registerChannelInJmx()
{
if (server != null)
@@ -6729,7 +6729,7 @@
String protocolPrefix = JGROUPS_JMX_DOMAIN + ":" + PROTOCOL_JMX_ATTRIBUTES + getClusterName();
JmxConfigurator.registerProtocols(server, channel, protocolPrefix);
protocolsRegistered = true;
-
+
String name = JGROUPS_JMX_DOMAIN + ":" + CHANNEL_JMX_ATTRIBUTES + getClusterName();
JmxConfigurator.registerChannel(channel, server, name);
channelRegistered = true;
@@ -6740,12 +6740,12 @@
}
}
}
-
+
protected void unregisterChannelFromJmx()
{
ObjectName on = null;
if (channelRegistered)
- {
+ {
// Unregister the channel itself
try
{
@@ -6760,7 +6760,7 @@
log.error("Caught exception unregistering channel", e);
}
}
-
+
if (protocolsRegistered)
{
// Unregister the protocols
Modified: core/branches/1.4.X/tests/functional/org/jboss/cache/TreeCacheFunctionalTest.java
===================================================================
--- core/branches/1.4.X/tests/functional/org/jboss/cache/TreeCacheFunctionalTest.java 2009-03-31 05:46:19 UTC (rev 7958)
+++ core/branches/1.4.X/tests/functional/org/jboss/cache/TreeCacheFunctionalTest.java 2009-04-02 03:34:16 UTC (rev 7959)
@@ -160,8 +160,18 @@
return tmptx;
}
+ public void testFindNodeWhenFindInternalReturnsNull() throws CacheException {
+ try {
+ // This remove causes findNode to be invoked and findInternal to return null
+ // which used to throw an NPE since findNode didn't handle the situation. See
+ // JBCACHE-1483 for more information.
+ cache._remove(null, FQN, false, false, true, new org.jboss.cache.optimistic.DefaultDataVersion());
+ }
+ catch (NullPointerException npe) {
+ fail("cache.findNode threw an NPE when cache.findInternal returned null.");
+ }
+ }
-
public static Test suite() {
return new TestSuite(TreeCacheFunctionalTest.class);
}
15 years, 5 months