From d91b8908f8f2cfb84cb9ac258cf57c440970e739 Mon Sep 17 00:00:00 2001 From: Caspar De Groot Date: Thu, 1 Sep 2011 07:52:03 +0000 Subject: [351912] Lock coordination with SynchronizableRepositories https://bugs.eclipse.org/bugs/show_bug.cgi?id=351912 --- .../eclipse/emf/cdo/common/CDOCommonSession.java | 35 +++ .../org/eclipse/emf/cdo/common/CDOCommonView.java | 49 +++- .../emf/cdo/common/lock/CDOLockChangeInfo.java | 7 + .../cdo/common/lock/CDOLockChangeInfoHandler.java | 20 ++ .../eclipse/emf/cdo/common/lock/CDOLockOwner.java | 22 +- .../eclipse/emf/cdo/common/lock/CDOLockUtil.java | 71 +++++- .../cdo/common/lock/IDurableLockingManager.java | 12 +- .../emf/cdo/common/protocol/CDODataInput.java | 6 + .../emf/cdo/common/protocol/CDODataOutput.java | 6 + .../cdo/common/protocol/CDOProtocolConstants.java | 5 + .../cdo/internal/common/lock/CDOLockAreaImpl.java | 106 +++++++++ .../common/lock/CDOLockChangeInfoImpl.java | 12 +- .../cdo/internal/common/lock/CDOLockOwnerImpl.java | 21 +- .../cdo/internal/common/lock/CDOLockStateImpl.java | 51 +++-- .../internal/common/protocol/CDODataInputImpl.java | 46 +++- .../common/protocol/CDODataOutputImpl.java | 43 ++-- .../emf/cdo/spi/common/CDOReplicationContext.java | 7 +- .../emf/cdo/spi/common/CDOReplicationInfo.java | 9 +- .../net4j/CDONet4jSessionConfigurationImpl.java | 17 ++ .../cdo/internal/net4j/CDONet4jSessionImpl.java | 3 +- .../internal/net4j/protocol/CDOClientProtocol.java | 10 +- .../net4j/protocol/LockDelegationRequest.java | 6 +- .../net4j/protocol/LockNotificationIndication.java | 2 +- .../net4j/protocol/LockObjectsRequest.java | 14 +- .../net4j/protocol/OpenSessionRequest.java | 13 +- .../net4j/protocol/ReplicateRepositoryRequest.java | 25 ++- .../RepositoryStateNotificationIndication.java | 4 + .../cdo/server/internal/db/DBStoreAccessor.java | 5 + .../server/internal/db/DurableLockingManager.java | 8 +- .../internal/db4o/DB4ODurableLockingManager.java | 6 +- .../emf/cdo/server/internal/db4o/DB4OLockArea.java | 5 +- .../.settings/.api_filters | 8 + .../internal/net4j/protocol/CDOServerProtocol.java | 10 +- .../net4j/protocol/CommitDelegationIndication.java | 6 + .../protocol/EnableLockNotificationIndication.java | 2 +- .../net4j/protocol/LockDelegationIndication.java | 37 +-- .../net4j/protocol/LockObjectsIndication.java | 8 +- .../net4j/protocol/OpenSessionIndication.java | 10 + .../protocol/ReplicateRepositoryIndication.java | 56 +++++ .../RepositoryStateNotificationRequest.java | 11 +- .../internal/objectivity/schema/ObjyLockArea.java | 15 -- .../objectivity/schema/ObjyLockAreaManager.java | 4 +- .../.settings/.api_filters | 26 +++ .../emf/cdo/internal/server/LockManager.java | 114 +++++++++- .../emf/cdo/internal/server/Repository.java | 118 ++++++---- .../emf/cdo/internal/server/ServerCDOView.java | 4 +- .../eclipse/emf/cdo/internal/server/Session.java | 45 +++- .../emf/cdo/internal/server/SessionManager.java | 16 +- .../internal/server/TransactionCommitContext.java | 21 ++ .../org/eclipse/emf/cdo/internal/server/View.java | 14 +- .../embedded/EmbeddedServerSessionProtocol.java | 10 +- .../emf/cdo/internal/server/mem/MEMStore.java | 15 +- .../cdo/internal/server/mem/MEMStoreAccessor.java | 5 + .../server/syncing/RepositorySynchronizer.java | 65 +++++- .../server/syncing/SynchronizableRepository.java | 179 +++++++++++---- .../org/eclipse/emf/cdo/server/IStoreAccessor.java | 4 +- .../emf/cdo/server/ISynchronizableRepository.java | 10 + .../emf/cdo/spi/server/DurableLockArea.java | 23 +- .../emf/cdo/spi/server/ISessionProtocol.java | 11 + .../emf/cdo/spi/server/InternalLockManager.java | 11 + .../spi/server/InternalLockingManagerContext.java | 20 -- .../emf/cdo/spi/server/InternalRepository.java | 3 +- .../emf/cdo/spi/server/InternalSession.java | 12 + .../emf/cdo/spi/server/InternalSessionManager.java | 13 ++ .../server/InternalSynchronizableRepository.java | 3 +- .../eclipse/emf/cdo/spi/server/InternalView.java | 10 - .../eclipse/emf/cdo/spi/server/SyncingUtil.java | 60 +++++ .../emf/cdo/tests/LockingNotificationsTest.java | 185 +++++++++++++-- .../cdo/tests/config/impl/RepositoryConfig.java | 79 +++---- .../cdo/tests/offline/Bugzilla_312879_Test.java | 3 +- .../cdo/tests/offline/Bugzilla_319552_Test.java | 2 +- .../cdo/tests/offline/Bugzilla_325097_Test.java | 3 +- .../cdo/tests/offline/Bugzilla_326047_Test.java | 2 +- .../cdo/tests/offline/Bugzilla_328352_Test.java | 2 +- .../cdo/tests/offline/Bugzilla_329014_Test.java | 2 +- .../emf/cdo/tests/offline/FailoverTest.java | 20 +- .../emf/cdo/tests/offline/OfflineDelayed2Test.java | 3 +- .../emf/cdo/tests/offline/OfflineDelayedTest.java | 6 +- .../emf/cdo/tests/offline/OfflineLockingTest.java | 247 ++++++++++++++++++++- .../emf/cdo/tests/offline/OfflineRawTest.java | 6 +- .../eclipse/emf/cdo/tests/offline/OfflineTest.java | 14 +- .../eclipse/emf/cdo/tests/util/TestListener2.java | 54 ++++- .../cdo/tests/util/TestSessionConfiguration.java | 31 ++- plugins/org.eclipse.emf.cdo/.settings/.api_filters | 49 +++- .../emf/cdo/session/CDOSessionConfiguration.java | 11 + .../cdo/session/CDOSessionLocksChangedEvent.java | 26 +++ .../eclipse/emf/cdo/view/CDOLocksChangedEvent.java | 24 -- .../src/org/eclipse/emf/cdo/view/CDOView.java | 37 +-- .../emf/cdo/view/CDOViewLocksChangedEvent.java | 25 +++ .../cdo/session/CDOSessionConfigurationImpl.java | 20 ++ .../emf/internal/cdo/session/CDOSessionImpl.java | 43 +++- .../cdo/transaction/CDOTransactionImpl.java | 3 +- .../cdo/util/DefaultLocksChangedEvent.java | 77 +++++++ .../emf/internal/cdo/view/AbstractCDOView.java | 5 + .../eclipse/emf/internal/cdo/view/CDOViewImpl.java | 143 ++++++------ .../eclipse/emf/spi/cdo/InternalCDOSession.java | 2 +- .../org/eclipse/emf/spi/cdo/InternalCDOView.java | 31 +-- .../net4j/util/concurrent/RWOLockManager.java | 33 ++- .../org/eclipse/net4j/util/io/ExtendedIOUtil.java | 48 ++-- .../src-gen/templates/MenuCardTemplate.java | 124 +++++------ 100 files changed, 2287 insertions(+), 698 deletions(-) create mode 100644 plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockChangeInfoHandler.java create mode 100644 plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockAreaImpl.java delete mode 100644 plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockingManagerContext.java create mode 100644 plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/SyncingUtil.java create mode 100644 plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSessionLocksChangedEvent.java delete mode 100644 plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOLocksChangedEvent.java create mode 100644 plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOViewLocksChangedEvent.java create mode 100644 plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/util/DefaultLocksChangedEvent.java diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/CDOCommonSession.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/CDOCommonSession.java index 533044166a..4ef53d763a 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/CDOCommonSession.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/CDOCommonSession.java @@ -84,6 +84,16 @@ public interface CDOCommonSession extends IUserAware, IOptionsContainer, Closeab */ public void setPassiveUpdateMode(PassiveUpdateMode mode); + /** + * @since 4.1 + */ + public LockNotificationMode getLockNotificationMode(); + + /** + * @since 4.1 + */ + public void setLockNotificationMode(LockNotificationMode mode); + /** * Enumerates the possible {@link CDOCommonSession.Options#getPassiveUpdateMode() passive update modes} of a CDO * session. @@ -111,6 +121,31 @@ public interface CDOCommonSession extends IUserAware, IOptionsContainer, Closeab ADDITIONS } + /** + * Enumerates the possible {@link CDOCommonSession.Options#getLockNotificationMode() lock notification modes} of a + * CDO session. + * + * @since 4.1 + */ + public enum LockNotificationMode + { + /** + * This mode delivers no lock notifications + */ + OFF, + + /** + * This mode delivers lock notifications if one or more views have enabled them. + */ + IF_REQUIRED_BY_VIEWS, + + /** + * This mode always delivers lock notifications, even if no views have them enabled, and even if no views are + * open. + */ + ALWAYS + } + /** * An {@link IOptionsEvent options event} fired when the {@link PassiveUpdateMode passive update mode} of a CDO * session has changed. diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/CDOCommonView.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/CDOCommonView.java index f58ac44ccf..5834cb7e3f 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/CDOCommonView.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/CDOCommonView.java @@ -11,9 +11,14 @@ package org.eclipse.emf.cdo.common; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.revision.CDORevisionProvider; import org.eclipse.net4j.util.collection.Closeable; +import org.eclipse.net4j.util.event.IListener; +import org.eclipse.net4j.util.options.IOptions; +import org.eclipse.net4j.util.options.IOptionsContainer; +import org.eclipse.net4j.util.options.IOptionsEvent; /** * Abstracts the information about CDO views that is common to both client and server side. @@ -23,7 +28,7 @@ import org.eclipse.net4j.util.collection.Closeable; * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface CDOCommonView extends CDOBranchPoint, CDORevisionProvider, Closeable +public interface CDOCommonView extends CDOBranchPoint, CDORevisionProvider, IOptionsContainer, Closeable { public int getViewID(); @@ -38,4 +43,46 @@ public interface CDOCommonView extends CDOBranchPoint, CDORevisionProvider, Clos * @since 4.0 */ public String getDurableLockingID(); + + /** + * Returns the {@link Options options} of this view. + * + * @since 4.1 + */ + public Options options(); + + /** + * Encapsulates the configuration options of CDO views that are common to both client and server side. + * + * @author Eike Stepper + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + * @since 4.1 + */ + public interface Options extends IOptions + { + /** + * Returns true 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 other views), + * false otherwise. + * + * @see CDOLockState + */ + 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 other views), or not. + * + * @see CDOLockState + */ + public void setLockNotificationEnabled(boolean enabled); + + /** + * @author Caspar De Groot + */ + public interface LockNotificationEvent extends IOptionsEvent + { + } + } } diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockChangeInfo.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockChangeInfo.java index 0307719d42..b3a55b4833 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockChangeInfo.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockChangeInfo.java @@ -13,6 +13,8 @@ package org.eclipse.emf.cdo.common.lock; import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; + /** * Represents a change in the lock state of a set of objects. Instances are meant to be sent from the server to the * client for the purpose of notifying the latter. @@ -50,6 +52,11 @@ public interface CDOLockChangeInfo extends CDOBranchPoint */ public Operation getOperation(); + /** + * @return the type of locks that were affected by the lock operation + */ + public LockType getLockType(); + /** * Enumerates the possible locking operations. * diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockChangeInfoHandler.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockChangeInfoHandler.java new file mode 100644 index 0000000000..118f973516 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockChangeInfoHandler.java @@ -0,0 +1,20 @@ +/** + * 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.common.lock; + +/** + * @author Caspar De Groot + * @since 4.1 + */ +public interface CDOLockChangeInfoHandler +{ + public void handleLockChangeInfo(CDOLockChangeInfo lockChangeInfo); +} diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockOwner.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockOwner.java index 012fc15117..b5b42d29ff 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockOwner.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockOwner.java @@ -31,25 +31,7 @@ public interface CDOLockOwner */ public int getViewID(); - /** - * A constant to represent on the client-side that a lock's owner cannot be represented as a viewID-sessionID pair. - */ - public static final CDOLockOwner UNKNOWN = new CDOLockOwner() - { - public int getViewID() - { - return 0; - } - - public int getSessionID() - { - return 0; - } + public String getDurableLockingID(); - @Override - public String toString() - { - return CDOLockOwner.class.getSimpleName() + ".UNKNOWN"; - } - }; + public boolean isDurableView(); } diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockUtil.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockUtil.java index d36d9078b6..3250f5adfa 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockUtil.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/CDOLockUtil.java @@ -13,15 +13,25 @@ package org.eclipse.emf.cdo.common.lock; import org.eclipse.emf.cdo.common.CDOCommonSession; import org.eclipse.emf.cdo.common.CDOCommonView; 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.Operation; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade; import org.eclipse.emf.cdo.internal.common.lock.CDOLockChangeInfoImpl; import org.eclipse.emf.cdo.internal.common.lock.CDOLockOwnerImpl; import org.eclipse.emf.cdo.internal.common.lock.CDOLockStateImpl; +import org.eclipse.emf.cdo.internal.common.lock.CDOLockAreaImpl; import org.eclipse.emf.cdo.spi.common.lock.InternalCDOLockState; import org.eclipse.net4j.util.CheckUtil; +import org.eclipse.net4j.util.HexUtil; +import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; import org.eclipse.net4j.util.concurrent.RWOLockManager.LockState; +import java.util.Map; +import java.util.Random; + /** * Various static methods that may help with classes related to CDO locks. * @@ -47,9 +57,23 @@ public final class CDOLockUtil for (CDOCommonView view : lockState.getReadLockOwners()) { - int sessionID = view.getSession().getSessionID(); - int viewID = view.getViewID(); - CDOLockOwner owner = new CDOLockOwnerImpl(sessionID, viewID); + String durableLockingID = view.getDurableLockingID(); + int sessionID, viewID; + CDOCommonSession session = view.getSession(); + boolean isDurableView = session == null; + if (isDurableView) + { + // TODO (CD) Use some symbolic constants here? + sessionID = 0; + viewID = 0; + } + else + { + sessionID = session.getSessionID(); + viewID = view.getViewID(); + } + + CDOLockOwner owner = new CDOLockOwnerImpl(sessionID, viewID, durableLockingID, isDurableView); cdoLockState.addReadLockOwner(owner); } @@ -73,25 +97,54 @@ public final class CDOLockUtil public static CDOLockOwner createLockOwner(CDOCommonView view) { CDOCommonSession session = view.getSession(); + String durableLockingID = view.getDurableLockingID(); if (session != null) { int sessionID = session.getSessionID(); int viewID = view.getViewID(); - return new CDOLockOwnerImpl(sessionID, viewID); + return new CDOLockOwnerImpl(sessionID, viewID, durableLockingID, false); } - return CDOLockOwner.UNKNOWN; + + CheckUtil.checkNull(durableLockingID, "durableLockingID"); + return new CDOLockOwnerImpl(0, 0, durableLockingID, true); // TODO (CD) Symbolic constants? } public static CDOLockChangeInfo createLockChangeInfo(long timestamp, CDOLockOwner lockOwner, CDOBranch branch, - Operation op, CDOLockState[] cdoLockStates) + Operation op, LockType lockType, CDOLockState[] cdoLockStates) { - return new CDOLockChangeInfoImpl(branch.getPoint(timestamp), lockOwner, cdoLockStates, op); + return new CDOLockChangeInfoImpl(branch.getPoint(timestamp), lockOwner, cdoLockStates, op, lockType); } public static CDOLockChangeInfo createLockChangeInfo(long timestamp, CDOCommonView view, CDOBranch viewedBranch, - Operation op, CDOLockState[] cdoLockStates) + Operation op, LockType lockType, CDOLockState[] cdoLockStates) { CDOLockOwner lockOwner = createLockOwner(view); - return createLockChangeInfo(timestamp, lockOwner, viewedBranch, op, cdoLockStates); + return createLockChangeInfo(timestamp, lockOwner, viewedBranch, op, lockType, cdoLockStates); + } + + public static LockArea createLockArea(String durableLockingID, String userID, CDOBranchPoint branchPoint, + boolean readOnly, Map locks) + { + return new CDOLockAreaImpl(durableLockingID, userID, branchPoint, readOnly, locks); + } + + public static LockArea createLockArea(String durableLockingID) + { + return new CDOLockAreaImpl(durableLockingID); + } + + public static String createDurableLockingID() + { + return createDurableLockingID(LockArea.DEFAULT_DURABLE_LOCKING_ID_BYTES); + } + + public static String createDurableLockingID(int bytes) + { + byte[] buffer = new byte[bytes]; + + Random random = new Random(System.currentTimeMillis()); + random.nextBytes(buffer); + + return HexUtil.bytesToHex(buffer); } } diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/IDurableLockingManager.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/IDurableLockingManager.java index 5343f8f91a..6300d643d4 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/IDurableLockingManager.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/IDurableLockingManager.java @@ -28,7 +28,7 @@ import java.util.Map; public interface IDurableLockingManager { public LockArea createLockArea(String userID, CDOBranchPoint branchPoint, boolean readOnly, - Map locks); + Map locks) throws LockAreaAlreadyExistsException; /** * Returns the {@link LockArea lock area} specified by the given durableLockingID, never null. @@ -52,6 +52,11 @@ public interface IDurableLockingManager */ public interface LockArea extends CDOBranchPoint { + /** + * @since 4.1 + */ + public static final int DEFAULT_DURABLE_LOCKING_ID_BYTES = 32; + public String getDurableLockingID(); public String getUserID(); @@ -60,6 +65,11 @@ public interface IDurableLockingManager public Map getLocks(); + /** + * @since 4.1 + */ + public boolean isDeleted(); + /** * A call-back interface for handling {@link LockArea lock area} objects. * diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataInput.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataInput.java index acab6ac3ea..9b29f86a4c 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataInput.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataInput.java @@ -22,6 +22,7 @@ import org.eclipse.emf.cdo.common.id.CDOIDReference; 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.IDurableLockingManager.LockArea; import org.eclipse.emf.cdo.common.model.CDOClassifierRef; import org.eclipse.emf.cdo.common.model.CDOPackageInfo; import org.eclipse.emf.cdo.common.model.CDOPackageUnit; @@ -153,4 +154,9 @@ public interface CDODataInput extends ExtendedDataInput * @since 4.1 */ public CDOLockState readCDOLockState() throws IOException; + + /** + * @since 4.1 + */ + public LockArea readCDOLockArea() throws IOException; } diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataOutput.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataOutput.java index 9c040d46fe..f0fcfcc251 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataOutput.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataOutput.java @@ -23,6 +23,7 @@ import org.eclipse.emf.cdo.common.id.CDOIDReference; 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.IDurableLockingManager.LockArea; import org.eclipse.emf.cdo.common.model.CDOClassifierRef; import org.eclipse.emf.cdo.common.model.CDOPackageInfo; import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; @@ -159,4 +160,9 @@ public interface CDODataOutput extends ExtendedDataOutput * @since 4.1 */ public void writeCDOLockOwner(CDOLockOwner lockOwner) throws IOException; + + /** + * @since 4.1 + */ + public void writeCDOLockArea(LockArea lockArea) throws IOException; } diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOProtocolConstants.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOProtocolConstants.java index 722b158ca9..af623cafb9 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOProtocolConstants.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOProtocolConstants.java @@ -324,4 +324,9 @@ public interface CDOProtocolConstants * @since 3.0 */ public static final byte REPLICATE_COMMIT = 2; + + /** + * @since 4.1 + */ + public static final byte REPLICATE_LOCKAREA = 3; } diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockAreaImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockAreaImpl.java new file mode 100644 index 0000000000..4baa364851 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockAreaImpl.java @@ -0,0 +1,106 @@ +/** + * 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: + * Eike Stepper - initial API and implementation + * Caspar De Groot - maintenance + */ +package org.eclipse.emf.cdo.internal.common.lock; + +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.IDurableLockingManager.LockArea; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade; + +import java.text.MessageFormat; +import java.util.Map; + +/** + * @author Eike Stepper + * @since 4.1 + * @noextend This interface is not intended to be extended by clients. + */ +public class CDOLockAreaImpl implements LockArea +{ + public static final int DEFAULT_DURABLE_LOCKING_ID_BYTES = 32; + + private final String durableLockingID; + + private final String userID; + + private final CDOBranchPoint branchPoint; + + private final boolean readOnly; + + private final Map locks; + + private final boolean deleted; + + public CDOLockAreaImpl(String durableLockingID, String userID, CDOBranchPoint branchPoint, boolean readOnly, + Map locks) + { + this.durableLockingID = durableLockingID; + this.userID = userID; + this.branchPoint = branchPoint; + this.readOnly = readOnly; + this.locks = locks; + deleted = false; + } + + public CDOLockAreaImpl(String durableLockingID) + { + this.durableLockingID = durableLockingID; + userID = null; + branchPoint = null; + readOnly = false; + locks = null; + deleted = true; + } + + public String getDurableLockingID() + { + return durableLockingID; + } + + public String getUserID() + { + return userID; + } + + public CDOBranch getBranch() + { + return branchPoint.getBranch(); + } + + public long getTimeStamp() + { + return branchPoint.getTimeStamp(); + } + + public boolean isReadOnly() + { + return readOnly; + } + + public Map getLocks() + { + return locks; + } + + @Override + public String toString() + { + return MessageFormat.format("DurableLockArea\nid={0}\nuser={1}\nbranchPoint={2}\nreadOnly={3}\nlocks={4}", + durableLockingID, userID, branchPoint, readOnly, locks); + } + + public boolean isDeleted() + { + return deleted; + } +} diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockChangeInfoImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockChangeInfoImpl.java index 70c4c0a65f..e8a7a16b62 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockChangeInfoImpl.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockChangeInfoImpl.java @@ -16,6 +16,8 @@ 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.net4j.util.concurrent.IRWLockManager.LockType; + /** * @author Caspar De Groot */ @@ -29,13 +31,16 @@ public class CDOLockChangeInfoImpl implements CDOLockChangeInfo private final Operation operation; + private final LockType lockType; + public CDOLockChangeInfoImpl(CDOBranchPoint branchPoint, CDOLockOwner lockOwner, CDOLockState[] lockStates, - Operation operation) + Operation operation, LockType lockType) { this.branchPoint = branchPoint; this.lockOwner = lockOwner; this.lockStates = lockStates; this.operation = operation; + this.lockType = lockType; } public CDOBranch getBranch() @@ -62,4 +67,9 @@ public class CDOLockChangeInfoImpl implements CDOLockChangeInfo { return operation; } + + public LockType getLockType() + { + return lockType; + } } diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockOwnerImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockOwnerImpl.java index 3509e5fb46..29821d056b 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockOwnerImpl.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockOwnerImpl.java @@ -23,10 +23,16 @@ public class CDOLockOwnerImpl implements CDOLockOwner private final int viewID; - public CDOLockOwnerImpl(int sessionID, int viewID) + private final String durableLockingID; + + private final boolean isDurableView; + + public CDOLockOwnerImpl(int sessionID, int viewID, String durableLockingID, boolean isDurableView) { this.sessionID = sessionID; this.viewID = viewID; + this.durableLockingID = durableLockingID; + this.isDurableView = isDurableView; } public int getSessionID() @@ -39,6 +45,16 @@ public class CDOLockOwnerImpl implements CDOLockOwner return viewID; } + public String getDurableLockingID() + { + return durableLockingID; + } + + public boolean isDurableView() + { + return isDurableView; + } + @Override public int hashCode() { @@ -66,9 +82,8 @@ public class CDOLockOwnerImpl implements CDOLockOwner public String toString() { StringBuilder builder = new StringBuilder("CDOLockOwner["); - builder.append("session="); builder.append(sessionID); - builder.append(", view="); + builder.append(':'); builder.append(viewID); builder.append(']'); return builder.toString(); diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockStateImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockStateImpl.java index 3520709d0a..e3d5e33661 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockStateImpl.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/lock/CDOLockStateImpl.java @@ -58,12 +58,18 @@ public class CDOLockStateImpl implements InternalCDOLockState private boolean isReadLocked(CDOLockOwner by, boolean others) { - if (readLockOwners.size() == 0) + int n = readLockOwners.size(); + if (n == 0) { return false; } - return readLockOwners.contains(by) ^ others; + if (!others) + { + return readLockOwners.contains(by); + } + + return true; } private boolean isWriteLocked(CDOLockOwner by, boolean others) @@ -91,6 +97,16 @@ public class CDOLockStateImpl implements InternalCDOLockState return Collections.unmodifiableSet(readLockOwners); } + public void addReadLockOwner(CDOLockOwner lockOwner) + { + readLockOwners.add(lockOwner); + } + + public boolean removeReadLockOwner(CDOLockOwner lockOwner) + { + return readLockOwners.remove(lockOwner); + } + public CDOLockOwner getWriteLockOwner() { return writeLockOwner; @@ -119,12 +135,12 @@ public class CDOLockStateImpl implements InternalCDOLockState @Override public String toString() { - StringBuilder builder = new StringBuilder("CDOLockState[lockedObject="); + StringBuilder builder = new StringBuilder("CDOLockState\nlockedObject="); builder.append(lockedObject); + builder.append("\nreadLockOwners="); if (readLockOwners.size() > 0) { - builder.append(", read="); boolean first = true; for (CDOLockOwner lockOwner : readLockOwners) { @@ -142,30 +158,17 @@ public class CDOLockStateImpl implements InternalCDOLockState builder.deleteCharAt(builder.length() - 1); } - - if (writeLockOwner != null) + else { - builder.append(", write="); - builder.append(writeLockOwner); + builder.append("NONE"); } - if (writeOptionOwner != null) - { - builder.append(", option="); - builder.append(writeOptionOwner); - } + builder.append("\nwriteLockOwner="); + builder.append(writeLockOwner != null ? writeLockOwner : "NONE"); - builder.append(']'); - return builder.toString(); - } + builder.append("\nwriteOptionOwner="); + builder.append(writeOptionOwner != null ? writeOptionOwner : "NONE"); - public void addReadLockOwner(CDOLockOwner lockOwner) - { - readLockOwners.add(lockOwner); - } - - public boolean removeReadLockOwner(CDOLockOwner lockOwner) - { - return readLockOwners.remove(lockOwner); + return builder.toString(); } } diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataInputImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataInputImpl.java index d64799ed3e..8928db8eb3 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataInputImpl.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataInputImpl.java @@ -30,6 +30,8 @@ import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation; import org.eclipse.emf.cdo.common.lock.CDOLockOwner; import org.eclipse.emf.cdo.common.lock.CDOLockState; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade; import org.eclipse.emf.cdo.common.model.CDOClassifierRef; import org.eclipse.emf.cdo.common.model.CDOModelUtil; import org.eclipse.emf.cdo.common.model.CDOPackageInfo; @@ -56,6 +58,7 @@ import org.eclipse.emf.cdo.internal.common.id.CDOIDExternalImpl; import org.eclipse.emf.cdo.internal.common.id.CDOIDObjectLongImpl; import org.eclipse.emf.cdo.internal.common.id.CDOIDTempObjectExternalImpl; import org.eclipse.emf.cdo.internal.common.id.CDOIDTempObjectImpl; +import org.eclipse.emf.cdo.internal.common.lock.CDOLockAreaImpl; import org.eclipse.emf.cdo.internal.common.lock.CDOLockChangeInfoImpl; import org.eclipse.emf.cdo.internal.common.lock.CDOLockOwnerImpl; import org.eclipse.emf.cdo.internal.common.lock.CDOLockStateImpl; @@ -95,7 +98,9 @@ import org.eclipse.emf.ecore.util.FeatureMapUtil; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @author Eike Stepper @@ -268,6 +273,7 @@ public abstract class CDODataInputImpl extends ExtendedDataInput.Delegating impl CDOBranchPoint branchPoint = readCDOBranchPoint(); CDOLockOwner lockOwner = readCDOLockOwner(); Operation operation = readEnum(Operation.class); + LockType lockType = readCDOLockType(); int n = readInt(); CDOLockState[] lockStates = new CDOLockState[n]; @@ -276,19 +282,36 @@ public abstract class CDODataInputImpl extends ExtendedDataInput.Delegating impl lockStates[i] = readCDOLockState(); } - return new CDOLockChangeInfoImpl(branchPoint, lockOwner, lockStates, operation); + return new CDOLockChangeInfoImpl(branchPoint, lockOwner, lockStates, operation, lockType); } - public CDOLockOwner readCDOLockOwner() throws IOException + public LockArea readCDOLockArea() throws IOException { - boolean isUnknown = !readBoolean(); - if (isUnknown) + String durableLockingID = readString(); + CDOBranch branch = readCDOBranch(); + long timestamp = readLong(); + String userID = readString(); + boolean readOnly = readBoolean(); + + int nLockStates = readInt(); + Map locks = new HashMap(); + for (int i = 0; i < nLockStates; i++) { - return CDOLockOwner.UNKNOWN; + CDOID key = readCDOID(); + LockGrade value = readEnum(LockGrade.class); + locks.put(key, value); } + + return new CDOLockAreaImpl(durableLockingID, userID, branch.getPoint(timestamp), readOnly, locks); + } + + public CDOLockOwner readCDOLockOwner() throws IOException + { int session = readInt(); int view = readInt(); - return new CDOLockOwnerImpl(session, view); + String lockAreaID = readString(); + boolean isDurableView = readBoolean(); + return new CDOLockOwnerImpl(session, view, lockAreaID, isDurableView); } public CDOLockState readCDOLockState() throws IOException @@ -330,6 +353,11 @@ public abstract class CDODataInputImpl extends ExtendedDataInput.Delegating impl return lockState; } + public LockType readCDOLockType() throws IOException + { + return readEnum(LockType.class); + } + public CDOID readCDOID() throws IOException { byte ordinal = readByte(); @@ -587,12 +615,6 @@ public abstract class CDODataInputImpl extends ExtendedDataInput.Delegating impl return readCDORevisionOrPrimitive(); } - public LockType readCDOLockType() throws IOException - { - byte b = readByte(); - return b == 0 ? null : LockType.values()[b - 1]; - } - protected StringIO getPackageURICompressor() { return StringIO.DIRECT; diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataOutputImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataOutputImpl.java index 9ceed91d70..ef3bcdaa6b 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataOutputImpl.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataOutputImpl.java @@ -22,6 +22,8 @@ import org.eclipse.emf.cdo.common.id.CDOIDReference; 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.IDurableLockingManager.LockArea; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade; import org.eclipse.emf.cdo.common.model.CDOClassifierRef; import org.eclipse.emf.cdo.common.model.CDOModelUtil; import org.eclipse.emf.cdo.common.model.CDOPackageInfo; @@ -66,6 +68,7 @@ import org.eclipse.emf.ecore.util.FeatureMapUtil; import java.io.IOException; import java.text.MessageFormat; import java.util.Collection; +import java.util.Map; import java.util.Set; /** @@ -227,6 +230,7 @@ public abstract class CDODataOutputImpl extends ExtendedDataOutput.Delegating im writeCDOBranchPoint(lockChangeInfo); writeCDOLockOwner(lockChangeInfo.getLockOwner()); writeEnum(lockChangeInfo.getOperation()); + writeCDOLockType(lockChangeInfo.getLockType()); CDOLockState[] lockStates = lockChangeInfo.getLockStates(); writeInt(lockStates.length); @@ -236,20 +240,30 @@ public abstract class CDODataOutputImpl extends ExtendedDataOutput.Delegating im } } - public void writeCDOLockOwner(CDOLockOwner lockOwner) throws IOException + public void writeCDOLockArea(LockArea lockArea) throws IOException { - if (lockOwner != CDOLockOwner.UNKNOWN) - { - writeBoolean(true); - writeInt(lockOwner.getSessionID()); - writeInt(lockOwner.getViewID()); - } - else + writeString(lockArea.getDurableLockingID()); + writeCDOBranch(lockArea.getBranch()); + writeLong(lockArea.getTimeStamp()); + writeString(lockArea.getUserID()); + writeBoolean(lockArea.isReadOnly()); + + writeInt(lockArea.getLocks().size()); + for (Map.Entry entry : lockArea.getLocks().entrySet()) { - writeBoolean(false); + writeCDOID(entry.getKey()); + writeEnum(entry.getValue()); } } + public void writeCDOLockOwner(CDOLockOwner lockOwner) throws IOException + { + writeInt(lockOwner.getSessionID()); + writeInt(lockOwner.getViewID()); + writeString(lockOwner.getDurableLockingID()); + writeBoolean(lockOwner.isDurableView()); + } + public void writeCDOLockState(CDOLockState lockState) throws IOException { Object o = lockState.getLockedObject(); @@ -298,6 +312,11 @@ public abstract class CDODataOutputImpl extends ExtendedDataOutput.Delegating im } } + public void writeCDOLockType(LockType lockType) throws IOException + { + writeEnum(lockType); + } + public void writeCDOID(CDOID id) throws IOException { if (id == null) @@ -516,12 +535,6 @@ public abstract class CDODataOutputImpl extends ExtendedDataOutput.Delegating im } } - public void writeCDOLockType(LockType lockType) throws IOException - { - int b = lockType == null ? 0 : lockType.ordinal() + 1; - writeByte(b); - } - public CDOPackageRegistry getPackageRegistry() { return null; diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/CDOReplicationContext.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/CDOReplicationContext.java index 8a8c330f67..5c16082075 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/CDOReplicationContext.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/CDOReplicationContext.java @@ -12,11 +12,14 @@ package org.eclipse.emf.cdo.spi.common; import org.eclipse.emf.cdo.common.branch.CDOBranchHandler; import org.eclipse.emf.cdo.common.commit.CDOCommitInfoHandler; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager; /** * @author Eike Stepper - * @since 3.0 + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. */ -public interface CDOReplicationContext extends CDOReplicationInfo, CDOBranchHandler, CDOCommitInfoHandler +public interface CDOReplicationContext extends CDOReplicationInfo, CDOBranchHandler, CDOCommitInfoHandler, + IDurableLockingManager.LockArea.Handler { } diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/CDOReplicationInfo.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/CDOReplicationInfo.java index 0dde488948..0267e3c46c 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/CDOReplicationInfo.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/CDOReplicationInfo.java @@ -7,16 +7,23 @@ * * Contributors: * Eike Stepper - initial API and implementation + * Caspar De Groot - maintenance */ package org.eclipse.emf.cdo.spi.common; /** * @author Eike Stepper - * @since 3.0 + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. */ public interface CDOReplicationInfo { public int getLastReplicatedBranchID(); public long getLastReplicatedCommitTime(); + + /** + * @since 4.1 + */ + public String[] getLockAreaIDs(); } diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionConfigurationImpl.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionConfigurationImpl.java index ec77a73c52..253877a9b0 100644 --- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionConfigurationImpl.java +++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionConfigurationImpl.java @@ -250,6 +250,23 @@ public class CDONet4jSessionConfigurationImpl extends CDOSessionConfigurationImp return rootResourceID; } + public void setRootResourceID(CDOID rootResourceID) + { + // The rootResourceID may only be set if it is currently null + if (this.rootResourceID == null || this.rootResourceID.isNull()) + { + this.rootResourceID = rootResourceID; + } + else if (this.rootResourceID != null && this.rootResourceID.equals(rootResourceID)) + { + // Do nothing; it is the same. + } + else + { + throw new IllegalStateException("rootResourceID must not be changed unless it is null"); + } + } + public boolean isSupportingAudits() { return supportingAudits; diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionImpl.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionImpl.java index 7cea690ca0..62ab03c6e2 100644 --- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionImpl.java +++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionImpl.java @@ -235,7 +235,8 @@ public class CDONet4jSessionImpl extends CDOSessionImpl implements org.eclipse.e // TODO (CD) The next call is on the CDOClientProtocol; shouldn't it be on the DelegatingSessionProtocol instead? OpenSessionResult result = protocol.openSession(repositoryName, options().isPassiveUpdateEnabled(), options() - .getPassiveUpdateMode()); + .getPassiveUpdateMode(), options().getLockNotificationMode()); + setSessionID(result.getSessionID()); setUserID(result.getUserID()); setLastUpdateTime(result.getLastUpdateTime()); diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java index 9ba6ae8b50..956ed5199e 100644 --- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java +++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java @@ -11,6 +11,7 @@ package org.eclipse.emf.cdo.internal.net4j.protocol; import org.eclipse.emf.cdo.CDOObject; +import org.eclipse.emf.cdo.common.CDOCommonSession.Options.LockNotificationMode; import org.eclipse.emf.cdo.common.CDOCommonSession.Options.PassiveUpdateMode; import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.branch.CDOBranchHandler; @@ -97,9 +98,10 @@ public class CDOClientProtocol extends SignalProtocol implements CDO } public OpenSessionResult openSession(String repositoryName, boolean passiveUpdateEnabled, - PassiveUpdateMode passiveUpdateMode) + PassiveUpdateMode passiveUpdateMode, LockNotificationMode lockNotificationMode) { - return send(new OpenSessionRequest(this, repositoryName, passiveUpdateEnabled, passiveUpdateMode)); + return send(new OpenSessionRequest(this, repositoryName, passiveUpdateEnabled, passiveUpdateMode, + lockNotificationMode)); } public void disablePassiveUpdate() @@ -229,7 +231,7 @@ public class CDOClientProtocol extends SignalProtocol implements CDO { revisionKeys.add(rev); } - + return lockObjects2(revisionKeys, viewID, viewedBranch, lockType, timeout); } @@ -241,7 +243,7 @@ public class CDOClientProtocol extends SignalProtocol implements CDO try { - return new LockObjectsRequest(this, revisionKeys, viewID, viewedBranch, lockType, timeout).send(); + return new LockObjectsRequest(this, revisionKeys, viewID, lockType, timeout).send(); } catch (RemoteException ex) { diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockDelegationRequest.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockDelegationRequest.java index 08be5b6615..dccc18ee02 100644 --- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockDelegationRequest.java +++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockDelegationRequest.java @@ -27,17 +27,21 @@ public class LockDelegationRequest extends LockObjectsRequest { private String lockAreaID; + private CDOBranch viewedBranch; + public LockDelegationRequest(CDOClientProtocol protocol, String lockAreaID, List revisionKeys, CDOBranch viewedBranch, LockType lockType, long timeout) { - super(protocol, CDOProtocolConstants.SIGNAL_LOCK_DELEGATION, revisionKeys, 0, viewedBranch, lockType, timeout); + super(protocol, CDOProtocolConstants.SIGNAL_LOCK_DELEGATION, revisionKeys, 0, lockType, timeout); this.lockAreaID = lockAreaID; + this.viewedBranch = viewedBranch; } @Override protected void requesting(CDODataOutput out) throws IOException { out.writeString(lockAreaID); + out.writeCDOBranch(viewedBranch); super.requesting(out); } } diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockNotificationIndication.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockNotificationIndication.java index 2d4175c8ef..9ad8ae9754 100644 --- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockNotificationIndication.java +++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockNotificationIndication.java @@ -33,6 +33,6 @@ public class LockNotificationIndication extends CDOClientIndication { CDOLockChangeInfo lockChangeInfo = in.readCDOLockChangeInfo(); InternalCDOSession session = getSession(); - session.handleLockNotification(lockChangeInfo); + session.handleLockNotification(lockChangeInfo, null); } } diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockObjectsRequest.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockObjectsRequest.java index 2d8e9325d9..b01f0a0b0d 100644 --- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockObjectsRequest.java +++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LockObjectsRequest.java @@ -11,7 +11,6 @@ **************************************************************************/ package org.eclipse.emf.cdo.internal.net4j.protocol; -import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.protocol.CDODataInput; import org.eclipse.emf.cdo.common.protocol.CDODataOutput; @@ -39,19 +38,14 @@ public class LockObjectsRequest extends CDOClientRequest private List revisionKeys; - /** - * The branch being viewed - */ - private CDOBranch viewedBranch; - public LockObjectsRequest(CDOClientProtocol protocol, List revisionKeys, int viewID, - CDOBranch viewedBranch, LockType lockType, long timeout) + LockType lockType, long timeout) { - this(protocol, CDOProtocolConstants.SIGNAL_LOCK_OBJECTS, revisionKeys, viewID, viewedBranch, lockType, timeout); + this(protocol, CDOProtocolConstants.SIGNAL_LOCK_OBJECTS, revisionKeys, viewID, lockType, timeout); } protected LockObjectsRequest(CDOClientProtocol protocol, short signalID, List revisionKeys, - int viewID, CDOBranch viewedBranch, LockType lockType, long timeout) + int viewID, LockType lockType, long timeout) { super(protocol, signalID); @@ -59,7 +53,6 @@ public class LockObjectsRequest extends CDOClientRequest this.lockType = lockType; this.timeout = timeout; this.revisionKeys = revisionKeys; - this.viewedBranch = viewedBranch; } @Override @@ -68,7 +61,6 @@ public class LockObjectsRequest extends CDOClientRequest out.writeInt(viewID); out.writeCDOLockType(lockType); out.writeLong(timeout); - out.writeCDOBranch(viewedBranch); out.writeInt(revisionKeys.size()); for (CDORevisionKey revKey : revisionKeys) diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/OpenSessionRequest.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/OpenSessionRequest.java index 601496df3f..f7ba9581ba 100644 --- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/OpenSessionRequest.java +++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/OpenSessionRequest.java @@ -13,6 +13,7 @@ package org.eclipse.emf.cdo.internal.net4j.protocol; import org.eclipse.emf.cdo.common.CDOCommonRepository; import org.eclipse.emf.cdo.common.CDOCommonRepository.IDGenerationLocation; +import org.eclipse.emf.cdo.common.CDOCommonSession.Options.LockNotificationMode; import org.eclipse.emf.cdo.common.CDOCommonSession.Options.PassiveUpdateMode; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOID.ObjectType; @@ -46,15 +47,18 @@ public class OpenSessionRequest extends CDOClientRequestWithMonitoring { out.writeInt(context.getLastReplicatedBranchID()); out.writeLong(context.getLastReplicatedCommitTime()); + + String[] lockAreaIDs = context.getLockAreaIDs(); + out.writeInt(lockAreaIDs.length); + for (int i = 0; i < lockAreaIDs.length; i++) + { + out.writeString(lockAreaIDs[i]); + } } @Override @@ -58,8 +67,22 @@ public class ReplicateRepositoryRequest extends CDOClientRequest context.handleCommitInfo(in.readCDOCommitInfo()); break; + case CDOProtocolConstants.REPLICATE_LOCKAREA: + boolean deleted = !in.readBoolean(); + if (deleted) + { + String deletedLockAreaID = in.readString(); + LockArea area = CDOLockUtil.createLockArea(deletedLockAreaID); + context.handleLockArea(area); + } + else + { + context.handleLockArea(in.readCDOLockArea()); + } + break; + default: - throw new IOException("Invalid replicate opcode: " + opcode); + throw new IllegalStateException("Invalid replicate opcode: " + opcode); } } } diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/RepositoryStateNotificationIndication.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/RepositoryStateNotificationIndication.java index 1831d3c7af..557e043461 100644 --- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/RepositoryStateNotificationIndication.java +++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/RepositoryStateNotificationIndication.java @@ -12,6 +12,7 @@ package org.eclipse.emf.cdo.internal.net4j.protocol; import org.eclipse.emf.cdo.common.CDOCommonRepository; +import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.protocol.CDODataInput; import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; import org.eclipse.emf.cdo.internal.net4j.CDONet4jSessionConfigurationImpl.RepositoryInfo; @@ -34,10 +35,13 @@ public class RepositoryStateNotificationIndication extends CDOClientIndication { CDOCommonRepository.State oldState = in.readEnum(CDOCommonRepository.State.class); CDOCommonRepository.State newState = in.readEnum(CDOCommonRepository.State.class); + CDOID rootResourceID = in.readCDOID(); CDONet4jSessionImpl session = (CDONet4jSessionImpl)getSession(); RepositoryInfo repositoryInfo = (RepositoryInfo)session.getRepositoryInfo(); repositoryInfo.setState(newState); + repositoryInfo.setRootResourceID(rootResourceID); + session.handleRepositoryStateChanged(oldState, newState); } } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java index dfad801b99..bc1481a8bd 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java @@ -1301,6 +1301,11 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, return manager.createLockArea(this, durableLockingID, userID, branchPoint, readOnly, locks); } + public void updateLockArea(LockArea lockArea) + { + throw new RuntimeException("TODO (CD)"); // TODO (CD) + } + public LockArea getLockArea(String durableLockingID) throws LockAreaNotFoundException { DurableLockingManager manager = getStore().getDurableLockingManager(); diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java index 789e425a75..1e2183698d 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java @@ -12,6 +12,7 @@ package org.eclipse.emf.cdo.server.internal.db; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.lock.CDOLockUtil; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea.Handler; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockAreaAlreadyExistsException; @@ -22,7 +23,6 @@ import org.eclipse.emf.cdo.server.db.IIDHandler; import org.eclipse.emf.cdo.server.db.IPreparedStatementCache; import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability; import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager; -import org.eclipse.emf.cdo.spi.server.DurableLockArea; import org.eclipse.emf.cdo.spi.server.InternalLockManager; import org.eclipse.net4j.db.DBException; @@ -179,7 +179,7 @@ public class DurableLockingManager extends Lifecycle accessor.getConnection().commit(); - return new DurableLockArea(durableLockingID, userID, branchPoint, readOnly, locks); + return CDOLockUtil.createLockArea(durableLockingID, userID, branchPoint, readOnly, locks); } catch (SQLException ex) { @@ -531,7 +531,7 @@ public class DurableLockingManager extends Lifecycle { for (;;) { - String durableLockingID = DurableLockArea.createDurableLockingID(); + String durableLockingID = CDOLockUtil.createDurableLockingID(); try { @@ -550,7 +550,7 @@ public class DurableLockingManager extends Lifecycle { CDOBranchPoint branchPoint = branchManager.getBranch(branchID).getPoint(timeStamp); Map lockMap = getLockMap(accessor, durableLockingID); - return new DurableLockArea(durableLockingID, userID, branchPoint, readOnly, lockMap); + return CDOLockUtil.createLockArea(durableLockingID, userID, branchPoint, readOnly, lockMap); } private Map getLockMap(DBStoreAccessor accessor, String durableLockingID) diff --git a/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4ODurableLockingManager.java b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4ODurableLockingManager.java index 2efdf7e275..64b03cbd22 100644 --- a/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4ODurableLockingManager.java +++ b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4ODurableLockingManager.java @@ -12,11 +12,11 @@ package org.eclipse.emf.cdo.server.internal.db4o; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.lock.CDOLockUtil; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea.Handler; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockAreaNotFoundException; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade; -import org.eclipse.emf.cdo.spi.server.DurableLockArea; import org.eclipse.emf.cdo.spi.server.InternalLockManager; import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; @@ -42,7 +42,7 @@ public class DB4ODurableLockingManager extends Lifecycle boolean readOnly, Map locks) { String durableLockingID = getNextDurableLockingID(accessor); - LockArea lockArea = new DurableLockArea(durableLockingID, userID, branchPoint, readOnly, locks); + LockArea lockArea = CDOLockUtil.createLockArea(durableLockingID, userID, branchPoint, readOnly, locks); storeLockArea(accessor, lockArea); return lockArea; } @@ -183,7 +183,7 @@ public class DB4ODurableLockingManager extends Lifecycle { for (;;) { - String durableLockingID = DurableLockArea.createDurableLockingID(); + String durableLockingID = CDOLockUtil.createDurableLockingID(); try { diff --git a/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OLockArea.java b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OLockArea.java index 35d248e751..92e5d02e13 100644 --- a/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OLockArea.java +++ b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OLockArea.java @@ -15,10 +15,10 @@ import org.eclipse.emf.cdo.common.branch.CDOBranchManager; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.lock.CDOLockUtil; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade; import org.eclipse.emf.cdo.server.db4o.IDB4OStore; -import org.eclipse.emf.cdo.spi.server.DurableLockArea; import java.util.HashMap; import java.util.LinkedList; @@ -82,7 +82,8 @@ public class DB4OLockArea lockMap.put(cdoid, lockGrade); } - LockArea lockArea = new DurableLockArea(primitive.id, primitive.userID, branchpoint, primitive.readOnly, lockMap); + LockArea lockArea = CDOLockUtil.createLockArea(primitive.id, primitive.userID, branchpoint, primitive.readOnly, + lockMap); map.put(lockArea, primitive); return lockArea; } diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/.settings/.api_filters b/plugins/org.eclipse.emf.cdo.server.net4j/.settings/.api_filters index dcf823f69d..a491d67f25 100644 --- a/plugins/org.eclipse.emf.cdo.server.net4j/.settings/.api_filters +++ b/plugins/org.eclipse.emf.cdo.server.net4j/.settings/.api_filters @@ -8,4 +8,12 @@ + + + + + + + + diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java index a0fc0cbb82..c3c7d4f8db 100644 --- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java +++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java @@ -16,6 +16,7 @@ package org.eclipse.emf.cdo.server.internal.net4j.protocol; import org.eclipse.emf.cdo.common.CDOCommonRepository; import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; import org.eclipse.emf.cdo.server.IRepositoryProvider; @@ -94,12 +95,19 @@ public class CDOServerProtocol extends SignalProtocol implement } } + @Deprecated public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState) throws Exception + { + sendRepositoryStateNotification(oldState, newState, null); + } + + public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState, + CDOID rootResourceID) throws Exception { if (LifecycleUtil.isActive(getChannel())) { - new RepositoryStateNotificationRequest(this, oldState, newState).sendAsync(); + new RepositoryStateNotificationRequest(this, oldState, newState, rootResourceID).sendAsync(); } else { diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CommitDelegationIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CommitDelegationIndication.java index 1118f85a44..680d4e88f8 100644 --- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CommitDelegationIndication.java +++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CommitDelegationIndication.java @@ -35,6 +35,12 @@ public class CommitDelegationIndication extends CommitTransactionIndication super(protocol, CDOProtocolConstants.SIGNAL_COMMIT_DELEGATION); } + @Override + protected void indicating(CDODataInput in, OMMonitor monitor) throws Exception + { + super.indicating(in, monitor); + } + @Override protected void initializeCommitContext(CDODataInput in) throws Exception { diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/EnableLockNotificationIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/EnableLockNotificationIndication.java index 34ca52a802..5c95ae8ee1 100644 --- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/EnableLockNotificationIndication.java +++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/EnableLockNotificationIndication.java @@ -34,7 +34,7 @@ public class EnableLockNotificationIndication extends CDOServerIndication boolean enable = in.readBoolean(); InternalView view = getSession().getView(viewID); - view.setLockNotificationEnabled(enable); + view.options().setLockNotificationEnabled(enable); } @Override diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockDelegationIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockDelegationIndication.java index eaa67fd485..50322c5a03 100644 --- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockDelegationIndication.java +++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockDelegationIndication.java @@ -11,8 +11,6 @@ package org.eclipse.emf.cdo.server.internal.net4j.protocol; import org.eclipse.emf.cdo.common.branch.CDOBranch; -import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; -import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockAreaNotFoundException; import org.eclipse.emf.cdo.common.protocol.CDODataInput; import org.eclipse.emf.cdo.common.protocol.CDODataOutput; import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; @@ -20,8 +18,7 @@ import org.eclipse.emf.cdo.server.IView; import org.eclipse.emf.cdo.spi.server.InternalLockManager; import org.eclipse.emf.cdo.spi.server.InternalSession; import org.eclipse.emf.cdo.spi.server.InternalView; - -import org.eclipse.net4j.util.CheckUtil; +import org.eclipse.emf.cdo.spi.server.SyncingUtil; import java.io.IOException; @@ -34,6 +31,8 @@ public class LockDelegationIndication extends LockObjectsIndication private String lockAreaID; + private CDOBranch viewedBranch; + public LockDelegationIndication(CDOServerProtocol protocol) { super(protocol, CDOProtocolConstants.SIGNAL_LOCK_DELEGATION); @@ -43,6 +42,7 @@ public class LockDelegationIndication extends LockObjectsIndication protected void indicating(CDODataInput in) throws IOException { lockAreaID = in.readString(); + viewedBranch = in.readCDOBranch(); super.indicating(in); } @@ -60,35 +60,14 @@ public class LockDelegationIndication extends LockObjectsIndication } @Override - protected IView getView(int viewID, CDOBranch viewedBranch) + protected IView getView(int viewID) { - // The view needs a lockArea... - InternalLockManager lockManager = getRepository().getLockManager(); - InternalSession session = getSession(); - LockArea lockArea; - - try - { - lockArea = lockManager.getLockArea(lockAreaID); - - // If we get here, the lockArea already exists. - view = (InternalView)lockManager.openView(session, InternalSession.TEMP_VIEW_ID, true, lockAreaID); - } - catch (LockAreaNotFoundException e) - { - // If we get here, the lockArea does not yet exist on the master, so we open - // a view without a lockArea first, then create a lockArea with the given ID, - // and associate it with the view. - view = session.openView(InternalSession.TEMP_VIEW_ID, viewedBranch.getHead()); - lockArea = lockManager.createLockArea(view, lockAreaID); - view.setDurableLockingID(lockAreaID); - } - // The viewID received as an argument, is the ID of the client's view, which // does not exist on the master. So we ignore this argument and open a new // view instead. - CheckUtil.checkState(lockAreaID.equals(lockArea.getDurableLockingID()), "lockAreaID has incorrect value"); - + InternalLockManager lockManager = getRepository().getLockManager(); + InternalSession session = getSession(); + view = SyncingUtil.openViewWithLockArea(session, lockManager, viewedBranch, lockAreaID); return view; } } diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockObjectsIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockObjectsIndication.java index b61cc1cf8b..4484526c62 100644 --- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockObjectsIndication.java +++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LockObjectsIndication.java @@ -12,7 +12,6 @@ */ package org.eclipse.emf.cdo.server.internal.net4j.protocol; -import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.protocol.CDODataInput; import org.eclipse.emf.cdo.common.protocol.CDODataOutput; @@ -53,7 +52,6 @@ public class LockObjectsIndication extends CDOServerWriteIndication int viewID = in.readInt(); LockType lockType = in.readCDOLockType(); long timeout = in.readLong(); - CDOBranch viewedBranch = in.readCDOBranch(); int nRevisions = in.readInt(); List revisionKeys = new LinkedList(); @@ -63,11 +61,11 @@ public class LockObjectsIndication extends CDOServerWriteIndication } InternalRepository repository = getRepository(); - IView view = getView(viewID, viewedBranch); - result = repository.lock((InternalView)view, lockType, revisionKeys, viewedBranch, timeout); + IView view = getView(viewID); + result = repository.lock((InternalView)view, lockType, revisionKeys, timeout); } - protected IView getView(int viewID, CDOBranch viewedBranch) + protected IView getView(int viewID) { return getSession().getView(viewID); } diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/OpenSessionIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/OpenSessionIndication.java index 7d8a9962d4..fa7d727384 100644 --- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/OpenSessionIndication.java +++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/OpenSessionIndication.java @@ -10,6 +10,7 @@ */ package org.eclipse.emf.cdo.server.internal.net4j.protocol; +import org.eclipse.emf.cdo.common.CDOCommonSession.Options.LockNotificationMode; import org.eclipse.emf.cdo.common.CDOCommonSession.Options.PassiveUpdateMode; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.model.CDOPackageUnit; @@ -42,6 +43,8 @@ public class OpenSessionIndication extends CDOServerIndicationWithMonitoring private PassiveUpdateMode passiveUpdateMode; + private LockNotificationMode lockNotificationMode; + private InternalRepository repository; private InternalSession session; @@ -83,6 +86,12 @@ public class OpenSessionIndication extends CDOServerIndicationWithMonitoring { TRACER.format("Read passiveUpdateMode: {0}", passiveUpdateMode); //$NON-NLS-1$ } + + lockNotificationMode = in.readEnum(LockNotificationMode.class); + if (TRACER.isEnabled()) + { + TRACER.format("Read lockNotificationMode: {0}", lockNotificationMode); //$NON-NLS-1$ + } } @Override @@ -105,6 +114,7 @@ public class OpenSessionIndication extends CDOServerIndicationWithMonitoring session = sessionManager.openSession(protocol); session.setPassiveUpdateEnabled(passiveUpdateEnabled); session.setPassiveUpdateMode(passiveUpdateMode); + session.setLockNotificationMode(lockNotificationMode); protocol.setInfraStructure(session); if (TRACER.isEnabled()) diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/ReplicateRepositoryIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/ReplicateRepositoryIndication.java index 1b0315f99a..d39b40a9ee 100644 --- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/ReplicateRepositoryIndication.java +++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/ReplicateRepositoryIndication.java @@ -12,6 +12,7 @@ package org.eclipse.emf.cdo.server.internal.net4j.protocol; import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; import org.eclipse.emf.cdo.common.protocol.CDODataInput; import org.eclipse.emf.cdo.common.protocol.CDODataOutput; import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; @@ -20,6 +21,8 @@ import org.eclipse.emf.cdo.spi.common.CDOReplicationContext; import org.eclipse.net4j.util.WrappedException; import java.io.IOException; +import java.util.HashSet; +import java.util.Set; /** * @author Eike Stepper @@ -30,6 +33,8 @@ public class ReplicateRepositoryIndication extends CDOServerReadIndication private long lastReplicatedCommitTime; + private String[] lockAreaIDs; + public ReplicateRepositoryIndication(CDOServerProtocol protocol) { super(protocol, CDOProtocolConstants.SIGNAL_REPLICATE_REPOSITORY); @@ -40,11 +45,32 @@ public class ReplicateRepositoryIndication extends CDOServerReadIndication { lastReplicatedBranchID = in.readInt(); lastReplicatedCommitTime = in.readLong(); + lockAreaIDs = new String[in.readInt()]; + for (int i = 0; i < lockAreaIDs.length; i++) + { + lockAreaIDs[i] = in.readString(); + } + } + + private Set createLockAreaIDSet() + { + Set idSet = new HashSet(lockAreaIDs.length); + for (String id : lockAreaIDs) + { + idSet.add(id); + } + return idSet; } @Override protected void responding(final CDODataOutput out) throws IOException { + // We will remove IDs from this set as we process lockAreas one by one; + // what remains in this set at the end are the lockAreas that the client + // has, but we don't have, which means that they were removed. + // + final Set lockAreaIDSet = createLockAreaIDSet(); + getRepository().replicate(new CDOReplicationContext() { public int getLastReplicatedBranchID() @@ -57,6 +83,11 @@ public class ReplicateRepositoryIndication extends CDOServerReadIndication return lastReplicatedCommitTime; } + public String[] getLockAreaIDs() + { + return lockAreaIDs; + } + public void handleBranch(CDOBranch branch) { try @@ -82,8 +113,33 @@ public class ReplicateRepositoryIndication extends CDOServerReadIndication throw WrappedException.wrap(ex); } } + + public boolean handleLockArea(LockArea lockArea) + { + try + { + out.writeByte(CDOProtocolConstants.REPLICATE_LOCKAREA); + out.writeBoolean(true); + out.writeCDOLockArea(lockArea); + lockAreaIDSet.remove(lockArea.getDurableLockingID()); + return true; + } + catch (IOException ex) + { + throw WrappedException.wrap(ex); + } + } }); + // The IDs that are still in the lockAreaIDSet, must be the IDs of lockAreas that have + // been removed. + for (String deletedLockAreaID : lockAreaIDSet) + { + out.writeByte(CDOProtocolConstants.REPLICATE_LOCKAREA); + out.writeBoolean(false); + out.writeString(deletedLockAreaID); + } + out.writeByte(CDOProtocolConstants.REPLICATE_FINISHED); } } diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/RepositoryStateNotificationRequest.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/RepositoryStateNotificationRequest.java index a2835c2522..05d12fad25 100644 --- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/RepositoryStateNotificationRequest.java +++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/RepositoryStateNotificationRequest.java @@ -13,6 +13,7 @@ package org.eclipse.emf.cdo.server.internal.net4j.protocol; import org.eclipse.emf.cdo.common.CDOCommonRepository; +import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.protocol.CDODataOutput; import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; @@ -23,16 +24,19 @@ import java.io.IOException; */ public class RepositoryStateNotificationRequest extends CDOServerRequest { - private CDOCommonRepository.State oldState; + private final CDOCommonRepository.State oldState; - private CDOCommonRepository.State newState; + private final CDOCommonRepository.State newState; + + private final CDOID rootResourceID; public RepositoryStateNotificationRequest(CDOServerProtocol serverProtocol, CDOCommonRepository.State oldState, - CDOCommonRepository.State newState) + CDOCommonRepository.State newState, CDOID rootResourceID) { super(serverProtocol, CDOProtocolConstants.SIGNAL_REPOSITORY_STATE_NOTIFICATION); this.oldState = oldState; this.newState = newState; + this.rootResourceID = rootResourceID; } @Override @@ -40,5 +44,6 @@ public class RepositoryStateNotificationRequest extends CDOServerRequest { out.writeEnum(oldState); out.writeEnum(newState); + out.writeCDOID(rootResourceID); } } diff --git a/plugins/org.eclipse.emf.cdo.server.objectivity/src/org/eclipse/emf/cdo/server/internal/objectivity/schema/ObjyLockArea.java b/plugins/org.eclipse.emf.cdo.server.objectivity/src/org/eclipse/emf/cdo/server/internal/objectivity/schema/ObjyLockArea.java index 9a2303cea3..c2eb781cae 100644 --- a/plugins/org.eclipse.emf.cdo.server.objectivity/src/org/eclipse/emf/cdo/server/internal/objectivity/schema/ObjyLockArea.java +++ b/plugins/org.eclipse.emf.cdo.server.objectivity/src/org/eclipse/emf/cdo/server/internal/objectivity/schema/ObjyLockArea.java @@ -164,19 +164,4 @@ public class ObjyLockArea extends ooObj durableLockingID, userID, branchPoint, readOnly, readLockSet.size(), writeLockSet.size(), readWriteLockSet.size()); } - - // public static String createDurableLockingID() - // { - // return createDurableLockingID(DEFAULT_DURABLE_LOCKING_ID_BYTES); - // } - // - // public static String createDurableLockingID(int bytes) - // { - // byte[] buffer = new byte[bytes]; - // - // Random random = new Random(System.currentTimeMillis()); - // random.nextBytes(buffer); - // - // return HexUtil.bytesToHex(buffer); - // } } diff --git a/plugins/org.eclipse.emf.cdo.server.objectivity/src/org/eclipse/emf/cdo/server/internal/objectivity/schema/ObjyLockAreaManager.java b/plugins/org.eclipse.emf.cdo.server.objectivity/src/org/eclipse/emf/cdo/server/internal/objectivity/schema/ObjyLockAreaManager.java index 959f7b8a5b..80943e5f4c 100644 --- a/plugins/org.eclipse.emf.cdo.server.objectivity/src/org/eclipse/emf/cdo/server/internal/objectivity/schema/ObjyLockAreaManager.java +++ b/plugins/org.eclipse.emf.cdo.server.objectivity/src/org/eclipse/emf/cdo/server/internal/objectivity/schema/ObjyLockAreaManager.java @@ -11,10 +11,10 @@ package org.eclipse.emf.cdo.server.internal.objectivity.schema; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.lock.CDOLockUtil; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea.Handler; import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager; -import org.eclipse.emf.cdo.spi.server.DurableLockArea; import com.objy.db.app.Iterator; import com.objy.db.app.ooId; @@ -73,7 +73,7 @@ public class ObjyLockAreaManager extends ooObj ObjyBranch objyBranch = objyLockArea.getBranch(); CDOBranchPoint branchPoint = branchManager.getBranch(objyBranch.getBranchId()) .getPoint(objyLockArea.getTimeStamp()); - return new DurableLockArea(objyLockArea.getDurableLockingID(), objyLockArea.getUserID(), branchPoint, + return CDOLockUtil.createLockArea(objyLockArea.getDurableLockingID(), objyLockArea.getUserID(), branchPoint, objyLockArea.isReadOnly(), objyLockArea.getLocks()); } diff --git a/plugins/org.eclipse.emf.cdo.server/.settings/.api_filters b/plugins/org.eclipse.emf.cdo.server/.settings/.api_filters index 9e39d0d361..833c77689b 100644 --- a/plugins/org.eclipse.emf.cdo.server/.settings/.api_filters +++ b/plugins/org.eclipse.emf.cdo.server/.settings/.api_filters @@ -10,6 +10,12 @@ + + + + + + @@ -28,6 +34,12 @@ + + + + + + @@ -100,6 +112,12 @@ + + + + + + @@ -286,6 +304,14 @@ + + + + + + + + diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/LockManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/LockManager.java index e6fe19fb5d..19d20940e8 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/LockManager.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/LockManager.java @@ -12,6 +12,7 @@ */ package org.eclipse.emf.cdo.internal.server; +import org.eclipse.emf.cdo.common.CDOCommonView; import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.id.CDOID; @@ -32,6 +33,7 @@ import org.eclipse.emf.cdo.spi.server.InternalRepository; import org.eclipse.emf.cdo.spi.server.InternalStore; import org.eclipse.emf.cdo.spi.server.InternalView; +import org.eclipse.net4j.util.CheckUtil; import org.eclipse.net4j.util.ImplementationError; import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump; import org.eclipse.net4j.util.WrappedException; @@ -41,6 +43,7 @@ import org.eclipse.net4j.util.container.IContainer; import org.eclipse.net4j.util.event.IListener; import org.eclipse.net4j.util.lifecycle.ILifecycle; import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter; +import org.eclipse.net4j.util.options.IOptionsContainer; import java.text.MessageFormat; import java.util.ArrayList; @@ -60,6 +63,8 @@ public class LockManager extends RWOLockManager implements Intern private Map openViews = new HashMap(); + private Map durableViews = new HashMap(); + @ExcludeFromDump private transient IListener sessionListener = new ContainerEventAdapter() { @@ -112,7 +117,7 @@ public class LockManager extends RWOLockManager implements Intern public synchronized Object getLockEntryObject(Object key) { LockState lockState = getObjectToLocksMap().get(key); - return lockState.getLockedObject(); + return lockState == null ? null : lockState.getLockedObject(); } public Object getLockKey(CDOID id, CDOBranch branch) @@ -438,7 +443,7 @@ public class LockManager extends RWOLockManager implements Intern /** * @author Eike Stepper */ - private final class DurableView implements IView + private final class DurableView implements IView, CDOCommonView.Options { private String durableLockingID; @@ -525,6 +530,43 @@ public class LockManager extends RWOLockManager implements Intern { return MessageFormat.format("DurableView[{0}]", durableLockingID); } + + public IOptionsContainer getContainer() + { + return null; + } + + public void addListener(IListener listener) + { + } + + public void removeListener(IListener listener) + { + } + + public boolean hasListeners() + { + return false; + } + + public IListener[] getListeners() + { + return null; + } + + public Options options() + { + return this; + } + + public boolean isLockNotificationEnabled() + { + return false; + } + + public void setLockNotificationEnabled(boolean enabled) + { + } } /** @@ -532,9 +574,34 @@ public class LockManager extends RWOLockManager implements Intern */ private final class DurableLockLoader implements LockArea.Handler { + // Note (CD) This field is a sneaky way of avoiding more API changes. + // The view should properly be an argument on #handleLockArea(LockArea) + private IView view; + + public DurableLockLoader() + { + } + + public DurableLockLoader(IView view) + { + this.view = view; + } + + private IView getView(LockArea area) + { + if (view != null) + { + return view; + } + + DurableView view = new DurableView(area.getDurableLockingID()); + durableViews.put(area.getDurableLockingID(), view); + return view; + } + public boolean handleLockArea(LockArea area) { - IView view = new DurableView(area.getDurableLockingID()); + IView view = getView(area); Collection readLocks = new ArrayList(); Collection writeLocks = new ArrayList(); @@ -590,4 +657,45 @@ public class LockManager extends RWOLockManager implements Intern } return grade; } + + public void updateLockArea(LockArea lockArea) + { + DurableLocking2 accessor = getDurableLocking2(); + if (lockArea.isDeleted()) + { + accessor.deleteLockArea(lockArea.getDurableLockingID()); + } + else + { + accessor.updateLockArea(lockArea); + } + + IView view = openViews.get(lockArea.getDurableLockingID()); + if (view == null) + { + view = durableViews.get(lockArea.getDurableLockingID()); + + // If we already have this durableView, we remove all the locks first... + if (view != null) + { + unlock2(view); + } + + // ...then reload from the new lockArea + // + if (lockArea.isDeleted()) + { + DurableView deletedView = durableViews.remove(lockArea.getDurableLockingID()); + CheckUtil.checkNull(deletedView, "deletedView"); + } + else + { + DurableLockLoader handler = new DurableLockLoader(view); + handler.handleLockArea(lockArea); + } + + view = durableViews.get(lockArea.getDurableLockingID()); + CheckUtil.checkNull(view, "view"); + } + } } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java index d8c51bf38d..2b35f7b31a 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java @@ -285,7 +285,7 @@ public class Repository extends Container implements InternalRepository if (sessionManager != null) { - sessionManager.sendRepositoryStateNotification(oldState, newState); + sessionManager.sendRepositoryStateNotification(oldState, newState, getRootResourceID()); } } @@ -1147,6 +1147,11 @@ public class Repository extends Container implements InternalRepository { return toCommitTime; } + + public String[] getLockAreaIDs() + { + return null; // TODO (CD) + } }; } @@ -1157,6 +1162,8 @@ public class Repository extends Container implements InternalRepository long startTime = context.getLastReplicatedCommitTime(); commitInfoManager.getCommitInfos(null, startTime + 1L, CDOBranchPoint.UNSPECIFIED_DATE, context); + + lockManager.getLockAreas(null, context); } public CDOChangeSetData getChangeSet(CDOBranchPoint startPoint, CDOBranchPoint endPoint) @@ -1340,30 +1347,38 @@ public class Repository extends Container implements InternalRepository } } - public LockObjectsResult lock(InternalView view, LockType lockType, List revisionKeys, - CDOBranch viewedBranch, long timeout) + public static List revisionKeysToObjects(List revisionKeys, CDOBranch viewedBranch, + boolean isSupportingBranches) { - List objectsToLock = new ArrayList(); - boolean isSupportingBranches = isSupportingBranches(); + List lockables = new ArrayList(); for (CDORevisionKey revKey : revisionKeys) { CDOID id = revKey.getID(); if (isSupportingBranches) { - objectsToLock.add(CDOIDUtil.createIDAndBranch(id, viewedBranch)); + lockables.add(CDOIDUtil.createIDAndBranch(id, viewedBranch)); } else { - objectsToLock.add(id); + lockables.add(id); } } + return lockables; + } - InternalLockManager lockManager = getLockManager(); - List> newLockStates = null; + public LockObjectsResult lock(InternalView view, LockType lockType, List revKeys, long timeout) + { + List lockables = revisionKeysToObjects(revKeys, view.getBranch(), isSupportingBranches()); + return lock(view, lockType, lockables, revKeys, timeout); + } + protected LockObjectsResult lock(InternalView view, LockType type, List lockables, + List loadedRevs, long timeout) + { + List> newLockStates = null; try { - newLockStates = lockManager.lock2(true, lockType, view, objectsToLock, timeout); + newLockStates = lockManager.lock2(true, type, view, lockables, timeout); } catch (TimeoutRuntimeException ex) { @@ -1374,13 +1389,35 @@ public class Repository extends Container implements InternalRepository throw WrappedException.wrap(ex); } - List staleRevisions = new LinkedList(); - long requiredTimestamp = 0; + long[] requiredTimestamp = { 0L }; + CDORevisionKey[] staleRevisionsArray = checkStaleRevisions(view, loadedRevs, lockables, type, requiredTimestamp); - try + // If some of the clients' revisions are stale and it has passiveUpdates disabled, + // then the locks are useless so we release them and report the stale revisions + // + InternalSession session = view.getSession(); + boolean staleNoUpdate = staleRevisionsArray.length > 0 && !session.isPassiveUpdateEnabled(); + if (staleNoUpdate) { - InternalCDORevisionManager revManager = getRevisionManager(); + lockManager.unlock2(true, type, view, lockables); + return new LockObjectsResult(false, false, false, requiredTimestamp[0], staleRevisionsArray, new CDOLockState[0]); + } + CDOLockState[] cdoLockStates = toCDOLockStates(newLockStates); + sendLockNotifications(view, Operation.LOCK, type, cdoLockStates); + + boolean waitForUpdate = staleRevisionsArray.length > 0; + return new LockObjectsResult(true, false, waitForUpdate, requiredTimestamp[0], staleRevisionsArray, cdoLockStates); + } + + private CDORevisionKey[] checkStaleRevisions(InternalView view, List revisionKeys, + List objectsToLock, LockType lockType, long[] requiredTimestamp) + { + List staleRevisions = new LinkedList(); + if (revisionKeys != null) + { + InternalCDORevisionManager revManager = getRevisionManager(); + CDOBranch viewedBranch = view.getBranch(); for (CDORevisionKey revKey : revisionKeys) { CDOID id = revKey.getID(); @@ -1389,6 +1426,7 @@ public class Repository extends Container implements InternalRepository if (rev == null) { + lockManager.unlock2(true, lockType, view, objectsToLock); throw new IllegalArgumentException(String.format("Object %s not found in branch %s (possibly detached)", id, viewedBranch)); } @@ -1396,56 +1434,37 @@ public class Repository extends Container implements InternalRepository if (!revKey.equals(rev)) { staleRevisions.add(revKey); - requiredTimestamp = Math.max(requiredTimestamp, rev.getTimeStamp()); + requiredTimestamp[0] = Math.max(requiredTimestamp[0], rev.getTimeStamp()); } } } - catch (IllegalArgumentException ex) - { - lockManager.unlock2(true, lockType, view, objectsToLock); - throw ex; - } // Convert the list to an array, to satisfy the API later // CDORevisionKey[] staleRevisionsArray = new CDORevisionKey[staleRevisions.size()]; staleRevisions.toArray(staleRevisionsArray); - // If some of the clients' revisions are stale and it has passiveUpdates disabled, - // then the locks are useless so we release them and report the stale revisions - InternalSession session = view.getSession(); - boolean staleNoUpdate = staleRevisionsArray.length > 0 && !session.isPassiveUpdateEnabled(); - if (staleNoUpdate) - { - lockManager.unlock2(true, lockType, view, objectsToLock); - return new LockObjectsResult(false, false, false, requiredTimestamp, staleRevisionsArray, new CDOLockState[0]); - } - - CDOLockState[] cdoLockStates = toCDOLockStates(newLockStates); - sendLockNotifications(view, viewedBranch, Operation.LOCK, cdoLockStates); - - boolean waitForUpdate = staleRevisionsArray.length > 0; - return new LockObjectsResult(true, false, waitForUpdate, requiredTimestamp, staleRevisionsArray, cdoLockStates); + return staleRevisionsArray; } - private void sendLockNotifications(IView view, CDOBranch viewedBranch, Operation operation, - CDOLockState[] cdoLockStates) + private void sendLockNotifications(IView view, Operation operation, LockType lockType, CDOLockState[] cdoLockStates) { long timestamp = getTimeStamp(); - CDOLockChangeInfo lockChangeInfo = CDOLockUtil.createLockChangeInfo(timestamp, view, viewedBranch, operation, - cdoLockStates); + CDOLockChangeInfo lockChangeInfo = CDOLockUtil.createLockChangeInfo(timestamp, view, view.getBranch(), operation, + lockType, cdoLockStates); getSessionManager().sendLockNotification((InternalSession)view.getSession(), lockChangeInfo); } // TODO (CD) This doesn't really belong here.. but getting it into CDOLockUtil isn't possible - private CDOLockState[] toCDOLockStates(List> lockStates) + public static CDOLockState[] toCDOLockStates(List> lockStates) { CDOLockState[] cdoLockStates = new CDOLockState[lockStates.size()]; int i = 0; for (LockState lockState : lockStates) { - cdoLockStates[i++] = CDOLockUtil.createLockState(lockState); + CDOLockState cdoLockState = CDOLockUtil.createLockState(lockState); + cdoLockStates[i++] = cdoLockState; } return cdoLockStates; @@ -1453,30 +1472,35 @@ public class Repository extends Container implements InternalRepository public UnlockObjectsResult unlock(InternalView view, LockType lockType, List objectIDs) { - List revisionKeys = null; + List unlockables = null; if (objectIDs != null) { - revisionKeys = new ArrayList(objectIDs.size()); + unlockables = new ArrayList(objectIDs.size()); CDOBranch branch = view.getBranch(); for (CDOID id : objectIDs) { Object key = supportingBranches ? CDOIDUtil.createIDAndBranch(id, branch) : id; - revisionKeys.add(key); + unlockables.add(key); } } + return doUnlock(view, lockType, unlockables); + } + + protected UnlockObjectsResult doUnlock(InternalView view, LockType lockType, List unlockables) + { List> newLockStates = null; - if (lockType == null && revisionKeys == null) + if (lockType == null) // Signals an unlock-all operation { newLockStates = lockManager.unlock2(true, view); } else { - newLockStates = lockManager.unlock2(true, lockType, view, revisionKeys); + newLockStates = lockManager.unlock2(true, lockType, view, unlockables); } CDOLockState[] cdoLockStates = toCDOLockStates(newLockStates); - sendLockNotifications(view, view.getBranch(), Operation.UNLOCK, cdoLockStates); + sendLockNotifications(view, Operation.UNLOCK, lockType, cdoLockStates); return new UnlockObjectsResult(cdoLockStates); } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java index 3af601ddb4..f463f4a583 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java @@ -211,7 +211,7 @@ public class ServerCDOView extends AbstractCDOView implements org.eclipse.emf.cd throw new UnsupportedOperationException(); } - public void handleLockNotification(CDOLockChangeInfo lockChangeInfo) + public void handleLockNotification(InternalCDOView sender, CDOLockChangeInfo lockChangeInfo) { // Do nothing } @@ -806,7 +806,7 @@ public class ServerCDOView extends AbstractCDOView implements org.eclipse.emf.cd throw new UnsupportedOperationException(); } - public void handleLockNotification(CDOLockChangeInfo lockChangeInfo) + public void handleLockNotification(CDOLockChangeInfo lockChangeInfo, InternalCDOView sender) { throw new UnsupportedOperationException(); } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java index cf32de47d4..ef6ee5482e 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java @@ -77,6 +77,9 @@ public class Session extends Container implements InternalSession private PassiveUpdateMode passiveUpdateMode = PassiveUpdateMode.INVALIDATIONS; + private LockNotificationMode lockNotificationMode = LockNotificationMode.ALWAYS; // TODO (CD) Default should be + // PER_VIEW + private long lastUpdateTime; @ExcludeFromDump @@ -203,6 +206,18 @@ public class Session extends Container implements InternalSession this.passiveUpdateMode = passiveUpdateMode; } + public LockNotificationMode getLockNotificationMode() + { + return lockNotificationMode; + } + + public void setLockNotificationMode(LockNotificationMode lockNotificationMode) + { + checkActive(); + checkArg(lockNotificationMode, "lockNotificationMode"); + this.lockNotificationMode = lockNotificationMode; + } + public long getLastUpdateTime() { synchronized (lastUpdateTimeLock) @@ -346,12 +361,19 @@ public class Session extends Container implements InternalSession } } + @Deprecated public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState) throws Exception + { + sendRepositoryStateNotification(oldState, newState, null); + } + + public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState, + CDOID rootResourceID) throws Exception { if (protocol != null) { - protocol.sendRepositoryStateNotification(oldState, newState); + protocol.sendRepositoryStateNotification(oldState, newState, rootResourceID); } } @@ -458,14 +480,23 @@ public class Session extends Container implements InternalSession { if (protocol != null) { - // If this session has one (or more) views configured for this branch, - // only then do we send the lockChangeInfo. - for (InternalView view : getViews()) + if (options().getLockNotificationMode() == LockNotificationMode.ALWAYS) + { + protocol.sendLockNotification(lockChangeInfo); + return; + } + + if (options().getLockNotificationMode() == LockNotificationMode.IF_REQUIRED_BY_VIEWS) { - if (view.isLockNotificationEnabled() && view.getBranch().equals(lockChangeInfo.getBranch())) + // If this session has one (or more) views configured for this branch, + // only then do we send the lockChangeInfo. + for (InternalView view : getViews()) { - protocol.sendLockNotification(lockChangeInfo); - break; + if (view.options().isLockNotificationEnabled() && view.getBranch().equals(lockChangeInfo.getBranch())) + { + protocol.sendLockNotification(lockChangeInfo); + break; + } } } } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java index 7869c798d1..22f71b80d7 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java @@ -13,7 +13,9 @@ package org.eclipse.emf.cdo.internal.server; import org.eclipse.emf.cdo.common.CDOCommonRepository; +import org.eclipse.emf.cdo.common.CDOCommonSession.Options.LockNotificationMode; import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; import org.eclipse.emf.cdo.internal.server.bundle.OM; @@ -257,13 +259,20 @@ public class SessionManager extends Container implements InternalSessi } } + @Deprecated public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState) + { + sendRepositoryStateNotification(oldState, newState, null); + } + + public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState, + CDOID rootResourceID) { for (InternalSession session : getSessions()) { try { - session.sendRepositoryStateNotification(oldState, newState); + session.sendRepositoryStateNotification(oldState, newState, rootResourceID); } catch (Exception ex) { @@ -312,7 +321,10 @@ public class SessionManager extends Container implements InternalSessi { for (InternalSession session : getSessions()) { - // TODO Exclude the sender and notify locally there + if (session == sender || session.options().getLockNotificationMode() == LockNotificationMode.OFF) + { + continue; + } try { 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 e2290cee19..e978f5c7e0 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 @@ -20,6 +20,10 @@ import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDObject; import org.eclipse.emf.cdo.common.id.CDOIDReference; import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation; +import org.eclipse.emf.cdo.common.lock.CDOLockState; +import org.eclipse.emf.cdo.common.lock.CDOLockUtil; import org.eclipse.emf.cdo.common.model.CDOModelUtil; import org.eclipse.emf.cdo.common.model.CDOPackageUnit; import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch; @@ -1056,6 +1060,10 @@ public class TransactionCommitContext implements InternalCommitContext if (isAutoReleaseLocksEnabled()) { postCommitLockStates = repository.getLockManager().unlock2(true, transaction); + if (!postCommitLockStates.isEmpty()) + { + sendLockNotifications(postCommitLockStates); + } } monitor.worked(); @@ -1067,6 +1075,19 @@ public class TransactionCommitContext implements InternalCommitContext } } + private void sendLockNotifications(List> newLockStates) + { + CDOLockState[] newStates = Repository.toCDOLockStates(newLockStates); + + long timeStamp = getTimeStamp(); + InternalTransaction tx = getTransaction(); + CDOBranch branch = tx.getBranch(); + Operation unlock = Operation.UNLOCK; + + CDOLockChangeInfo info = CDOLockUtil.createLockChangeInfo(timeStamp, tx, branch, unlock, null, newStates); + repository.getSessionManager().sendLockNotification(tx.getSession(), info); + } + private void addNewPackageUnits(OMMonitor monitor) { InternalCDOPackageRegistry repositoryPackageRegistry = repository.getPackageRegistry(false); diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/View.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/View.java index a81cbb8d19..8e72f32596 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/View.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/View.java @@ -11,6 +11,7 @@ */ package org.eclipse.emf.cdo.internal.server; +import org.eclipse.emf.cdo.common.CDOCommonView; import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.id.CDOID; @@ -24,6 +25,7 @@ import org.eclipse.emf.cdo.spi.server.InternalView; import org.eclipse.net4j.util.ObjectUtil; import org.eclipse.net4j.util.lifecycle.Lifecycle; +import org.eclipse.net4j.util.options.IOptionsContainer; import java.text.MessageFormat; import java.util.HashSet; @@ -34,7 +36,7 @@ import java.util.Set; /** * @author Eike Stepper */ -public class View extends Lifecycle implements InternalView +public class View extends Lifecycle implements InternalView, CDOCommonView.Options { private InternalSession session; @@ -263,6 +265,16 @@ public class View extends Lifecycle implements InternalView } } + public IOptionsContainer getContainer() + { + return this; + } + + public Options options() + { + return this; + } + public boolean isLockNotificationEnabled() { return lockNotificationsEnabled; diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedServerSessionProtocol.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedServerSessionProtocol.java index adfec3f101..3dd8efaa73 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedServerSessionProtocol.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedServerSessionProtocol.java @@ -12,6 +12,7 @@ package org.eclipse.emf.cdo.internal.server.embedded; import org.eclipse.emf.cdo.common.CDOCommonRepository; import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage; import org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult; @@ -65,7 +66,14 @@ public class EmbeddedServerSessionProtocol extends Lifecycle implements ISession clientSession.handleRepositoryTypeChanged(oldType, newType); } + @Deprecated public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState) + { + sendRepositoryStateNotification(oldState, newState, null); + } + + public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState, + CDOID rootResourceID) { EmbeddedClientSession clientSession = clientSessionProtocol.getSession(); clientSession.handleRepositoryStateChanged(oldState, newState); @@ -86,7 +94,7 @@ public class EmbeddedServerSessionProtocol extends Lifecycle implements ISession public void sendLockNotification(CDOLockChangeInfo lockChangeInfo) { EmbeddedClientSession clientSession = clientSessionProtocol.getSession(); - clientSession.handleLockNotification(lockChangeInfo); + clientSession.handleLockNotification(lockChangeInfo, null); } public void sendRemoteSessionNotification(InternalSession sender, byte opcode) diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java index 1f3b13f3b4..dfdb97e09c 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java @@ -23,6 +23,7 @@ import org.eclipse.emf.cdo.common.commit.CDOCommitInfoHandler; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDUtil; import org.eclipse.emf.cdo.common.lob.CDOLobHandler; +import org.eclipse.emf.cdo.common.lock.CDOLockUtil; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea.Handler; import org.eclipse.emf.cdo.common.model.CDOModelConstants; import org.eclipse.emf.cdo.common.protocol.CDODataInput; @@ -46,7 +47,6 @@ import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager; import org.eclipse.emf.cdo.spi.common.revision.DetachedCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.common.revision.SyntheticCDORevision; -import org.eclipse.emf.cdo.spi.server.DurableLockArea; import org.eclipse.emf.cdo.spi.server.InternalLockManager; import org.eclipse.emf.cdo.spi.server.LongIDStore; import org.eclipse.emf.cdo.spi.server.StoreAccessorPool; @@ -758,15 +758,21 @@ public class MEMStore extends LongIDStore implements IMEMStore, BranchLoader, Du { do { - durableLockingID = DurableLockArea.createDurableLockingID(); + durableLockingID = CDOLockUtil.createDurableLockingID(); } while (lockAreas.containsKey(durableLockingID)); } - LockArea area = new DurableLockArea(durableLockingID, userID, branchPoint, readOnly, locks); + LockArea area = CDOLockUtil.createLockArea(durableLockingID, userID, branchPoint, readOnly, locks); lockAreas.put(durableLockingID, area); return area; } + public synchronized void updateLockArea(LockArea lockArea) + { + String durableLockingID = lockArea.getDurableLockingID(); + lockAreas.put(durableLockingID, lockArea); + } + public synchronized LockArea getLockArea(String durableLockingID) throws LockAreaNotFoundException { LockArea area = lockAreas.get(durableLockingID); @@ -783,7 +789,8 @@ public class MEMStore extends LongIDStore implements IMEMStore, BranchLoader, Du for (LockArea area : lockAreas.values()) { String userID = area.getUserID(); - if (userID != null && userID.startsWith(userIDPrefix)) + if (userID == null || userID.startsWith(userIDPrefix)) + // if (userID != null && userID.startsWith(userIDPrefix)) // TODO (CD) Used to be this. Any breakage? { if (!handler.handleLockArea(area)) { diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java index 90974d1a21..55da263437 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java @@ -414,6 +414,11 @@ public class MEMStoreAccessor extends LongIDStoreAccessor implements Raw, Durabl return getStore().createLockArea(durableLockingID, userID, branchPoint, readOnly, locks); } + public void updateLockArea(LockArea lockArea) + { + getStore().updateLockArea(lockArea); + } + public LockArea getLockArea(String durableLockingID) throws LockAreaNotFoundException { return getStore().getLockArea(durableLockingID); diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/RepositorySynchronizer.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/RepositorySynchronizer.java index 33bdeb1f3b..a2fe4df2de 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/RepositorySynchronizer.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/RepositorySynchronizer.java @@ -11,16 +11,20 @@ package org.eclipse.emf.cdo.internal.server.syncing; import org.eclipse.emf.cdo.common.CDOCommonRepository; +import org.eclipse.emf.cdo.common.CDOCommonSession.Options.LockNotificationMode; import org.eclipse.emf.cdo.common.CDOCommonSession.Options.PassiveUpdateMode; import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.branch.CDOBranchCreatedEvent; import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; import org.eclipse.emf.cdo.internal.common.revision.NOOPRevisionCache; import org.eclipse.emf.cdo.internal.server.bundle.OM; +import org.eclipse.emf.cdo.server.StoreThreadLocal; import org.eclipse.emf.cdo.session.CDOSessionConfiguration; import org.eclipse.emf.cdo.session.CDOSessionConfigurationFactory; import org.eclipse.emf.cdo.session.CDOSessionInvalidationEvent; +import org.eclipse.emf.cdo.session.CDOSessionLocksChangedEvent; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionCache; import org.eclipse.emf.cdo.spi.server.InternalRepositorySynchronizer; import org.eclipse.emf.cdo.spi.server.InternalSynchronizableRepository; @@ -66,12 +70,18 @@ public class RepositorySynchronizer extends QueueRunner implements InternalRepos private static final Integer COMMIT_PRIORITY = 3; + private static final Integer LOCKS_PRIORITY = COMMIT_PRIORITY; + private int retryInterval = DEFAULT_RETRY_INTERVAL; private Object connectLock = new Object(); private InternalSynchronizableRepository localRepository; + /** + * The session that connects to the master; used passively to receive notifications, and actively to request + * replications. + */ private InternalCDOSession remoteSession; private RemoteSessionListener remoteSessionListener = new RemoteSessionListener(); @@ -117,10 +127,10 @@ public class RepositorySynchronizer extends QueueRunner implements InternalRepos return remoteSessionConfigurationFactory; } - public void setRemoteSessionConfigurationFactory(CDOSessionConfigurationFactory remoteSessionConfigurationFactory) + public void setRemoteSessionConfigurationFactory(CDOSessionConfigurationFactory masterSessionConfigurationFactory) { - checkArg(remoteSessionConfigurationFactory, "remoteSessionConfigurationFactory"); //$NON-NLS-1$ - this.remoteSessionConfigurationFactory = remoteSessionConfigurationFactory; + checkArg(masterSessionConfigurationFactory, "remoteSessionConfigurationFactory"); //$NON-NLS-1$ + remoteSessionConfigurationFactory = masterSessionConfigurationFactory; } public InternalCDOSession getRemoteSession() @@ -206,7 +216,7 @@ public class RepositorySynchronizer extends QueueRunner implements InternalRepos super.doDeactivate(); } - private void disconnect() + private void handleDisconnect() { OM.LOG.info("Disconnected from master."); if (localRepository.getRootResourceID() == null) @@ -299,12 +309,17 @@ public class RepositorySynchronizer extends QueueRunner implements InternalRepos addWork(new CommitRunnable(e)); } } + else if (event instanceof CDOSessionLocksChangedEvent) + { + CDOSessionLocksChangedEvent e = (CDOSessionLocksChangedEvent)event; + addWork(new LocksRunnable(e)); + } else if (event instanceof ILifecycleEvent) { ILifecycleEvent e = (ILifecycleEvent)event; if (e.getKind() == ILifecycleEvent.Kind.DEACTIVATED && e.getSource() == remoteSession) { - disconnect(); + handleDisconnect(); } } } @@ -346,6 +361,7 @@ public class RepositorySynchronizer extends QueueRunner implements InternalRepos { CDOSessionConfiguration masterConfiguration = remoteSessionConfigurationFactory.createSessionConfiguration(); masterConfiguration.setPassiveUpdateMode(PassiveUpdateMode.ADDITIONS); + masterConfiguration.setLockNotificationMode(LockNotificationMode.ALWAYS); remoteSession = (InternalCDOSession)masterConfiguration.openSession(); @@ -442,7 +458,7 @@ public class RepositorySynchronizer extends QueueRunner implements InternalRepos { OM.LOG.warn("Replication attempt failed. Retrying in " + retryInterval + " seconds...", ex); sleepRetryInterval(); - disconnect(); + handleDisconnect(); } } } @@ -573,4 +589,41 @@ public class RepositorySynchronizer extends QueueRunner implements InternalRepos return COMMIT_PRIORITY; } } + + /** + * @author Caspar De Groot + */ + private final class LocksRunnable extends QueueRunnable + { + private CDOLockChangeInfo lockChangeInfo; + + public LocksRunnable(CDOLockChangeInfo lockChangeInfo) + { + this.lockChangeInfo = lockChangeInfo; + } + + public void run() + { + try + { + StoreThreadLocal.setSession(localRepository.getReplicatorSession()); + localRepository.handleLockChangeInfo(lockChangeInfo); + } + catch (Exception ex) + { + // TODO (CD) Retry as for commit? + ex.printStackTrace(); + } + finally + { + StoreThreadLocal.release(); + } + } + + @Override + protected Integer getPriority() + { + return LOCKS_PRIORITY; + } + } } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/SynchronizableRepository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/SynchronizableRepository.java index 9f424cbd0b..06e640bc58 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/SynchronizableRepository.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/SynchronizableRepository.java @@ -11,6 +11,7 @@ package org.eclipse.emf.cdo.internal.server.syncing; import org.eclipse.emf.cdo.common.CDOCommonRepository; +import org.eclipse.emf.cdo.common.CDOCommonSession.Options.LockNotificationMode; import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; @@ -19,6 +20,11 @@ import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; import org.eclipse.emf.cdo.common.commit.CDOCommitInfoHandler; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.lob.CDOLob; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation; +import org.eclipse.emf.cdo.common.lock.CDOLockOwner; +import org.eclipse.emf.cdo.common.lock.CDOLockState; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; import org.eclipse.emf.cdo.common.model.CDOPackageUnit; import org.eclipse.emf.cdo.common.protocol.CDODataInput; import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; @@ -37,6 +43,7 @@ import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager; import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionCache; import org.eclipse.emf.cdo.spi.server.InternalCommitContext; +import org.eclipse.emf.cdo.spi.server.InternalLockManager; import org.eclipse.emf.cdo.spi.server.InternalRepository; import org.eclipse.emf.cdo.spi.server.InternalRepositorySynchronizer; import org.eclipse.emf.cdo.spi.server.InternalSession; @@ -45,10 +52,11 @@ import org.eclipse.emf.cdo.spi.server.InternalStore; import org.eclipse.emf.cdo.spi.server.InternalSynchronizableRepository; import org.eclipse.emf.cdo.spi.server.InternalTransaction; import org.eclipse.emf.cdo.spi.server.InternalView; +import org.eclipse.emf.cdo.spi.server.SyncingUtil; -import org.eclipse.net4j.util.CheckUtil; import org.eclipse.net4j.util.WrappedException; import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; +import org.eclipse.net4j.util.lifecycle.LifecycleUtil; import org.eclipse.net4j.util.om.monitor.Monitor; import org.eclipse.net4j.util.om.monitor.OMMonitor; import org.eclipse.net4j.util.transaction.TransactionException; @@ -65,6 +73,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -181,6 +190,11 @@ public abstract class SynchronizableRepository extends Repository.Default implem } } + public String[] getLockAreaIDs() + { + return new String[0]; // TODO (CD) + } + public void handleBranch(CDOBranch branch) { if (branch.isLocal()) @@ -235,6 +249,62 @@ public abstract class SynchronizableRepository extends Repository.Default implem } } + public void handleLockChangeInfo(CDOLockChangeInfo lockChangeInfo) + { + CDOLockOwner owner = lockChangeInfo.getLockOwner(); + String durableLockingID = owner.getDurableLockingID(); + CDOBranch viewedBranch = lockChangeInfo.getBranch(); + InternalLockManager lockManager = getLockManager(); + LockType lockType = lockChangeInfo.getLockType(); + + InternalView view = null; + + try + { + view = SyncingUtil.openViewWithLockArea(replicatorSession, lockManager, viewedBranch, durableLockingID); + List lockables = new LinkedList(); + + for (CDOLockState lockState : lockChangeInfo.getLockStates()) + { + lockables.add(lockState.getLockedObject()); + } + + if (lockChangeInfo.getOperation() == Operation.LOCK) + { + long timeout = 10000; // TODO (CD) + super.lock(view, lockType, lockables, null, timeout); + } + else if (lockChangeInfo.getOperation() == Operation.UNLOCK) + { + super.doUnlock(view, lockType, lockables); + } + else + { + throw new IllegalStateException("Unexpected: " + lockChangeInfo.getOperation()); + } + } + finally + { + LifecycleUtil.deactivate(view); + } + } + + public boolean handleLockArea(LockArea area) + { + try + { + StoreThreadLocal.setSession(replicatorSession); + getLockManager().updateLockArea(area); + + // TODO (CD) getSessionManager().sendLockNotification(sender, lockChangeInfo); + return true; + } + finally + { + StoreThreadLocal.release(); + } + } + public void replicateRaw(CDODataInput in, OMMonitor monitor) throws IOException { try @@ -261,6 +331,25 @@ public abstract class SynchronizableRepository extends Repository.Default implem } } + public void goOnline() + { + if (getState() == OFFLINE) + { + LifecycleUtil.activate(synchronizer); + // Do not set the state to ONLINE yet; the synchronizer will set it to SYNCING first, + // and then to ONLINE after a succesful replication. + } + } + + public void goOffline() + { + if (getState() != OFFLINE) + { + LifecycleUtil.deactivate(synchronizer); + setState(OFFLINE); + } + } + private void replicateRawReviseRevisions() { InternalCDORevisionCache cache = getRevisionManager().getCache(); @@ -398,6 +487,7 @@ public abstract class SynchronizableRepository extends Repository.Default implem { replicatorSession = getSessionManager().openSession(null); replicatorSession.options().setPassiveUpdateEnabled(false); + replicatorSession.options().setLockNotificationMode(LockNotificationMode.OFF); synchronizer.setLocalRepository(this); synchronizer.activate(); @@ -429,59 +519,64 @@ public abstract class SynchronizableRepository extends Repository.Default implem } @Override - public LockObjectsResult lock(InternalView view, LockType lockType, List revisionKeys, - CDOBranch viewedBranch, long timeout) + public LockObjectsResult lock(InternalView view, LockType lockType, List revisionKeys, long timeout) { - CheckUtil.checkState(view.getBranch().equals(viewedBranch), - "Client view's branch and server view's branch are different."); - if (view.getBranch().isLocal()) { - return super.lock(view, lockType, revisionKeys, viewedBranch, timeout); + return super.lock(view, lockType, revisionKeys, timeout); } - + if (getState() != ONLINE) { throw new CDOException("Cannot lock in a non-local branch when clone is not connected to master"); } - - return lockThrough(true, view, lockType, revisionKeys, viewedBranch, timeout); + + return lockThrough(view, lockType, revisionKeys, timeout); } - private LockObjectsResult lockThrough(boolean explicit, InternalView view, LockType lockType, - List revisionKeys, CDOBranch viewedBranch, long timeout) + private LockObjectsResult lockOnMaster(InternalView view, LockType type, List revKeys, long timeout) + throws InterruptedException { // Delegate locking to the master InternalCDOSession remoteSession = getSynchronizer().getRemoteSession(); CDOSessionProtocol sessionProtocol = remoteSession.getSessionProtocol(); - try + + String areaID = view.getDurableLockingID(); + if (areaID == null) + { + throw new IllegalStateException("Durable locking is not enabled."); + } + + LockObjectsResult masterLockingResult = sessionProtocol.delegateLockObjects(areaID, revKeys, view.getBranch(), + type, timeout); + + if (masterLockingResult.isSuccessful() && masterLockingResult.isWaitForUpdate()) { - String lockAreaID = view.getDurableLockingID(); - if (lockAreaID == null) + if (!getSynchronizer().getRemoteSession().options().isPassiveUpdateEnabled()) { - throw new IllegalStateException("Durable locking is not enabled."); + throw new AssertionError( + "Master lock result requires clone to wait, but clone does not have passiveUpdates enabled."); } - - LockObjectsResult masterLockingResult = sessionProtocol.delegateLockObjects(lockAreaID, revisionKeys, - viewedBranch, lockType, timeout); + + long requiredTimestamp = masterLockingResult.getRequiredTimestamp(); + remoteSession.waitForUpdate(requiredTimestamp); + } + + return masterLockingResult; + } + + private LockObjectsResult lockThrough(InternalView view, LockType type, List keys, long timeout) + { + try + { + LockObjectsResult masterLockingResult = lockOnMaster(view, type, keys, timeout); if (!masterLockingResult.isSuccessful()) { return masterLockingResult; } - - if (masterLockingResult.isWaitForUpdate()) - { - if (!getSynchronizer().getRemoteSession().options().isPassiveUpdateEnabled()) - { - throw new AssertionError( - "Master lock result requires clone to wait, but clone does not have passiveUpdates enabled."); - } - - long requiredTimestamp = masterLockingResult.getRequiredTimestamp(); - remoteSession.waitForUpdate(requiredTimestamp); - } - - return super.lock(view, lockType, revisionKeys, viewedBranch, timeout); + + LockObjectsResult localLockingResult = super.lock(view, type, keys, timeout); + return localLockingResult; } catch (InterruptedException ex) { @@ -494,30 +589,34 @@ public abstract class SynchronizableRepository extends Repository.Default implem { if (view.getBranch().isLocal()) { - return super.unlock(view, lockType, objectIDs); + super.unlock(view, lockType, objectIDs); } - + if (getState() != ONLINE) { throw new CDOException("Cannot unlock in a non-local branch when clone is not connected to master"); } - + return unlockThrough(view, lockType, objectIDs); } - private UnlockObjectsResult unlockThrough(InternalView view, LockType lockType, List objectIDs) + private void unlockOnMaster(InternalView view, LockType lockType, List objectIDs) { - // Delegate unlocking to the master InternalCDOSession remoteSession = getSynchronizer().getRemoteSession(); CDOSessionProtocol sessionProtocol = remoteSession.getSessionProtocol(); - + String lockAreaID = view.getDurableLockingID(); if (lockAreaID == null) { throw new IllegalStateException("Durable locking is not enabled."); } - + sessionProtocol.delegateUnlockObjects(lockAreaID, objectIDs, lockType); + } + + private UnlockObjectsResult unlockThrough(InternalView view, LockType lockType, List objectIDs) + { + unlockOnMaster(view, lockType, objectIDs); return super.unlock(view, lockType, objectIDs); } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java index d9da5d9cc5..26d6524f43 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java @@ -708,12 +708,14 @@ public interface IStoreAccessor extends IQueryHandlerProvider, BranchLoader, Com } /** - * @author Eike Stepper + * @author Caspar De Groot * @since 4.1 */ public interface DurableLocking2 extends DurableLocking { LockArea createLockArea(String durableLockingID, String userID, CDOBranchPoint branchPoint, boolean readOnly, Map locks); + + public void updateLockArea(LockArea lockArea); } } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/ISynchronizableRepository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/ISynchronizableRepository.java index 4a64a170a4..334f8bf77c 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/ISynchronizableRepository.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/ISynchronizableRepository.java @@ -27,4 +27,14 @@ public interface ISynchronizableRepository extends IRepository public int getLastReplicatedBranchID(); public long getLastReplicatedCommitTime(); + + /** + * @since 4.1 + */ + public void goOnline(); + + /** + * @since 4.1 + */ + public void goOffline(); } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/DurableLockArea.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/DurableLockArea.java index e31811842e..1db5bfc221 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/DurableLockArea.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/DurableLockArea.java @@ -13,20 +13,20 @@ package org.eclipse.emf.cdo.spi.server; 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.CDOLockUtil; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade; -import org.eclipse.net4j.util.HexUtil; - import java.text.MessageFormat; import java.util.Map; -import java.util.Random; /** * @author Eike Stepper * @since 4.0 * @noextend This interface is not intended to be extended by clients. + * @deprecated Use {@link CDOLockUtil#createLockArea(String, String, CDOBranchPoint, boolean, Map)} instead */ +@Deprecated public class DurableLockArea implements LockArea { public static final int DEFAULT_DURABLE_LOCKING_ID_BYTES = 32; @@ -84,22 +84,25 @@ public class DurableLockArea implements LockArea @Override public String toString() { - return MessageFormat.format("DurableLockArea[id={0}, user={1}, branchPoint={2}, readOnly={3}, locks={4}]", + return MessageFormat.format("DurableLockArea\nid={0}\nuser={1}\nbranchPoint={2}\nreadOnly={3}\nlocks={4}", durableLockingID, userID, branchPoint, readOnly, locks); } public static String createDurableLockingID() { - return createDurableLockingID(DEFAULT_DURABLE_LOCKING_ID_BYTES); + return CDOLockUtil.createDurableLockingID(); } public static String createDurableLockingID(int bytes) { - byte[] buffer = new byte[bytes]; - - Random random = new Random(System.currentTimeMillis()); - random.nextBytes(buffer); + return CDOLockUtil.createDurableLockingID(bytes); + } - return HexUtil.bytesToHex(buffer); + /** + * @since 4.1 + */ + public boolean isDeleted() + { + return false; } } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/ISessionProtocol.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/ISessionProtocol.java index d8e378f566..1562ae0689 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/ISessionProtocol.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/ISessionProtocol.java @@ -12,6 +12,7 @@ package org.eclipse.emf.cdo.spi.server; import org.eclipse.emf.cdo.common.CDOCommonRepository; import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; import org.eclipse.emf.cdo.common.protocol.CDOProtocol; import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage; @@ -34,9 +35,19 @@ public interface ISessionProtocol extends CDOProtocol public void sendRepositoryTypeNotification(CDOCommonRepository.Type oldType, CDOCommonRepository.Type newType) throws Exception; + /** + * @deprecated + */ + @Deprecated public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState) throws Exception; + /** + * @since 4.1 + */ + public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState, + CDOID rootResourceID) throws Exception; + public void sendBranchNotification(InternalCDOBranch branch) throws Exception; public void sendCommitNotification(CDOCommitInfo commitInfo) throws Exception; diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockManager.java index d96cc595bf..ab8d9a2c37 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockManager.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockManager.java @@ -111,6 +111,12 @@ public interface InternalLockManager extends IRWOLockManager, IDu */ public LockArea createLockArea(InternalView view, String lockAreaID); + /** + * @since 4.1 + */ + // TODO (CD) I've also added this to DurableLocking2 Refactoring opportunity? + public void updateLockArea(LockArea lockArea); + /** * @since 4.0 */ @@ -125,4 +131,9 @@ public interface InternalLockManager extends IRWOLockManager, IDu * @since 4.1 */ public LockState getLockState(Object key); + + /** + * @since 4.1 + */ + public void setLockState(Object key, LockState lockState); } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockingManagerContext.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockingManagerContext.java deleted file mode 100644 index 00782c3f19..0000000000 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockingManagerContext.java +++ /dev/null @@ -1,20 +0,0 @@ -/** - * 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.spi.server; - -/** - * @author Caspar De Groot - * @since 4.1 - */ -public interface InternalLockingManagerContext -{ - -} diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java index 732f716931..eb8c0b50ce 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java @@ -221,8 +221,7 @@ public interface InternalRepository extends IRepository, PackageProcessor, Packa /** * @since 4.1 */ - public LockObjectsResult lock(InternalView view, LockType lockType, List revisionKeys, - CDOBranch viewedBranch, long timeout); + public LockObjectsResult lock(InternalView view, LockType lockType, List revisionKeys, long timeout); /** * @since 4.1 diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java index e06734b554..9195c68c5c 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java @@ -56,9 +56,21 @@ public interface InternalSession extends ISession, CDOIDProvider, CDOCommonSessi public void sendRepositoryTypeNotification(CDOCommonRepository.Type oldType, CDOCommonRepository.Type newType) throws Exception; + /** + * @deprecated use + * {@link #sendRepositoryStateNotification(org.eclipse.emf.cdo.common.CDOCommonRepository.State, org.eclipse.emf.cdo.common.CDOCommonRepository.State, CDOID)} + * instead + */ + @Deprecated public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState) throws Exception; + /** + * @since 4.1 + */ + public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState, + CDOID rootResourceID) throws Exception; + public void sendBranchNotification(InternalCDOBranch branch) throws Exception; public void sendCommitNotification(CDOCommitInfo commitInfo) throws Exception; diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java index f82d68a887..435b78e680 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java @@ -12,6 +12,7 @@ package org.eclipse.emf.cdo.spi.server; import org.eclipse.emf.cdo.common.CDOCommonRepository; import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; import org.eclipse.emf.cdo.server.ISessionManager; import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage; @@ -48,8 +49,20 @@ public interface InternalSessionManager extends ISessionManager public void sendRepositoryTypeNotification(CDOCommonRepository.Type oldType, CDOCommonRepository.Type newType); + /** + * @deprecated use + * {@link #sendRepositoryStateNotification(org.eclipse.emf.cdo.common.CDOCommonRepository.State, org.eclipse.emf.cdo.common.CDOCommonRepository.State, CDOID)} + * instead + */ + @Deprecated public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState); + /** + * @since 4.1 + */ + public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState, + CDOID rootResourceID); + public void sendBranchNotification(InternalSession sender, InternalCDOBranch branch); public void sendCommitNotification(InternalSession sender, CDOCommitInfo commitInfo); diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSynchronizableRepository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSynchronizableRepository.java index d764fbdb67..f4c3298dc0 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSynchronizableRepository.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSynchronizableRepository.java @@ -10,6 +10,7 @@ */ package org.eclipse.emf.cdo.spi.server; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfoHandler; import org.eclipse.emf.cdo.server.ISynchronizableRepository; import org.eclipse.emf.cdo.spi.common.CDORawReplicationContext; import org.eclipse.emf.cdo.spi.common.CDOReplicationContext; @@ -21,7 +22,7 @@ import org.eclipse.emf.cdo.spi.common.CDOReplicationContext; * @noimplement This interface is not intended to be implemented by clients. */ public interface InternalSynchronizableRepository extends ISynchronizableRepository, InternalRepository, - CDOReplicationContext, CDORawReplicationContext + CDOReplicationContext, CDORawReplicationContext, CDOLockChangeInfoHandler { public InternalRepositorySynchronizer getSynchronizer(); diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalView.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalView.java index 7440be841f..8adca8fe50 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalView.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalView.java @@ -53,14 +53,4 @@ public interface InternalView extends IView, ILifecycle public void clearChangeSubscription(); public void doClose(); - - /** - * @since 4.1 - */ - public boolean isLockNotificationEnabled(); - - /** - * @since 4.1 - */ - public void setLockNotificationEnabled(boolean enable); } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/SyncingUtil.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/SyncingUtil.java new file mode 100644 index 0000000000..a6eef7052e --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/SyncingUtil.java @@ -0,0 +1,60 @@ +/** + * 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: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.spi.server; + +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockAreaNotFoundException; + +import org.eclipse.net4j.util.CheckUtil; + +/** + * Static methods that may help with classes related to repository synchronization. + * + * @author Eike Stepper + * @since 4.1 + */ +public final class SyncingUtil +{ + private SyncingUtil() + { + } + + public static InternalView openViewWithLockArea(InternalSession session, InternalLockManager lockManager, + CDOBranch viewedBranch, String lockAreaID) + { + LockArea lockArea; + InternalView view; + + try + { + lockArea = lockManager.getLockArea(lockAreaID); + + // If we get here, the lockArea already exists. + view = (InternalView)lockManager.openView(session, InternalSession.TEMP_VIEW_ID, true, lockAreaID); + } + catch (LockAreaNotFoundException e) + { + // If we get here, the lockArea does not yet exist, so we open + // a view without a lockArea first, then create a lockArea with the given ID, + // and associate it with the view. + view = session.openView(InternalSession.TEMP_VIEW_ID, viewedBranch.getHead()); + lockArea = lockManager.createLockArea(view, lockAreaID); + view.setDurableLockingID(lockAreaID); + } + + CheckUtil.checkNull(lockAreaID, "lockAreaID"); + CheckUtil.checkNull(lockArea, "lockArea"); + CheckUtil.checkState(lockAreaID.equals(lockArea.getDurableLockingID()), "lockAreaID has incorrect value"); + + return view; + } +} diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/LockingNotificationsTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/LockingNotificationsTest.java index 424762bb4d..b43e368938 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/LockingNotificationsTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/LockingNotificationsTest.java @@ -14,6 +14,7 @@ import org.eclipse.emf.cdo.CDOObject; import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation; import org.eclipse.emf.cdo.common.lock.CDOLockOwner; import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.lock.CDOLockUtil; @@ -26,8 +27,10 @@ import org.eclipse.emf.cdo.tests.util.TestListener2; 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.view.CDOLocksChangedEvent; import org.eclipse.emf.cdo.view.CDOView; +import org.eclipse.emf.cdo.view.CDOViewLocksChangedEvent; + +import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; /** * @author Caspar De Groot @@ -41,60 +44,135 @@ public class LockingNotificationsTest extends AbstractLockingTest return view; } - public void testSameBranchDifferentSession() throws CommitException + public void testSameBranchDifferentSession_explicitRelease() throws CommitException + { + sameBranchDifferentSession(LockReleaseMode.EXPLICIT); + } + + public void testSameBranchDifferentSession_autoRelease() throws CommitException + { + sameBranchDifferentSession(LockReleaseMode.AUTO); + } + + private void sameBranchDifferentSession(LockReleaseMode mode) throws CommitException { CDOSession session1 = openSession(); CDOSession session2 = openSession(); CDOView controlView = openViewWithLockNotifications(session2, null); - test(session1, controlView, true); + if (mode == LockReleaseMode.EXPLICIT) + { + withExplicitRelease(session1, controlView, true); + } + else if (mode == LockReleaseMode.AUTO) + { + withAutoRelease(session1, controlView, true); + } + session1.close(); session2.close(); } - public void testSameBranchSameSession() throws CommitException + public void testSameBranchSameSession_explicitRelease() throws CommitException + { + sameBranchSameSession(LockReleaseMode.EXPLICIT); + } + + public void testSameBranchSameSession_autoRelease() throws CommitException + { + sameBranchSameSession(LockReleaseMode.AUTO); + } + + private void sameBranchSameSession(LockReleaseMode mode) throws CommitException { CDOSession session1 = openSession(); CDOView controlView = openViewWithLockNotifications(session1, null); - test(session1, controlView, true); + if (mode == LockReleaseMode.EXPLICIT) + { + withExplicitRelease(session1, controlView, true); + } + else if (mode == LockReleaseMode.AUTO) + { + withAutoRelease(session1, controlView, true); + } + session1.close(); } @Requires(IRepositoryConfig.CAPABILITY_BRANCHING) public void testDifferentBranchDifferentSession() throws CommitException + { + differentBranchDifferentSession(LockReleaseMode.EXPLICIT); + } + + @Requires(IRepositoryConfig.CAPABILITY_BRANCHING) + public void testDifferentBranchDifferentSession_autoRelease() throws CommitException + { + differentBranchDifferentSession(LockReleaseMode.AUTO); + } + + private void differentBranchDifferentSession(LockReleaseMode mode) throws CommitException { CDOSession session1 = openSession(); CDOBranch subBranch = session1.getBranchManager().getMainBranch().createBranch("sub1"); CDOSession session2 = openSession(); CDOView controlView = openViewWithLockNotifications(session2, subBranch); - test(session1, controlView, false); + if (mode == LockReleaseMode.EXPLICIT) + { + withExplicitRelease(session1, controlView, false); + } + else if (mode == LockReleaseMode.AUTO) + { + withAutoRelease(session1, controlView, false); + } + session1.close(); session2.close(); } @Requires(IRepositoryConfig.CAPABILITY_BRANCHING) public void testDifferentBranchSameSession() throws CommitException + { + differentBranchSameSession(LockReleaseMode.EXPLICIT); + } + + @Requires(IRepositoryConfig.CAPABILITY_BRANCHING) + public void testDifferentBranchSameSession_autoRelease() throws CommitException + { + differentBranchSameSession(LockReleaseMode.AUTO); + } + + private void differentBranchSameSession(LockReleaseMode mode) throws CommitException { CDOSession session1 = openSession(); CDOBranch subBranch = session1.getBranchManager().getMainBranch().createBranch("sub2"); CDOView controlView = openViewWithLockNotifications(session1, subBranch); - test(session1, controlView, false); + if (mode == LockReleaseMode.EXPLICIT) + { + withExplicitRelease(session1, controlView, false); + } + else if (mode == LockReleaseMode.AUTO) + { + withAutoRelease(session1, controlView, false); + } + session1.close(); } - private void test(CDOSession session1, CDOView controlView, boolean mustReceiveNotifications) throws CommitException + private void withExplicitRelease(CDOSession session1, CDOView controlView, boolean mustReceiveNotifications) + throws CommitException { + TestListener2 controlViewListener = new TestListener2(CDOViewLocksChangedEvent.class); + controlView.addListener(controlViewListener); + CDOTransaction tx1 = session1.openTransaction(); CDOResource res1 = tx1.getOrCreateResource(getResourcePath("r1")); - TestListener2 transactionListener = new TestListener2(CDOLocksChangedEvent.class); + TestListener2 transactionListener = new TestListener2(CDOViewLocksChangedEvent.class); tx1.addListener(transactionListener); res1.getContents().clear(); Company company = getModel1Factory().createCompany(); res1.getContents().add(company); tx1.commit(); - TestListener2 controlViewListener = new TestListener2(CDOLocksChangedEvent.class); - controlView.addListener(controlViewListener); - CDOObject cdoCompany = CDOUtil.getCDOObject(company); CDOObject cdoCompanyInControlView = null; @@ -111,7 +189,7 @@ public class LockingNotificationsTest extends AbstractLockingTest controlViewListener.waitFor(1); assertEquals(1, controlViewListener.getEvents().size()); - CDOLocksChangedEvent event = (CDOLocksChangedEvent)controlViewListener.getEvents().get(0); + CDOViewLocksChangedEvent event = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(0); assertLockOwner(tx1, event.getLockOwner()); CDOLockState[] lockStates = event.getLockStates(); @@ -128,7 +206,7 @@ public class LockingNotificationsTest extends AbstractLockingTest assertEquals(2, controlViewListener.getEvents().size()); - CDOLocksChangedEvent event = (CDOLocksChangedEvent)controlViewListener.getEvents().get(1); + CDOViewLocksChangedEvent event = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(1); assertLockOwner(tx1, event.getLockOwner()); CDOLockState[] lockStates = event.getLockStates(); @@ -146,7 +224,7 @@ public class LockingNotificationsTest extends AbstractLockingTest controlViewListener.waitFor(3); assertEquals(3, controlViewListener.getEvents().size()); - CDOLocksChangedEvent event = (CDOLocksChangedEvent)controlViewListener.getEvents().get(2); + CDOViewLocksChangedEvent event = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(2); assertLockOwner(tx1, event.getLockOwner()); CDOLockState[] lockStates = event.getLockStates(); @@ -165,7 +243,7 @@ public class LockingNotificationsTest extends AbstractLockingTest assertEquals(4, controlViewListener.getEvents().size()); - CDOLocksChangedEvent event = (CDOLocksChangedEvent)controlViewListener.getEvents().get(3); + CDOViewLocksChangedEvent event = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(3); assertLockOwner(tx1, event.getLockOwner()); CDOLockState[] lockStates = event.getLockStates(); @@ -182,7 +260,7 @@ public class LockingNotificationsTest extends AbstractLockingTest controlViewListener.waitFor(5); assertEquals(5, controlViewListener.getEvents().size()); - CDOLocksChangedEvent event = (CDOLocksChangedEvent)controlViewListener.getEvents().get(4); + CDOViewLocksChangedEvent event = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(4); assertLockOwner(tx1, event.getLockOwner()); CDOLockState[] lockStates = event.getLockStates(); @@ -199,7 +277,7 @@ public class LockingNotificationsTest extends AbstractLockingTest assertEquals(6, controlViewListener.getEvents().size()); - CDOLocksChangedEvent event = (CDOLocksChangedEvent)controlViewListener.getEvents().get(5); + CDOViewLocksChangedEvent event = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(5); assertLockOwner(tx1, event.getLockOwner()); CDOLockState[] lockStates = event.getLockStates(); @@ -217,6 +295,58 @@ public class LockingNotificationsTest extends AbstractLockingTest } } + private void withAutoRelease(CDOSession session1, CDOView controlView, boolean mustReceiveNotifications) + throws CommitException + { + TestListener2 controlViewListener = new TestListener2(CDOViewLocksChangedEvent.class); + controlView.addListener(controlViewListener); + + CDOTransaction tx1 = session1.openTransaction(); + tx1.options().setAutoReleaseLocksEnabled(true); + CDOResource res1 = tx1.getOrCreateResource(getResourcePath("r1")); + res1.getContents().clear(); + Company company = getModel1Factory().createCompany(); + res1.getContents().add(company); + tx1.commit(); + + implicitRelease(company, LockType.WRITE, tx1, controlViewListener, mustReceiveNotifications); + implicitRelease(company, LockType.READ, tx1, controlViewListener, mustReceiveNotifications); + implicitRelease(company, LockType.OPTION, tx1, controlViewListener, mustReceiveNotifications); + } + + private void implicitRelease(Company company, LockType type, CDOTransaction tx, TestListener2 controlViewListener, + boolean mustReceiveNotifications) throws CommitException + { + CDOViewLocksChangedEvent e; + CDOObject cdoCompany = CDOUtil.getCDOObject(company); + + company.setName(company.getName() + "x"); // Make name field dirty + cdoCompany.cdoWriteLock().lock(); + + if (mustReceiveNotifications) + { + controlViewListener.waitFor(1); + e = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(0); + assertSame(Operation.LOCK, e.getOperation()); + assertSame(LockType.WRITE, e.getLockType()); + } + + tx.commit(); + + if (mustReceiveNotifications) + { + controlViewListener.waitFor(2); + e = (CDOViewLocksChangedEvent)controlViewListener.getEvents().get(1); + assertSame(Operation.UNLOCK, e.getOperation()); + assertNull(e.getLockType()); + } + + if (!mustReceiveNotifications) + { + assertEquals(0, controlViewListener.getEvents().size()); + } + } + private void assertLockedObject(CDOObject obj, Object lockedObject) { if (lockedObject instanceof CDOIDAndBranch) @@ -241,13 +371,13 @@ public class LockingNotificationsTest extends AbstractLockingTest CDOSession session1 = openSession(); CDOSession session2 = openSession(); CDOView controlView = session2.openView(); - test(session1, controlView, false); + withExplicitRelease(session1, controlView, false); controlView.options().setLockNotificationEnabled(true); - test(session1, controlView, true); + withExplicitRelease(session1, controlView, true); controlView.options().setLockNotificationEnabled(false); - test(session1, controlView, false); + withExplicitRelease(session1, controlView, false); session1.close(); session2.close(); @@ -275,7 +405,7 @@ public class LockingNotificationsTest extends AbstractLockingTest Company company1 = (Company)resource.getContents().get(0); CDOObject cdoObj = CDOUtil.getCDOObject(company1); assertEquals(true, cdoObj.cdoWriteLock().isLockedByOthers()); - assertSame(CDOLockOwner.UNKNOWN, cdoObj.cdoLockState().getWriteLockOwner()); + assertEquals(true, cdoObj.cdoLockState().getWriteLockOwner().isDurableView()); session2.close(); } @@ -297,7 +427,14 @@ public class LockingNotificationsTest extends AbstractLockingTest assertClean(cdoObj, tx1); assertNotNull(cdoObj.cdoLockState()); - res1.getContents().add(company1); - tx1.commit(); + session1.close(); + } + + /** + * @author Caspar De Groot + */ + private static enum LockReleaseMode + { + EXPLICIT, AUTO } } 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 409492315a..4186b96b2c 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 @@ -637,35 +637,40 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf stopMasterTransport(); } - @Override - protected InternalRepository createRepository(String name) + protected InternalRepository createMasterRepository(String masterName, String name, Map props, + boolean failover) { - boolean failover = getTestFailover(); - Map props = getRepositoryProperties(); - - final String masterName = name + "_master"; IStore masterStore = createStore(masterName); - - InternalRepository master; if (failover) { InternalRepositorySynchronizer synchronizer = createSynchronizer("backup", name); - master = (InternalRepository)CDOServerUtil.createFailoverParticipant(masterName, masterStore, props, + return (InternalRepository)CDOServerUtil.createFailoverParticipant(masterName, masterStore, props, synchronizer, true); } - else - { - master = (InternalRepository)CDOServerUtil.createRepository(masterName, masterStore, props); - } + return (InternalRepository)CDOServerUtil.createRepository(masterName, masterStore, props); + } + + @Override + protected InternalRepository createRepository(String name) + { + boolean failover = getTestFailover(); + Map props = getRepositoryProperties(); + + final String masterName = "master"; + InternalRepository master; synchronized (repositories) { - repositories.put(masterName, master); + master = repositories.get(masterName); + if (master == null) + { + master = createMasterRepository(masterName, name, props, failover); + repositories.put(masterName, master); + LifecycleUtil.activate(master); + startMasterTransport(); + } } - LifecycleUtil.activate(master); - startMasterTransport(); - InternalRepositorySynchronizer synchronizer = createSynchronizer("master", masterName); IStore store = createStore(name); @@ -673,33 +678,31 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf { return (InternalRepository)CDOServerUtil.createFailoverParticipant(name, store, props, synchronizer, false); } - else + + OfflineClone repository = new OfflineClone() { - OfflineClone repository = new OfflineClone() + @Override + public void handleCommitInfo(CDOCommitInfo commitInfo) { - @Override - public void handleCommitInfo(CDOCommitInfo commitInfo) - { - waitIfLockAvailable(); - super.handleCommitInfo(commitInfo); - } + waitIfLockAvailable(); + super.handleCommitInfo(commitInfo); + } - private void waitIfLockAvailable() + private void waitIfLockAvailable() + { + long millis = getTestDelayedCommitHandling(); + if (millis != 0L) { - long millis = getTestDelayedCommitHandling(); - if (millis != 0L) - { - ConcurrencyUtil.sleep(millis); - } + ConcurrencyUtil.sleep(millis); } - }; + } + }; - repository.setName(name); - repository.setStore((InternalStore)store); - repository.setProperties(props); - repository.setSynchronizer(synchronizer); - return repository; - } + repository.setName(name); + repository.setStore((InternalStore)store); + repository.setProperties(props); + repository.setSynchronizer(synchronizer); + return repository; } protected InternalRepositorySynchronizer createSynchronizer(final String acceptorName, final String repositoryName) diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_312879_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_312879_Test.java index 445bb9c939..2d208c952e 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_312879_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_312879_Test.java @@ -71,8 +71,7 @@ public class Bugzilla_312879_Test extends AbstractSyncingTest public void testSwitchMasterAndCommit() throws Exception { - InternalSynchronizableRepository repo1_master = (InternalSynchronizableRepository)getRepository(getRepository() - .getName() + "_master"); + InternalSynchronizableRepository repo1_master = (InternalSynchronizableRepository)getRepository("master"); InternalSynchronizableRepository repo1 = getRepository(); InternalSynchronizableRepository master = repo1_master; diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_319552_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_319552_Test.java index 479ff23821..0e532d5455 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_319552_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_319552_Test.java @@ -42,7 +42,7 @@ public class Bugzilla_319552_Test extends AbstractSyncingTest InternalRepository clone = getRepository(); waitForOnline(clone); - CDOSession masterSession = openSession(clone.getName() + "_master"); + CDOSession masterSession = openSession("master"); CDOTransaction masterTransaction = masterSession.openTransaction(); CDOSession session = openSession(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_325097_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_325097_Test.java index fa8e2f8596..2fab297d66 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_325097_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_325097_Test.java @@ -77,8 +77,7 @@ public class Bugzilla_325097_Test extends AbstractSyncingTest public void testNewObjectAfterSwitch() throws Exception { - InternalSynchronizableRepository repo1_master = (InternalSynchronizableRepository)getRepository(getRepository() - .getName() + "_master"); + InternalSynchronizableRepository repo1_master = (InternalSynchronizableRepository)getRepository("master"); InternalSynchronizableRepository repo1 = getRepository(); InternalSynchronizableRepository master = repo1_master; diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_326047_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_326047_Test.java index 3961f0e596..d12a932c2d 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_326047_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_326047_Test.java @@ -48,7 +48,7 @@ public class Bugzilla_326047_Test extends AbstractSyncingTest InternalRepository clone = getRepository(); waitForOnline(clone); - CDOSession masterSession = openSession(clone.getName() + "_master"); + CDOSession masterSession = openSession("master"); CDOTransaction masterTransaction = masterSession.openTransaction(); CDOSession session = openSession(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_328352_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_328352_Test.java index 3011c2df92..37caf351af 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_328352_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_328352_Test.java @@ -54,7 +54,7 @@ public class Bugzilla_328352_Test extends AbstractSyncingTest waitForOnline(clone); // create master session & transaction. - InternalRepository master = getRepository(clone.getName() + "_master"); + InternalRepository master = getRepository("master"); CDOSession masterSession = openSession(master.getName()); CDOTransaction masterTransaction = masterSession.openTransaction(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_329014_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_329014_Test.java index fe48027911..144648c21b 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_329014_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/Bugzilla_329014_Test.java @@ -61,7 +61,7 @@ public class Bugzilla_329014_Test extends AbstractSyncingTest cloneSession.options().setPassiveUpdateMode(PassiveUpdateMode.CHANGES); waitForOnline(clone); - master = getRepository(clone.getName() + "_master"); + master = getRepository("master"); masterSession = openSession(master.getName()); masterSession.options().setPassiveUpdateMode(PassiveUpdateMode.CHANGES); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/FailoverTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/FailoverTest.java index 88c50875c3..69d2d7f10b 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/FailoverTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/FailoverTest.java @@ -69,7 +69,7 @@ public class FailoverTest extends AbstractSyncingTest public void testMasterCommits_ArrivalInBackup() throws Exception { - CDOSession session = openSession(getRepository().getName() + "_master"); + CDOSession session = openSession("master"); CDOTransaction transaction = session.openTransaction(); CDOResource resource = transaction.createResource(getResourcePath("/my/resource")); @@ -112,7 +112,7 @@ public class FailoverTest extends AbstractSyncingTest public void testMasterCommits_NotificationsFromBackup() throws Exception { - CDOSession masterSession = openSession(getRepository().getName() + "_master"); + CDOSession masterSession = openSession("master"); CDOTransaction transaction = masterSession.openTransaction(); CDOResource resource = transaction.createResource("/my/resource"); @@ -158,8 +158,10 @@ public class FailoverTest extends AbstractSyncingTest public void testClientCommitsToBackupForbidden() throws Exception { - InternalRepository backup = getRepository(); - InternalRepository master = getRepository(backup.getName() + "_master"); + /* InternalRepository backup = */ + getRepository(); + + InternalRepository master = getRepository("master"); TestListener listener = new TestListener(); CDOSession masterSession = openSession(master.getName()); @@ -189,7 +191,7 @@ public class FailoverTest extends AbstractSyncingTest public void testPauseMasterTransport() throws Exception { - CDOSession session = openSession(getRepository().getName() + "_master"); + CDOSession session = openSession("master"); CDOTransaction transaction = session.openTransaction(); CDOResource resource = transaction.createResource(getResourcePath("/my/resource")); @@ -229,7 +231,7 @@ public class FailoverTest extends AbstractSyncingTest public void testSwitchMaster() throws Exception { - CDOSession session = openSession(getRepository().getName() + "_master"); + CDOSession session = openSession("master"); CDOTransaction transaction = session.openTransaction(); CDOResource resource = transaction.createResource(getResourcePath("/my/resource")); @@ -262,7 +264,7 @@ public class FailoverTest extends AbstractSyncingTest try { getRepository().setType(CDOCommonRepository.Type.MASTER); - getRepository(getRepository().getName() + "_master").setType(CDOCommonRepository.Type.BACKUP); + getRepository("master").setType(CDOCommonRepository.Type.BACKUP); company.setName("Commit should fail"); try @@ -292,7 +294,7 @@ public class FailoverTest extends AbstractSyncingTest public void testSwitchMasterAndCommit() throws Exception { - CDOSession session = openSession(getRepository().getName() + "_master"); + CDOSession session = openSession("master"); CDOTransaction transaction = session.openTransaction(); CDOResource resource = transaction.createResource(getResourcePath("/my/resource")); @@ -315,7 +317,7 @@ public class FailoverTest extends AbstractSyncingTest try { getRepository().setType(CDOCommonRepository.Type.MASTER); - getRepository(getRepository().getName() + "_master").setType(CDOCommonRepository.Type.BACKUP); + getRepository("master").setType(CDOCommonRepository.Type.BACKUP); session.close(); session = openSession(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineDelayed2Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineDelayed2Test.java index 1bada7bcda..e6b100f9bc 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineDelayed2Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineDelayed2Test.java @@ -34,8 +34,7 @@ public class OfflineDelayed2Test extends AbstractSyncingTest { int nbrOfCommits = 5; - InternalRepository clone = getRepository(); - InternalRepository master = getRepository(clone.getName() + "_master"); + InternalRepository master = getRepository("master"); CDOSession masterSession = openSession(master.getName()); CDOTransaction masterTransaction = masterSession.openTransaction(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineDelayedTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineDelayedTest.java index ae4dd9193d..a2055ca6e6 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineDelayedTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineDelayedTest.java @@ -43,7 +43,7 @@ public class OfflineDelayedTest extends AbstractSyncingTest getOfflineConfig().stopMasterTransport(); waitForOffline(clone); - CDOSession masterSession = openSession(clone.getName() + "_master"); + CDOSession masterSession = openSession("master"); CDOTransaction masterTransaction = masterSession.openTransaction(); CDOResource masterResource = masterTransaction.createResource("/master/resource"); for (int i = 0; i < 10; i++) @@ -81,7 +81,7 @@ public class OfflineDelayedTest extends AbstractSyncingTest waitForOnline(clone); { - CDOSession masterSession = openSession(clone.getName() + "_master"); + CDOSession masterSession = openSession("master"); CDOTransaction masterTransaction = masterSession.openTransaction(); CDOResource masterResource = masterTransaction.createResource("/master/resource"); @@ -131,7 +131,7 @@ public class OfflineDelayedTest extends AbstractSyncingTest getOfflineConfig().stopMasterTransport(); waitForOffline(clone); - CDOSession masterSession = openSession(clone.getName() + "_master"); + CDOSession masterSession = openSession("master"); CDOTransaction masterTransaction = masterSession.openTransaction(); CDOResource masterResource = masterTransaction.createResource("/master/resource"); for (int i = 0; i < 20; i++) diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineLockingTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineLockingTest.java index 7983d3919b..6c741957b1 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineLockingTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineLockingTest.java @@ -11,15 +11,26 @@ package org.eclipse.emf.cdo.tests.offline; import org.eclipse.emf.cdo.CDOObject; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation; import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.internal.server.syncing.OfflineClone; import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.session.CDOSessionInvalidationEvent; +import org.eclipse.emf.cdo.session.CDOSessionLocksChangedEvent; +import org.eclipse.emf.cdo.spi.server.InternalRepository; import org.eclipse.emf.cdo.tests.AbstractSyncingTest; import org.eclipse.emf.cdo.tests.model1.Company; import org.eclipse.emf.cdo.tests.util.TestListener2; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.util.CDOUtil; -import org.eclipse.emf.cdo.view.CDOLocksChangedEvent; +import org.eclipse.emf.cdo.util.CommitException; import org.eclipse.emf.cdo.view.CDOView; +import org.eclipse.emf.cdo.view.CDOViewLocksChangedEvent; + +import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; /** * @author Caspar De Groot @@ -28,9 +39,10 @@ public class OfflineLockingTest extends AbstractSyncingTest { public void testLockAndUnlockThrough() throws Exception { - CDOSession masterSession = openSession(getRepository().getName() + "_master"); + assertEquals(true, getRepository("repo1") instanceof OfflineClone); - CDOSession cloneSession = openSession(); + CDOSession masterSession = openSession("master"); + CDOSession cloneSession = openSession("repo1"); waitForOnline(cloneSession.getRepositoryInfo()); CDOTransaction cloneTx = cloneSession.openTransaction(); @@ -44,7 +56,7 @@ public class OfflineLockingTest extends AbstractSyncingTest CDOView masterView = masterSession.openView(); masterView.options().setLockNotificationEnabled(true); - TestListener2 masterViewListener = new TestListener2(CDOLocksChangedEvent.class); + TestListener2 masterViewListener = new TestListener2(CDOViewLocksChangedEvent.class); masterView.addListener(masterViewListener); CDOObject cdoCompanyOnMaster = masterView.getObject(cdoCompany.cdoID()); @@ -60,7 +72,232 @@ public class OfflineLockingTest extends AbstractSyncingTest masterSession.close(); } - public void testMasterLocks_ArrivalInClone() throws Exception + public void testCloneLocks_arrivalInOtherClone() throws Exception + { + // Create a 2nd clone repository + assertEquals(true, getRepository("repo1") instanceof OfflineClone); + assertEquals(true, getRepository("repo2") instanceof OfflineClone); + + CDOSession clone1Session = openSession("repo1"); + TestListener2 session1lockListener = new TestListener2(CDOSessionLocksChangedEvent.class, "session1lockListener"); + clone1Session.addListener(session1lockListener); + waitForOnline(clone1Session.getRepositoryInfo()); + + CDOSession clone2Session = openSession("repo2"); + TestListener2 session2invalidationListener = new TestListener2(CDOSessionInvalidationEvent.class, + "session2invalidationListener"); + clone2Session.addListener(session2invalidationListener); + TestListener2 session2lockListener = new TestListener2(CDOSessionLocksChangedEvent.class, "session2lockListener"); + clone2Session.addListener(session2lockListener); + waitForOnline(clone2Session.getRepositoryInfo()); + + CDOTransaction clone1Tx = openTransaction(clone1Session); + + CDOResource resourceInSession1 = clone1Tx.createResource(getResourcePath("test")); + Company companyA = getModel1Factory().createCompany(); + Company companyB = getModel1Factory().createCompany(); + Company companyC = getModel1Factory().createCompany(); + resourceInSession1.getContents().add(companyA); + resourceInSession1.getContents().add(companyB); + resourceInSession1.getContents().add(companyC); + clone1Tx.commit(); + + CDOObject companyA_session1 = CDOUtil.getCDOObject(companyA); + CDOObject companyB_session1 = CDOUtil.getCDOObject(companyB); + CDOObject companyC_session1 = CDOUtil.getCDOObject(companyC); + + session2invalidationListener.setTimeout(Integer.MAX_VALUE); + session2invalidationListener.waitFor(1); // Wait for the commit notification + + CDOTransaction clone2Tx = openTransaction(clone2Session); + + CDOResource resourceInSession2 = clone2Tx.getResource(getResourcePath("test")); + CDOObject companyA_session2 = CDOUtil.getCDOObject(resourceInSession2.getContents().get(0)); + CDOObject companyB_session2 = CDOUtil.getCDOObject(resourceInSession2.getContents().get(1)); + CDOObject companyC_session2 = CDOUtil.getCDOObject(resourceInSession2.getContents().get(2)); + + CDOSessionLocksChangedEvent e; + + // Verify that thusfar we haven't received any locking events in session 1 + assertEquals(0, session1lockListener.getEvents().size()); + + // Perform the lock in session 2, connected to clone 2 + companyA_session2.cdoWriteLock().lock(); + + // Wait for the lock notification in session 1, which is connected to clone 1 + session1lockListener.waitFor(1); + + e = (CDOSessionLocksChangedEvent)session1lockListener.getEvents().get(0); + assertSame(LockType.WRITE, e.getLockType()); + assertSame(Operation.LOCK, e.getOperation()); + assertEquals(true, companyA_session1.cdoWriteLock().isLockedByOthers()); + + // Perform the unlock in session 2, connected to clone 2 + companyA_session2.cdoWriteLock().unlock(); + + // Wait for the lock notification in session 1, which is connected to clone 1 + session1lockListener.waitFor(2); + + e = (CDOSessionLocksChangedEvent)session1lockListener.getEvents().get(1); + assertSame(LockType.WRITE, e.getLockType()); + assertSame(Operation.UNLOCK, e.getOperation()); + assertEquals(false, companyA_session1.cdoWriteLock().isLockedByOthers()); + + // Now vice versa . . . + + session2lockListener.getEvents().clear(); + + // Perform the lock in session 1, connected to clone 1 + companyA_session1.cdoWriteLock().lock(); + + // Wait for the lock notification in session 2, which is connected to clone 2 + session2lockListener.waitFor(1); + + e = (CDOSessionLocksChangedEvent)session2lockListener.getEvents().get(0); + assertSame(LockType.WRITE, e.getLockType()); + assertSame(Operation.LOCK, e.getOperation()); + assertEquals(true, companyA_session2.cdoWriteLock().isLockedByOthers()); + + // Perform the unlock in session 1, connected to clone 1 + companyA_session1.cdoWriteLock().unlock(); + + // Wait for the lock notification in session 1, which is connected to clone 1 + session2lockListener.waitFor(2); + + e = (CDOSessionLocksChangedEvent)session2lockListener.getEvents().get(1); + assertSame(LockType.WRITE, e.getLockType()); + assertSame(Operation.UNLOCK, e.getOperation()); + assertEquals(false, companyA_session2.cdoWriteLock().isLockedByOthers()); + + // Now try an unlock-all . . . + + session1lockListener.getEvents().clear(); + + companyA_session2.cdoReadLock().lock(); + companyB_session2.cdoWriteLock().lock(); + companyC_session2.cdoWriteOption().lock(); + + session1lockListener.waitFor(3); + + assertEquals(true, companyA_session1.cdoReadLock().isLockedByOthers()); + assertEquals(true, companyB_session1.cdoWriteLock().isLockedByOthers()); + assertEquals(true, companyC_session1.cdoWriteOption().isLockedByOthers()); + + clone2Tx.unlockObjects(); + + session1lockListener.waitFor(4); + + assertEquals(false, companyA_session1.cdoReadLock().isLockedByOthers()); + assertEquals(false, companyA_session1.cdoWriteLock().isLockedByOthers()); + assertEquals(false, companyA_session1.cdoWriteOption().isLockedByOthers()); + + clone1Session.close(); + clone2Session.close(); + } + + public void testCloneLocks_replicationToOtherClone() throws CommitException + { + InternalRepository repo1 = getRepository("repo1"); + assertEquals(true, repo1 instanceof OfflineClone); + InternalRepository repo2 = getRepository("repo2"); + assertEquals(true, repo2 instanceof OfflineClone); + + OfflineClone clone2 = (OfflineClone)repo2; + + waitForOnline(getRepository("repo1")); + waitForOnline(getRepository("repo2")); + + CDOSession clone1session = openSession("repo1"); + + // Store 3 objects in repo1 + CDOTransaction tx1_sess1 = openTransaction(clone1session); + CDOResource resource_tx1_sess1 = tx1_sess1.createResource(getResourcePath("test")); + Company companyA = getModel1Factory().createCompany(); + Company companyB = getModel1Factory().createCompany(); + Company companyC = getModel1Factory().createCompany(); + resource_tx1_sess1.getContents().add(companyA); + resource_tx1_sess1.getContents().add(companyB); + resource_tx1_sess1.getContents().add(companyC); + tx1_sess1.commit(); + + { + // Verify that they're visible in repo2 + CDOSession clone2session = openSession("repo2"); + CDOTransaction tx1_sess2 = openTransaction(clone2session); + CDOResource resource_tx1_sess2 = tx1_sess2.getResource(getResourcePath("test")); + assertEquals(3, resource_tx1_sess2.getContents().size()); + tx1_sess2.close(); + clone2session.close(); + } + + clone2.goOffline(); + waitForOffline(clone2); + + // Lock the objects in repo1. Since repo1 is ONLINE, this will also lock them + // in the master. + CDOUtil.getCDOObject(companyA).cdoReadLock().lock(); + CDOUtil.getCDOObject(companyB).cdoWriteLock().lock(); + CDOUtil.getCDOObject(companyC).cdoWriteOption().lock(); + + clone2.goOnline(); + waitForOnline(clone2); + + { + // Verify that the locks are visible in repo2 + CDOSession clone2session = openSession("repo2"); + CDOTransaction tx1_sess2 = openTransaction(clone2session); + CDOResource resource_tx1_sess2 = tx1_sess2.getResource(getResourcePath("test")); + EList contents = resource_tx1_sess2.getContents(); + CDOObject companyA_in_sess2 = CDOUtil.getCDOObject(contents.get(0)); + CDOObject companyB_in_sess2 = CDOUtil.getCDOObject(contents.get(1)); + CDOObject companyC_in_sess2 = CDOUtil.getCDOObject(contents.get(2)); + + assertEquals(true, companyA_in_sess2.cdoReadLock().isLockedByOthers()); + assertEquals(true, companyB_in_sess2.cdoWriteLock().isLockedByOthers()); + assertEquals(true, companyC_in_sess2.cdoWriteOption().isLockedByOthers()); + + tx1_sess2.close(); + clone2session.close(); + } + + clone2.goOffline(); + waitForOffline(clone2); + + // Unlock the objects in repo1. Since repo1 is ONLINE, this will also lock them + // in the master. + CDOUtil.getCDOObject(companyA).cdoReadLock().unlock(); + CDOUtil.getCDOObject(companyB).cdoWriteLock().unlock(); + CDOUtil.getCDOObject(companyC).cdoWriteOption().unlock(); + + clone2.goOnline(); + waitForOnline(clone2); + + { + // Verify in repo2 + CDOSession clone2session = openSession("repo2"); + CDOTransaction tx1_sess2 = openTransaction(clone2session); + CDOResource resource_tx1_sess2 = tx1_sess2.getResource(getResourcePath("test")); + EList contents = resource_tx1_sess2.getContents(); + CDOObject companyA_in_sess2 = CDOUtil.getCDOObject(contents.get(0)); + CDOObject companyB_in_sess2 = CDOUtil.getCDOObject(contents.get(1)); + CDOObject companyC_in_sess2 = CDOUtil.getCDOObject(contents.get(2)); + + assertEquals(false, companyA_in_sess2.cdoReadLock().isLockedByOthers()); + assertEquals(false, companyB_in_sess2.cdoWriteLock().isLockedByOthers()); + assertEquals(false, companyC_in_sess2.cdoWriteOption().isLockedByOthers()); + + tx1_sess2.close(); + clone2session.close(); + } + + clone1session.close(); + } + + private static CDOTransaction openTransaction(CDOSession session) { + CDOTransaction tx = session.openTransaction(); + tx.options().setLockNotificationEnabled(true); + tx.enableDurableLocking(true); + return tx; } } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineRawTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineRawTest.java index a23a1aa775..e9f3d02e8b 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineRawTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineRawTest.java @@ -69,7 +69,7 @@ public class OfflineRawTest extends OfflineTest transaction.addListener(transactionListener); { - CDOSession masterSession = openSession(clone.getName() + "_master"); + CDOSession masterSession = openSession("master"); CDOTransaction masterTransaction = masterSession.openTransaction(); CDOResource masterResource = masterTransaction.getResource("/my/resource"); @@ -136,7 +136,7 @@ public class OfflineRawTest extends OfflineTest transaction.addListener(transactionListener); { - CDOSession masterSession = openSession(clone.getName() + "_master"); + CDOSession masterSession = openSession("master"); CDOTransaction masterTransaction = masterSession.openTransaction(); CDOResource masterResource = masterTransaction.getResource("/my/resource"); @@ -198,7 +198,7 @@ public class OfflineRawTest extends OfflineTest waitForOffline(clone); { - CDOSession masterSession = openSession(clone.getName() + "_master"); + CDOSession masterSession = openSession("master"); CDOTransaction masterTransaction = masterSession.openTransaction(); CDOResource masterResource = masterTransaction.getResource("/my/resource"); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineTest.java index 5c848502cc..8787e1a332 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineTest.java @@ -40,7 +40,7 @@ public class OfflineTest extends AbstractSyncingTest { public void testMasterCommits_ArrivalInClone() throws Exception { - CDOSession session = openSession(getRepository().getName() + "_master"); + CDOSession session = openSession("master"); CDOTransaction transaction = session.openTransaction(); CDOResource resource = transaction.createResource("/my/resource"); @@ -83,7 +83,7 @@ public class OfflineTest extends AbstractSyncingTest protected void masterCommits_NotificationsFromClone() throws Exception { - CDOSession masterSession = openSession(getRepository().getName() + "_master"); + CDOSession masterSession = openSession("master"); CDOTransaction transaction = masterSession.openTransaction(); CDOResource resource = transaction.createResource("/my/resource"); @@ -130,7 +130,7 @@ public class OfflineTest extends AbstractSyncingTest public void testClientCommits() throws Exception { InternalRepository clone = getRepository(); - InternalRepository master = getRepository(clone.getName() + "_master"); + InternalRepository master = getRepository("master"); TestListener listener = new TestListener(); CDOSession masterSession = openSession(master.getName()); @@ -165,7 +165,7 @@ public class OfflineTest extends AbstractSyncingTest getOfflineConfig().stopMasterTransport(); waitForOffline(clone); - CDOSession masterSession = openSession(clone.getName() + "_master"); + CDOSession masterSession = openSession("master"); CDOTransaction masterTransaction = masterSession.openTransaction(); CDOResource masterResource = masterTransaction.createResource("/master/resource"); @@ -205,7 +205,7 @@ public class OfflineTest extends AbstractSyncingTest getOfflineConfig().stopMasterTransport(); waitForOffline(clone); - CDOSession masterSession = openSession(clone.getName() + "_master"); + CDOSession masterSession = openSession("master"); CDOTransaction masterTransaction = masterSession.openTransaction(); CDOResource masterResource = masterTransaction.createResource("/master/resource"); @@ -238,7 +238,7 @@ public class OfflineTest extends AbstractSyncingTest getOfflineConfig().stopMasterTransport(); waitForOffline(clone); - CDOSession masterSession = openSession(clone.getName() + "_master"); + CDOSession masterSession = openSession("master"); CDOTransaction masterTransaction = masterSession.openTransaction(); CDOResource masterResource = masterTransaction.createResource("/master/resource"); @@ -356,7 +356,7 @@ public class OfflineTest extends AbstractSyncingTest getOfflineConfig().stopMasterTransport(); waitForOffline(clone); - CDOSession masterSession = openSession(clone.getName() + "_master"); + CDOSession masterSession = openSession("master"); CDOTransaction transaction = masterSession.openTransaction(); CDOResource resource = transaction.createResource("/my/resource"); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestListener2.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestListener2.java index b05050dac8..3e77c7ca93 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestListener2.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestListener2.java @@ -24,18 +24,31 @@ import junit.framework.Assert; */ public class TestListener2 implements IListener { + private final static long DEFAULT_TIMEOUT = 3000; // 3 seconds + private List events = new LinkedList(); private Class eventClass; + private long timeout; + + private String name; + public TestListener2(Class eventClass) + { + this(eventClass, null); + } + + public TestListener2(Class eventClass, String name) { this.eventClass = eventClass; + this.name = name; + timeout = DEFAULT_TIMEOUT; } public synchronized void notifyEvent(IEvent event) { - if (eventClass.isAssignableFrom(event.getClass())) + if (eventClass == null || eventClass.isAssignableFrom(event.getClass())) { events.add(event); notify(); @@ -47,9 +60,13 @@ public class TestListener2 implements IListener return events; } - public synchronized void waitFor(int n) + public void setTimeout(long timeout) + { + this.timeout = timeout; + } + + public synchronized void waitFor(int n, long timeout) { - long timeout = 2000; long t = 0; while (events.size() < n) @@ -72,4 +89,35 @@ public class TestListener2 implements IListener timeout -= System.currentTimeMillis() - t; } } + + public void waitFor(int i) + { + waitFor(i, timeout); + } + + @Override + public String toString() + { + StringBuilder builder = new StringBuilder(TestListener2.class.getSimpleName()); + builder.append('['); + if (name != null) + { + builder.append("name=\""); + builder.append(name); + builder.append('\"'); + } + + if (eventClass != null) + { + if (builder.charAt(builder.length() - 1) != '[') + { + builder.append(';'); + } + builder.append("eventClass="); + builder.append(eventClass.getSimpleName()); + } + + builder.append(']'); + return builder.toString(); + } } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestSessionConfiguration.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestSessionConfiguration.java index 81c2408d9e..f9b3b7a379 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestSessionConfiguration.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestSessionConfiguration.java @@ -10,6 +10,7 @@ */ package org.eclipse.emf.cdo.tests.util; +import org.eclipse.emf.cdo.common.CDOCommonSession.Options.LockNotificationMode; import org.eclipse.emf.cdo.common.CDOCommonSession.Options.PassiveUpdateMode; import org.eclipse.emf.cdo.common.id.CDOIDGenerator; import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator; @@ -23,47 +24,52 @@ import org.eclipse.net4j.util.event.Notifier; */ public abstract class TestSessionConfiguration extends Notifier implements CDOSessionConfiguration { - public void setPassiveUpdateMode(PassiveUpdateMode passiveUpdateMode) + public boolean isSessionOpen() { throw new UnsupportedOperationException(); } - public void setPassiveUpdateEnabled(boolean passiveUpdateEnabled) + public boolean isActivateOnOpen() { throw new UnsupportedOperationException(); } - public void setExceptionHandler(CDOSession.ExceptionHandler exceptionHandler) + public void setActivateOnOpen(boolean activateOnOpen) { throw new UnsupportedOperationException(); } - public void setIDGenerator(CDOIDGenerator idGenerator) + public CDOAuthenticator getAuthenticator() { throw new UnsupportedOperationException(); } - public void setActivateOnOpen(boolean activateOnOpen) + public boolean isPassiveUpdateEnabled() { throw new UnsupportedOperationException(); } - public boolean isSessionOpen() + public void setPassiveUpdateEnabled(boolean passiveUpdateEnabled) { throw new UnsupportedOperationException(); } - public boolean isPassiveUpdateEnabled() + public PassiveUpdateMode getPassiveUpdateMode() { throw new UnsupportedOperationException(); } - public boolean isActivateOnOpen() + public void setPassiveUpdateMode(PassiveUpdateMode passiveUpdateMode) { throw new UnsupportedOperationException(); } - public PassiveUpdateMode getPassiveUpdateMode() + public LockNotificationMode getLockNotificationMode() + { + throw new UnsupportedOperationException(); + } + + public void setLockNotificationMode(LockNotificationMode mode) { throw new UnsupportedOperationException(); } @@ -73,12 +79,17 @@ public abstract class TestSessionConfiguration extends Notifier implements CDOSe throw new UnsupportedOperationException(); } + public void setExceptionHandler(CDOSession.ExceptionHandler exceptionHandler) + { + throw new UnsupportedOperationException(); + } + public CDOIDGenerator getIDGenerator() { throw new UnsupportedOperationException(); } - public CDOAuthenticator getAuthenticator() + public void setIDGenerator(CDOIDGenerator idGenerator) { throw new UnsupportedOperationException(); } diff --git a/plugins/org.eclipse.emf.cdo/.settings/.api_filters b/plugins/org.eclipse.emf.cdo/.settings/.api_filters index c9ee6895d7..19ffeb033c 100644 --- a/plugins/org.eclipse.emf.cdo/.settings/.api_filters +++ b/plugins/org.eclipse.emf.cdo/.settings/.api_filters @@ -60,6 +60,14 @@ + + + + + + + + @@ -91,33 +99,35 @@ - + - - + + + + - - + + - + - - + + - + - - + + @@ -157,6 +167,14 @@ + + + + + + + + @@ -166,6 +184,15 @@ + + + + + + + + + diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSessionConfiguration.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSessionConfiguration.java index 02912bb8ff..c219833a51 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSessionConfiguration.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSessionConfiguration.java @@ -10,6 +10,7 @@ */ package org.eclipse.emf.cdo.session; +import org.eclipse.emf.cdo.common.CDOCommonSession.Options.LockNotificationMode; import org.eclipse.emf.cdo.common.CDOCommonSession.Options.PassiveUpdateMode; import org.eclipse.emf.cdo.common.id.CDOIDGenerator; import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator; @@ -51,6 +52,16 @@ public interface CDOSessionConfiguration extends INotifier */ public void setPassiveUpdateMode(PassiveUpdateMode passiveUpdateMode); + /** + * @since 4.1 + */ + public LockNotificationMode getLockNotificationMode(); + + /** + * @since 4.1 + */ + public void setLockNotificationMode(LockNotificationMode mode); + /** * @see CDOSession#getExceptionHandler() */ diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSessionLocksChangedEvent.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSessionLocksChangedEvent.java new file mode 100644 index 0000000000..90faae741d --- /dev/null +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSessionLocksChangedEvent.java @@ -0,0 +1,26 @@ +/** + * 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.session; + +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; +import org.eclipse.emf.cdo.view.CDOView; + +/** + * @author Caspar De Groot + * @since 4.1 + */ +public interface CDOSessionLocksChangedEvent extends CDOSessionEvent, CDOLockChangeInfo +{ + /** + * Returns the view that caused the lock changes if this view is local, or null if the view was remote. + */ + public CDOView getSender(); +} 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 deleted file mode 100644 index 904dabbaaf..0000000000 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOLocksChangedEvent.java +++ /dev/null @@ -1,24 +0,0 @@ -/** - * 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 4d74a8f3c2..100d1a4f65 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,7 +21,6 @@ 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; @@ -35,10 +34,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; import org.eclipse.net4j.util.options.IOptionsEvent; import org.eclipse.net4j.util.ref.ReferenceType; @@ -76,7 +72,7 @@ import java.util.Set; * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface CDOView extends CDOCommonView, CDOUpdatable, INotifier, IOptionsContainer +public interface CDOView extends CDOCommonView, CDOUpdatable, INotifier { /** * Returns the {@link CDOSession session} this view was opened by. @@ -406,7 +402,7 @@ public interface CDOView extends CDOCommonView, CDOUpdatable, INotifier, IOption * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ - public interface Options extends IOptions + public interface Options extends org.eclipse.emf.cdo.common.CDOCommonView.Options { /** * Returns the {@link CDOView view} of this options object. @@ -467,27 +463,6 @@ public interface CDOView extends CDOCommonView, CDOUpdatable, INotifier, IOption */ public void setInvalidationNotificationEnabled(boolean enabled); - /** - * Returns true 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 other views), - * false 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 other 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}. * @@ -668,14 +643,6 @@ 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 diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOViewLocksChangedEvent.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOViewLocksChangedEvent.java new file mode 100644 index 0000000000..8bdb7d8005 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOViewLocksChangedEvent.java @@ -0,0 +1,25 @@ +/** + * 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; + +/** + * @author Caspar De Groot + * @since 4.1 + */ +public interface CDOViewLocksChangedEvent extends CDOViewEvent, CDOLockChangeInfo +{ + /** + * Returns the view that caused the lock changes if this view is local, or null if the view was remote. + */ + public CDOView getSender(); +} diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionConfigurationImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionConfigurationImpl.java index 607d3855fe..3bb1caf936 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionConfigurationImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionConfigurationImpl.java @@ -10,6 +10,7 @@ */ package org.eclipse.emf.internal.cdo.session; +import org.eclipse.emf.cdo.common.CDOCommonSession.Options.LockNotificationMode; import org.eclipse.emf.cdo.common.CDOCommonSession.Options.PassiveUpdateMode; import org.eclipse.emf.cdo.common.branch.CDOBranchManager; import org.eclipse.emf.cdo.common.commit.CDOCommitInfoManager; @@ -43,6 +44,8 @@ public abstract class CDOSessionConfigurationImpl extends Notifier implements In private PassiveUpdateMode passiveUpdateMode = PassiveUpdateMode.INVALIDATIONS; + private LockNotificationMode lockNotificationMode = LockNotificationMode.IF_REQUIRED_BY_VIEWS; + private CDOAuthenticator authenticator = new CDOAuthenticatorImpl(); private CDOSession.ExceptionHandler exceptionHandler; @@ -120,6 +123,22 @@ public abstract class CDOSessionConfigurationImpl extends Notifier implements In this.passiveUpdateMode = passiveUpdateMode; } + public LockNotificationMode getLockNotificationMode() + { + return lockNotificationMode; + } + + public void setLockNotificationMode(LockNotificationMode lockNotificationMode) + { + checkNotOpen(); + uncheckedSetLockNotificationMode(lockNotificationMode); + } + + protected void uncheckedSetLockNotificationMode(LockNotificationMode lockNotificationMode) + { + this.lockNotificationMode = lockNotificationMode; + } + public CDOAuthenticator getAuthenticator() { return authenticator; @@ -272,6 +291,7 @@ public abstract class CDOSessionConfigurationImpl extends Notifier implements In { session.options().setPassiveUpdateEnabled(passiveUpdateEnabled); session.options().setPassiveUpdateMode(passiveUpdateMode); + session.options().setLockNotificationMode(lockNotificationMode); session.setMainBranchLocal(mainBranchLocal); session.setExceptionHandler(exceptionHandler); 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 0c3f04c28c..4e5b154dff 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 @@ -57,6 +57,7 @@ import org.eclipse.emf.cdo.session.CDOCollectionLoadingPolicy; import org.eclipse.emf.cdo.session.CDORepositoryInfo; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.session.CDOSessionInvalidationEvent; +import org.eclipse.emf.cdo.session.CDOSessionLocksChangedEvent; import org.eclipse.emf.cdo.session.remote.CDORemoteSessionManager; import org.eclipse.emf.cdo.spi.common.CDOLobStoreImpl; import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil; @@ -83,6 +84,7 @@ import org.eclipse.emf.internal.cdo.bundle.OM; import org.eclipse.emf.internal.cdo.messages.Messages; import org.eclipse.emf.internal.cdo.object.CDOFactoryImpl; import org.eclipse.emf.internal.cdo.session.remote.CDORemoteSessionManagerImpl; +import org.eclipse.emf.internal.cdo.util.DefaultLocksChangedEvent; import org.eclipse.net4j.util.ObjectUtil; import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump; @@ -836,12 +838,17 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme } } - public void handleLockNotification(CDOLockChangeInfo lockChangeInfo) + public void handleLockNotification(CDOLockChangeInfo lockChangeInfo, InternalCDOView sender) { for (InternalCDOView view : getViews()) { - view.handleLockNotification(lockChangeInfo); + if (view != sender) + { + view.handleLockNotification(sender, lockChangeInfo); + } } + + fireEvent(new LocksChangedEvent(sender, lockChangeInfo)); } private void registerPackageUnits(List packageUnits) @@ -1334,6 +1341,8 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme private PassiveUpdateMode passiveUpdateMode = PassiveUpdateMode.INVALIDATIONS; + private LockNotificationMode lockNotificationMode = LockNotificationMode.IF_REQUIRED_BY_VIEWS; + private CDOCollectionLoadingPolicy collectionLoadingPolicy; private CDOLobStore lobCache = CDOLobStoreImpl.INSTANCE; @@ -1429,6 +1438,16 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme } } + public LockNotificationMode getLockNotificationMode() + { + return lockNotificationMode; + } + + public void setLockNotificationMode(LockNotificationMode lockNotificationMode) + { + this.lockNotificationMode = lockNotificationMode; + } + public CDOCollectionLoadingPolicy getCollectionLoadingPolicy() { synchronized (this) @@ -1717,4 +1736,24 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme return "CDOSessionInvalidationEvent[" + commitInfo + "]"; //$NON-NLS-1$ //$NON-NLS-2$ } } + + /** + * @author Caspar De Groot + * @since 4.1 + */ + private final class LocksChangedEvent extends DefaultLocksChangedEvent implements CDOSessionLocksChangedEvent + { + private static final long serialVersionUID = 1L; + + public LocksChangedEvent(InternalCDOView sender, CDOLockChangeInfo lockChangeInfo) + { + super(CDOSessionImpl.this, sender, lockChangeInfo); + } + + @Override + public CDOSession getSource() + { + return (CDOSession)super.getSource(); + } + } } 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 0d1a9d2329..73d8546d3a 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.CDOLockChangeInfo.Operation; import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.model.CDOModelUtil; import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; @@ -2652,7 +2653,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa CDOLockState[] newLockStates = result.getNewLockStates(); if (newLockStates != null) { - updateLockStates(newLockStates); + updateAndNotifyLockStates(Operation.UNLOCK, null, newLockStates); } } catch (RuntimeException ex) diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/util/DefaultLocksChangedEvent.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/util/DefaultLocksChangedEvent.java new file mode 100644 index 0000000000..3a3577d454 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/util/DefaultLocksChangedEvent.java @@ -0,0 +1,77 @@ +/** + * 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: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.internal.cdo.util; + +import org.eclipse.emf.cdo.common.branch.CDOBranch; +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.net4j.util.concurrent.IRWLockManager.LockType; +import org.eclipse.net4j.util.event.Event; +import org.eclipse.net4j.util.event.INotifier; + +import org.eclipse.emf.spi.cdo.InternalCDOView; + +/** + * @author Caspar De Groot + * @since 4.1 + */ +public class DefaultLocksChangedEvent extends Event implements CDOLockChangeInfo +{ + private static final long serialVersionUID = 1L; + + private final InternalCDOView sender; + + private final CDOLockChangeInfo lockChangeInfo; + + public DefaultLocksChangedEvent(INotifier notifier, InternalCDOView sender, CDOLockChangeInfo lockChangeInfo) + { + super(notifier); + this.sender = sender; + this.lockChangeInfo = lockChangeInfo; + } + + public InternalCDOView getSender() + { + return sender; + } + + 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(); + } + + public LockType getLockType() + { + return lockChangeInfo.getLockType(); + } +} diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java index 2c481cdf2d..8137cbc8a4 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java @@ -208,6 +208,11 @@ public abstract class AbstractCDOView extends Lifecycle implements InternalCDOVi if (rootResource == null) { CDOID rootResourceID = getSession().getRepositoryInfo().getRootResourceID(); + if (rootResourceID == null || rootResourceID.isNull()) + { + throw new IllegalStateException("RootResourceID is null; is the repository not yet initialized?"); + } + CDOResourceImpl resource = (CDOResourceImpl)getObject(rootResourceID); setRootResource(resource); } 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 ccf4144098..5f6be8a610 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 @@ -19,6 +19,7 @@ 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.CDOLockChangeInfo.Operation; import org.eclipse.emf.cdo.common.lock.CDOLockOwner; import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.lock.CDOLockUtil; @@ -41,18 +42,19 @@ 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; import org.eclipse.emf.cdo.view.CDOViewDurabilityChangedEvent; import org.eclipse.emf.cdo.view.CDOViewInvalidationEvent; +import org.eclipse.emf.cdo.view.CDOViewLocksChangedEvent; import org.eclipse.emf.internal.cdo.bundle.OM; import org.eclipse.emf.internal.cdo.messages.Messages; import org.eclipse.emf.internal.cdo.object.CDODeltaNotificationImpl; import org.eclipse.emf.internal.cdo.object.CDOInvalidationNotificationImpl; import org.eclipse.emf.internal.cdo.object.CDONotificationBuilder; +import org.eclipse.emf.internal.cdo.util.DefaultLocksChangedEvent; import org.eclipse.net4j.util.ObjectUtil; import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump; @@ -86,6 +88,7 @@ import org.eclipse.emf.spi.cdo.FSMUtil; import org.eclipse.emf.spi.cdo.InternalCDOObject; import org.eclipse.emf.spi.cdo.InternalCDOSession; import org.eclipse.emf.spi.cdo.InternalCDOTransaction; +import org.eclipse.emf.spi.cdo.InternalCDOView; import org.eclipse.core.runtime.NullProgressMonitor; @@ -293,7 +296,8 @@ public class CDOViewImpl extends AbstractCDOView throw new AssertionError("Unexpected lock result state"); } - updateLockStates(result.getNewLockStates()); + // Update the lock states in this view + updateAndNotifyLockStates(Operation.LOCK, lockType, result.getNewLockStates()); if (result.isWaitForUpdate()) { @@ -308,6 +312,15 @@ public class CDOViewImpl extends AbstractCDOView } } + protected void updateAndNotifyLockStates(Operation op, LockType type, CDOLockState[] newLockStates) + { + updateLockStates(newLockStates); + notifyOtherViewsAboutLockChanges(op, type, newLockStates); + } + + /** + * Updates the lock states of objects held in this view + */ protected void updateLockStates(CDOLockState[] newLockStates) { for (CDOLockState lockState : newLockStates) @@ -331,6 +344,60 @@ public class CDOViewImpl extends AbstractCDOView } } + /** + * Notifies other views of lock changes performed in this view + */ + private void notifyOtherViewsAboutLockChanges(Operation op, LockType type, CDOLockState[] lockStates) + { + if (lockStates.length > 0) + { + CDOLockChangeInfo lockChangeInfo = makeLockChangeInfo(op, type, lockStates); + getSession().handleLockNotification(lockChangeInfo, this); + } + } + + private CDOLockChangeInfo makeLockChangeInfo(Operation op, LockType type, CDOLockState[] newLockStates) + { + long timestamp = 0L; // TODO (CD) Get rid of timestamps; replace with sequential number + return CDOLockUtil.createLockChangeInfo(timestamp, this, getBranch(), op, type, newLockStates); + } + + public void handleLockNotification(InternalCDOView sender, 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; + } + + // TODO (CD) I know it is Eike's desideratum that this be done asynchronously.. but beware, + // this will require the tests to be fixed to listen for the view events instead of the + // session events. + updateLockStates(lockChangeInfo.getLockStates()); + fireLocksChangedEvent(sender, lockChangeInfo); + } + + private void fireLocksChangedEvent(InternalCDOView sender, CDOLockChangeInfo lockChangeInfo) + { + IListener[] listeners = getListeners(); + if (listeners != null) + { + fireEvent(new LocksChangedEvent(sender, lockChangeInfo), listeners); + } + } + protected InternalCDORevision getRevision(CDOObject object) { if (object.cdoState() == CDOState.NEW) @@ -367,7 +434,7 @@ public class CDOViewImpl extends AbstractCDOView CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); UnlockObjectsResult result = sessionProtocol.unlockObjects2(this, objectIDs, lockType); - updateLockStates(result.getNewLockStates()); + updateAndNotifyLockStates(Operation.UNLOCK, lockType, result.getNewLockStates()); } /** @@ -928,39 +995,6 @@ 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; - } - - updateLockStates(lockChangeInfo.getLockStates()); - fireLocksChangedEvent(lockChangeInfo); - } - - private void fireLocksChangedEvent(CDOLockChangeInfo lockChangeInfo) - { - IListener[] listeners = getListeners(); - if (listeners != null) - { - fireEvent(new LocksChangedEvent(lockChangeInfo), listeners); - } - } - /** * @author Simon McDuff * @since 2.0 @@ -1392,40 +1426,19 @@ public class CDOViewImpl extends AbstractCDOView * @author Caspar De Groot * @since 4.1 */ - private final class LocksChangedEvent extends Event implements CDOLocksChangedEvent + private final class LocksChangedEvent extends DefaultLocksChangedEvent implements CDOViewLocksChangedEvent { 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() + public LocksChangedEvent(InternalCDOView sender, CDOLockChangeInfo lockChangeInfo) { - return lockChangeInfo.getLockOwner(); + super(CDOViewImpl.this, sender, lockChangeInfo); } - public CDOLockState[] getLockStates() - { - return lockChangeInfo.getLockStates(); - } - - public Operation getOperation() + @Override + public InternalCDOView getSource() { - return lockChangeInfo.getOperation(); + return (InternalCDOView)super.getSource(); } } @@ -1524,7 +1537,7 @@ public class CDOViewImpl extends AbstractCDOView event = new LockNotificationEventImpl(); } } - + fireEvent(event); } @@ -1817,7 +1830,7 @@ public class CDOViewImpl extends AbstractCDOView private final class LockNotificationEventImpl extends OptionsEvent implements LockNotificationEvent { private static final long serialVersionUID = 1L; - + public LockNotificationEventImpl() { super(OptionsImpl.this); 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 2f0459575c..e7dac87441 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 @@ -183,7 +183,7 @@ public interface InternalCDOSession extends CDOSession, PackageProcessor, Packag /** * @since 4.1 */ - public void handleLockNotification(CDOLockChangeInfo lockChangeInfo); + public void handleLockNotification(CDOLockChangeInfo lockChangeInfo, InternalCDOView sender); /** * @since 3.0 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 27ba5cc0b0..f2e163ceb1 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 @@ -139,39 +139,10 @@ public interface InternalCDOView extends CDOView, CDOIDProvider, ILifecycle /** * @since 4.1 */ - public void handleLockNotification(CDOLockChangeInfo lockChangeInfo); + public void handleLockNotification(InternalCDOView sender, CDOLockChangeInfo lockChangeInfo); /** * @since 4.1 */ public CDOLockState[] getLockStates(Collection ids); - - // /** - // * Each time CDORevision or CDOState of an CDOObject is modified, ensure that no concurrent access is modifying it - // at - // * the same time. Uses {@link InternalCDOView#getStateLock()} to be thread safe. - // *

- // * In the case where {@link CDOObject#cdoRevision()} or {@link CDOObject#cdoState()} is called without using this - // * lock, it is not guarantee that the state didn't change immediately after. - // *

- // * - // * if (cdoObject.cdoState() != CDOState.PROXY) - // * { - // * // At this point could be a proxy! - // * cdoObject.cdoRevision(); - // * } - // * - // *

- // * The reason were we didn't use {@link CDOView#getLock()} is to not allow the access of that lock to the users - // since - // * it is very critical. Instead of giving this API to the end-users, a better API should be given in the CDOObject - // to - // * give them want they need. - // */ - // public ReentrantLock getStateLock(); - // - // /** - // * @since 4.0 - // */ - // public Object getObjectsLock(); } 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 846e9f3e35..89e6844b5c 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 @@ -40,6 +40,13 @@ public class RWOLockManager extends Lifecycle implements IRWOLo private final Map> objectToLockStateMap = createObjectToLocksMap(); + /** + * A mapping of contexts (owners of locks) to the lock states that they are involved in. Here, an 'involvement' means + * that the context owns at least one lock on the object that the lock state is for. To determine exactly what kind of + * lock, the lock state object obtained from this map must be queried. + *

+ * This map is a performance optimization to avoid having to scan all lock states. + */ private final Map>> contextToLockStates = createContextToLocksMap(); public void lock(LockType type, CONTEXT context, Collection objectsToLock, long timeout) @@ -73,7 +80,7 @@ public class RWOLockManager extends Lifecycle implements IRWOLo { LockState lockState = lockStates.get(i); lockState.lock(type, context); - addLockToContext(context, lockState); + addContextToLockStateMapping(context, lockState); } return lockStates; @@ -256,11 +263,31 @@ public class RWOLockManager extends Lifecycle implements IRWOLo return contextToLockStates; } - public LockState getLockState(Object key) + public LockState getLockState(OBJECT key) { return objectToLockStateMap.get(key); } + public synchronized void setLockState(OBJECT key, LockState lockState) + { + objectToLockStateMap.put(key, lockState); + + for (CONTEXT readLockOwner : lockState.getReadLockOwners()) + { + addContextToLockStateMapping(readLockOwner, lockState); + } + CONTEXT writeLockOwner = lockState.getWriteLockOwner(); + if (writeLockOwner != null) + { + addContextToLockStateMapping(writeLockOwner, lockState); + } + CONTEXT writeOptionOwner = lockState.getWriteOptionOwner(); + if (writeOptionOwner != null) + { + addContextToLockStateMapping(writeOptionOwner, lockState); + } + } + private LockState getOrCreateLockState(OBJECT o) { LockState lockState = objectToLockStateMap.get(o); @@ -292,7 +319,7 @@ public class RWOLockManager extends Lifecycle implements IRWOLo return true; } - private void addLockToContext(CONTEXT context, LockState lockState) + private void addContextToLockStateMapping(CONTEXT context, LockState lockState) { Set> lockStates = contextToLockStates.get(context); if (lockStates == null) diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/ExtendedIOUtil.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/ExtendedIOUtil.java index d069d31e98..59a99a3b02 100644 --- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/ExtendedIOUtil.java +++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/ExtendedIOUtil.java @@ -40,6 +40,10 @@ public final class ExtendedIOUtil private static final int MAX_UTF_CHARS = MAX_UTF_LENGTH / 3; + private static final int MAX_ENUM_LITERALS = Byte.MAX_VALUE - Byte.MIN_VALUE; + + private static final byte NO_ENUM_LITERAL = Byte.MIN_VALUE; + private ExtendedIOUtil() { } @@ -207,19 +211,16 @@ public final class ExtendedIOUtil */ public static void writeEnum(DataOutput out, Enum literal) throws IOException { - int ordinal = literal.ordinal(); - int size = literal.getDeclaringClass().getEnumConstants().length; - if (size <= Byte.MAX_VALUE) + if (literal == null) { - out.writeByte(ordinal); - } - else if (size <= Short.MAX_VALUE) - { - out.writeShort(ordinal); + out.writeByte(NO_ENUM_LITERAL); } else { - out.writeInt(ordinal); + getEnumLiterals(literal.getDeclaringClass()); // Check valid size + + int ordinal = literal.ordinal(); + out.writeByte(ordinal + Byte.MIN_VALUE + 1); } } @@ -228,23 +229,28 @@ public final class ExtendedIOUtil */ public static > T readEnum(DataInput in, Class type) throws IOException { - T[] literals = type.getEnumConstants(); - int size = literals.length; - int ordinal; - if (size <= Byte.MAX_VALUE) - { - ordinal = in.readByte(); - } - else if (size <= Short.MAX_VALUE) + T[] literals = getEnumLiterals(type); + + int ordinal = in.readByte(); + if (ordinal == NO_ENUM_LITERAL) { - ordinal = in.readShort(); + return null; } - else + + return literals[ordinal - Byte.MIN_VALUE - 1]; + } + + private static T[] getEnumLiterals(Class type) + { + T[] literals = type.getEnumConstants(); + + int size = literals.length; + if (size > MAX_ENUM_LITERALS) { - ordinal = in.readInt(); + throw new AssertionError("Enum too large: " + size + " literals"); } - return literals[ordinal]; + return literals; } /** diff --git a/plugins/org.gastro.server.web/src-gen/templates/MenuCardTemplate.java b/plugins/org.gastro.server.web/src-gen/templates/MenuCardTemplate.java index bab6834d67..1ddb695ad9 100644 --- a/plugins/org.gastro.server.web/src-gen/templates/MenuCardTemplate.java +++ b/plugins/org.gastro.server.web/src-gen/templates/MenuCardTemplate.java @@ -1,62 +1,62 @@ -package templates; - -import org.gastro.inventory.*; -import org.gastro.server.internal.web.*; - -public class MenuCardTemplate -{ - protected static String nl; - public static synchronized MenuCardTemplate create(String lineSeparator) - { - nl = lineSeparator; - MenuCardTemplate result = new MenuCardTemplate(); - nl = null; - return result; - } - - public final String NL = nl == null ? (System.getProperties().getProperty("line.separator")) : nl; - protected final String TEXT_1 = ""; - protected final String TEXT_2 = NL + NL + "" + NL + "

" + NL + "\t " + NL + "\t\t\t"; - protected final String TEXT_3 = NL + "\t " + NL + "\t\t" + NL + "\t
" + NL + "" + NL + "" + NL + "

"; - protected final String TEXT_4 = "

" + NL + ""; - protected final String TEXT_5 = NL + "\t" + NL + "\t" + NL + "\t"; - protected final String TEXT_8 = NL + "\t\t" + NL + "\t\t" + NL + "\t\t\t\t\t" + NL + "\t"; - protected final String TEXT_12 = NL + "

"; - protected final String TEXT_6 = "

"; - protected final String TEXT_7 = "

     

"; - protected final String TEXT_9 = "

     "; - protected final String TEXT_10 = ""; - protected final String TEXT_11 = "
" + NL + "" + NL + "" + NL + ""; - protected final String TEXT_13 = NL; - - public String generate(Object argument) - { - final StringBuffer stringBuffer = new StringBuffer(); - stringBuffer.append(TEXT_1); - MenuCard menuCard = (MenuCard)argument; - stringBuffer.append(TEXT_2); - stringBuffer.append(GastroServlet.html(menuCard.getTitle())); - stringBuffer.append(TEXT_3); - stringBuffer.append(GastroServlet.html(menuCard.getTitle())); - stringBuffer.append(TEXT_4); - for (Section section : menuCard.getSections()) { - stringBuffer.append(TEXT_5); - stringBuffer.append(GastroServlet.html(section.getTitle())); - stringBuffer.append(TEXT_6); - stringBuffer.append(GastroServlet.html(section.getText())); - stringBuffer.append(TEXT_7); - for (Offering offering : section.getOfferings()) { - stringBuffer.append(TEXT_8); - stringBuffer.append(GastroServlet.html(offering.getName())); - stringBuffer.append(TEXT_9); - stringBuffer.append(GastroServlet.html(offering.getDescription())); - stringBuffer.append(TEXT_10); - stringBuffer.append(GastroServlet.html(offering.getPrice())); - stringBuffer.append(TEXT_11); - } - } - stringBuffer.append(TEXT_12); - stringBuffer.append(TEXT_13); - return stringBuffer.toString(); - } -} +package templates; + +import org.gastro.inventory.*; +import org.gastro.server.internal.web.*; + +public class MenuCardTemplate +{ + protected static String nl; + public static synchronized MenuCardTemplate create(String lineSeparator) + { + nl = lineSeparator; + MenuCardTemplate result = new MenuCardTemplate(); + nl = null; + return result; + } + + public final String NL = nl == null ? (System.getProperties().getProperty("line.separator")) : nl; + protected final String TEXT_1 = ""; + protected final String TEXT_2 = NL + NL + "" + NL + "
" + NL + "\t " + NL + "\t\t\t"; + protected final String TEXT_3 = NL + "\t " + NL + "\t\t" + NL + "\t
" + NL + "" + NL + "" + NL + "

"; + protected final String TEXT_4 = "

" + NL + ""; + protected final String TEXT_5 = NL + "\t" + NL + "\t" + NL + "\t"; + protected final String TEXT_8 = NL + "\t\t" + NL + "\t\t" + NL + "\t\t\t\t\t" + NL + "\t"; + protected final String TEXT_12 = NL + "

"; + protected final String TEXT_6 = "

"; + protected final String TEXT_7 = "

     

"; + protected final String TEXT_9 = "

     "; + protected final String TEXT_10 = ""; + protected final String TEXT_11 = "
" + NL + "" + NL + "" + NL + ""; + protected final String TEXT_13 = NL; + + public String generate(Object argument) + { + final StringBuffer stringBuffer = new StringBuffer(); + stringBuffer.append(TEXT_1); + MenuCard menuCard = (MenuCard)argument; + stringBuffer.append(TEXT_2); + stringBuffer.append(GastroServlet.html(menuCard.getTitle())); + stringBuffer.append(TEXT_3); + stringBuffer.append(GastroServlet.html(menuCard.getTitle())); + stringBuffer.append(TEXT_4); + for (Section section : menuCard.getSections()) { + stringBuffer.append(TEXT_5); + stringBuffer.append(GastroServlet.html(section.getTitle())); + stringBuffer.append(TEXT_6); + stringBuffer.append(GastroServlet.html(section.getText())); + stringBuffer.append(TEXT_7); + for (Offering offering : section.getOfferings()) { + stringBuffer.append(TEXT_8); + stringBuffer.append(GastroServlet.html(offering.getName())); + stringBuffer.append(TEXT_9); + stringBuffer.append(GastroServlet.html(offering.getDescription())); + stringBuffer.append(TEXT_10); + stringBuffer.append(GastroServlet.html(offering.getPrice())); + stringBuffer.append(TEXT_11); + } + } + stringBuffer.append(TEXT_12); + stringBuffer.append(TEXT_13); + return stringBuffer.toString(); + } +} -- cgit v1.2.3