summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCaspar De Groot2011-05-23 05:18:35 (EDT)
committerCaspar De Groot2011-05-23 05:18:35 (EDT)
commit8a304dfc1408c1622272b4914096619ebfdfead3 (patch)
tree6483494694103be7ba4bb8ab2dfa84c631043e35
parent75464e206f9e91d298729eb28d21ea5197145e38 (diff)
downloadcdo-8a304dfc1408c1622272b4914096619ebfdfead3.zip
cdo-8a304dfc1408c1622272b4914096619ebfdfead3.tar.gz
cdo-8a304dfc1408c1622272b4914096619ebfdfead3.tar.bz2
[Bug 341995] ConcurrentModificationException on commit while holding a write
https://bugs.eclipse.org/bugs/show_bug.cgi?id=341995
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java1
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_341995_Test.java103
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java17
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestSessionManager.java70
4 files changed, 189 insertions, 2 deletions
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
index 707776c..5ee103a 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
@@ -223,6 +223,7 @@ public abstract class AllConfigs extends ConfigTestSuite
testClasses.add(Bugzilla_339908_Test.class);
testClasses.add(Bugzilla_340961_Test.class);
testClasses.add(Bugzilla_341875_Test.class);
+ testClasses.add(Bugzilla_341995_Test.class);
testClasses.add(Bugzilla_342130_Test.class);
testClasses.add(Bugzilla_342135_Test.class);
testClasses.add(Bugzilla_343332_Test.class);
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_341995_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_341995_Test.java
new file mode 100644
index 0000000..97af85d
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_341995_Test.java
@@ -0,0 +1,103 @@
+/**
+ * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Caspar De Groot - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.bugzilla;
+
+import org.eclipse.emf.cdo.CDOObject;
+import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.tests.model1.Category;
+import org.eclipse.emf.cdo.tests.model1.Model1Factory;
+import org.eclipse.emf.cdo.tests.util.TestSessionManager;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.CDOUtil;
+import org.eclipse.emf.cdo.util.CommitException;
+
+/**
+ * @author Caspar De Groot
+ */
+public class Bugzilla_341995_Test extends AbstractCDOTest
+{
+ public void test() throws CommitException, InterruptedException
+ {
+ CDOSession session = openSession();
+ CDOTransaction tx = session.openTransaction();
+ CDOResource resource = tx.createResource(getResourcePath("test"));
+
+ Model1Factory factory = getModel1Factory();
+ Category cat = factory.createCategory();
+ resource.getContents().add(cat);
+ tx.commit();
+
+ CDOObject cdoCat = CDOUtil.getCDOObject(cat);
+ msg(cdoCat.cdoRevision().getVersion());
+
+ long delay = 2000L;
+ TestSessionManager sessionManager = (TestSessionManager)getRepository().getSessionManager();
+ sessionManager.setCommitNotificationDelay(delay);
+ try
+ {
+ doSecondSessionAsync();
+ sessionManager.getDelayLatch().await(); // Wait until the delay commences
+
+ long time1 = System.currentTimeMillis();
+
+ // Attempt the lock; this must block for a while, because it needs to receive
+ // the commitNotification from the commit in the other session, which we are
+ // artificially delaying
+ cdoCat.cdoWriteLock().lock();
+
+ long timeTaken = System.currentTimeMillis() - time1;
+
+ // We verify that there really was a delay
+ assertEquals("timeTaken == " + timeTaken, true, timeTaken >= delay);
+
+ tx.close();
+ session.close();
+ }
+ finally
+ {
+ sessionManager.setCommitNotificationDelay(0L);
+ }
+ }
+
+ private void doSecondSessionAsync() throws CommitException
+ {
+ Runnable r = new Runnable()
+ {
+ public void run()
+ {
+ CDOSession session = openSession();
+ CDOTransaction tx = session.openTransaction();
+ CDOResource resource = tx.getResource(getResourcePath("test"));
+
+ Category cat = (Category)resource.getContents().get(0);
+ cat.setName("dirty");
+ CDOCommitInfo info;
+ try
+ {
+ info = tx.commit();
+ }
+ catch (CommitException ex)
+ {
+ throw new RuntimeException(ex);
+ }
+
+ msg(info.getTimeStamp());
+
+ tx.close();
+ session.close();
+ }
+ };
+ new Thread(r).start();
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
index e1ca266..43cfde0 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
@@ -46,6 +46,7 @@ import org.eclipse.emf.cdo.tests.config.IRepositoryConfig;
import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesAfter;
import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesBefore;
import org.eclipse.emf.cdo.tests.util.TestRevisionManager;
+import org.eclipse.emf.cdo.tests.util.TestSessionManager;
import org.eclipse.net4j.Net4jUtil;
import org.eclipse.net4j.acceptor.IAcceptor;
@@ -82,6 +83,8 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf
public static final String PROP_TEST_REVISION_MANAGER = "test.repository.RevisionManager";
+ public static final String PROP_TEST_SESSION_MANAGER = "test.repository.SessionManager";
+
public static final String PROP_TEST_USER_MANAGER = "test.repository.UserManager";
public static final String PROP_TEST_QUERY_HANDLER_PROVIDER = "test.repository.QueryHandlerProvider";
@@ -389,13 +392,18 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf
{
revisionManager = new TestRevisionManager();
}
-
repository.setRevisionManager(revisionManager);
+ InternalSessionManager sessionManager = getTestSessionManager();
+ if (sessionManager == null)
+ {
+ sessionManager = new TestSessionManager();
+ }
+ repository.setSessionManager(sessionManager);
+
IUserManager userManager = getTestUserManager();
if (userManager != null)
{
- InternalSessionManager sessionManager = (InternalSessionManager)CDOServerUtil.createSessionManager();
sessionManager.setUserManager(userManager);
repository.setSessionManager(sessionManager);
}
@@ -421,6 +429,11 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf
return (InternalCDORevisionManager)getTestProperty(PROP_TEST_REVISION_MANAGER);
}
+ protected InternalSessionManager getTestSessionManager()
+ {
+ return (InternalSessionManager)getTestProperty(PROP_TEST_SESSION_MANAGER);
+ }
+
protected IUserManager getTestUserManager()
{
return (IUserManager)getTestProperty(PROP_TEST_USER_MANAGER);
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestSessionManager.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestSessionManager.java
new file mode 100644
index 0000000..0e32332
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestSessionManager.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Caspar De Groot - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.util;
+
+import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
+import org.eclipse.emf.cdo.internal.server.SessionManager;
+import org.eclipse.emf.cdo.spi.server.InternalSession;
+
+import org.eclipse.net4j.util.concurrent.ConcurrencyUtil;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * @author Caspar De Groot
+ */
+public class TestSessionManager extends SessionManager
+{
+ /**
+ * Prevents other threads from changing/resetting the commitNotificationDelay while we are just about to execute the
+ * delay.
+ */
+ private Object lock = new Object();
+
+ private long commitNotificationDelay;
+
+ /**
+ * Allows tests to wait until the delay is about to commence
+ */
+ private CountDownLatch delayLatch;
+
+ public void setCommitNotificationDelay(long millis)
+ {
+ synchronized (lock)
+ {
+ commitNotificationDelay = millis;
+ if (commitNotificationDelay > 0)
+ {
+ delayLatch = new CountDownLatch(1);
+ }
+ }
+ }
+
+ public CountDownLatch getDelayLatch()
+ {
+ return delayLatch;
+ }
+
+ @Override
+ public void sendCommitNotification(InternalSession sender, CDOCommitInfo commitInfo)
+ {
+ synchronized (lock)
+ {
+ if (commitNotificationDelay != 0)
+ {
+ delayLatch.countDown();
+ ConcurrencyUtil.sleep(commitNotificationDelay);
+ }
+ }
+
+ super.sendCommitNotification(sender, commitInfo);
+ }
+}