summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCaspar De Groot2012-01-31 00:15:22 (EST)
committer Eike Stepper2012-01-31 00:15:22 (EST)
commit4325b01b3e4e9c8f97d64e8756029c44ad424776 (patch)
tree9acdf2cea6d9544a0dc5bc43e0f1f8f11f331988
parent0cba8dd5ad899ca675a45d5a9842031a4f86716b (diff)
downloadcdo-4325b01b3e4e9c8f97d64e8756029c44ad424776.zip
cdo-4325b01b3e4e9c8f97d64e8756029c44ad424776.tar.gz
cdo-4325b01b3e4e9c8f97d64e8756029c44ad424776.tar.bz2
[359035] Deleting a locked object leaves dangling locks in the LockManager
https://bugs.eclipse.org/bugs/show_bug.cgi?id=359035
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java29
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/LockingManagerTest.java43
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/IRWOLockManager.java19
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWOLockManager.java46
4 files changed, 135 insertions, 2 deletions
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java
index f4ec3db..230cf95 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java
@@ -86,11 +86,13 @@ import org.eclipse.emf.ecore.EStructuralFeature;
import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -799,7 +801,7 @@ public class TransactionCommitContext implements InternalCommitContext
{
// First lock all objects (incl. possible ref targets).
// This is a transient operation, it does not check for existance!
- lockManager.lock(LockType.WRITE, transaction, lockedObjects, 1000);
+ lockManager.lock2(LockType.WRITE, transaction, lockedObjects, 1000);
// If all locks could be acquired, check if locked targets do still exist
if (lockedTargets != null)
@@ -949,9 +951,32 @@ public class TransactionCommitContext implements InternalCommitContext
{
if (!lockedObjects.isEmpty())
{
- lockManager.unlock(LockType.WRITE, transaction, lockedObjects);
+ lockManager.unlock2(LockType.WRITE, transaction, lockedObjects);
lockedObjects.clear();
}
+
+ if (detachedObjects.length > 0)
+ {
+ boolean branching = getTransaction().getRepository().isSupportingBranches();
+ Collection<? extends Object> unlockables = null;
+ if (branching)
+ {
+ List<CDOIDAndBranch> keys = new LinkedList<CDOIDAndBranch>();
+ for (CDOID id : detachedObjects)
+ {
+ CDOIDAndBranch idAndBranch = CDOIDUtil.createIDAndBranch(id, transaction.getBranch());
+ keys.add(idAndBranch);
+ }
+
+ unlockables = keys;
+ }
+ else
+ {
+ unlockables = Arrays.asList(detachedObjects);
+ }
+
+ lockManager.unlock2(transaction, unlockables);
+ }
}
private void computeDirtyObjects(OMMonitor monitor)
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/LockingManagerTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/LockingManagerTest.java
index 3437faa..e46df0c 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/LockingManagerTest.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/LockingManagerTest.java
@@ -14,9 +14,12 @@ package org.eclipse.emf.cdo.tests;
import org.eclipse.emf.cdo.CDOLock;
import org.eclipse.emf.cdo.CDOObject;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.eresource.CDOResource;
import org.eclipse.emf.cdo.server.IView;
import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.spi.server.InternalLockManager;
import org.eclipse.emf.cdo.spi.server.InternalRepository;
import org.eclipse.emf.cdo.tests.model1.Category;
import org.eclipse.emf.cdo.tests.model1.Company;
@@ -24,11 +27,13 @@ import org.eclipse.emf.cdo.transaction.CDOTransaction;
import org.eclipse.emf.cdo.util.CDOUtil;
import org.eclipse.emf.cdo.util.CommitException;
import org.eclipse.emf.cdo.util.LockTimeoutException;
+import org.eclipse.emf.cdo.util.ObjectNotFoundException;
import org.eclipse.emf.cdo.util.StaleRevisionLockException;
import org.eclipse.emf.cdo.view.CDOView;
import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
import org.eclipse.net4j.util.concurrent.RWOLockManager;
+import org.eclipse.net4j.util.concurrent.RWOLockManager.LockState;
import org.eclipse.net4j.util.concurrent.TimeoutRuntimeException;
import org.eclipse.net4j.util.io.IOUtil;
@@ -1148,4 +1153,42 @@ public class LockingManagerTest extends AbstractLockingTest
session1.close();
session2.close();
}
+
+ public void testDeleteLockedObject() throws Exception
+ {
+ CDOSession session1 = openSession();
+ CDOSession session2 = openSession();
+
+ CDOTransaction tx = session1.openTransaction();
+ tx.options().setAutoReleaseLocksEnabled(false);
+ CDOResource resource = tx.createResource(getResourcePath("/res1"));
+ Category category1 = getModel1Factory().createCategory();
+ resource.getContents().add(category1);
+ tx.commit();
+
+ CDOID id = CDOUtil.getCDOObject(category1).cdoID();
+
+ writeLock(category1);
+
+ resource.getContents().remove(category1);
+ tx.commit();
+
+ CDOView controlView = session2.openView();
+
+ try
+ {
+ controlView.getObject(id);
+ fail("Should have thrown " + ObjectNotFoundException.class.getSimpleName());
+ }
+ catch (ObjectNotFoundException ignore)
+ {
+ // Do nothing
+ }
+
+ InternalLockManager mgr = getRepository().getLockingManager();
+ boolean branching = getRepository().isSupportingBranches();
+ Object key = branching ? CDOIDUtil.createIDAndBranch(id, tx.getBranch()) : id;
+ LockState<Object, IView> state = mgr.getLockState(key);
+ assertNull(state);
+ }
}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/IRWOLockManager.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/IRWOLockManager.java
index 53fed6e..df1900a 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/IRWOLockManager.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/IRWOLockManager.java
@@ -16,14 +16,33 @@ import java.util.Collection;
import java.util.List;
/**
+ * A {@link IRWLockManager read/write lock manager} that supports {@link IRWLockManager.LockType#OPTION write option}
+ * locks.
+ *
* @author Caspar De Groot
* @since 3.2
*/
public interface IRWOLockManager<OBJECT, CONTEXT> extends IRWLockManager<OBJECT, CONTEXT>
{
+ /**
+ * Adds locks of the given type, owned by the given context on the given objects.
+ */
public List<LockState<OBJECT, CONTEXT>> lock2(LockType type, CONTEXT context,
Collection<? extends OBJECT> objectsToLock, long timeout) throws InterruptedException;
+ /**
+ * Removes all locks of the given type, owned by the given context on the given objects.
+ */
public List<LockState<OBJECT, CONTEXT>> unlock2(LockType type, CONTEXT context,
Collection<? extends OBJECT> objectsToUnlock);
+
+ /**
+ * Removes all locks owned by the given context on any objects.
+ */
+ public List<LockState<OBJECT, CONTEXT>> unlock2(CONTEXT context);
+
+ /**
+ * Removes all locks owned by the given context.
+ */
+ public List<LockState<OBJECT, CONTEXT>> unlock2(CONTEXT context, Collection<? extends OBJECT> objectsToUnlock);
}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWOLockManager.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWOLockManager.java
index a2d0014..7988bf8 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWOLockManager.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/RWOLockManager.java
@@ -102,6 +102,52 @@ public class RWOLockManager<OBJECT, CONTEXT> extends Lifecycle implements IRWOLo
unlock2(type, context, objectsToUnlock);
}
+ public synchronized List<LockState<OBJECT, CONTEXT>> unlock2(CONTEXT context,
+ Collection<? extends OBJECT> objectsToUnlock)
+ {
+ if (objectsToUnlock.isEmpty())
+ {
+ return EMPTY_RESULT;
+ }
+
+ Set<LockState<OBJECT, CONTEXT>> lockStates = new HashSet<LockState<OBJECT, CONTEXT>>();
+
+ Iterator<? extends OBJECT> it = objectsToUnlock.iterator();
+ while (it.hasNext())
+ {
+ OBJECT o = it.next();
+ LockState<OBJECT, CONTEXT> lockState = objectToLockStateMap.get(o);
+
+ if (lockState == null)
+ {
+ continue;
+ }
+
+ for (LockType lockType : LockType.values())
+ {
+ while (lockState.canUnlock(lockType, context))
+ {
+ lockState.unlock(lockType, context);
+ lockStates.add(lockState);
+ }
+ }
+ }
+
+ for (LockState<OBJECT, CONTEXT> lockState : lockStates)
+ {
+ removeLockStateForContext(context, lockState);
+
+ if (lockState.hasNoLocks())
+ {
+ objectToLockStateMap.remove(lockState.getLockedObject());
+ }
+ }
+
+ notifyAll();
+
+ return new LinkedList<RWOLockManager.LockState<OBJECT, CONTEXT>>(lockStates);
+ }
+
public synchronized List<LockState<OBJECT, CONTEXT>> unlock2(LockType type, CONTEXT context,
Collection<? extends OBJECT> objectsToUnlock)
{