diff options
author | Caspar De Groot | 2011-08-18 02:24:31 +0000 |
---|---|---|
committer | Caspar De Groot | 2011-08-18 02:24:31 +0000 |
commit | b7e84a0e190445f303dc8fa918cd5a7c6c0670f6 (patch) | |
tree | 776782d6099f9228e8764ce57b692914e9b80812 /plugins/org.eclipse.emf.cdo/src/org/eclipse | |
parent | 8c9b3bb2192a53b7ee1eff6035462f04c20ba842 (diff) | |
download | cdo-b7e84a0e190445f303dc8fa918cd5a7c6c0670f6.tar.gz cdo-b7e84a0e190445f303dc8fa918cd5a7c6c0670f6.tar.xz cdo-b7e84a0e190445f303dc8fa918cd5a7c6c0670f6.zip |
[353691] Add lock notifications and lock caching
https://bugs.eclipse.org/bugs/show_bug.cgi?id=353691
Diffstat (limited to 'plugins/org.eclipse.emf.cdo/src/org/eclipse')
14 files changed, 577 insertions, 39 deletions
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOObject.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOObject.java index 24e65bfe08..c08fc07adf 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOObject.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOObject.java @@ -13,6 +13,7 @@ package org.eclipse.emf.cdo; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDTemp; import org.eclipse.emf.cdo.common.id.CDOWithID; +import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.revision.CDORevisionManager; import org.eclipse.emf.cdo.eresource.CDOResource; @@ -141,6 +142,13 @@ public interface CDOObject extends EObject, CDOWithID public CDOLock cdoWriteOption(); /** + * Returns the {@link CDOLockState} of this object. + * + * @since 4.1 + */ + public CDOLockState cdoLockState(); + + /** * Ensures that the revisions of the contained objects up to the given depth are in the local * {@link CDORevisionManager revision cache}. Subsequent access to the respective contained objects will not lead to * server round-trips after calling this method. diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOLocksChangedEvent.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOLocksChangedEvent.java new file mode 100644 index 0000000000..904dabbaaf --- /dev/null +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOLocksChangedEvent.java @@ -0,0 +1,24 @@ +/** + * 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.view; + +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; + +/** + * A {@link CDOViewEvent view event} fired when lock notifications are being received from a repository. + * {@link CDOView.Options#setLockNotificationEnabled(boolean)} must be enabled for this event to be fired. + * + * @author Caspar De Groot + * @since 4.1 + */ +public interface CDOLocksChangedEvent extends CDOViewEvent, CDOLockChangeInfo +{ +} diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOView.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOView.java index bfe7d060d3..4d74a8f3c2 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOView.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOView.java @@ -21,6 +21,7 @@ import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.util.CDOException; import org.eclipse.emf.cdo.eresource.CDOResource; @@ -34,6 +35,7 @@ import org.eclipse.emf.cdo.util.ReadOnlyException; import org.eclipse.net4j.util.collection.CloseableIterator; import org.eclipse.net4j.util.concurrent.IRWLockManager; import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; +import org.eclipse.net4j.util.event.IListener; import org.eclipse.net4j.util.event.INotifier; import org.eclipse.net4j.util.options.IOptions; import org.eclipse.net4j.util.options.IOptionsContainer; @@ -466,6 +468,27 @@ public interface CDOView extends CDOCommonView, CDOUpdatable, INotifier, IOption public void setInvalidationNotificationEnabled(boolean enabled); /** + * Returns <code>true</code> if this view will notify its {@link IListener listeners} about changes to the + * {@link CDOLockState lock states} of the objects in this view (due to lock operations in <i>other</i> views), + * <code>false</code> otherwise. + * + * @see CDOLocksChangedEvent + * @see CDOLockState + * @since 4.1 + */ + public boolean isLockNotificationEnabled(); + + /** + * Specifies whether this view will notify its {@link IListener listeners} about changes to the {@link CDOLockState + * lock states} of the objects in this view (due to lock operations in <i>other</i> views), or not. + * + * @see CDOLocksChangedEvent + * @see CDOLockState + * @since 4.1 + */ + public void setLockNotificationEnabled(boolean enabled); + + /** * Returns the current set of {@link CDOAdapterPolicy change subscription policies}. * * @return The current set of change subscription policies, never <code>null</code>. @@ -646,6 +669,14 @@ public interface CDOView extends CDOCommonView, CDOUpdatable, INotifier, IOption } /** + * @author Caspar De Groot + * @since 4.1 + */ + public interface LockNotificationEvent extends IOptionsEvent + { + } + + /** * An {@link IOptionsEvent options event} fired from view {@link CDOView#options() options} when the * {@link Options#setRevisionPrefetchingPolicy(CDORevisionPrefetchingPolicy) revision prefetching policy} option has * changed. diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java index e2e2aa0924..ffe5f921ce 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java @@ -15,6 +15,7 @@ import org.eclipse.emf.cdo.CDOLock; import org.eclipse.emf.cdo.CDOObject; import org.eclipse.emf.cdo.CDOState; import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.model.EMFUtil; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.eresource.CDOResource; @@ -63,6 +64,7 @@ import org.eclipse.emf.spi.cdo.InternalCDOObject; import org.eclipse.emf.spi.cdo.InternalCDOView; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.ListIterator; @@ -84,6 +86,8 @@ public class CDOObjectImpl extends EStoreEObjectImpl implements InternalCDOObjec private InternalCDORevision revision; + private CDOLockState lockState; + /** * CDO uses this list instead of eSettings for transient objects. EMF uses eSettings as cache. CDO deactivates the * cache but EMF still used eSettings to store list wrappers. CDO needs another place to store the real list with the @@ -184,17 +188,7 @@ public class CDOObjectImpl extends EStoreEObjectImpl implements InternalCDOObjec */ public CDOLock cdoReadLock() { - if (FSMUtil.isTransient(this)) - { - throw new IllegalStateException("Call CDOView.lockObjects() for transient object " + this); - } - - if (FSMUtil.isNew(this)) - { - return CDOLockImpl.NOOP; - } - - return new CDOLockImpl(this, LockType.READ); + return createCDOLock(LockType.READ); } /** @@ -202,6 +196,19 @@ public class CDOObjectImpl extends EStoreEObjectImpl implements InternalCDOObjec */ public CDOLock cdoWriteLock() { + return createCDOLock(LockType.WRITE); + } + + /** + * @since 4.1 + */ + public CDOLock cdoWriteOption() + { + return createCDOLock(LockType.OPTION); + } + + private CDOLock createCDOLock(LockType type) + { if (FSMUtil.isTransient(this)) { throw new IllegalStateException("Call CDOView.lockObjects() for transient object " + this); @@ -212,25 +219,31 @@ public class CDOObjectImpl extends EStoreEObjectImpl implements InternalCDOObjec return CDOLockImpl.NOOP; } - return new CDOLockImpl(this, LockType.WRITE); + return new CDOLockImpl(this, type); } /** * @since 4.1 */ - public CDOLock cdoWriteOption() + public synchronized CDOLockState cdoLockState() { - if (FSMUtil.isTransient(this)) + if (lockState == null) { - throw new IllegalStateException("Call CDOView.lockObjects() for transient object " + this); + if (!FSMUtil.isTransient(this) && !FSMUtil.isNew(this)) + { + lockState = view.getLockStates(Collections.singletonList(id))[0]; + } } - if (FSMUtil.isNew(this)) - { - return CDOLockImpl.NOOP; - } + return lockState; + } - return new CDOLockImpl(this, LockType.OPTION); + /** + * @since 4.1 + */ + public synchronized void cdoInternalSetLockState(CDOLockState lockState) + { + this.lockState = lockState; } public void cdoInternalSetID(CDOID id) diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java index 3678c01d21..e0be18394d 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java @@ -14,6 +14,7 @@ package org.eclipse.emf.internal.cdo.object; import org.eclipse.emf.cdo.CDOObject; import org.eclipse.emf.cdo.CDOState; import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.model.CDOModelUtil; import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; import org.eclipse.emf.cdo.common.model.CDOType; @@ -57,6 +58,7 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -95,6 +97,8 @@ public abstract class CDOLegacyWrapper extends CDOObjectWrapper protected InternalCDORevision revision; + protected CDOLockState lockState; + /** * It could happen that while <i>revisionToInstance()</i> is executed externally the <i>internalPostLoad()</i> method * will be called. This happens for example if <i>internalPostInvalidate()</i> is called. The leads to another @@ -121,6 +125,24 @@ public abstract class CDOLegacyWrapper extends CDOObjectWrapper return revision; } + public synchronized CDOLockState cdoLockState() + { + if (lockState == null) + { + if (!FSMUtil.isTransient(this) && !FSMUtil.isNew(this)) + { + lockState = view.getLockStates(Collections.singletonList(id))[0]; + } + } + + return lockState; + } + + public synchronized void cdoInternalSetLockState(CDOLockState lockState) + { + this.lockState = lockState; + } + @Override public CDOResourceImpl cdoResource() { diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLockImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLockImpl.java index 851c0a10cf..d161642a22 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLockImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLockImpl.java @@ -12,6 +12,8 @@ package org.eclipse.emf.internal.cdo.object; import org.eclipse.emf.cdo.CDOLock; +import org.eclipse.emf.cdo.common.lock.CDOLockOwner; +import org.eclipse.emf.cdo.common.lock.CDOLockUtil; import org.eclipse.emf.cdo.util.LockTimeoutException; import org.eclipse.net4j.util.WrappedException; @@ -33,14 +35,17 @@ public class CDOLockImpl implements CDOLock { public static final CDOLock NOOP = new NOOPLockImpl(); - private InternalCDOObject object; + private final InternalCDOObject object; - private LockType type; + private final LockType type; + + private final CDOLockOwner owner; public CDOLockImpl(InternalCDOObject object, LockType type) { this.object = object; this.type = type; + owner = CDOLockUtil.createLockOwner(object.cdoView()); } public LockType getType() @@ -50,7 +55,7 @@ public class CDOLockImpl implements CDOLock public boolean isLocked() { - return object.cdoView().isObjectLocked(object, type, false); + return object.cdoLockState().isLocked(type, owner, false); } /** @@ -58,7 +63,7 @@ public class CDOLockImpl implements CDOLock */ public boolean isLockedByOthers() { - return object.cdoView().isObjectLocked(object, type, true); + return object.cdoLockState().isLocked(type, owner, true); } public void lock() diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java index 4a39ec7d44..293f899465 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java @@ -27,6 +27,7 @@ import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDGenerator; import org.eclipse.emf.cdo.common.lob.CDOLobInfo; import org.eclipse.emf.cdo.common.lob.CDOLobStore; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; import org.eclipse.emf.cdo.common.model.CDOPackageUnit; import org.eclipse.emf.cdo.common.model.EMFUtil; import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator; @@ -89,6 +90,7 @@ import org.eclipse.net4j.util.WrappedException; import org.eclipse.net4j.util.collection.Pair; import org.eclipse.net4j.util.concurrent.IRWLockManager; import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; +import org.eclipse.net4j.util.concurrent.IRWOLockManager; import org.eclipse.net4j.util.concurrent.RWOLockManager; import org.eclipse.net4j.util.event.Event; import org.eclipse.net4j.util.event.EventUtil; @@ -183,7 +185,7 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme } }; - private IRWLockManager<CDOSessionImpl, Object> lockManager = new RWOLockManager<CDOSessionImpl, Object>(); + private IRWOLockManager<CDOSessionImpl, Object> lockManager = new RWOLockManager<CDOSessionImpl, Object>(); @ExcludeFromDump private Set<CDOSessionImpl> singletonCollection = Collections.singleton(this); @@ -715,17 +717,48 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme public boolean waitForUpdate(long updateTime, long timeoutMillis) { long end = timeoutMillis == NO_TIMEOUT ? Long.MAX_VALUE : System.currentTimeMillis() + timeoutMillis; - for (CDOView view : getViews()) + InternalCDOView views[] = getViews(); + if (views.length > 0) { - long viewTimeoutMillis = timeoutMillis == NO_TIMEOUT ? NO_TIMEOUT : end - System.currentTimeMillis(); - boolean ok = view.waitForUpdate(updateTime, viewTimeoutMillis); - if (!ok) + for (CDOView view : views) { - return false; + long viewTimeoutMillis = timeoutMillis == NO_TIMEOUT ? NO_TIMEOUT : end - System.currentTimeMillis(); + boolean ok = view.waitForUpdate(updateTime, viewTimeoutMillis); + if (!ok) + { + return false; + } } + + return true; } - return true; + // Session without views + for (;;) + { + synchronized (lastUpdateTimeLock) + { + if (lastUpdateTime >= updateTime) + { + return true; + } + + long now = System.currentTimeMillis(); + if (now >= end) + { + return false; + } + + try + { + lastUpdateTimeLock.wait(end - now); + } + catch (InterruptedException ex) + { + throw WrappedException.wrap(ex); + } + } + } } /** @@ -803,6 +836,14 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme } } + public void handleLockNotification(CDOLockChangeInfo lockChangeInfo) + { + for (InternalCDOView view : getViews()) + { + view.handleLockNotification(lockChangeInfo); + } + } + private void registerPackageUnits(List<CDOPackageUnit> packageUnits) { InternalCDOPackageRegistry packageRegistry = getPackageRegistry(); diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java index 875a77172d..c88715ae53 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java @@ -24,6 +24,7 @@ import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDProvider; import org.eclipse.emf.cdo.common.lob.CDOLob; import org.eclipse.emf.cdo.common.lob.CDOLobInfo; +import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.model.CDOPackageUnit; import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; @@ -384,6 +385,38 @@ public class DelegatingSessionProtocol extends Lifecycle implements CDOSessionPr } } + public CDOLockState[] getLockStates(int viewID, Collection<CDOID> ids) + { + int attempt = 0; + for (;;) + { + try + { + return delegate.getLockStates(viewID, ids); + } + catch (Exception ex) + { + handleException(++attempt, ex); + } + } + } + + public void enableLockNotifications(int viewID, boolean enable) + { + int attempt = 0; + for (;;) + { + try + { + delegate.enableLockNotifications(viewID, enable); + } + catch (Exception ex) + { + handleException(++attempt, ex); + } + } + } + public boolean isObjectLocked(CDOView view, CDOObject object, LockType lockType, boolean byOthers) { int attempt = 0; @@ -579,6 +612,7 @@ public class DelegatingSessionProtocol extends Lifecycle implements CDOSessionPr } } + @Deprecated public LockObjectsResult lockObjects(List<InternalCDORevision> viewedRevisions, int viewID, CDOBranch viewedBranch, LockType lockType, long timeout) throws InterruptedException { @@ -596,6 +630,60 @@ public class DelegatingSessionProtocol extends Lifecycle implements CDOSessionPr } } + /** + * @since 4.1 + */ + public LockObjectsResult lockObjects2(List<CDORevisionKey> revisionKeys, int viewID, CDOBranch viewedBranch, + LockType lockType, long timeout) throws InterruptedException + + { + int attempt = 0; + for (;;) + { + try + { + return delegate.lockObjects2(revisionKeys, viewID, viewedBranch, lockType, timeout); + } + catch (Exception ex) + { + handleException(++attempt, ex); + } + } + } + + public LockObjectsResult delegateLockObjects(String lockAreaID, List<CDORevisionKey> revisionKeys, + CDOBranch viewedBranch, LockType lockType, long timeout) throws InterruptedException + { + int attempt = 0; + for (;;) + { + try + { + return delegate.delegateLockObjects(lockAreaID, revisionKeys, viewedBranch, lockType, timeout); + } + catch (Exception ex) + { + handleException(++attempt, ex); + } + } + } + + public UnlockObjectsResult delegateUnlockObjects(String lockAreaID, Collection<CDOID> objectIDs, LockType lockType) + { + int attempt = 0; + for (;;) + { + try + { + return delegate.delegateUnlockObjects(lockAreaID, objectIDs, lockType); + } + catch (Exception ex) + { + handleException(++attempt, ex); + } + } + } + public void query(CDOView view, AbstractQueryIterator<?> queryResult) { int attempt = 0; @@ -665,14 +753,14 @@ public class DelegatingSessionProtocol extends Lifecycle implements CDOSessionPr } } - public void unlockObjects(CDOView view, Collection<? extends CDOObject> objects, LockType lockType) + public void unlockObjects(CDOView view, Collection<CDOID> objectIDs, LockType lockType) { int attempt = 0; for (;;) { try { - delegate.unlockObjects(view, objects, lockType); + delegate.unlockObjects(view, objectIDs, lockType); return; } catch (Exception ex) @@ -682,6 +770,22 @@ public class DelegatingSessionProtocol extends Lifecycle implements CDOSessionPr } } + public UnlockObjectsResult unlockObjects2(CDOView view, Collection<CDOID> objectIDs, LockType lockType) + { + int attempt = 0; + for (;;) + { + try + { + return delegate.unlockObjects2(view, objectIDs, lockType); + } + catch (Exception ex) + { + handleException(++attempt, ex); + } + } + } + public List<CDORemoteSession> getRemoteSessions(InternalCDORemoteSessionManager manager, boolean subscribe) { int attempt = 0; diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java index 0968432db1..2f81f19424 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java @@ -34,6 +34,7 @@ import org.eclipse.emf.cdo.common.id.CDOIDTemp; import org.eclipse.emf.cdo.common.id.CDOIDUtil; import org.eclipse.emf.cdo.common.lob.CDOLob; import org.eclipse.emf.cdo.common.lob.CDOLobStore; +import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.model.CDOModelUtil; import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; import org.eclipse.emf.cdo.common.model.CDOPackageUnit; @@ -2625,6 +2626,12 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa fireEvent(new FinishedEvent(CDOTransactionFinishedEvent.Type.COMMITTED, idMappings), listeners); } + + CDOLockState[] newLockStates = result.getNewLockStates(); + if (newLockStates != null) + { + updateLockStates(newLockStates); + } } catch (RuntimeException ex) { diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java index 5f4d77d889..7e69345d50 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java @@ -18,6 +18,11 @@ import org.eclipse.emf.cdo.CDOState; import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; +import org.eclipse.emf.cdo.common.lock.CDOLockOwner; +import org.eclipse.emf.cdo.common.lock.CDOLockState; +import org.eclipse.emf.cdo.common.lock.CDOLockUtil; +import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch; import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.revision.CDORevisionKey; @@ -36,6 +41,7 @@ import org.eclipse.emf.cdo.util.StaleRevisionLockException; import org.eclipse.emf.cdo.view.CDOAdapterPolicy; import org.eclipse.emf.cdo.view.CDOFeatureAnalyzer; import org.eclipse.emf.cdo.view.CDOInvalidationPolicy; +import org.eclipse.emf.cdo.view.CDOLocksChangedEvent; import org.eclipse.emf.cdo.view.CDORevisionPrefetchingPolicy; import org.eclipse.emf.cdo.view.CDOStaleReferencePolicy; import org.eclipse.emf.cdo.view.CDOView; @@ -75,6 +81,7 @@ import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.spi.cdo.CDOSessionProtocol; import org.eclipse.emf.spi.cdo.CDOSessionProtocol.LockObjectsResult; +import org.eclipse.emf.spi.cdo.CDOSessionProtocol.UnlockObjectsResult; import org.eclipse.emf.spi.cdo.FSMUtil; import org.eclipse.emf.spi.cdo.InternalCDOObject; import org.eclipse.emf.spi.cdo.InternalCDOSession; @@ -257,18 +264,18 @@ public class CDOViewImpl extends AbstractCDOView checkActive(); checkState(getTimeStamp() == CDOBranchPoint.UNSPECIFIED_DATE, "Locking not supported for historial views"); - List<InternalCDORevision> revisions = new LinkedList<InternalCDORevision>(); + List<CDORevisionKey> revisionKeys = new LinkedList<CDORevisionKey>(); for (CDOObject object : objects) { InternalCDORevision revision = getRevision(object); if (revision != null) { - revisions.add(revision); + revisionKeys.add(revision); } } CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); - LockObjectsResult result = sessionProtocol.lockObjects(revisions, viewID, getBranch(), lockType, timeout); + LockObjectsResult result = sessionProtocol.lockObjects2(revisionKeys, viewID, getBranch(), lockType, timeout); if (!result.isSuccessful()) { @@ -286,6 +293,8 @@ public class CDOViewImpl extends AbstractCDOView throw new AssertionError("Unexpected lock result state"); } + updateLockStates(result.getNewLockStates()); + if (result.isWaitForUpdate()) { if (!getSession().options().isPassiveUpdateEnabled()) @@ -299,6 +308,29 @@ public class CDOViewImpl extends AbstractCDOView } } + protected void updateLockStates(CDOLockState[] newLockStates) + { + for (CDOLockState lockState : newLockStates) + { + Object o = lockState.getLockedObject(); + CDOID id; + if (o instanceof CDOID) + { + id = (CDOID)o; + } + else + { + id = ((CDOIDAndBranch)o).getID(); + } + + InternalCDOObject obj = getObject(id, false); + if (obj != null) + { + obj.cdoInternalSetLockState(lockState); + } + } + } + protected InternalCDORevision getRevision(CDOObject object) { if (object.cdoState() == CDOState.NEW) @@ -321,8 +353,21 @@ public class CDOViewImpl extends AbstractCDOView public synchronized void unlockObjects(Collection<? extends CDOObject> objects, LockType lockType) { checkActive(); + + List<CDOID> objectIDs = null; + if (objects != null) + { + objectIDs = new LinkedList<CDOID>(); + for (CDOObject obj : objects) + { + objectIDs.add(obj.cdoID()); + } + } + CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); - sessionProtocol.unlockObjects(this, objects, lockType); + UnlockObjectsResult result = sessionProtocol.unlockObjects2(this, objectIDs, lockType); + + updateLockStates(result.getNewLockStates()); } /** @@ -439,6 +484,13 @@ public class CDOViewImpl extends AbstractCDOView return revisionManager.getRevision(id, branchPoint, initialChunkSize, CDORevision.DEPTH_NONE, loadOnDemand); } + public CDOLockState[] getLockStates(Collection<CDOID> ids) + { + CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); + CDOLockState[] lockStates = sessionProtocol.getLockStates(viewID, ids); + return lockStates; + } + private CDOBranchPoint getBranchPointForID(CDOID id) { // If this view's timestamp is something other than UNSPECIFIED_DATE, @@ -876,6 +928,38 @@ public class CDOViewImpl extends AbstractCDOView } } + public void handleLockNotification(CDOLockChangeInfo lockChangeInfo) + { + if (!options().isLockNotificationEnabled()) + { + return; + } + + // If lockChangeInfo pertains to a different view, do nothing. + if (!lockChangeInfo.getBranch().equals(getBranch())) + { + return; + } + + // If lockChangeInfo represents lock changes authored by this view itself, do nothing. + CDOLockOwner thisView = CDOLockUtil.createLockOwner(this); + if (lockChangeInfo.getLockOwner().equals(thisView)) + { + return; + } + + fireLocksChangedEvent(lockChangeInfo); + } + + private void fireLocksChangedEvent(CDOLockChangeInfo lockChangeInfo) + { + IListener[] listeners = getListeners(); + if (listeners != null) + { + fireEvent(new LocksChangedEvent(lockChangeInfo), listeners); + } + } + /** * @author Simon McDuff * @since 2.0 @@ -1304,6 +1388,47 @@ public class CDOViewImpl extends AbstractCDOView } /** + * @author Caspar De Groot + * @since 4.1 + */ + private final class LocksChangedEvent extends Event implements CDOLocksChangedEvent + { + private static final long serialVersionUID = 1L; + + private CDOLockChangeInfo lockChangeInfo; + + public LocksChangedEvent(CDOLockChangeInfo lockChangeInfo) + { + this.lockChangeInfo = lockChangeInfo; + } + + public CDOBranch getBranch() + { + return lockChangeInfo.getBranch(); + } + + public long getTimeStamp() + { + return lockChangeInfo.getTimeStamp(); + } + + public CDOLockOwner getLockOwner() + { + return lockChangeInfo.getLockOwner(); + } + + public CDOLockState[] getLockStates() + { + return lockChangeInfo.getLockStates(); + } + + public Operation getOperation() + { + return lockChangeInfo.getOperation(); + } + } + + /** * @author Eike Stepper * @since 2.0 */ @@ -1313,6 +1438,8 @@ public class CDOViewImpl extends AbstractCDOView private CDOInvalidationPolicy invalidationPolicy = CDOInvalidationPolicy.DEFAULT; + private boolean lockNotificationsEnabled; + private CDORevisionPrefetchingPolicy revisionPrefetchingPolicy = CDOUtil .createRevisionPrefetchingPolicy(NO_REVISION_PREFETCHING); @@ -1378,6 +1505,28 @@ public class CDOViewImpl extends AbstractCDOView fireEvent(event); } + public boolean isLockNotificationEnabled() + { + return lockNotificationsEnabled; + } + + public void setLockNotificationEnabled(boolean enabled) + { + IEvent event = null; + synchronized (CDOViewImpl.this) + { + if (enabled != lockNotificationsEnabled) + { + CDOSessionProtocol protocol = getSession().getSessionProtocol(); + protocol.enableLockNotifications(viewID, enabled); + lockNotificationsEnabled = enabled; + event = new LockNotificationEventImpl(); + } + } + + fireEvent(event); + } + public boolean hasChangeSubscriptionPolicies() { synchronized (CDOViewImpl.this) @@ -1662,6 +1811,19 @@ public class CDOViewImpl extends AbstractCDOView } /** + * @author Caspar De Groot + */ + private final class LockNotificationEventImpl extends OptionsEvent implements LockNotificationEvent + { + private static final long serialVersionUID = 1L; + + public LockNotificationEventImpl() + { + super(OptionsImpl.this); + } + } + + /** * @author Eike Stepper */ private final class RevisionPrefetchingPolicyEventImpl extends OptionsEvent implements diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java index 1032720deb..fdfc9111ed 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java @@ -24,6 +24,7 @@ import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDProvider; import org.eclipse.emf.cdo.common.lob.CDOLob; import org.eclipse.emf.cdo.common.lob.CDOLobInfo; +import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.model.CDOPackageUnit; import org.eclipse.emf.cdo.common.protocol.CDOProtocol; import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; @@ -45,6 +46,7 @@ import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager.RevisionLoader; import org.eclipse.emf.cdo.view.CDOView; +import org.eclipse.net4j.util.CheckUtil; import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; import org.eclipse.net4j.util.om.monitor.OMMonitor; @@ -131,15 +133,41 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo public boolean cancelQuery(int queryId); /** + * Use #lockObjects2 instead. + * * @since 4.0 + * @deprecated Not called anymore. */ + @Deprecated public LockObjectsResult lockObjects(List<InternalCDORevision> viewedRevisions, int viewID, CDOBranch viewedBranch, LockType lockType, long timeout) throws InterruptedException; /** + * @since 4.1 + */ + public LockObjectsResult lockObjects2(List<CDORevisionKey> revisionKeys, int viewID, CDOBranch viewedBranch, + LockType lockType, long timeout) throws InterruptedException; + + /** + * @since 4.1 + */ + public LockObjectsResult delegateLockObjects(String lockAreaID, List<CDORevisionKey> revisionKeys, + CDOBranch viewedBranch, LockType lockType, long timeout) throws InterruptedException; + + /** * @since 3.0 */ - public void unlockObjects(CDOView view, Collection<? extends CDOObject> objects, LockType lockType); + public void unlockObjects(CDOView view, Collection<CDOID> objectIDs, LockType lockType); + + /** + * @since 4.1 + */ + public UnlockObjectsResult unlockObjects2(CDOView view, Collection<CDOID> objectIDs, LockType lockType); + + /** + * @since 4.1 + */ + public UnlockObjectsResult delegateUnlockObjects(String lockAreaID, Collection<CDOID> objectIDs, LockType lockType); /** * @since 3.0 @@ -233,6 +261,16 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo CDORevisionHandler handler); /** + * @since 4.1 + */ + public CDOLockState[] getLockStates(int viewID, Collection<CDOID> ids); + + /** + * @since 4.1 + */ + public void enableLockNotifications(int viewID, boolean enable); + + /** * @author Eike Stepper * @since 3.0 * @noinstantiate This class is not intended to be instantiated by clients. @@ -606,6 +644,8 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo private CDOReferenceAdjuster referenceAdjuster; + private CDOLockState[] newLockStates; + /** * @since 4.0 */ @@ -697,6 +737,14 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo idMappings.put(oldID, newID); } + /** + * @since 4.1 + */ + public CDOLockState[] getNewLockStates() + { + return newLockStates; + } + protected PostCommitReferenceAdjuster createReferenceAdjuster() { return new PostCommitReferenceAdjuster(idProvider, new CDOIDMapper(idMappings)); @@ -735,6 +783,15 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo return idMapper.adjustReference(id, feature, index); } } + + /** + * @since 4.1 + */ + public void setNewLockStates(CDOLockState[] newLockStates) + { + CheckUtil.checkArg(newLockStates, "newLockStates"); + this.newLockStates = newLockStates; + } } /** @@ -752,14 +809,27 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo private CDORevisionKey[] staleRevisions; + private CDOLockState[] newLockStates; + + @Deprecated public LockObjectsResult(boolean successful, boolean timedOut, boolean waitForUpdate, long requiredTimestamp, CDORevisionKey[] staleRevisions) { + throw new AssertionError("Deprecated"); // TODO (CD) What to do about this?? + } + + /** + * @since 4.1 + */ + public LockObjectsResult(boolean successful, boolean timedOut, boolean waitForUpdate, long requiredTimestamp, + CDORevisionKey[] staleRevisions, CDOLockState[] newLockStates) + { this.successful = successful; this.timedOut = timedOut; this.waitForUpdate = waitForUpdate; this.requiredTimestamp = requiredTimestamp; this.staleRevisions = staleRevisions; + this.newLockStates = newLockStates; } public boolean isSuccessful() @@ -786,5 +856,31 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo { return staleRevisions; } + + /** + * @since 4.1 + */ + public CDOLockState[] getNewLockStates() + { + return newLockStates; + } + } + + /** + * @since 4.1 + */ + public static final class UnlockObjectsResult + { + private CDOLockState[] newLockStates; + + public UnlockObjectsResult(CDOLockState[] newLockStates) + { + this.newLockStates = newLockStates; + } + + public CDOLockState[] getNewLockStates() + { + return newLockStates; + } } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOObject.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOObject.java index ee269a96a8..4329baf19c 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOObject.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOObject.java @@ -7,13 +7,14 @@ * * Contributors: * Eike Stepper - initial API and implementation - * Martin Flügge - enhancements + * Martin Fl�gge - enhancements */ package org.eclipse.emf.spi.cdo; import org.eclipse.emf.cdo.CDOObject; import org.eclipse.emf.cdo.CDOState; import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.model.CDOPackageTypeRegistry.CDOObjectMarker; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; @@ -55,6 +56,11 @@ public interface InternalCDOObject extends CDOObject, InternalEObject, InternalC public CDOState cdoInternalSetState(CDOState state); + /** + * @since 4.1 + */ + public void cdoInternalSetLockState(CDOLockState lockState); + public InternalEObject cdoInternalInstance(); public EStructuralFeature cdoInternalDynamicFeature(int dynamicFeatureID); diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSession.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSession.java index c82f67d8ad..2f0459575c 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSession.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSession.java @@ -17,6 +17,7 @@ import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDGenerator; import org.eclipse.emf.cdo.common.lob.CDOLobStore; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.session.CDORepositoryInfo; @@ -180,6 +181,11 @@ public interface InternalCDOSession extends CDOSession, PackageProcessor, Packag public void handleCommitNotification(CDOCommitInfo commitInfo); /** + * @since 4.1 + */ + public void handleLockNotification(CDOLockChangeInfo lockChangeInfo); + + /** * @since 3.0 */ public void invalidate(CDOCommitInfo commitInfo, InternalCDOTransaction sender); diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOView.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOView.java index 345a1ae2ce..27ba5cc0b0 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOView.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOView.java @@ -15,6 +15,8 @@ import org.eclipse.emf.cdo.CDOState; import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDProvider; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; +import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; import org.eclipse.emf.cdo.common.revision.CDORevisionKey; import org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl; @@ -28,6 +30,7 @@ import org.eclipse.net4j.util.lifecycle.ILifecycle; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.ecore.EObject; +import java.util.Collection; import java.util.List; import java.util.Map; @@ -133,6 +136,16 @@ public interface InternalCDOView extends CDOView, CDOIDProvider, ILifecycle public boolean hasSubscription(CDOID id); + /** + * @since 4.1 + */ + public void handleLockNotification(CDOLockChangeInfo lockChangeInfo); + + /** + * @since 4.1 + */ + public CDOLockState[] getLockStates(Collection<CDOID> ids); + // /** // * Each time CDORevision or CDOState of an CDOObject is modified, ensure that no concurrent access is modifying it // at |