Author: galder.zamarreno(a)jboss.com
Date: 2009-08-05 06:54:02 -0400 (Wed, 05 Aug 2009)
New Revision: 8148
Added:
core/trunk/src/test/java/org/jboss/cache/api/mvcc/PutRemoveTest.java
Modified:
core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java
Log:
[JBCACHE-1519] (ClassCastException in ReadCommittedNode.markForUpdate()) Fixed by making
sure that when parent node is updated after a removal, the parent is wrapped in a
NodeReference if read committed is in use.
Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java 2009-08-05 10:36:32
UTC (rev 8147)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java 2009-08-05 10:54:02
UTC (rev 8148)
@@ -35,6 +35,7 @@
import org.jboss.cache.factories.annotations.Inject;
import org.jboss.cache.factories.annotations.NonVolatile;
import org.jboss.cache.factories.annotations.Start;
+import org.jboss.cache.lock.IsolationLevel;
import org.jboss.cache.lock.LockManager;
import static org.jboss.cache.lock.LockType.WRITE;
import org.jboss.cache.lock.TimeoutException;
@@ -51,6 +52,7 @@
* locking, if necessary.
*
* @author Manik Surtani (<a href="mailto:manik AT jboss DOT org">manik
AT jboss DOT org</a>)
+ * @author Galder Zamarreño
* @since 3.0
*/
@NonVolatile
@@ -196,7 +198,6 @@
// create a copy of the underlying node
n.markForUpdate(dataContainer, writeSkewCheck);
}
- if (trace) log.trace("Retrieving wrapped node " + fqn);
if (n.isDeleted() && createIfAbsent) {
if (trace) log.trace("Node is deleted in current scope. Need to
un-delete.");
n.markAsDeleted(false);
@@ -335,7 +336,16 @@
// update child ref on parent to point to child as this is now a copy.
if (parentLockNeeded && (needToCopyNode || needToCopyParent)) {
if (parent == null) throw new NodeNotExistsException("Parent node "
+ parentFqn + " does not exist!");
- parent.getDelegationTarget().addChild(node.getDelegationTarget());
+ InternalNode ref = null;
+ if (configuration.getIsolationLevel() == IsolationLevel.READ_COMMITTED)
+ {
+ ref = new NodeReference(node.getDelegationTarget());
+ }
+ else
+ {
+ ref = node.getDelegationTarget();
+ }
+ parent.getDelegationTarget().addChild(ref);
}
// now deal with children.
Added: core/trunk/src/test/java/org/jboss/cache/api/mvcc/PutRemoveTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/PutRemoveTest.java
(rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/PutRemoveTest.java 2009-08-05
10:54:02 UTC (rev 8148)
@@ -0,0 +1,83 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at
gnu.org.
+ */
+
+package org.jboss.cache.api.mvcc;
+
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.UnitTestCacheFactory;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.factories.UnitTestConfigurationFactory;
+import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.transaction.DummyTransactionManagerLookup;
+import org.jboss.cache.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.transaction.TransactionManager;
+
+@Test(groups = { "functional" }, testName =
"api.mvcc.PutRemoveTest")
+public class PutRemoveTest
+{
+ private CacheSPI<String, String> cache;
+ private TransactionManager tm;
+
+ @BeforeMethod(alwaysRun = true)
+ public void setUp() throws Exception
+ {
+ UnitTestCacheFactory<String, String> factory = new
UnitTestCacheFactory<String, String>();
+ Configuration conf =
UnitTestConfigurationFactory.createConfiguration(Configuration.CacheMode.LOCAL, true);
+ conf.setIsolationLevel(IsolationLevel.READ_COMMITTED);
+ conf.setLockParentForChildInsertRemove(true);
+
conf.setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
+ cache = (CacheSPI<String, String>) factory.createCache(conf, true,
getClass());
+ tm = cache.getTransactionManager();
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void tearDown() throws Exception
+ {
+ TestingUtil.killCaches(cache);
+ }
+
+ public void testPutRemove() throws Exception
+ {
+ Fqn fqn = Fqn.fromElements("test", "a", "b");
+
+ for (int i = 0; i < 5; i++)
+ {
+ System.out.println("i == " + i + " [1]");
+ tm.begin();
+ check(fqn);
+ tm.commit();
+
+ System.out.println("i == " + i + " [2]");
+ tm.begin();
+ // the exception is in remove() on the SECOND pass!
+ if (remove(fqn))
+ {
+ check(fqn);
+ }
+ tm.commit();
+ }
+ }
+
+ private void check(Fqn fqn)
+ {
+ if (cache.get(fqn.getAncestor(1), "a") == null)
+ {
+ cache.put(fqn.getAncestor(1), "key-a", "value-a");
+ cache.put(fqn, "test-key-a", "value-a");
+ }
+ }
+
+ private boolean remove(Fqn fqn)
+ {
+ return cache.removeNode(fqn.getAncestor(1));
+ }
+}