diff options
author | Caspar De Groot | 2011-09-01 07:52:03 +0000 |
---|---|---|
committer | Caspar De Groot | 2011-09-01 07:52:03 +0000 |
commit | d91b8908f8f2cfb84cb9ac258cf57c440970e739 (patch) | |
tree | 7e28c7ac6bbc9e69a2eeb75169783fe43d45d20d /plugins/org.eclipse.emf.cdo.server/src/org | |
parent | 06652cd713e41e414f12e8254b9a3716d825371b (diff) | |
download | cdo-d91b8908f8f2cfb84cb9ac258cf57c440970e739.tar.gz cdo-d91b8908f8f2cfb84cb9ac258cf57c440970e739.tar.xz cdo-d91b8908f8f2cfb84cb9ac258cf57c440970e739.zip |
[351912] Lock coordination with SynchronizableRepositories
https://bugs.eclipse.org/bugs/show_bug.cgi?id=351912
Diffstat (limited to 'plugins/org.eclipse.emf.cdo.server/src/org')
24 files changed, 629 insertions, 157 deletions
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<Object, IView> implements Intern private Map<String, InternalView> openViews = new HashMap<String, InternalView>(); + private Map<String, DurableView> durableViews = new HashMap<String, DurableView>(); + @ExcludeFromDump private transient IListener sessionListener = new ContainerEventAdapter<IView>() { @@ -112,7 +117,7 @@ public class LockManager extends RWOLockManager<Object, IView> implements Intern public synchronized Object getLockEntryObject(Object key) { LockState<Object, IView> 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<Object, IView> 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<Object, IView> 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<Object, IView> 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<Object> readLocks = new ArrayList<Object>(); Collection<Object> writeLocks = new ArrayList<Object>(); @@ -590,4 +657,45 @@ public class LockManager extends RWOLockManager<Object, IView> 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<Object> implements InternalRepository if (sessionManager != null) { - sessionManager.sendRepositoryStateNotification(oldState, newState); + sessionManager.sendRepositoryStateNotification(oldState, newState, getRootResourceID()); } } @@ -1147,6 +1147,11 @@ public class Repository extends Container<Object> implements InternalRepository { return toCommitTime; } + + public String[] getLockAreaIDs() + { + return null; // TODO (CD) + } }; } @@ -1157,6 +1162,8 @@ public class Repository extends Container<Object> 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<Object> implements InternalRepository } } - public LockObjectsResult lock(InternalView view, LockType lockType, List<CDORevisionKey> revisionKeys, - CDOBranch viewedBranch, long timeout) + public static List<Object> revisionKeysToObjects(List<CDORevisionKey> revisionKeys, CDOBranch viewedBranch, + boolean isSupportingBranches) { - List<Object> objectsToLock = new ArrayList<Object>(); - boolean isSupportingBranches = isSupportingBranches(); + List<Object> lockables = new ArrayList<Object>(); 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<LockState<Object, IView>> newLockStates = null; + public LockObjectsResult lock(InternalView view, LockType lockType, List<CDORevisionKey> revKeys, long timeout) + { + List<Object> lockables = revisionKeysToObjects(revKeys, view.getBranch(), isSupportingBranches()); + return lock(view, lockType, lockables, revKeys, timeout); + } + protected LockObjectsResult lock(InternalView view, LockType type, List<Object> lockables, + List<CDORevisionKey> loadedRevs, long timeout) + { + List<LockState<Object, IView>> 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<Object> implements InternalRepository throw WrappedException.wrap(ex); } - List<CDORevisionKey> staleRevisions = new LinkedList<CDORevisionKey>(); - 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<CDORevisionKey> revisionKeys, + List<Object> objectsToLock, LockType lockType, long[] requiredTimestamp) + { + List<CDORevisionKey> staleRevisions = new LinkedList<CDORevisionKey>(); + 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<Object> 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<Object> 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<LockState<Object, IView>> lockStates) + public static CDOLockState[] toCDOLockStates(List<LockState<Object, IView>> lockStates) { CDOLockState[] cdoLockStates = new CDOLockState[lockStates.size()]; int i = 0; for (LockState<Object, ? extends CDOCommonView> 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<Object> implements InternalRepository public UnlockObjectsResult unlock(InternalView view, LockType lockType, List<CDOID> objectIDs) { - List<Object> revisionKeys = null; + List<Object> unlockables = null; if (objectIDs != null) { - revisionKeys = new ArrayList<Object>(objectIDs.size()); + unlockables = new ArrayList<Object>(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<Object> unlockables) + { List<LockState<Object, IView>> 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<IView> 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<IView> 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<IView> 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<IView> 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<ISession> 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<ISession> 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<LockState<Object, IView>> 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,8 +66,15 @@ 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<Object> lockables = new LinkedList<Object>(); + + 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<CDORevisionKey> revisionKeys, - CDOBranch viewedBranch, long timeout) + public LockObjectsResult lock(InternalView view, LockType lockType, List<CDORevisionKey> 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<CDORevisionKey> revisionKeys, CDOBranch viewedBranch, long timeout) + private LockObjectsResult lockOnMaster(InternalView view, LockType type, List<CDORevisionKey> 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<CDORevisionKey> 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<CDOID> objectIDs) + private void unlockOnMaster(InternalView view, LockType lockType, List<CDOID> 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<CDOID> 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<CDOID, LockGrade> 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 @@ -112,6 +112,12 @@ public interface InternalLockManager extends IRWOLockManager<Object, IView>, 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 */ public IView openView(ISession session, int viewID, boolean readOnly, String durableLockingID); @@ -125,4 +131,9 @@ public interface InternalLockManager extends IRWOLockManager<Object, IView>, IDu * @since 4.1 */ public LockState<Object, IView> getLockState(Object key); + + /** + * @since 4.1 + */ + public void setLockState(Object key, LockState<Object, IView> 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<CDORevisionKey> revisionKeys, - CDOBranch viewedBranch, long timeout); + public LockObjectsResult lock(InternalView view, LockType lockType, List<CDORevisionKey> 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; + } +} |